diff --git a/.coveralls.yml b/.coveralls.yml index 1621caa9..30b618e3 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1,3 +1,2 @@ coverage_clover: build/logs/clover.xml json_path: build/logs/coveralls-upload.json -service_name: travis-ci diff --git a/.gitattributes b/.gitattributes index 05317e78..298934e4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,22 +2,27 @@ # Exclude these files from release archives. # This will also make them unavailable when using Composer with `--prefer-dist`. # If you develop for this repo using Composer, use `--prefer-source`. -# https://www.reddit.com/r/PHP/comments/2jzp6k/i_dont_need_your_tests_in_my_production +# https://www.reddit.com/r/PHP/comments/2jzp6k/i_dont_need_your_tests_in_my_production/ # https://blog.madewithlove.be/post/gitattributes/ # -/.coveralls.yml export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore -/.travis.yml export-ignore -/phpcs.xml.dist export-ignore -/phpdoc.xml.dist export-ignore -/phpunit.xml.dist export-ignore -/docs/ export-ignore -/Tests/ export-ignore +.coveralls.yml export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.markdownlint-cli2.yaml export-ignore +.remarkignore export-ignore +.remarkrc export-ignore +.yamllint.yml export-ignore +phpcs.xml.dist export-ignore +phpdoc.dist.xml export-ignore +phpdoc.xml.dist export-ignore +phpunit.xml.dist export-ignore +/.github/ export-ignore +/docs/ export-ignore +/Tests/ export-ignore # # Auto detect text files and perform LF normalization -# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ +# https://pablorsk.medium.com/be-a-git-ninja-the-gitattributes-file-e58c07c9e915 # * text=auto diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..fa4063ba --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,28 @@ +# Dependabot configuration. +# +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 5 # Set to 0 to (temporarily) disable. + versioning-strategy: widen + commit-message: + prefix: "Composer:" + include: "scope" + labels: + - "Type: chores/QA" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 5 + commit-message: + prefix: "GH Actions:" + labels: + - "Type: chores/QA" diff --git a/.github/release-checklist.md b/.github/release-checklist.md new file mode 100644 index 00000000..3fef8612 --- /dev/null +++ b/.github/release-checklist.md @@ -0,0 +1,43 @@ +# Template to use for release PRs from `develop` to `stable` + +PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH DAY YEAR**. + +## Release checklist + +### Update website + +- [ ] Regenerate the PHPDoc documentation - PR #xxx + :pencil2: Clear out the `docs/phpdoc` directory and then use phpDocumentor 3 with the command `phpdoc` +- [ ] Sync any changes in the Readme into the website `index.md` file. - PR #xxx + :pencil2: Copy & paste the content from the `README.md` file to `docs/index.md` (and double-check the few remaining differences are intact). + To verify the output locally: + ```bash + bundle update + bundle exec jekyll serve + ``` + and then visiting to see the result. + +### General + +- [ ] Verify, and if necessary, update the version constraints for dependencies in the `composer.json` - PR #xxx +- [ ] Verify that any new functions have type declarations whenever possible. +- [ ] Add changelog for the release - PR #xxx + :pencil2: Remember to add a release link at the bottom and to adjust the link for "Unreleased"! + +### Release + +- [ ] Merge this PR +- [ ] Make sure all CI builds are green. +- [ ] Verify that the website regenerated correctly. +- [ ] Tag the release (careful, GH defaults to `develop`!). +- [ ] Create a release from the tag (careful, GH defaults to `develop`!) & copy & paste the changelog to it. + :pencil2: Don't forget to copy the link collection from the bottom of the changelog! +- [ ] Close the milestone +- [ ] Open a new milestone for the next release +- [ ] If any open PRs/issues which were milestoned for this release did not make it into the release, update their milestone. +- [ ] Fast-forward `develop` to be equal to `stable` + +### Publicize + +- [ ] Tweet about the release. +- [ ] Inform the primary dependants of this repo (PHPCSExtra, WordPressCS, PHPCompatibility and VariableAnalysis) about the release. diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml new file mode 100644 index 00000000..69ac5f08 --- /dev/null +++ b/.github/workflows/basics.yml @@ -0,0 +1,186 @@ +name: CS + +on: + # Run on all pushes and on all pull requests. + # Prevent the build from running when there are only irrelevant changes. + push: + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + checkcs: + name: 'Basic CS and QA checks' + runs-on: ubuntu-latest + + env: + XMLLINT_INDENT: ' ' + # - COMPOSER_ROOT_VERSION is needed to get round the recursive dependency when using CI. + COMPOSER_ROOT_VERSION: '1.99.99' + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + coverage: none + tools: cs2pr + + # Validate the composer.json file. + # @link https://getcomposer.org/doc/03-cli.md#validate + - name: Validate Composer installation + run: composer validate --no-check-all --strict + + - name: 'Composer: adjust dependencies' + run: | + # The sniff stage doesn't run the unit tests, so no need for PHPUnit. + composer remove --no-update --dev phpunit/phpunit --no-scripts + # Using PHPCS `master` as an early detection system for bugs upstream. + composer require --no-update squizlabs/php_codesniffer:"dev-master" + + # Install dependencies and handle caching in one go. + # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer + - name: Install Composer dependencies + uses: "ramsey/composer-install@v2" + + - name: Install xmllint + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y libxml2-utils + + # Show XML violations inline in the file diff. + # @link https://github.com/marketplace/actions/xmllint-problem-matcher + - uses: korelstar/xmllint-problem-matcher@v1 + + # Validate the XML file. + # @link http://xmlsoft.org/xmllint.html + - name: Validate rulesets against schema + run: xmllint --noout --schema vendor/squizlabs/php_codesniffer/phpcs.xsd ./*/ruleset.xml + + # Check the code-style consistency of the XML file. + - name: Check XML code style + run: | + diff -B ./PHPCSUtils/ruleset.xml <(xmllint --format "./PHPCSUtils/ruleset.xml") + diff -B ./PHPCS23Utils/ruleset.xml <(xmllint --format "./PHPCS23Utils/ruleset.xml") + + # Check the code-style consistency of the PHP files. + - name: Check PHP code style + id: phpcs + run: vendor/bin/phpcs --report-full --report-checkstyle=./phpcs-report.xml + + - name: Show PHPCS results in PR + if: ${{ always() && steps.phpcs.outcome == 'failure' }} + run: cs2pr ./phpcs-report.xml + + markdownlint: + name: 'Lint Markdown' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # This action also handles the caching of the dependencies. + # https://github.com/actions/setup-node + - name: Set up node and enable caching of dependencies + uses: actions/setup-node@v3 + with: + node-version: '16' + + # @link https://github.com/DavidAnson/markdownlint-cli2 + # @link https://github.com/DavidAnson/markdownlint + - name: Install Markdownlint CLI2 + run: npm install -g markdownlint-cli2 + + # @link https://github.com/marketplace/actions/problem-matcher-for-markdownlint-cli + - name: Enable showing issue in PRs + uses: xt0rted/markdownlint-problem-matcher@v2 + + - name: Check markdown with CLI2 + run: markdownlint-cli2 + + remark: + name: 'QA Markdown' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up node and enable caching of dependencies + uses: actions/setup-node@v3 + with: + node-version: '16' + + # To make the command available on CLI, it needs to be installed globally. + - name: Install Remark CLI globally + run: npm install --global remark-cli --foreground-scripts true --fund false + + # To allow for creating a custom config which references rules which are included + # in the presets, without having to install all rules individually, a local install + # works best (and installing the presets in the first place, of course). + # + # Note: the first group of packages are all part of the mono "Remark lint" repo. + # The second group of packages (heading-whitespace and down) are additional + # "external" rules/plugins. + - name: Install Remark rules locally + run: > + npm install --foreground-scripts true --fund false + remark-lint + remark-gfm + remark-preset-lint-consistent + remark-preset-lint-recommended + remark-preset-lint-markdown-style-guide + remark-lint-checkbox-content-indent + remark-lint-linebreak-style + remark-lint-no-duplicate-defined-urls + remark-lint-no-empty-url + remark-lint-no-heading-like-paragraph + remark-lint-no-reference-like-url + remark-lint-no-unneeded-full-reference-image + remark-lint-no-unneeded-full-reference-link + remark-lint-strikethrough-marker + remark-lint-heading-whitespace + remark-lint-list-item-punctuation + remark-lint-match-punctuation + remark-lint-no-hr-after-heading + remark-lint-are-links-valid-alive + remark-lint-are-links-valid-duplicate + remark-validate-links + + - name: Run Remark-lint + run: remark . --frail + + # @link https://github.com/reviewdog/action-remark-lint + - name: Show Remark-lint annotations in PR + if: ${{ failure() && github.event_name == 'pull_request' }} + uses: reviewdog/action-remark-lint@v5 + with: + fail_on_error: true + install_deps: false + level: info + reporter: github-pr-check + + yamllint: + name: 'Lint Yaml' + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Run Yamllint on all yaml files in repo + run: yamllint . --format colored --strict + + - name: Pipe Yamllint results on to GH for inline display + if: ${{ failure() }} + run: yamllint . --format github --strict diff --git a/.github/workflows/ghpages.yml b/.github/workflows/ghpages.yml new file mode 100644 index 00000000..fa41daf9 --- /dev/null +++ b/.github/workflows/ghpages.yml @@ -0,0 +1,41 @@ +name: Docs + +on: + push: + paths: + - 'docs/**' + pull_request: + paths: + - 'docs/**' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + #### TEST DOCUMENTATION SITE GENERATION #### + test: + runs-on: ubuntu-latest + + name: "Test build GHPages site" + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + # Use the version as per https://pages.github.com/versions/ + ruby-version: 2.7.4 + bundler-cache: true + working-directory: docs + + - name: Test building the GH Pages site + run: | + cd docs + bundle exec jekyll build diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml new file mode 100644 index 00000000..56b3835b --- /dev/null +++ b/.github/workflows/quicktest.yml @@ -0,0 +1,85 @@ +name: Quicktest + +on: + # Run on pushes, including merges, to all branches except `stable` and `develop`. + push: + branches-ignore: + - stable + - develop + paths-ignore: + - '**.md' + - 'docs/**' + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + #### QUICK TEST STAGE #### + # This is a much quicker test which only runs the unit tests and linting against the low/high + # supported PHP/PHPCS combinations. + # These are basically the same builds as in the Test->Coverage workflow, but then without doing + # the code-coverage. + quicktest: + runs-on: ubuntu-latest + + env: + # - COMPOSER_ROOT_VERSION is needed to get round the recursive dependency when using CI. + COMPOSER_ROOT_VERSION: '1.99.99' + + strategy: + matrix: + php: ['5.4', 'latest'] + phpcs_version: ['3.7.1', 'dev-master'] + + name: "QTest${{ matrix.phpcs_version == 'dev-master' && ' + Lint' || '' }}: PHP ${{ matrix.php }} - PHPCS ${{ matrix.phpcs_version }}" + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # On stable PHPCS versions, allow for PHP deprecation notices. + # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. + - name: Setup ini config + id: set_ini + run: | + if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT + else + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT + fi + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-values: ${{ steps.set_ini.outputs.PHP_INI }} + coverage: none + + - name: 'Composer: set PHPCS version for tests' + run: composer require --no-update squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" + + # Install dependencies and handle caching in one go. + # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer + - name: Install Composer dependencies + uses: "ramsey/composer-install@v2" + + - name: Lint against parse errors + if: matrix.phpcs_version == 'dev-master' + run: composer lint + + - name: Run the unit tests without caching + run: vendor/bin/phpunit --no-coverage + env: + PHPCS_VERSION: ${{ matrix.phpcs_version }} + PHPCSUTILS_USE_CACHE: false + + - name: Run the unit tests with caching + run: vendor/bin/phpunit --testsuite PHPCSUtils --no-coverage --repeat 2 + env: + PHPCS_VERSION: ${{ matrix.phpcs_version }} + PHPCSUTILS_USE_CACHE: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..855c2167 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,341 @@ +name: Test + +on: + # Run on pushes to `stable` and `develop` and on all pull requests. + push: + branches: + - stable + - develop + paths-ignore: + - '**.md' + - 'docs/**' + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # - COMPOSER_ROOT_VERSION is needed to get round the recursive dependency when using CI. + COMPOSER_ROOT_VERSION: '1.99.99' + +jobs: + lint: + if: ${{ github.ref != 'refs/heads/develop' }} + runs-on: ubuntu-latest + + strategy: + matrix: + php: ['5.4', '7.0', '7.4', '8.0', '8.1', '8.2'] + + name: "Lint: PHP ${{ matrix.php }}" + + continue-on-error: ${{ matrix.php == '8.2' }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-file: 'development' + coverage: none + tools: cs2pr + + - name: Install Composer dependencies - normal + if: ${{ matrix.php < 8.2 }} + uses: "ramsey/composer-install@v2" + + # For the PHP "nightly", we need to install with ignore platform reqs as not all dependencies allow it yet. + - name: Install Composer dependencies - with ignore platform + if: ${{ matrix.php >= 8.2 }} + uses: "ramsey/composer-install@v2" + with: + composer-options: --ignore-platform-reqs + + - name: Lint against parse errors + run: composer lint -- --checkstyle | cs2pr + + + #### TEST STAGE #### + test: + if: ${{ github.ref != 'refs/heads/develop' }} + needs: lint + runs-on: ubuntu-latest + + strategy: + # Keys: + # - risky: Whether to run with tests which check for being in sync with PHPCS. + # - experimental: Whether the build is "allowed to fail". + matrix: + # The GHA matrix works different from Travis. + # You can define jobs here and then augment them with extra variables in `include`, + # as well as add extra jobs in `include`. + # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix + # + # IMPORTANT: test runs shouldn't fail because of PHPCS being incompatible with a PHP version. + # + # The matrix is set up so as not to duplicate the builds which are run for code coverage. + php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0'] + phpcs_version: ['3.7.1', 'dev-master'] + risky: [false] + experimental: [false] + + include: + - php: '5.6' + phpcs_version: '3.7.1' + risky: false + experimental: false + extensions: ':iconv' # Run with iconv disabled. + - php: '8.0' + phpcs_version: 'dev-master' + risky: false + experimental: false + extensions: ':iconv' # Run with iconv disabled. + + # Experimental builds. These are allowed to fail. + - php: '8.2' + phpcs_version: 'dev-master' + risky: false + experimental: true + + - php: '7.4' + phpcs_version: '4.0.x-dev' + risky: false + experimental: true + + # Run risky tests separately. + - php: '7.4' + phpcs_version: '4.0.x-dev' + risky: true + experimental: true + + - php: '5.4' + phpcs_version: '3.7.1' + risky: true + experimental: true + + - php: '5.4' + phpcs_version: 'dev-master' + risky: true + experimental: true + + - php: '8.1' + phpcs_version: '3.7.1' + risky: true + experimental: true + + - php: '8.1' + phpcs_version: 'dev-master' + risky: true + experimental: true + + name: "Test: PHP ${{ matrix.php }} - PHPCS ${{ matrix.phpcs_version }}${{ matrix.risky == true && ' (risky)' || '' }}" + + continue-on-error: ${{ matrix.experimental }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # On stable PHPCS versions, allow for PHP deprecation notices. + # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. + - name: Setup ini config + id: set_ini + run: | + if [[ "${{ matrix.phpcs_version }}" != "dev-master" && "${{ matrix.phpcs_version }}" != "4.0.x-dev" ]]; then + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT + else + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT + fi + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ matrix.extensions }} + ini-values: ${{ steps.set_ini.outputs.PHP_INI }} + coverage: none + + - name: 'Composer: set PHPCS version for tests' + run: composer require --no-update squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" + + # Remove PHPCSDevCS as it would (for now) prevent the tests from being able to run against PHPCS 4.x. + - name: 'Composer: remove PHPCSDevCS' + run: composer remove --dev --no-update phpcsstandards/phpcsdevcs + + # Install dependencies and handle caching in one go. + # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer + - name: Install Composer dependencies - normal + if: ${{ matrix.php < 8.2 }} + uses: "ramsey/composer-install@v2" + + # For the PHP "nightly", we need to install with ignore platform reqs as not all dependencies allow it yet. + - name: Install Composer dependencies - with ignore platform + if: ${{ matrix.php >= 8.2 }} + uses: "ramsey/composer-install@v2" + with: + composer-options: --ignore-platform-reqs + + - name: Run the unit tests without caching (non-risky) + if: ${{ matrix.risky == false }} + run: vendor/bin/phpunit --no-coverage + env: + PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }} + PHPCSUTILS_USE_CACHE: false + + - name: Run the unit tests with caching (non-risky) + if: ${{ matrix.risky == false }} + run: vendor/bin/phpunit --testsuite PHPCSUtils --no-coverage --repeat 2 + env: + PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }} + PHPCSUTILS_USE_CACHE: true + + # Only run the "compare with PHPCS" group against dev-master as it ensures that PHPCSUtils + # functionality is up to date with `dev-master`, so would quickly fail on older PHPCS. + - name: Run the unit tests (risky, comparewithPHPCS) + if: ${{ matrix.risky && matrix.phpcs_version == 'dev-master' }} + # "nothing" is excluded to force PHPUnit to ignore the settings in phpunit.xml.dist. + run: vendor/bin/phpunit --no-coverage --group compareWithPHPCS --exclude-group nothing + env: + PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }} + + # Run the "xtra" group against high and low PHPCS as these are tests safeguarding PHPCS itself. + - name: Run the unit tests (risky, xtra) + if: ${{ matrix.risky }} + # "nothing" is excluded to force PHPUnit to ignore the settings in phpunit.xml.dist. + run: vendor/bin/phpunit --no-coverage --group xtra --exclude-group nothing + env: + PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }} + + + #### CODE COVERAGE STAGE #### + # N.B.: Coverage is only checked on the lowest and highest stable PHP versions + # and a low/high of each major for PHPCS. + # These builds are left out off the "test" stage so as not to duplicate test runs. + coverage: + # No use running the coverage builds if there are failing test builds. + needs: test + # The default condition is success(), but this is false when one of the previous jobs is skipped + if: always() && (needs.test.result == 'success' || needs.test.result == 'skipped') + + runs-on: ubuntu-latest + + strategy: + matrix: + include: + - php: '8.1' + phpcs_version: 'dev-master' + - php: '8.1' + phpcs_version: '3.7.1' + extensions: ':iconv' # Run one build with iconv disabled. + - php: '5.4' + phpcs_version: 'dev-master' + - php: '5.4' + phpcs_version: '3.7.1' + + name: "Coverage: PHP ${{ matrix.php }} - PHPCS ${{ matrix.phpcs_version }}" + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + # On stable PHPCS versions, allow for PHP deprecation notices. + # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. + - name: Setup ini config + id: set_ini + run: | + if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT + else + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT + fi + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: ${{ matrix.extensions }} + ini-values: ${{ steps.set_ini.outputs.PHP_INI }} + coverage: xdebug + + - name: "DEBUG: Show version details" + run: php -v + + - name: 'Composer: adjust dependencies' + run: | + # Set a specific PHPCS version. + composer require --no-update squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-scripts + + - name: Install Composer dependencies + uses: "ramsey/composer-install@v2" + + - name: Grab PHPUnit version + id: phpunit_version + # yamllint disable-line rule:line-length + run: echo "VERSION=$(vendor/bin/phpunit --version | grep --only-matching --max-count=1 --extended-regexp '\b[0-9]+\.[0-9]+')" >> $GITHUB_OUTPUT + + - name: "DEBUG: Show grabbed version" + run: echo ${{ steps.phpunit_version.outputs.VERSION }} + + # PHPUnit 9.3 started using PHP-Parser for code coverage causing some of our coverage builds to fail. + # As of PHPUnit 9.3.4, a cache warming option is available. + # Using that option prevents issues with PHP-Parser backfilling PHP tokens when PHPCS does not (yet), + # which would otherwise cause tests to fail on tokens being available when they shouldn't be. + - name: "Warm the PHPUnit cache (PHPUnit 9.3+)" + if: ${{ steps.phpunit_version.outputs.VERSION >= '9.3' }} + run: vendor/bin/phpunit --coverage-cache ./build/phpunit-cache --warm-coverage-cache + + - name: "Run the unit tests without caching with code coverage (PHPUnit < 9.3)" + if: ${{ steps.phpunit_version.outputs.VERSION < '9.3' }} + run: vendor/bin/phpunit + env: + PHPCS_VERSION: ${{ matrix.phpcs_version }} + PHPCSUTILS_USE_CACHE: false + + - name: "Run the unit tests without caching with code coverage (PHPUnit 9.3+)" + if: ${{ steps.phpunit_version.outputs.VERSION >= '9.3' }} + run: vendor/bin/phpunit --coverage-cache ./build/phpunit-cache + env: + PHPCS_VERSION: ${{ matrix.phpcs_version }} + PHPCSUTILS_USE_CACHE: false + + # Uploading the results with PHP Coveralls v1 won't work from GH Actions, so switch the PHP version. + # Also PHP Coveralls itself (still) isn't fully compatible with PHP 8.0+. + - name: Switch to PHP 7.4 + if: ${{ success() && matrix.php != '7.4' }} + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + coverage: none + + - name: Install Coveralls + if: ${{ success() }} + run: composer require php-coveralls/php-coveralls:"^2.4.2" + + - name: Upload coverage results to Coveralls + if: ${{ success() }} + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: php-${{ matrix.php }}-phpcs-${{ matrix.phpcs_version }} + run: vendor/bin/php-coveralls -v -x build/logs/clover.xml + + coveralls-finish: + needs: coverage + if: always() && needs.coverage.result == 'success' + + runs-on: ubuntu-latest + + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true diff --git a/.github/workflows/update-phpcs-versionnr.yml b/.github/workflows/update-phpcs-versionnr.yml new file mode 100644 index 00000000..bbd9078e --- /dev/null +++ b/.github/workflows/update-phpcs-versionnr.yml @@ -0,0 +1,85 @@ +name: Update PHPCS version + +on: + # Run every day at 3:40. + schedule: + - cron: '40 3 * * *' + # And whenever this workflow is updated. + pull_request: + paths: + - '.github/workflows/update-phpcs-versionnr.yml' + # Also allow manually triggering the workflow. + workflow_dispatch: + +# Cancels all previous workflow runs for the same branch that have not yet completed. +concurrency: + # The concurrency group contains the workflow name and the branch name. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + phpcs-version-check: + name: "Check latest PHPCS version" + # Don't run the cron job on forks. + if: ${{ github.event_name != 'schedule' || github.repository == 'PHPCSStandards/PHPCSUtils' }} + + runs-on: ubuntu-latest + steps: + - name: Retrieve latest PHPCS release info + uses: octokit/request-action@v2.x + id: get_latest_release + with: + route: GET /repos/squizlabs/PHP_CodeSniffer/releases/latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "Debug info: Show API request failure status" + if: ${{ failure() }} + run: "echo No release found. Request failed with status ${{ steps.get_latest_release.outputs.status }}" + + - name: Grab latest tag name from API response + id: version + run: | + echo "TAG=${{ fromJson(steps.get_latest_release.outputs.data).tag_name }}" >> $GITHUB_OUTPUT + + - name: Show tag name found in API response + run: "echo latest release: ${{ steps.version.outputs.TAG }}" + + - name: Set branches to use + id: branches + run: | + echo "BASE=develop" >> $GITHUB_OUTPUT + echo "PR_BRANCH=feature/getversiontest-update-phpcs-version" >> $GITHUB_OUTPUT + + - name: Checkout code + uses: actions/checkout@v3 + with: + ref: ${{ steps.branches.outputs.BASE }} + + - name: Update the version constant in the test file + uses: jacobtomlinson/gha-find-replace@v2 + with: + find: "const DEVMASTER = '[^']+';" + replace: "const DEVMASTER = '${{ steps.version.outputs.TAG }}';" + include: "Tests/BackCompat/Helper/GetVersionTest.php" + regex: true + + - name: "Debug info: Show git status" + run: git status -vv --untracked=all + + - name: Create pull request + uses: peter-evans/create-pull-request@v4 + with: + base: ${{ steps.branches.outputs.BASE }} + branch: ${{ steps.branches.outputs.PR_BRANCH }} + delete-branch: true + commit-message: "GetVersionTest: update for release of PHPCS ${{ steps.version.outputs.TAG }}" + title: "GetVersionTest: update for release of PHPCS ${{ steps.version.outputs.TAG }}" + # yamllint disable rule:line-length + body: | + This PR is auto-generated by [create-pull-request](https://github.com/peter-evans/create-pull-request) using the [`update-phpcs-versionnr.yml` workflow](https://github.com/PHPCSStandards/PHPCSUtils/blob/develop/.github/workflows/update-phpcs-versionnr.yml). + # yamllint enable rule:line-length + labels: | + Type: chores/QA + reviewers: | + jrfnl diff --git a/.gitignore b/.gitignore index d1df7be2..634eb3fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ build/ +node_modules/ vendor/ /composer.lock /.phpcs.xml /phpcs.xml +/.phpdoc.xml /phpdoc.xml /phpunit.xml /.phpunit.result.cache diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 00000000..d5a5197c --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,110 @@ +# +# Configuration file for MarkdownLint-CLI2. +# +# Example file with all options: +# https://github.com/DavidAnson/markdownlint-cli2/blob/main/test/markdownlint-cli2-yaml-example/.markdownlint-cli2.yaml +# + +# Do not fix any fixable errors. +fix: false + +# Define glob expressions to use (only valid at root). +globs: + - "**/*.md" + - ".github/**/*.md" + +# Define glob expressions to ignore. +ignores: + - "docs/index.md" # This file is kept in sync with the README, so will inherit all changes. + - "node_modules/" + - "vendor/" + +# Disable inline config comments. +noInlineConfig: true + +# Disable progress on stdout (only valid at root). +noProgress: false + +# Adjust the configuration for some built-in rules. +# For full information on the options and defaults, see: +# https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml +config: + ###################### + # Disable a few rules. + ###################### + # MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines. + MD031: false + # MD032/blanks-around-lists - Lists should be surrounded by blank lines. + MD032: false + + ############################## + # Customize a few other rules. + ############################## + # MD003/heading-style/header-style - Heading style. + MD003: + # Heading style - Always use hashes. + style: "atx" + + # MD004/ul-style - Unordered list style. + MD004: + # List style - each level has a different, but consistent symbol. + style: "sublist" + + # MD007/ul-indent - Unordered list indentation. + MD007: + indent: 4 + # Whether to indent the first level of the list. + start_indented: false + + # MD012/no-multiple-blanks - Multiple consecutive blank lines. + MD012: + maximum: 2 + + # MD013/line-length - Line length. + MD013: + # Number of characters. No need for being too fussy. + line_length: 1000 + # Number of characters for headings. + heading_line_length: 100 + # Number of characters for code blocks. + code_block_line_length: 100 + # Stern length checking (applies to tables, code blocks etc which have their own max line length). + stern: true + + # MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content. + MD024: + # Only check sibling headings. + siblings_only: true + + # MD033/no-inline-html - Inline HTML. + MD033: + # Allowed elements. + allowed_elements: + - div + - details + - summary + - b + - code + + # MD044/proper-names - Proper names should have the correct capitalization. + MD044: + # List of proper names. + names: ["PHPCSUtils", "PHP", "PHP_CodeSniffer", "CodeSniffer", "PHPUnit"] + # Include code blocks. + code_blocks: false + + # MD046/code-block-style - Code block style + MD046: + style: "fenced" + + # MD048/code-fence-style - Code fence style + MD048: + style: "backtick" + + # MD049/emphasis-style - Emphasis style should be consistent + MD049: + style: "underscore" + + # MD050/strong-style - Strong style should be consistent + MD050: + style: "asterisk" diff --git a/phpdoc.dist.xml b/.phpdoc.xml.dist similarity index 54% rename from phpdoc.dist.xml rename to .phpdoc.xml.dist index f924abe8..9ec6fd20 100644 --- a/phpdoc.dist.xml +++ b/.phpdoc.xml.dist @@ -3,7 +3,7 @@ configVersion="3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://www.phpdoc.org" - xsi:noNamespaceSchemaLocation="https://docs.phpdoc.org/latest/phpdoc.xsd" + xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/phpDocumentor/phpDocumentor/master/data/xsd/phpdoc.xsd" > PHPCSUtils @@ -19,6 +19,15 @@ phpcsutils-autoload.php PHPCSUtils + + public + protected + + codeCoverageIgnore + phpcs + diff --git a/.remarkignore b/.remarkignore new file mode 100644 index 00000000..f24c3d74 --- /dev/null +++ b/.remarkignore @@ -0,0 +1,6 @@ +# Ignore rules for Remark. +# Docs: https://github.com/unifiedjs/unified-engine/blob/HEAD/doc/ignore.md + +/docs/index.md +/node_modules/ +/vendor/ diff --git a/.remarkrc b/.remarkrc new file mode 100644 index 00000000..83ab108b --- /dev/null +++ b/.remarkrc @@ -0,0 +1,36 @@ +{ + "plugins": [ + "remark-gfm", + ["remark-lint-checkbox-character-style", "consistent"], + ["remark-lint-checkbox-content-indent", "consistent"], + "remark-lint-definition-spacing", + "remark-lint-file-extension", + ["remark-lint-linebreak-style", "unix"], + ["remark-lint-link-title-style", "\""], + ["remark-lint-ordered-list-marker-style", "."], + "remark-lint-no-duplicate-defined-urls", + "remark-lint-no-duplicate-definitions", + "remark-lint-no-empty-url", + "remark-lint-no-file-name-consecutive-dashes", + "remark-lint-no-file-name-irregular-characters", + "remark-lint-no-file-name-outer-dashes", + "remark-lint-no-heading-like-paragraph", + "remark-lint-no-literal-urls", + "remark-lint-no-reference-like-url", + "remark-lint-no-shortcut-reference-image", + "remark-lint-no-table-indentation", + "remark-lint-no-undefined-references", + "remark-lint-no-unneeded-full-reference-image", + "remark-lint-no-unneeded-full-reference-link", + "remark-lint-no-unused-definitions", + ["remark-lint-strikethrough-marker", "~~"], + ["remark-lint-table-cell-padding", "consistent"], + "remark-lint-heading-whitespace", + "remark-lint-list-item-punctuation", + "remark-lint-match-punctuation", + "remark-lint-no-hr-after-heading", + "remark-lint-are-links-valid-alive", + "remark-lint-are-links-valid-duplicate", + "remark-validate-links" + ] +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c03a7706..00000000 --- a/.travis.yml +++ /dev/null @@ -1,225 +0,0 @@ -os: linux -dist: trusty - -language: php - -## Cache composer and apt downloads. -cache: - apt: true - directories: - # Cache directory for older Composer versions. - - $HOME/.composer/cache/files - # Cache directory for more recent Composer versions. - - $HOME/.cache/composer/files - - /home/travis/.rvm/ - -php: - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - 7.2 - -env: - - PHPCS_VERSION="dev-master" LINT=1 - - PHPCS_VERSION="3.1.0" - - PHPCS_VERSION="2.9.2" - - PHPCS_VERSION="2.6.0" - -# Define the stages used. -# For non-PRs, only the sniff and quicktest stages are run. -# For pull requests and merges, the full script is run (skipping quicktest). -# Note: for pull requests, "develop" is the base branch name. -# See: https://docs.travis-ci.com/user/conditions-v1 -stages: - - name: sniff - - name: docs - if: branch IN (master) - - name: quicktest - if: type = push AND branch NOT IN (master, develop) - - name: test - if: branch IN (master, develop) - - name: coverage - if: branch IN (master, develop) - -jobs: - fast_finish: true - include: - #### SNIFF STAGE #### - - stage: sniff - php: 7.4 - env: PHPCS_VERSION="dev-master" - addons: - apt: - packages: - - libxml2-utils - install: skip - script: - # Validate the composer.json file. - # @link https://getcomposer.org/doc/03-cli.md#validate - - composer validate --no-check-all --strict - - # Check the code style of the code base. - - composer travis-checkcs - - # Validate the xml files. - # @link http://xmlsoft.org/xmllint.html - - xmllint --noout --schema ./vendor/squizlabs/php_codesniffer/phpcs.xsd ./PHPCSUtils/ruleset.xml - - xmllint --noout --schema ./vendor/squizlabs/php_codesniffer/phpcs.xsd ./PHPCS23Utils/ruleset.xml - - # Check the code-style consistency of the xml files. - - diff -B ./PHPCSUtils/ruleset.xml <(xmllint --format "./PHPCSUtils/ruleset.xml") - - diff -B ./PHPCS23Utils/ruleset.xml <(xmllint --format "./PHPCS23Utils/ruleset.xml") - after_success: skip - - #### DOCUMENTATION SITE TESTING STAGE #### - - stage: docs - language: ruby - cache: bundler - rvm: 2.5.8 - before_install: skip - install: - - cd ./docs - - gem install bundler - - bundle install - before_script: skip - script: - # Test the documentation generation. - - bundle exec jekyll build - after_success: skip - - #### QUICK TEST STAGE #### - # This is a much quicker test which only runs the unit tests and linting against the low/high - # supported PHP/PHPCS combinations. - # These are basically the same builds as in the Coverage stage, but then without doing - # the code-coverage. - - stage: quicktest - php: 7.4 - env: PHPCS_VERSION="dev-master" LINT=1 - - stage: quicktest - php: 7.3 - # PHPCS is only compatible with PHP 7.3 as of version 3.3.1/2.9.2. - env: PHPCS_VERSION="2.9.2" - - - stage: quicktest - php: 5.4 - env: PHPCS_VERSION="dev-master" LINT=1 - - stage: quicktest - php: 5.4 - env: PHPCS_VERSION="2.6.0" - - #### TEST STAGE #### - # Additional builds to prevent issues with PHPCS versions incompatible with certain PHP versions. - - stage: test - php: 7.3 - env: PHPCS_VERSION="dev-master" LINT=1 - - php: 7.3 - # PHPCS is only compatible with PHP 7.3 as of version 3.3.1/2.9.2. - env: PHPCS_VERSION="3.3.1" - - - php: 5.4 - env: PHPCS_VERSION="3.1.0" - - php: 5.4 - env: PHPCS_VERSION="2.9.2" - - # PHPCS is only compatible with PHP 7.4 as of version 3.5.0. - - php: 7.4 - env: PHPCS_VERSION="3.5.0" - - # One extra build to verify issues around PHPCS annotations when they weren't fully accounted for yet. - - php: 7.2 - env: PHPCS_VERSION="3.2.0" - - - php: 7.4 - env: PHPCS_VERSION="4.0.x-dev@dev" - - - php: "nightly" - env: PHPCS_VERSION="n/a" LINT=1 - - #### CODE COVERAGE STAGE #### - # N.B.: Coverage is only checked on the lowest and highest stable PHP versions for all PHPCS versions. - # These builds are left out off the "test" stage so as not to duplicate test runs. - # The script used is the default script below, the same as for the `test` stage. - - stage: coverage - php: 7.4 - env: PHPCS_VERSION="dev-master" LINT=1 COVERALLS_VERSION="^2.0" - - php: 7.3 - # PHPCS is only compatible with PHP 7.3 as of version 3.3.1/2.9.2. - env: PHPCS_VERSION="2.9.2" COVERALLS_VERSION="^2.0" - - - php: 5.4 - env: PHPCS_VERSION="dev-master" LINT=1 COVERALLS_VERSION="^1.0" - - php: 5.4 - env: PHPCS_VERSION="2.6.0" COVERALLS_VERSION="^1.0" - - - allow_failures: - # Allow failures for unstable builds. - - php: "nightly" - - env: PHPCS_VERSION="4.0.x-dev@dev" - - -before_install: - # Speed up build time by disabling Xdebug when its not needed. - - | - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" != "Coverage" ]]; then - phpenv config-rm xdebug.ini || echo 'No xdebug config.' - fi - - # On stable PHPCS versions, allow for PHP deprecation notices. - # Unit tests don't need to fail on those for stable releases where those issues won't get fixed anymore. - - | - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" != "Sniff" && $PHPCS_VERSION != "dev-master" && "$PHPCS_VERSION" != "n/a" ]]; then - echo 'error_reporting = E_ALL & ~E_DEPRECATED' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - fi - - - export XMLLINT_INDENT=" " - - -install: - # Set up test environment using Composer. - - | - if [[ $PHPCS_VERSION != "n/a" ]]; then - composer require --no-update --no-scripts squizlabs/php_codesniffer:${PHPCS_VERSION} - fi - - | - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" ]]; then - composer require --dev --no-update --no-suggest --no-scripts php-coveralls/php-coveralls:${COVERALLS_VERSION} - fi - - | - if [[ $PHPCS_VERSION == "n/a" ]]; then - # Don't install PHPUnit when it's not needed. - composer remove --dev phpunit/phpunit --no-update --no-scripts - fi - - # --prefer-dist will allow for optimal use of the travis caching ability. - # The Composer PHPCS plugin takes care of setting the installed_paths for PHPCS. - - composer install --prefer-dist --no-suggest - - -before_script: - - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" ]]; then mkdir -p build/logs; fi - - phpenv rehash - - -script: - # Lint PHP files against parse errors. - - if [[ "$LINT" == "1" ]]; then composer lint; fi - - # Run the unit tests. - - | - if [[ $PHPCS_VERSION != "n/a" && "${TRAVIS_BUILD_STAGE_NAME^}" != "Coverage" ]]; then - composer test - elif [[ $PHPCS_VERSION != "n/a" && "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" ]]; then - composer coverage - fi - -after_success: - - | - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" && $COVERALLS_VERSION == "^1.0" ]]; then - php vendor/bin/coveralls -v -x build/logs/clover.xml - fi - - | - if [[ "${TRAVIS_BUILD_STAGE_NAME^}" == "Coverage" && $COVERALLS_VERSION == "^2.0" ]]; then - php vendor/bin/php-coveralls -v -x build/logs/clover.xml - fi diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 00000000..fe521ad6 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,22 @@ +# Details on the default config: +# https://yamllint.readthedocs.io/en/stable/configuration.html#default-configuration +extends: default + +yaml-files: + - '*.yaml' + - '*.yml' + - '.yamllint' + +# Rule documentation: https://yamllint.readthedocs.io/en/stable/rules.html +rules: + colons: + max-spaces-after: -1 # Disabled to allow aligning of values. + comments: + min-spaces-from-content: 1 + comments-indentation: {} + document-start: + present: false + line-length: + max: 140 + truthy: + allowed-values: ["true", "false", "on", "off"] diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3fa08d..90f3d71f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ -# Change Log for PHPCSUtils for PHP Codesniffer +# Change Log for PHPCSUtils for PHP CodeSniffer All notable changes to this project will be documented in this file. -This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses [Semantic Versioning](http://semver.org/). +This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and uses [Semantic Versioning](https://semver.org/). ## [Unreleased] @@ -10,9 +10,392 @@ This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses _Nothing yet._ +## [1.0.0-alpha4] - 2022-10-25 + +Notes: +* While still in alpha, some BC-breaks may be introduced. These are clearly indicated in the changelog with the :warning: symbol. +* Until PHPCS 4.x has been released, PHPCSUtils does not formally support it, though an effort is made to keep up with the changes and anticipate potential compatibility issues. + For testing purposes only, the composer configuration allows for PHPCSUtils to be installed with PHPCS 4.x. + +### Breaking Changes + +Support for PHP_CodeSniffer < 3.7.1 has been dropped after consultation with the principle external standards which depend on PHPCSUtils. [#347] + +This was unfortunately necessary as the incessant additions of new syntaxes since PHP 7.4 made it impossible to continue to support PHPCS < 3.7.1, while still providing reliable results for modern PHP code. + +### Added + +Now support for PHPCS < 3.7.1 has been dropped, this edition adds support to all functionality in PHPCSUtils for new syntaxes and features from PHP 8.0 and 8.1 and preliminary support for PHP 8.2. + +This means that support for the following syntaxes/features has been added (or existing support verified/improved): +* PHP 7.4 + - Array unpacking in array expressions. +* PHP 8.0 + - The `mixed` type. [#163] + - Union types, including supporting the `false` and `null` types. [#168], [#225] + - Constructor property promotion. [#169], [#226] + - Nullsafe object operators. [#176], [#183] + - Namespaced names as single token (cross-version PHPCS 3.x vs 4.x). [#205], [#206], [#207], [#208], [#209], [#210], [#211], [#212], [#213], [#217], [#241] + - Dereferencing of interpolated text strings. + - Named arguments in function calls. [#235], [#243], [#383] + - Match expressions. [#247], [#335], [#356] + - Trailing commas in parameter lists and closure `use` lists. + - Attributes. [#357] +* PHP 8.1 + - Enumerations. [#285], [#358] + - Explicit octal notation. [#293] + - Array unpacking with string keys. + - `never` type. + - Named parameters after argument unpacking. + - First class callables. [#362] + - Readonly properties. [#363] + - `new` in initializers. + - Intersection types. [#365] +* PHP 8.2 + - Constants in traits. [#366] + - Readonly classes. [#367] + - `true` type. [#368] + - `null` and `false` as stand-alone types. + +Please report any bugs/oversights you encounter! + +#### PHPCS Backcompat + +* `BCTokens::magicConstants()` as introduced in PHPCS 3.5.6. [#172] + The same token array previously already existed in PHPCSUtils as `Collections::$magicConstants` (which has now been deprecated). + +#### TestUtils + +* New [`UtilityMethodTestCase::usesPhp8NameTokens()`][UtilityMethodTestCase::usesPhp8NameTokens] method as a helper for tests using token position calculations when testing against both PHPCS 3.x as well as 4.x. [#200], [#217], [#241] + +#### Tokens + +* New [`PHPCSUtils\Tokens\TokenHelper`][`TokenHelper`] class: Utility functions for working with tokens and token collections. [#304] + This class initially contains a `tokenExists()` method to work around potential interference from PHP-Parser also backfilling tokens. + :point_right: External standards using a function call to `defined()` to determine whether a token is available should replace those with a function call to the `TokenHelper::tokenExists()` method. +* New [`Collections::arrayOpenTokensBC()`][`Collections`] method. [#233], [#311] +* New [`Collections::functionCallTokens()`][`Collections`] method to retrieve the tokens which can represent function calls and function-call-like language constructs, like class instantiations. [#233] +* New [`Collections::nameTokens()`][`Collections`] method to retrieve the tokens which can be used for "names", be it namespace, OO, function or constant names. [#204], [#217] +* New [`Collections::namespacedNameTokens()`][`Collections`] method to retrieve the tokens which can be encountered in a fully, partially or unqualified name and in namespace relative names. [#202], [#217] +* New [`Collections::parameterPassingTokens()`][`Collections`] method to retrieve the tokens which can be passed to the methods in the [`PassedParameters`] class. [#233] +* New [`Collections::phpOpenTags()`][`Collections`] method. [#254] +* New [`Collections::shortArrayListOpenTokensBC()`][`Collections`] method. [#381] + +#### Utils + +* New [`PHPCSUtils\Utils\Context`][`Context`] class: Utility functions to determine the context in which an arbitrary token is used. [#219]. [#390] + Initial set of available methods: `inEmpty()`, `inIsset()`, `inUnset()`, `inAttribute`, `inForeachCondition()` and `inForCondition()`. +* New [`PHPCSUtils\Utils\MessageHelper`][`MessageHelper`] class: Utility functions for creating error/warning messages. [#249], [#391] + Initial set of available methods: `addMessage()`, `addFixableMessage()`, `stringToErrorcode()` and `showEscapeChars()`. +* New [`PHPCSUtils\Utils\PassedParameters::getParameterFromStack()`][PassedParameters::getParameterFromStack] efficiency method to retrieve a potentially named function call parameter from a parameter information stack as previously retrieved via `PassedParameters::getParameters()`. [#235], [#237], [#383] +* New [`PHPCSUtils\Utils\TextStrings::getEndOfCompleteTextString()`][TextStrings::getEndOfCompleteTextString] method. [#320] + This method allows to retrieve the stack pointer to the last token within a - potentially multi-line - text string. + This method compliments the `TextStrings::getCompleteTextString()` method which will retrieve the contents of the complete text string. +* New [`PHPCSUtils\Utils\TextStrings::getEmbeds()`][TextStrings::getEmbeds] method to retrieve an array with all variables/expressions as embedded in a text string. [#321] +* New [`PHPCSUtils\Utils\TextStrings::stripEmbeds()`][TextStrings::stripEmbeds] method to strip all embedded variables/expressions from a text string. [#321] +* New [`PHPCSUtils\Utils\TextStrings::getStripEmbeds()`][TextStrings::getStripEmbeds] method. [#321] + This method is `public` for those rare cases where both the embeds, as well as the text stripped off embeds, is needed. +* New [`PHPCSUtils\Utils\UseStatements::mergeImportUseStatements()`][UseStatements::mergeImportUseStatements] method. [#196] + +#### Other + +* PHPCSUtils will now cache the results of (potentially) token walking intensive or processing intensive function calls during a run. [#332], [#377] + This should significantly improve performance when multiple sniffs call these functions for the same token during a PHPCS run. + The results of the following functions will now be cached: + - `Arrays::getDoubleArrowPtr()` + - `Arrays::isShortArray()` + - `FunctionDeclarations::getParameters()` + - `Lists::getAssignments()` + - `Lists::isShortList()` + - `Namespaces::findNamespacePtr()` + - `PassedParameters::getParameters()` + - `TextStrings::getEndOfCompleteTextString()` + - `TextStrings::getStripEmbeds()` + - `UseStatements::splitImportUseStatement()` + +### Changed + +#### PHPCS Backcompat + +* All token array methods in the [`BCTokens`] class are fully up-to-date with the upstream `PHP_CodeSniffer\Util\Tokens` properties as per PHPCS `master` at the time of this release. [#327], [#347], [#360] +* All methods in the [`BCFile`] class are fully up-to-date with the upstream `PHP_CodeSniffer\Files\File` methods as per PHPCS `master` at the time of this release. [#347] +* `BCFile::getMethodParameters()`: forward compatibility with PHPCS 4.x in which closure `use` will be a parenthesis owner. [#251] +* If a non-existent token array is requested from the `BCTokens` class, a `PHPCSUtils\Exceptions\InvalidTokenArray` exception will be thrown. [#344] + The `PHPCSUtils\Exceptions\InvalidTokenArray` exception extends the PHPCS native `PHP_CodeSniffer\Exceptions\RuntimeException`. + Previously, an empty array would be returned. + +#### TestUtils + +* `UtilityMethodTestCase`: all properties contained in the test case class will now always be reset after the tests have run. [#325] +* `UtilityMethodTestCase::getTargetToken()`: when the target token cannot be found, the method will now throw a (catchable) `PHPCSUtils\Exceptions\TestTargetNotFound` exception instead of failing the test. [#248], [#371] + If uncaught, this means that the test will be marked as _errored_ instead of _failed_. +* `UtilityMethodTestCase::getTargetToken()`: this method is now `static`, which allows for it to be used in "set up before class" fixtures. [#382]. [#385] + +#### Tokens + +* `Collections::functionCallTokens()` and `Collections::parameterPassingTokens()`: now include the `T_PARENT` token. [#328] + This accounts for a change in PHPCS 3.7.0 for how `parent` in `new parent` is tokenized. +* If a non-existent token array is requested from the `Collections` class, a `PHPCSUtils\Exceptions\InvalidTokenArray` exception will be thrown. [#349] + The `PHPCSUtils\Exceptions\InvalidTokenArray` exception extends the PHPCS native `PHP_CodeSniffer\Exceptions\RuntimeException`. + +#### Utils + +* `Arrays::isShortArray()`/`Lists::isShortList()`: the underlying logic has been completely refactored for improved accuracy and improved performance. [#392] +* `FunctionDeclarations::getParameters()`: the return array of the method may contain two new keys - `property_visibility` and `visibility_token`. [#169] + These keys will only be included if constructor property promotion is detected. +* `FunctionDeclarations::getParameters()`: forward compatibility with PHPCS 4.x in which closure `use` will be a parenthesis owner. [#251] +* [`GetTokensAsString`]: previously the `tabReplaced()` method was an alias for the `normal()` method. This has now been reversed. [#297] +* `Operators::isReference()`: forward compatibility with PHPCS 4.x in which closure `use` will be a parenthesis owner. [#195] +* [`Parentheses`]: all methods will now recognize `isset()`, `unset()`, `empty()`, `exit()`, `die()` and `eval()` as parentheses owners. [#215] + Note: PHPCS natively does not recognize these constructs as parentheses owners, though this _may_ change in the future. See: [PHPCS#3118] +* [`PassedParameters`]: all methods will now recognize anonymous class instantiations as constructs which can pass parameters. [#234] +* `PassedParameters::getParameters()`: when a named parameter is encountered in a function call, the returned parameter information array for that parameter will now contain the following additional keys: `'name'`, `'name_token'` and the top-level index for the parameter will be set to the parameter `'name'` instead of its position. [#235], [#243], [#383] + The existing `'start'`, `'end'`, `'raw'` and `'clean'` keys will contain the same content as before: the information about the parameter value (excluding the name part). +* `PassedParameters::getParameters()`: new, optional parameter `$limit` to allow for limiting the number of parameters/array items to be parsed. [#261] + This allows for higher efficiency when retrieving the parameters/array entries, especially for large arrays if only the first few entries need to be examined. + Use with care on function calls, as this can break support for named parameters! +* `PassedParameters::getParameters()`: new, optional parameter `$isShortArray` to allow for skipping the "is short array" check for predetermined short arrays. [#269], [#270] + Use judiciously and with extreme care! +* `PassedParameters::getParameter()`: new _semi-optional_ `$paramNames` parameter to allow for retrieving a parameter from a function call using named parameters. [#235] + :warning: This parameter is **_required_** when examining a function call and an exception will be thrown if it was not passed. + This new `$paramNames` parameter allows for passing either the parameter name as a _string_ or as an _array of strings_. + _While a parameter can only have one name, a lot of packages have been, and may still be, reviewing and renaming parameters to more descriptive names to support named parameters in PHP 8.0, so, to allow for supporting multiple versions of packages, different names can be used for the same parameter in a PHP 8.0+ function call and by allowing multiple names to be passed, the method supports this._ +* `PassedParameters::getParameter()`: efficiency improvement applicable to function calls not using named parameters and arrays. [#261], [#262] +* `PassedParameters::hasParameters()`: now allows for the `T_PARENT` token for `new parent()` class instantiations. [#328] + This accounts for a change in PHPCS 3.7.0 regarding how `parent` in `new parent` is tokenized. +* `PassedParameters::hasParameters()`: new, optional parameter `$isShortArray` to allow for skipping the "is short array" check for predetermined short arrays. [#269], [#270] + Use judiciously and with extreme care! +* `UseStatements::getType()`: forward compatibility with PHPCS 4.x in which closure `use` will be a parenthesis owner. [#251] + +#### Other + +* The `master` branch has been renamed to `stable`. [#397] +* :warning: All non-`abstract` classes in this package are now `final`. [#376] +* The parameter names in various function declarations have been changed to not intersect with reserved keywords. [#256] + :warning: In the unlikely event an external standard using PHPCSUtils would be using function calls with named parameters, the parameter names will need to be updated to match. +* Composer: The package will now identify itself as a static analysis tool. Thanks [@GaryJones]! [#341] +* Readme/website homepage: the installation instructions have been updated to include information on installing this library and the included [Composer PHPCS plugin] in combination with Composer >= 2.2. [#291], [#292] +* Various documentation improvements. [#216], [#309], [#394], [#395], [#396], [#398] +* Various housekeeping and CI maintainance. + Amongst other things, CI is now run via GitHub Actions ([#239]), the PHPCSUtils native tests now use the [PHPUnit Polyfills] package ([#277]) and the tests are now run against PHP 5.4 - 8.2. + +### Deprecated + +:warning: Everything which has currently been deprecated, will be removed before the final `1.0.0` version of PHPCSUtils is tagged. + +#### Tokens + +[`Collections`] class: direct access to the properties in the class is now deprecated for forward-compatibility reasons. +All properties have a replacement which should be used instead, in most cases this will be a method with the same name as the previously used property, + +| Deprecated | Replacement | PR | Remarks | +|---------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------|------------------------------------------| +| `Collections::$alternativeControlStructureSyntaxTokens` | `Collections::alternativeControlStructureSyntaxes()` | [#311] | Mind the change name! | +| `Collections::$alternativeControlStructureSyntaxCloserTokens` | `Collections::alternativeControlStructureSyntaxClosers()` | [#311] | Mind the change name! | +| `Collections::$arrayTokens` | `Collections::arrayTokens()` | [#311] | | +| `Collections::$arrayTokensBC` | `Collections::arrayTokensBC()` | [#311] | | +| `Collections::$classModifierKeywords` | `Collections::classModifierKeywords()` | [#311] | | +| `Collections::$closedScopes` | `Collections::closedScopes()` | [#311] | | +| `Collections::$controlStructureTokens` | `Collections::controlStructureTokens()` | [#311] | | +| `Collections::$incrementDecrementOperators` | `Collections::incrementDecrementOperators()` | [#311] | | +| `Collections::$listTokens` | `Collections::listTokens()` | [#311] | | +| `Collections::$listTokensBC` | `Collections::listTokensBC()` | [#311] | | +| `Collections::$magicConstants` | `PHPCSUtils\BackCompat\BCTokens::magicConstants()` or `PHP_CodeSniffer\Util\Tokens::$magicConstants` | [#311] | | +| `Collections::$namespaceDeclarationClosers` | `Collections::namespaceDeclarationClosers()` | [#311] | | +| `Collections::$objectOperators` | `Collections::objectOperators()` | [#176] | | +| `Collections::$OOCanImplement` | `Collections::ooCanImplement()` | [#311] | Mind the case change in the `oo` prefix! | +| `Collections::$OOCanExtend` | `Collections::ooCanExtend()` | [#311] | Mind the case change in the `oo` prefix! | +| `Collections::$OOConstantScopes` | `Collections::ooConstantScopes()` | [#311] | Mind the case change in the `oo` prefix! | +| `Collections::$OOPropertyScopes` | `Collections::ooPropertyScopes()` | [#311] | Mind the case change in the `oo` prefix! | +| `Collections::$OOHierarchyKeywords` | `Collections::ooHierarchyKeywords()` | [#311] | Mind the case change in the `oo` prefix! | +| `Collections::$OONameTokens` | `Collections::namespacedNameTokens()` | [#202] | Mind the change name! | +| `Collections::$parameterTypeTokens` | `Collections::parameterTypeTokens()` | [#168] | | +| `Collections::$propertyModifierKeywords` | `Collections::propertyModifierKeywords()` | [#311] | | +| `Collections::$propertyTypeTokens` | `Collections::propertyTypeTokens()` | [#168] | | +| `Collections::$returnTypeTokens` | `Collections::returnTypeTokens()` | [#168] | | +| `Collections::$shortArrayTokens` | `Collections::shortArrayTokens()` | [#311] | | +| `Collections::$shortArrayTokensBC` | `Collections::shortArrayTokensBC()` | [#311] | | +| `Collections::$shortListTokens` | `Collections::shortListTokens()` | [#311] | | +| `Collections::$shortListTokensBC` | `Collections::shortListTokensBC()` | [#311] | | +| `Collections::$textStingStartTokens` | `Collections::textStringStartTokens()` | [#311], [#319] | Mind the fixed typo in the name! | + +Additionally, the following methods in the `Collections` class have been deprecated: + +| Deprecated | Replacement | PR | +|----------------------------------------------|--------------------------------------------|--------| +| `Collections::arrowFunctionTokensBC()` | Use the `T_FN` token instead. | [#347] | +| `Collections::functionDeclarationTokensBC()` | `Collections::functionDeclarationTokens()` | [#347] | +| `Collections::parameterTypeTokensBC()` | `Collections::parameterTypeTokens()` | [#347] | +| `Collections::propertyTypeTokensBC()` | `Collections::propertyTypeTokens()` | [#347] | +| `Collections::returnTypeTokensBC()` | `Collections::returnTypeTokens()` | [#347] | + +#### Utils + +* `ControlStructures::getDeclareScopeOpenClose()`: this method is no longer needed, check the `scope_opener`/`scope_closer` on the `T_DECLARE` token instead. [#347] +* `FunctionDeclarations::getArrowFunctionOpenClose()`: this method is no longer needed, check the `scope_opener`/`scope_closer` etc on the `T_FN` token instead. [#347] +* `FunctionDeclarations::isArrowFunction()`: this method is no longer needed, use the `T_FN` token instead. [#347] + +### Removed + +* Support for PHPCS < 3.7.1. [#347] + +#### Utils + +* The following constants, which were only intended for internal use, have been removed: [#347] + - `PHPCSUtils\Utils\Numbers::REGEX_NUMLIT_STRING` + - `PHPCSUtils\Utils\Numbers::REGEX_HEX_NUMLIT_STRING` + - `PHPCSUtils\Utils\Numbers::UNSUPPORTED_PHPCS_VERSION` + +### Fixed + +#### Abstract Sniffs + +* `AbstractArrayDeclarationSniff::getActualArrayKey()`: will now handle escaped vars in heredoc array keys better. [#379] + +#### Fixers + +* [`SpacesFixer`]: in a specific new line vs trailing comment situation, the fixer would incorrectly add a stray new line. [#229] + +#### TestUtils + +* `UtilityMethodTestCase::getTargetToken()`: will now throw a `PHPCSUtils\Exceptions\TestMarkerNotFound` exception if the provided test marker comment is not found. [#273], [#372] + This prevents the method potentially misidentifying the target token. + +#### Tokens + +* `Collections::parameterTypeTokens()`, `Collections::propertyTypeTokens()` and `Collections::returnTypeTokens()`: include the `namespace` keyword for namespace relative identifier names. [#180] + +#### Utils + +* `Arrays::isShortArray()`/`Lists::isShortList()`: fixed a number of bugs which previously resulted in an incorrect short list/short array determination. [#392] +* `FunctionDeclarations::getParameters()`: will now correctly recognize namespace relative names when used in a parameter type. [#180] +* `FunctionDeclarations::getProperties()`: will now correctly recognize namespace relative names when used in the return type. [#180] +* `ObjectDeclarations::findExtendedClassName()`: will now correctly recognize namespace relative names when used as the _extended_ parent class name. [#181] +* `ObjectDeclarations::findExtendedInterfaceNames()`: will now correctly recognize namespace relative names when used in _extended_ interface names. [#181] +* `ObjectDeclarations::findImplementedInterfaceNames()`: will now correctly recognize namespace relative names when used in _implemented_ interface names. [#181] +* `ObjectDeclarations::getClassProperties()`: will now correctly handle classes declared with both the `final` as well as the `abstract` keyword. [#252] +* `Operators::isReference()`: if one parameter in a function declaration was passed by reference, then all `T_BITWISE_AND` (not intersection type `&`'s) tokens would be regarded as references. [#188] +* `Operators::isReference()`: the `&` would not be recognized as a reference for arrow function parameters passed by reference. [#192] +* `Operators::isUnaryPlusMinus()`: a preceding `exit`, `break`, `continue` or arrow function `=>` is now recognized as an indicator that a plus/minus sign is unary. [#187], [#197] +* `Variables::getMemberProperties()`: will now correctly recognize namespace relative names when used in a property type. [#180] + +[UtilityMethodTestCase::usesPhp8NameTokens]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html#method_usesPhp8NameTokens +[PassedParameters::getParameterFromStack]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html#method_getParameterFromStack +[TextStrings::getEndOfCompleteTextString]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html#method_getEndOfCompleteTextString +[TextStrings::getEmbeds]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html#method_getEmbeds +[TextStrings::getStripEmbeds]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html#method_getStripEmbeds +[TextStrings::stripEmbeds]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html#method_stripEmbeds +[UseStatements::mergeImportUseStatements]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html#method_mergeImportUseStatements + +[#163]: https://github.com/PHPCSStandards/PHPCSUtils/pull/163 +[#168]: https://github.com/PHPCSStandards/PHPCSUtils/pull/168 +[#169]: https://github.com/PHPCSStandards/PHPCSUtils/pull/169 +[#172]: https://github.com/PHPCSStandards/PHPCSUtils/pull/172 +[#176]: https://github.com/PHPCSStandards/PHPCSUtils/pull/176 +[#180]: https://github.com/PHPCSStandards/PHPCSUtils/pull/180 +[#181]: https://github.com/PHPCSStandards/PHPCSUtils/pull/181 +[#183]: https://github.com/PHPCSStandards/PHPCSUtils/pull/183 +[#187]: https://github.com/PHPCSStandards/PHPCSUtils/pull/187 +[#188]: https://github.com/PHPCSStandards/PHPCSUtils/pull/188 +[#192]: https://github.com/PHPCSStandards/PHPCSUtils/pull/192 +[#195]: https://github.com/PHPCSStandards/PHPCSUtils/pull/195 +[#196]: https://github.com/PHPCSStandards/PHPCSUtils/pull/196 +[#197]: https://github.com/PHPCSStandards/PHPCSUtils/pull/197 +[#200]: https://github.com/PHPCSStandards/PHPCSUtils/pull/200 +[#202]: https://github.com/PHPCSStandards/PHPCSUtils/pull/202 +[#204]: https://github.com/PHPCSStandards/PHPCSUtils/pull/204 +[#205]: https://github.com/PHPCSStandards/PHPCSUtils/pull/205 +[#206]: https://github.com/PHPCSStandards/PHPCSUtils/pull/206 +[#207]: https://github.com/PHPCSStandards/PHPCSUtils/pull/207 +[#208]: https://github.com/PHPCSStandards/PHPCSUtils/pull/208 +[#209]: https://github.com/PHPCSStandards/PHPCSUtils/pull/209 +[#210]: https://github.com/PHPCSStandards/PHPCSUtils/pull/210 +[#211]: https://github.com/PHPCSStandards/PHPCSUtils/pull/211 +[#212]: https://github.com/PHPCSStandards/PHPCSUtils/pull/212 +[#213]: https://github.com/PHPCSStandards/PHPCSUtils/pull/213 +[#215]: https://github.com/PHPCSStandards/PHPCSUtils/pull/215 +[#216]: https://github.com/PHPCSStandards/PHPCSUtils/pull/216 +[#217]: https://github.com/PHPCSStandards/PHPCSUtils/pull/217 +[#219]: https://github.com/PHPCSStandards/PHPCSUtils/pull/219 +[#225]: https://github.com/PHPCSStandards/PHPCSUtils/pull/225 +[#226]: https://github.com/PHPCSStandards/PHPCSUtils/pull/226 +[#229]: https://github.com/PHPCSStandards/PHPCSUtils/pull/229 +[#233]: https://github.com/PHPCSStandards/PHPCSUtils/pull/233 +[#234]: https://github.com/PHPCSStandards/PHPCSUtils/pull/234 +[#235]: https://github.com/PHPCSStandards/PHPCSUtils/pull/235 +[#237]: https://github.com/PHPCSStandards/PHPCSUtils/pull/237 +[#239]: https://github.com/PHPCSStandards/PHPCSUtils/pull/239 +[#241]: https://github.com/PHPCSStandards/PHPCSUtils/pull/241 +[#243]: https://github.com/PHPCSStandards/PHPCSUtils/pull/243 +[#247]: https://github.com/PHPCSStandards/PHPCSUtils/pull/247 +[#248]: https://github.com/PHPCSStandards/PHPCSUtils/pull/248 +[#249]: https://github.com/PHPCSStandards/PHPCSUtils/pull/249 +[#251]: https://github.com/PHPCSStandards/PHPCSUtils/pull/251 +[#252]: https://github.com/PHPCSStandards/PHPCSUtils/pull/252 +[#254]: https://github.com/PHPCSStandards/PHPCSUtils/pull/254 +[#256]: https://github.com/PHPCSStandards/PHPCSUtils/pull/256 +[#261]: https://github.com/PHPCSStandards/PHPCSUtils/pull/261 +[#262]: https://github.com/PHPCSStandards/PHPCSUtils/pull/262 +[#269]: https://github.com/PHPCSStandards/PHPCSUtils/pull/269 +[#270]: https://github.com/PHPCSStandards/PHPCSUtils/pull/270 +[#273]: https://github.com/PHPCSStandards/PHPCSUtils/pull/273 +[#277]: https://github.com/PHPCSStandards/PHPCSUtils/pull/277 +[#285]: https://github.com/PHPCSStandards/PHPCSUtils/pull/285 +[#291]: https://github.com/PHPCSStandards/PHPCSUtils/pull/291 +[#292]: https://github.com/PHPCSStandards/PHPCSUtils/pull/292 +[#293]: https://github.com/PHPCSStandards/PHPCSUtils/pull/293 +[#297]: https://github.com/PHPCSStandards/PHPCSUtils/pull/297 +[#304]: https://github.com/PHPCSStandards/PHPCSUtils/pull/304 +[#309]: https://github.com/PHPCSStandards/PHPCSUtils/pull/309 +[#311]: https://github.com/PHPCSStandards/PHPCSUtils/pull/311 +[#319]: https://github.com/PHPCSStandards/PHPCSUtils/pull/319 +[#320]: https://github.com/PHPCSStandards/PHPCSUtils/pull/320 +[#321]: https://github.com/PHPCSStandards/PHPCSUtils/pull/321 +[#325]: https://github.com/PHPCSStandards/PHPCSUtils/pull/325 +[#327]: https://github.com/PHPCSStandards/PHPCSUtils/pull/327 +[#328]: https://github.com/PHPCSStandards/PHPCSUtils/pull/328 +[#332]: https://github.com/PHPCSStandards/PHPCSUtils/pull/332 +[#335]: https://github.com/PHPCSStandards/PHPCSUtils/pull/335 +[#341]: https://github.com/PHPCSStandards/PHPCSUtils/pull/341 +[#344]: https://github.com/PHPCSStandards/PHPCSUtils/pull/344 +[#347]: https://github.com/PHPCSStandards/PHPCSUtils/pull/347 +[#349]: https://github.com/PHPCSStandards/PHPCSUtils/pull/349 +[#356]: https://github.com/PHPCSStandards/PHPCSUtils/pull/356 +[#357]: https://github.com/PHPCSStandards/PHPCSUtils/pull/357 +[#358]: https://github.com/PHPCSStandards/PHPCSUtils/pull/358 +[#360]: https://github.com/PHPCSStandards/PHPCSUtils/pull/360 +[#362]: https://github.com/PHPCSStandards/PHPCSUtils/pull/362 +[#363]: https://github.com/PHPCSStandards/PHPCSUtils/pull/363 +[#365]: https://github.com/PHPCSStandards/PHPCSUtils/pull/365 +[#366]: https://github.com/PHPCSStandards/PHPCSUtils/pull/366 +[#367]: https://github.com/PHPCSStandards/PHPCSUtils/pull/367 +[#368]: https://github.com/PHPCSStandards/PHPCSUtils/pull/368 +[#371]: https://github.com/PHPCSStandards/PHPCSUtils/pull/371 +[#372]: https://github.com/PHPCSStandards/PHPCSUtils/pull/372 +[#376]: https://github.com/PHPCSStandards/PHPCSUtils/pull/376 +[#377]: https://github.com/PHPCSStandards/PHPCSUtils/pull/377 +[#379]: https://github.com/PHPCSStandards/PHPCSUtils/pull/379 +[#381]: https://github.com/PHPCSStandards/PHPCSUtils/pull/381 +[#382]: https://github.com/PHPCSStandards/PHPCSUtils/pull/382 +[#383]: https://github.com/PHPCSStandards/PHPCSUtils/pull/383 +[#385]: https://github.com/PHPCSStandards/PHPCSUtils/pull/385 +[#390]: https://github.com/PHPCSStandards/PHPCSUtils/pull/390 +[#391]: https://github.com/PHPCSStandards/PHPCSUtils/pull/391 +[#392]: https://github.com/PHPCSStandards/PHPCSUtils/pull/392 +[#394]: https://github.com/PHPCSStandards/PHPCSUtils/pull/394 +[#395]: https://github.com/PHPCSStandards/PHPCSUtils/pull/395 +[#396]: https://github.com/PHPCSStandards/PHPCSUtils/pull/396 +[#397]: https://github.com/PHPCSStandards/PHPCSUtils/pull/397 +[#398]: https://github.com/PHPCSStandards/PHPCSUtils/pull/398 + +[PHPCS#3118]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3118 +[PHPUnit Polyfills]: https://github.com/Yoast/PHPUnit-Polyfills + + ## [1.0.0-alpha3] - 2020-06-29 Notes: + * While still in alpha, some BC-breaks may be introduced. These are clearly indicated in the changelog with the :warning: symbol. * Until PHPCS 4.x has been released, PHPCSUtils does not formally support it, though an effort is made to keep up with the changes and anticipate potential compatibility issues. For testing purposes, the composer configuration allows for PHPCSUtils to be installed with PHPCS 4.x. @@ -21,157 +404,242 @@ Notes: ### Added -* New [`PHPCSUtils\Utils\NamingConventions`][`NamingConventions`] class: Utility functions for working with identifier names (namespace names, class/trait/interface names, function names, variable and constant names). [#119](https://github.com/PHPCSStandards/PHPCSUtils/pull/119) -* New [`PHPCSUtils\BackCompat\Helper::getEncoding()`](https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html#method_getEncoding) method. [#118](https://github.com/PHPCSStandards/PHPCSUtils/pull/118) -* New [`PHPCSUtils\Utils\ControlStructures::getCaughtExceptions()`](https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html#method_getCaughtExceptions) method. [#114](https://github.com/PHPCSStandards/PHPCSUtils/pull/114), [#138](https://github.com/PHPCSStandards/PHPCSUtils/pull/138) -* New [`PHPCSUtils\Utils\UseStatements::splitAndMergeImportUseStatement()`](https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html#method_splitAndMergeImportUseStatement) method. [#117](https://github.com/PHPCSStandards/PHPCSUtils/pull/117) +* New [`PHPCSUtils\Utils\NamingConventions`][`NamingConventions`] class: Utility functions for working with identifier names (namespace names, class/trait/interface names, function names, variable and constant names). [#119] +* New [`PHPCSUtils\BackCompat\Helper::getEncoding()`][Helper::getEncoding] method. [#118] +* New [`PHPCSUtils\Utils\ControlStructures::getCaughtExceptions()`][ControlStructures::getCaughtExceptions] method. [#114], [#138] +* New [`PHPCSUtils\Utils\UseStatements::splitAndMergeImportUseStatement()`][UseStatements::splitAndMergeImportUseStatement] method. [#117] -#### PHPCS Backcompat -* `BCFile::getMethodProperties()`: support for "static" as a return type (PHP 8). [#134](https://github.com/PHPCSStandards/PHPCSUtils/pull/134) [PHPCS#2952](https://github.com/squizlabs/PHP_CodeSniffer/pull/2952) +#### PHPCS BackCompat + +* `BCFile::getMethodProperties()`: support for "static" as a return type (PHP 8.0). [#134], [PHPCS#2952] #### TestUtils -* [`UtilityMethodTestCase`]: new public `$phpcsVersion` property for use in tests. [#107](https://github.com/PHPCSStandards/PHPCSUtils/pull/107) + +* [`UtilityMethodTestCase`]: new public `$phpcsVersion` property for use in tests. [#107] **Note**: if the PHPCS version is needed within a data provider method for a test, `Helper::getVersion()` still needs to be used as the data providers are run before the `setUpBeforeClass()`-like methods which set the property. #### Tokens -* New [`Collections::$incrementDecrementOperators`][`Collections`] property. [#130](https://github.com/PHPCSStandards/PHPCSUtils/pull/130) -* New [`Collections::$magicConstants`][`Collections`] property. [#106](https://github.com/PHPCSStandards/PHPCSUtils/pull/106) -* New [`Collections::$objectOperators`][`Collections`] property. [#130](https://github.com/PHPCSStandards/PHPCSUtils/pull/130) -* New [`Collections::$OOHierarchyKeywords`][`Collections`] property representing the keywords to access properties or methods from inside a class definition, i.e `self`, `parent` and `static`. [#115](https://github.com/PHPCSStandards/PHPCSUtils/pull/115) -* New [`Collections::$OONameTokens`][`Collections`] property containing tokens which can be part of a partially/fully qualified name when used in inline code. [#113](https://github.com/PHPCSStandards/PHPCSUtils/pull/113) -* New [`Collections::functionDeclarationTokens()`][`Collections`] method to retrieve the tokens which represent a keyword starting a function declaration. [#133](https://github.com/PHPCSStandards/PHPCSUtils/pull/133) + +* New [`Collections::$incrementDecrementOperators`][`Collections`] property. [#130] +* New [`Collections::$magicConstants`][`Collections`] property. [#106] +* New [`Collections::$objectOperators`][`Collections`] property. [#130] +* New [`Collections::$OOHierarchyKeywords`][`Collections`] property representing the keywords to access properties or methods from inside a class definition, i.e `self`, `parent` and `static`. [#115] +* New [`Collections::$OONameTokens`][`Collections`] property containing tokens which can be part of a partially/fully qualified name when used in inline code. [#113] +* New [`Collections::functionDeclarationTokens()`][`Collections`] method to retrieve the tokens which represent a keyword starting a function declaration. [#133] This method is compatible with PHPCS 3.5.3 and higher. -* New [`Collections::functionDeclarationTokensBC()`][`Collections`] method to retrieve the tokens which represent a keyword starting a function declaration (cross-version compatible). [#133](https://github.com/PHPCSStandards/PHPCSUtils/pull/133) +* New [`Collections::functionDeclarationTokensBC()`][`Collections`] method to retrieve the tokens which represent a keyword starting a function declaration (cross-version compatible). [#133] This method is compatible with PHPCS 2.6.0 and higher. -* New [`Collections::parameterTypeTokensBC()`][`Collections`] method to retrieve the tokens which need to be recognized for parameter types cross-version. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) +* New [`Collections::parameterTypeTokensBC()`][`Collections`] method to retrieve the tokens which need to be recognized for parameter types cross-version. [#109] Use this method when the implementing standard needs to support PHPCS < 3.3.0. -* New [`Collections::propertyTypeTokensBC()`][`Collections`] method to retrieve the tokens which need to be recognized for property types cross-version. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) +* New [`Collections::propertyTypeTokensBC()`][`Collections`] method to retrieve the tokens which need to be recognized for property types cross-version. [#109] Use this method when the implementing standard needs to support PHPCS < 3.3.0. -* New [`Collections::returnTypeTokensBC()`][`Collections`] method to retrieve the tokens which need to be recognized for return types cross-version. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) +* New [`Collections::returnTypeTokensBC()`][`Collections`] method to retrieve the tokens which need to be recognized for return types cross-version. [#109] Use this method when the implementing standard needs to support PHPCS < 3.5.4. -* `Collections::$returnTypeTokens`: support for "static" as a return type (PHP 8). [#134](https://github.com/PHPCSStandards/PHPCSUtils/pull/134) +* `Collections::$returnTypeTokens`: support for "static" as a return type (PHP 8.0). [#134] #### Utils -* `FunctionDeclarations::getProperties()`: support for "static" as a return type (PHP 8). [#134](https://github.com/PHPCSStandards/PHPCSUtils/pull/134) + +* `FunctionDeclarations::getProperties()`: support for "static" as a return type (PHP 8.0). [#134] ### Changed -#### PHPCS Backcompat -* `BCFile::getDeclarationName()`: has been made compatible with PHPCS 4.x. [#110](https://github.com/PHPCSStandards/PHPCSUtils/pull/110) -* `BCFile::getMethodProperties()`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) -* `BCFile::getMemberProperties()`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) -* `BCTokens`: :warning: The visibility of the `BCTokens::$phpcsCommentTokensTypes`, `BCTokens::$ooScopeTokens`, `BCTokens::$textStringTokens` properties has changed from `protected` to `private`. [#139](https://github.com/PHPCSStandards/PHPCSUtils/pull/139) -* `Helper::setConfigData()`: has been made compatible with PHPCS 4.x. [#137](https://github.com/PHPCSStandards/PHPCSUtils/pull/137) +#### PHPCS BackCompat + +* `BCFile::getDeclarationName()`: has been made compatible with PHPCS 4.x. [#110] +* `BCFile::getMethodProperties()`: has been made compatible with PHPCS 4.x. [#109] +* `BCFile::getMemberProperties()`: has been made compatible with PHPCS 4.x. [#109] +* `BCTokens`: :warning: The visibility of the `BCTokens::$phpcsCommentTokensTypes`, `BCTokens::$ooScopeTokens`, `BCTokens::$textStringTokens` properties has changed from `protected` to `private`. [#139] +* `Helper::setConfigData()`: has been made compatible with PHPCS 4.x. [#137] A new `$config` parameter has been added to the method. This parameter is a required parameter when the method is used with PHPCS 4.x. #### TestUtils -* [`UtilityMethodTestCase`]: tests for JS/CSS will now automatically be skipped when run in combination with PHPCS 4.x (which drops JS/CSS support). [#111](https://github.com/PHPCSStandards/PHPCSUtils/pull/111) -* Confirmed that the currently available test utils are compatible with PHPUnit 9.x. [#103](https://github.com/PHPCSStandards/PHPCSUtils/pull/103) + +* [`UtilityMethodTestCase`]: tests for JS/CSS will now automatically be skipped when run in combination with PHPCS 4.x (which drops JS/CSS support). [#111] +* Confirmed that the currently available test utils are compatible with PHPUnit 9.x. [#103] #### Tokens -* `Collections::$parameterTypeTokens`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) + +* `Collections::$parameterTypeTokens`: has been made compatible with PHPCS 4.x. [#109] :warning: This removes support for PHPCS < 3.3.0 from the property. Use the [`Collections::parameterTypeTokensBC()`][`Collections`] method instead if PHPCS < 3.3.0 needs to be supported. -* `Collections::$propertyTypeTokens`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) +* `Collections::$propertyTypeTokens`: has been made compatible with PHPCS 4.x. [#109] :warning: This removes support for PHPCS < 3.3.0 from the property. Use the [`Collections::propertyTypeTokensBC()`][`Collections`] method instead if PHPCS < 3.3.0 needs to be supported. -* `Collections::$returnTypeTokens`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) +* `Collections::$returnTypeTokens`: has been made compatible with PHPCS 4.x. [#109] :warning: This removes support for PHPCS < 3.5.4 from the property. Use the [`Collections::returnTypeTokensBC()`][`Collections`] method instead if PHPCS < 3.5.4 needs to be supported. #### Utils -* `FunctionDeclarations::getArrowFunctionOpenClose()`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) -* `FunctionDeclarations::getProperties()`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) -* :warning: `Lists::getAssignments()`: the return value of the method has been consolidated to be less fiddly to work with. [#129](https://github.com/PHPCSStandards/PHPCSUtils/pull/129) + +* `FunctionDeclarations::getArrowFunctionOpenClose()`: has been made compatible with PHPCS 4.x. [#109] +* `FunctionDeclarations::getProperties()`: has been made compatible with PHPCS 4.x. [#109] +* :warning: `Lists::getAssignments()`: the return value of the method has been consolidated to be less fiddly to work with. [#129] - :warning: The `nested_list` index key in the return value has been renamed to `is_nested_list`. -* `ObjectDeclarations::getName()`: has been made compatible with PHPCS 4.x. [#110](https://github.com/PHPCSStandards/PHPCSUtils/pull/110) -* `Variables::getMemberProperties()`: has been made compatible with PHPCS 4.x. [#109](https://github.com/PHPCSStandards/PHPCSUtils/pull/109) +* `ObjectDeclarations::getName()`: has been made compatible with PHPCS 4.x. [#110] +* `Variables::getMemberProperties()`: has been made compatible with PHPCS 4.x. [#109] #### Other + * Composer: PHPCSUtils can now be installed in combination with PHPCS `4.0.x-dev@dev` for testing purposes. -* Composer: The version requirements for the [DealerDirect Composer PHPCS plugin] have been widened to allow for version 0.7.0 which supports Composer 2.0.0. -* Readme/website homepage: textual improvements. Props [@GaryJones]. [#121](https://github.com/PHPCSStandards/PHPCSUtils/pull/121) -* Readme/website homepage: added additional FAQ question & answers. [#157](https://github.com/PHPCSStandards/PHPCSUtils/pull/157) -* The website homepage is now generated using the GitHub Pages gem with Jekyll, making maintenance easier. [#141](https://github.com/PHPCSStandards/PHPCSUtils/pull/141) -* Significant improvements to the docblock documentation and by extension the [generated API documentation](https://phpcsutils.com/phpdoc/). [#145](https://github.com/PHPCSStandards/PHPCSUtils/pull/145), [#146](https://github.com/PHPCSStandards/PHPCSUtils/pull/146), [#147](https://github.com/PHPCSStandards/PHPCSUtils/pull/147), [#148](https://github.com/PHPCSStandards/PHPCSUtils/pull/148), [#149](https://github.com/PHPCSStandards/PHPCSUtils/pull/149), [#150](https://github.com/PHPCSStandards/PHPCSUtils/pull/150), [#151](https://github.com/PHPCSStandards/PHPCSUtils/pull/151), [#152](https://github.com/PHPCSStandards/PHPCSUtils/pull/152), [#153](https://github.com/PHPCSStandards/PHPCSUtils/pull/153), [154](https://github.com/PHPCSStandards/PHPCSUtils/pull/154), [#155](https://github.com/PHPCSStandards/PHPCSUtils/pull/155), [#156](https://github.com/PHPCSStandards/PHPCSUtils/pull/156) +* Composer: The version requirements for the [Composer PHPCS plugin] have been widened to allow for version 0.7.0 which supports Composer 2.0.0. +* Readme/website homepage: textual improvements. Props [@GaryJones]. [#121] +* Readme/website homepage: added additional FAQ question & answers. [#157] +* The website homepage is now generated using the GitHub Pages gem with Jekyll, making maintenance easier. [#141] +* Significant improvements to the docblock documentation and by extension the [generated API documentation]. [#145], [#146], [#147], [#148], [#149], [#150], [#151], [#152], [#153], [#154], [#155], [#156] * Various housekeeping. ### Fixed #### Abstract Sniffs -* `AbstractArrayDeclarationSniff`: improved parse error handling. [#99](https://github.com/PHPCSStandards/PHPCSUtils/pull/99) -#### PHPCS Backcompat -* `BCFile::findEndOfStatement()`: now supports arrow functions when used as a function argument, in line with the same change made in PHPCS 3.5.5. [#143](https://github.com/PHPCSStandards/PHPCSUtils/pull/143) -* `BcFile::isReference()`: bug fix, the reference operator was not recognized as such for closures declared to return by reference. [#160](https://github.com/PHPCSStandards/PHPCSUtils/pull/160) [PHPCS#2977](https://github.com/squizlabs/PHP_CodeSniffer/pull/2977) +* `AbstractArrayDeclarationSniff`: improved parse error handling. [#99] + +#### PHPCS BackCompat + +* `BCFile::findEndOfStatement()`: now supports arrow functions when used as a function argument, in line with the same change made in PHPCS 3.5.5. [#143] +* `BcFile::isReference()`: bug fix, the reference operator was not recognized as such for closures declared to return by reference. [#160], [PHPCS#2977] #### Utils -* `FunctionDeclarations::getArrowFunctionOpenClose()`: now supports arrow functions when used as a function argument, in line with the same change made in PHPCS 3.5.5. [#143](https://github.com/PHPCSStandards/PHPCSUtils/pull/143) -* `FunctionDeclarations::getArrowFunctionOpenClose()`: now supports for arrow functions returning heredoc/nowdocs, in line with the same change made in PHPCS `master` and expected to be released in PHPCS 3.5.6. [#143](https://github.com/PHPCSStandards/PHPCSUtils/pull/143) -* `FunctionDeclarations::getName()`: bug fix for functions declared to return by reference. [#131](https://github.com/PHPCSStandards/PHPCSUtils/pull/131) -* `FunctionDeclarations::isMagicFunction()`: bug fix for nested functions. [#127](https://github.com/PHPCSStandards/PHPCSUtils/pull/127) -* `Operators::isReference()`: bug fix, the reference operator was not recognized as such for closures declared to return by reference. [#142](https://github.com/PHPCSStandards/PHPCSUtils/pull/142) -* `Namespaces::getType()`: improved type detection for when the `namespace` keyword is used as an operator in the global namespace. [#132](https://github.com/PHPCSStandards/PHPCSUtils/pull/132) -* `TextStrings::getCompleteTextString()`: will now remove the newline at the end of a heredoc/nowdoc. [#136](https://github.com/PHPCSStandards/PHPCSUtils/pull/136) + +* `FunctionDeclarations::getArrowFunctionOpenClose()`: now supports arrow functions when used as a function argument, in line with the same change made in PHPCS 3.5.5. [#143] +* `FunctionDeclarations::getArrowFunctionOpenClose()`: now supports for arrow functions returning heredoc/nowdocs, in line with the same change made in PHPCS `master` and expected to be released in PHPCS 3.5.6. [#143] +* `FunctionDeclarations::getName()`: bug fix for functions declared to return by reference. [#131] +* `FunctionDeclarations::isMagicFunction()`: bug fix for nested functions. [#127] +* `Operators::isReference()`: bug fix, the reference operator was not recognized as such for closures declared to return by reference. [#142] +* `Namespaces::getType()`: improved type detection for when the `namespace` keyword is used as an operator in the global namespace. [#132] +* `TextStrings::getCompleteTextString()`: will now remove the newline at the end of a heredoc/nowdoc. [#136] PHP itself does not include the last new line in a heredoc/nowdoc text string when handling it, so the method shouldn't either. +[generated API documentation]: https://phpcsutils.com/phpdoc/ +[Helper::getEncoding]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html#method_getEncoding +[ControlStructures::getCaughtExceptions]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html#method_getCaughtExceptions +[UseStatements::splitAndMergeImportUseStatement]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html#method_splitAndMergeImportUseStatement + +[#99]: https://github.com/PHPCSStandards/PHPCSUtils/pull/99 +[#103]: https://github.com/PHPCSStandards/PHPCSUtils/pull/103 +[#106]: https://github.com/PHPCSStandards/PHPCSUtils/pull/106 +[#107]: https://github.com/PHPCSStandards/PHPCSUtils/pull/107 +[#109]: https://github.com/PHPCSStandards/PHPCSUtils/pull/109 +[#110]: https://github.com/PHPCSStandards/PHPCSUtils/pull/110 +[#111]: https://github.com/PHPCSStandards/PHPCSUtils/pull/111 +[#113]: https://github.com/PHPCSStandards/PHPCSUtils/pull/113 +[#114]: https://github.com/PHPCSStandards/PHPCSUtils/pull/114 +[#115]: https://github.com/PHPCSStandards/PHPCSUtils/pull/115 +[#117]: https://github.com/PHPCSStandards/PHPCSUtils/pull/117 +[#118]: https://github.com/PHPCSStandards/PHPCSUtils/pull/118 +[#119]: https://github.com/PHPCSStandards/PHPCSUtils/pull/119 +[#129]: https://github.com/PHPCSStandards/PHPCSUtils/pull/129 +[#121]: https://github.com/PHPCSStandards/PHPCSUtils/pull/121 +[#127]: https://github.com/PHPCSStandards/PHPCSUtils/pull/127 +[#130]: https://github.com/PHPCSStandards/PHPCSUtils/pull/130 +[#131]: https://github.com/PHPCSStandards/PHPCSUtils/pull/131 +[#132]: https://github.com/PHPCSStandards/PHPCSUtils/pull/132 +[#133]: https://github.com/PHPCSStandards/PHPCSUtils/pull/133 +[#134]: https://github.com/PHPCSStandards/PHPCSUtils/pull/134 +[#136]: https://github.com/PHPCSStandards/PHPCSUtils/pull/136 +[#137]: https://github.com/PHPCSStandards/PHPCSUtils/pull/137 +[#138]: https://github.com/PHPCSStandards/PHPCSUtils/pull/138 +[#139]: https://github.com/PHPCSStandards/PHPCSUtils/pull/139 +[#141]: https://github.com/PHPCSStandards/PHPCSUtils/pull/141 +[#142]: https://github.com/PHPCSStandards/PHPCSUtils/pull/142 +[#143]: https://github.com/PHPCSStandards/PHPCSUtils/pull/143 +[#145]: https://github.com/PHPCSStandards/PHPCSUtils/pull/145 +[#146]: https://github.com/PHPCSStandards/PHPCSUtils/pull/146 +[#147]: https://github.com/PHPCSStandards/PHPCSUtils/pull/147 +[#148]: https://github.com/PHPCSStandards/PHPCSUtils/pull/148 +[#149]: https://github.com/PHPCSStandards/PHPCSUtils/pull/149 +[#150]: https://github.com/PHPCSStandards/PHPCSUtils/pull/150 +[#151]: https://github.com/PHPCSStandards/PHPCSUtils/pull/151 +[#152]: https://github.com/PHPCSStandards/PHPCSUtils/pull/152 +[#153]: https://github.com/PHPCSStandards/PHPCSUtils/pull/153 +[#154]: https://github.com/PHPCSStandards/PHPCSUtils/pull/154 +[#155]: https://github.com/PHPCSStandards/PHPCSUtils/pull/155 +[#156]: https://github.com/PHPCSStandards/PHPCSUtils/pull/156 +[#157]: https://github.com/PHPCSStandards/PHPCSUtils/pull/157 +[#160]: https://github.com/PHPCSStandards/PHPCSUtils/pull/160 +[PHPCS#2952]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2952 +[PHPCS#2977]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2977 + ## [1.0.0-alpha2] - 2020-02-16 Note: + * While still in alpha, some BC-breaks may be introduced. These are clearly indicated in the changelog with the :warning: symbol. ### Added -* New [`PHPCSUtils\Utils\ControlStructures`][`ControlStructures`] class: Utility functions for use when examining control structures. [#70](https://github.com/PHPCSStandards/PHPCSUtils/pull/70) -* New [`PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction()`](https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isArrowFunction) method. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) -* New [`PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose()`](https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_getArrowFunctionOpenClose) method. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) +* New [`PHPCSUtils\Utils\ControlStructures`][`ControlStructures`] class: Utility functions for use when examining control structures. [#70] +* New [`PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction()`][FunctionDeclarations::isArrowFunction] method. [#77], [#79] +* New [`PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose()`][FunctionDeclarations::getArrowFunctionOpenClose] method. [#77], [#79] -#### PHPCS Backcompat -* `BCFile::isReference()`: support for arrow functions returning by reference. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) -* `BCFile::getMethodParameters()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) -* `BCFile::getMethodProperties()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79), [#89](https://github.com/PHPCSStandards/PHPCSUtils/pull/89) -* `BCFile::getDeclarationName()`: allow functions to be called "fn". [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) -* `BCFile::findEndOfStatement()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) -* `BCFile::findStartOfStatement()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) +#### PHPCS BackCompat + +* `BCFile::isReference()`: support for arrow functions returning by reference. [#77] +* `BCFile::getMethodParameters()`: support for arrow functions. [#77], [#79] +* `BCFile::getMethodProperties()`: support for arrow functions. [#77], [#79], [#89] +* `BCFile::getDeclarationName()`: allow functions to be called "fn". [#77] +* `BCFile::findEndOfStatement()`: support for arrow functions. [#77], [#79] +* `BCFile::findStartOfStatement()`: support for arrow functions. [#77] #### Tokens -* New [`Collections::$alternativeControlStructureSyntaxTokens`][`Collections`] property. [#70](https://github.com/PHPCSStandards/PHPCSUtils/pull/70) -* New [`Collections::$alternativeControlStructureSyntaxCloserTokens`][`Collections`] property. [#68](https://github.com/PHPCSStandards/PHPCSUtils/pull/68), [#69](https://github.com/PHPCSStandards/PHPCSUtils/pull/69) -* New [`Collections::$controlStructureTokens`][`Collections`] property. [#70](https://github.com/PHPCSStandards/PHPCSUtils/pull/70) -* New [`Collections::arrowFunctionTokensBC()`][`Collections`] method. [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) + +* New [`Collections::$alternativeControlStructureSyntaxTokens`][`Collections`] property. [#70] +* New [`Collections::$alternativeControlStructureSyntaxCloserTokens`][`Collections`] property. [#68], [#69] +* New [`Collections::$controlStructureTokens`][`Collections`] property. [#70] +* New [`Collections::arrowFunctionTokensBC()`][`Collections`] method. [#79] #### Utils -* `Arrays::getDoubleArrowPtr()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79), [#84](https://github.com/PHPCSStandards/PHPCSUtils/pull/84) -* `FunctionDeclarations::getParameters()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) -* `FunctionDeclarations::getProperties()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) -* `Operators::isReference()`: support for arrow functions returning by reference. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) -* `Parentheses::getOwner()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) -* `Parentheses::isOwnerIn()`: support for arrow functions. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77), [#79](https://github.com/PHPCSStandards/PHPCSUtils/pull/79) + +* `Arrays::getDoubleArrowPtr()`: support for arrow functions. [#77], [#79], [#84] +* `FunctionDeclarations::getParameters()`: support for arrow functions. [#77], [#79] +* `FunctionDeclarations::getProperties()`: support for arrow functions. [#77], [#79] +* `Operators::isReference()`: support for arrow functions returning by reference. [#77] +* `Parentheses::getOwner()`: support for arrow functions. [#77] +* `Parentheses::isOwnerIn()`: support for arrow functions. [#77], [#79] #### Other -* Documentation website at https://phpcsutils.com/ + +* Documentation website at ### Changed -#### PHPCS Backcompat -* `BCFile::getCondition()`: sync with PHPCS 3.5.4 - added support for new `$first` parameter. [#73](https://github.com/PHPCSStandards/PHPCSUtils/pull/73) +#### PHPCS BackCompat + +* `BCFile::getCondition()`: sync with PHPCS 3.5.4 - added support for new `$first` parameter. [#73] #### Tokens -* The `Collections::$returnTypeTokens` property now includes `T_ARRAY` to allow for supporting arrow functions in PHPCS < 3.5.3. [#77](https://github.com/PHPCSStandards/PHPCSUtils/pull/77) + +* The `Collections::$returnTypeTokens` property now includes `T_ARRAY` to allow for supporting arrow functions in PHPCS < 3.5.3. [#77] #### Utils -* :warning: `Conditions::getCondition()`: sync with PHPCS 3.5.4 - renamed the existing `$reverse` parameter to `$first` and reversing the meaning of the boolean values, to stay in line with PHPCS itself. [#73](https://github.com/PHPCSStandards/PHPCSUtils/pull/73) -* :warning: `Numbers`: the `$unsupportedPHPCSVersions` property has been replaced with an `UNSUPPORTED_PHPCS_VERSION` constant. + +* :warning: `Conditions::getCondition()`: sync with PHPCS 3.5.4 - renamed the existing `$reverse` parameter to `$first` and reversing the meaning of the boolean values, to stay in line with PHPCS itself. [#73] +* :warning: `Numbers`: the `$unsupportedPHPCSVersions` property has been replaced with an `UNSUPPORTED_PHPCS_VERSION` constant. [#88] #### Other + * Various housekeeping. +[FunctionDeclarations::isArrowFunction]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_isArrowFunction +[FunctionDeclarations::getArrowFunctionOpenClose]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html#method_getArrowFunctionOpenClose + +[#68]: https://github.com/PHPCSStandards/PHPCSUtils/pull/68 +[#69]: https://github.com/PHPCSStandards/PHPCSUtils/pull/69 +[#70]: https://github.com/PHPCSStandards/PHPCSUtils/pull/70 +[#73]: https://github.com/PHPCSStandards/PHPCSUtils/pull/73 +[#77]: https://github.com/PHPCSStandards/PHPCSUtils/pull/77 +[#79]: https://github.com/PHPCSStandards/PHPCSUtils/pull/79 +[#84]: https://github.com/PHPCSStandards/PHPCSUtils/pull/84 +[#88]: https://github.com/PHPCSStandards/PHPCSUtils/pull/88 +[#89]: https://github.com/PHPCSStandards/PHPCSUtils/pull/89 + ## 1.0.0-alpha1 - 2020-01-23 Initial alpha release containing: + * A `PHPCS23Utils` standard which can be used to allow an external PHPCS standard to be compatible with both PHPCS 2.x as well as 3.x. * A `PHPCSUtils` standard which contains generic utilities which can be used when writing sniffs. **_This standard does not contain any sniffs!_** - To use these utilities in PHPCS 3.x, all that is needed is for this package to be installed and registered with PHPCS using `installed_paths`. If the package is requested via Composer, this will automatically be handled by the [DealerDirect Composer PHPCS plugin]. + To use these utilities in PHPCS 3.x, all that is needed is for this package to be installed and registered with PHPCS using `installed_paths`. If the package is requested via Composer, this will automatically be handled by the [Composer PHPCS plugin]. To use these utilities in PHPCS 2.x, make sure the external standard includes the `PHPCS23Utils` standard in the `ruleset.xml` file like so: ``. All utilities offered are compatible with PHP_CodeSniffer 2.6.0 up to the latest stable release. @@ -179,26 +647,32 @@ All utilities offered are compatible with PHP_CodeSniffer 2.6.0 up to the latest This initial alpha release contains the following utility classes: ### Abstract Sniffs + * [`AbstractArrayDeclarationSniff`]: to examine array declarations. -### Backcompat +### BackCompat + * [`BCFile`]: Backport of the latest versions of PHPCS native utility functions from the `PHP_CodeSniffer\Files\File` class to make them available in older PHPCS versions without the bugs and other quirks that the older versions of the native functions had. * [`BCTokens`]: Backport of the latest versions of PHPCS native token arrays from the `PHP_CodeSniffer\Util\Tokens` class to make them available in older PHPCS versions. * [`Helper`]: Utility methods to retrieve (configuration) information from PHP_CodeSniffer 2.x as well as 3.x. ### Fixers + * [`SpacesFixer`]: Utility to check and, if necessary, fix the whitespace between two tokens. ### TestUtils + * [`UtilityMethodTestCase`]: Base class for use when testing utility methods for PHP_CodeSniffer. Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 8.x. See the usage instructions in the class docblock. ### Tokens + * [`Collections`]: Collections of related tokens as often used and needed for sniffs. These are additional "token groups" to compliment the ones available through the PHPCS native `PHP_CodeSniffer\Util\Tokens` class. ### Utils + * [`Arrays`]: Utility functions for use when examining arrays. * [`Conditions`]: Utility functions for use when examining token conditions. * [`FunctionDeclarations`]: Utility functions for use when examining function declaration statements. @@ -217,37 +691,40 @@ This initial alpha release contains the following utility classes: * [`Variables`]: Utility functions for use when examining variables. - -[Unreleased]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-alpha3...HEAD +[Unreleased]: https://github.com/PHPCSStandards/PHPCSUtils/compare/stable...HEAD +[1.0.0-alpha4]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-alpha3...1.0.0-alpha4 [1.0.0-alpha3]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-alpha2...1.0.0-alpha3 [1.0.0-alpha2]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.0-alpha1...1.0.0-alpha2 -[DealerDirect Composer PHPCS plugin]: https://github.com/Dealerdirect/phpcodesniffer-composer-installer/ +[Composer PHPCS plugin]: https://github.com/PHPCSStandards/composer-installer [`AbstractArrayDeclarationSniff`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html -[`BCFile`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html -[`BCTokens`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html -[`Helper`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html -[`SpacesFixer`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html -[`UtilityMethodTestCase`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html -[`Collections`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Tokens-Collections.html -[`Arrays`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Arrays.html -[`Conditions`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Conditions.html -[`ControlStructures`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html -[`FunctionDeclarations`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html -[`GetTokensAsString`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html -[`Lists`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Lists.html -[`Namespaces`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html -[`NamingConventions`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-NamingConventions.html -[`Numbers`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Numbers.html -[`ObjectDeclarations`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html -[`Operators`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Operators.html -[`Orthography`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Orthography.html -[`Parentheses`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html -[`PassedParameters`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html -[`Scopes`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Scopes.html -[`TextStrings`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html -[`UseStatements`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html -[`Variables`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Variables.html +[`BCFile`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html +[`BCTokens`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html +[`Helper`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html +[`SpacesFixer`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html +[`UtilityMethodTestCase`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html +[`Collections`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Tokens-Collections.html +[`TokenHelper`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Tokens-TokenHelper.html +[`Arrays`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Arrays.html +[`Conditions`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Conditions.html +[`Context`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Context.html +[`ControlStructures`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html +[`FunctionDeclarations`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html +[`GetTokensAsString`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html +[`Lists`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Lists.html +[`MessageHelper`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-MessageHelper.html +[`Namespaces`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html +[`NamingConventions`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-NamingConventions.html +[`Numbers`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Numbers.html +[`ObjectDeclarations`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html +[`Operators`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Operators.html +[`Orthography`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Orthography.html +[`Parentheses`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html +[`PassedParameters`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html +[`Scopes`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Scopes.html +[`TextStrings`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html +[`UseStatements`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html +[`Variables`]: https://phpcsutils.com/phpdoc/classes/PHPCSUtils-Utils-Variables.html [@GaryJones]: https://github.com/GaryJones diff --git a/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php b/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php index 6d50c9df..3f8ea5ab 100644 --- a/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php +++ b/PHPCS23Utils/Sniffs/Load/LoadUtilsSniff.php @@ -24,7 +24,7 @@ * * @since 1.0.0 */ -class LoadUtilsSniff +final class LoadUtilsSniff { /** diff --git a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php index 3a9e5015..8f412733 100644 --- a/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php +++ b/PHPCSUtils/AbstractSniffs/AbstractArrayDeclarationSniff.php @@ -14,7 +14,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Arrays; use PHPCSUtils\Utils\Numbers; use PHPCSUtils\Utils\PassedParameters; @@ -24,6 +24,7 @@ * Abstract sniff to easily examine all parts of an array declaration. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ abstract class AbstractArrayDeclarationSniff implements Sniff { @@ -135,14 +136,14 @@ abstract class AbstractArrayDeclarationSniff implements Sniff final public function __construct() { // Enhance the list of accepted tokens. - $this->acceptedTokens += BCTokens::assignmentTokens(); - $this->acceptedTokens += BCTokens::comparisonTokens(); - $this->acceptedTokens += BCTokens::arithmeticTokens(); - $this->acceptedTokens += BCTokens::operators(); - $this->acceptedTokens += BCTokens::booleanOperators(); - $this->acceptedTokens += BCTokens::castTokens(); - $this->acceptedTokens += BCTokens::bracketTokens(); - $this->acceptedTokens += BCTokens::heredocTokens(); + $this->acceptedTokens += Tokens::$assignmentTokens; + $this->acceptedTokens += Tokens::$comparisonTokens; + $this->acceptedTokens += Tokens::$arithmeticTokens; + $this->acceptedTokens += Tokens::$operators; + $this->acceptedTokens += Tokens::$booleanOperators; + $this->acceptedTokens += Tokens::$castTokens; + $this->acceptedTokens += Tokens::$bracketTokens; + $this->acceptedTokens += Tokens::$heredocTokens; } /** @@ -156,11 +157,7 @@ final public function __construct() */ public function register() { - return [ - \T_ARRAY, - \T_OPEN_SHORT_ARRAY, - \T_OPEN_SQUARE_BRACKET, - ]; + return Collections::arrayOpenTokensBC(); } /** @@ -483,16 +480,9 @@ public function getActualArrayKey(File $phpcsFile, $startPtr, $endPtr) // Take PHP 7.4 numeric literal separators into account. if ($this->tokens[$i]['code'] === \T_LNUMBER || $this->tokens[$i]['code'] === \T_DNUMBER) { - try { - $number = Numbers::getCompleteNumber($phpcsFile, $i); - $content .= $number['content']; - $i = $number['last_token']; - } catch (RuntimeException $e) { - // This must be PHP 3.5.3 with the broken backfill. Let's presume it's a ordinary number. - // If it's not, the sniff will bow out on the following T_STRING anyway if the - // backfill was broken. - $content .= \str_replace('_', '', $this->tokens[$i]['content']); - } + $number = Numbers::getCompleteNumber($phpcsFile, $i); + $content .= $number['content']; + $i = $number['last_token']; continue; } @@ -501,7 +491,7 @@ public function getActualArrayKey(File $phpcsFile, $startPtr, $endPtr) $text = TextStrings::getCompleteTextString($phpcsFile, $i); // Check if there's a variable in the heredoc. - if (\preg_match('`(?getTokens(); - $tokenCode = $tokens[$stackPtr]['code']; - - if ($tokenCode === T_ANON_CLASS || $tokenCode === T_CLOSURE) { - return null; - } - - /* - * BC: Work-around JS ES6 classes not being tokenized as T_CLASS in PHPCS < 3.0.0. - */ - if (isset($phpcsFile->tokenizerType) - && $phpcsFile->tokenizerType === 'JS' - && $tokenCode === T_STRING - && $tokens[$stackPtr]['content'] === 'class' - ) { - $tokenCode = T_CLASS; - } - - if ($tokenCode !== T_FUNCTION - && $tokenCode !== T_CLASS - && $tokenCode !== T_INTERFACE - && $tokenCode !== T_TRAIT - ) { - throw new RuntimeException('Token type "' . $tokens[$stackPtr]['type'] . '" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); - } - - if ($tokenCode === T_FUNCTION - && strtolower($tokens[$stackPtr]['content']) !== 'function' - ) { - // This is a function declared without the "function" keyword. - // So this token is the function name. - return $tokens[$stackPtr]['content']; - } - - $content = null; - for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['code'] === T_STRING - // BC: PHPCS 3.5.3/3.5.4. - || $tokens[$i]['type'] === 'T_FN' - ) { - /* - * BC: In PHPCS 2.6.0, in case of live coding, the last token in a file will be tokenized - * as T_STRING, but won't have the `content` index set. - */ - if (isset($tokens[$i]['content'])) { - $content = $tokens[$i]['content']; - } - break; - } - } - - return $content; + return $phpcsFile->getDeclarationName($stackPtr); } /** @@ -193,6 +111,7 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * 'name' => '$var', // The variable name. * 'token' => integer, // The stack pointer to the variable name. * 'content' => string, // The full content of the variable definition. + * 'has_attributes' => boolean, // Does the parameter have one or more attributes attached ? * 'pass_by_reference' => boolean, // Is the variable passed by reference? * 'reference_token' => integer, // The stack pointer to the reference operator * // or FALSE if the param is not passed by reference. @@ -204,7 +123,8 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * // or FALSE if there is no type hint. * 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint * // or FALSE if there is no type hint. - * 'nullable_type' => boolean, // TRUE if the var type is nullable. + * 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability + * // operator. * 'comma_token' => integer, // The stack pointer to the comma after the param * // or FALSE if this is the last param. * ) @@ -217,49 +137,26 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) * 'default_equal_token' => integer, // The stack pointer to the equals sign. * ``` * + * Parameters declared using PHP 8 constructor property promotion, have these additional array indexes: + * ```php + * 'property_visibility' => string, // The property visibility as declared. + * 'visibility_token' => integer, // The stack pointer to the visibility modifier token. + * 'property_readonly' => bool, // TRUE if the readonly keyword was found. + * 'readonly_token' => integer, // The stack pointer to the readonly modifier token. + * ``` + * * PHPCS cross-version compatible version of the `File::getMethodParameters()` method. * * Changelog for the PHPCS native function: * - Introduced in PHPCS 0.0.5. - * - PHPCS 2.8.0: Now recognises `self` as a valid type declaration. - * - PHPCS 2.8.0: The return array now contains a new `"token"` index containing the stack pointer - * to the variable. - * - PHPCS 2.8.0: The return array now contains a new `"content"` index containing the raw content - * of the param definition. - * - PHPCS 2.8.0: Added support for nullable types. - * The return array now contains a new `"nullable_type"` index set to `true` or `false` - * for each method parameter. - * - PHPCS 2.8.0: Added support for closures. - * - PHPCS 3.0.0: The Exception thrown changed from a `PHP_CodeSniffer_Exception` to - * `\PHP_CodeSniffer\Exceptions\TokenizerException`. - * - PHPCS 3.3.0: The return array now contains a new `"type_hint_token"` array index. - * Provides the position in the token stack of the first token in the type declaration. - * - PHPCS 3.3.1: Fixed incompatibility with PHP 7.3. - * - PHPCS 3.5.0: The Exception thrown changed from a `\PHP_CodeSniffer\Exceptions\TokenizerException` - * to `\PHP_CodeSniffer\Exceptions\RuntimeException`. - * - PHPCS 3.5.0: Added support for closure USE groups. - * - PHPCS 3.5.0: The return array now contains yet more more information. - * - If a type hint is specified, the position of the last token in the hint will be - * set in a `"type_hint_end_token"` array index. - * - If a default is specified, the position of the first token in the default value - * will be set in a `"default_token"` array index. - * - If a default is specified, the position of the equals sign will be set in a - * `"default_equal_token"` array index. - * - If the param is not the last, the position of the comma will be set in a - * `"comma_token"` array index. - * - If the param is passed by reference, the position of the reference operator - * will be set in a `"reference_token"` array index. - * - If the param is variable length, the position of the variadic operator will - * be set in a `"variadic_token"` array index. - * - PHPCS 3.5.3: Fixed a bug where the `"type_hint_end_token"` array index for a type hinted - * parameter would bleed through to the next (non-type hinted) parameter. - * - PHPCS 3.5.3: Added support for PHP 7.4 `T_FN` arrow functions. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source. * @see \PHPCSUtils\Utils\FunctionDeclarations::getParameters() PHPCSUtils native improved version. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token @@ -273,25 +170,23 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr) */ public static function getMethodParameters(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - $arrowOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $stackPtr); + $tokens = $phpcsFile->getTokens(); - if ($tokens[$stackPtr]['code'] !== T_FUNCTION - && $tokens[$stackPtr]['code'] !== T_CLOSURE + if (isset(Collections::functionDeclarationTokens()[$tokens[$stackPtr]['code']]) === false && $tokens[$stackPtr]['code'] !== T_USE - && $arrowOpenClose === false ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_USE or T_FN'); } if ($tokens[$stackPtr]['code'] === T_USE) { $opener = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($stackPtr + 1)); - if ($opener === false || isset($tokens[$opener]['parenthesis_owner']) === true) { + if ($opener === false + || (isset($tokens[$opener]['parenthesis_owner']) === true + // BC: as of PHPCS 4.x, closure use tokens are parentheses owners. + && $tokens[$opener]['parenthesis_owner'] !== $stackPtr) + ) { throw new RuntimeException('$stackPtr was not a valid T_USE'); } - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/4/5. - $opener = $arrowOpenClose['parenthesis_opener']; } else { if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { // Live coding or syntax error, so no params to find. @@ -314,6 +209,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $defaultStart = null; $equalToken = null; $paramCount = 0; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; @@ -322,6 +218,8 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $typeHintToken = false; $typeHintEndToken = false; $nullableType = false; + $visibilityToken = null; + $readonlyToken = null; for ($i = $paramStart; $i <= $closer; $i++) { // Check to see if this token has a parenthesis or bracket opener. If it does @@ -342,23 +240,27 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) } } - // Changed from checking 'code' to 'type' to allow for T_NULLABLE not existing in PHPCS < 2.8.0. - switch ($tokens[$i]['type']) { - case 'T_BITWISE_AND': + switch ($tokens[$i]['code']) { + case T_ATTRIBUTE: + $hasAttributes = true; + + // Skip to the end of the attribute. + $i = $tokens[$i]['attribute_closer']; + break; + case T_BITWISE_AND: if ($defaultStart === null) { $passByReference = true; $referenceToken = $i; } break; - case 'T_VARIABLE': + case T_VARIABLE: $currVar = $i; break; - case 'T_ELLIPSIS': + case T_ELLIPSIS: $variableLength = true; $variadicToken = $i; break; - case 'T_ARRAY_HINT': // PHPCS < 3.3.0. - case 'T_CALLABLE': + case T_CALLABLE: if ($typeHintToken === false) { $typeHintToken = $i; } @@ -366,9 +268,9 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $typeHint .= $tokens[$i]['content']; $typeHintEndToken = $i; break; - case 'T_SELF': - case 'T_PARENT': - case 'T_STATIC': + case T_SELF: + case T_PARENT: + case T_STATIC: // Self and parent are valid, static invalid, but was probably intended as type hint. if (isset($defaultStart) === false) { if ($typeHintToken === false) { @@ -379,8 +281,11 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $typeHintEndToken = $i; } break; - case 'T_STRING': - // This is a string, so it may be a type hint, but it could + case T_STRING: + case T_NAME_QUALIFIED: + case T_NAME_FULLY_QUALIFIED: + case T_NAME_RELATIVE: + // This is an identifier name, so it may be a type declaration, but it could // also be a constant used as a default value. $prevComma = false; for ($t = $i; $t >= $opener; $t--) { @@ -413,7 +318,12 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $typeHintEndToken = $i; } break; - case 'T_NS_SEPARATOR': + case T_NAMESPACE: + case T_NS_SEPARATOR: + case T_TYPE_UNION: + case T_TYPE_INTERSECTION: + case T_FALSE: + case T_NULL: // Part of a type hint or default value. if ($defaultStart === null) { if ($typeHintToken === false) { @@ -424,16 +334,27 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $typeHintEndToken = $i; } break; - case 'T_NULLABLE': - case 'T_INLINE_THEN': // PHPCS < 2.8.0. + case T_NULLABLE: if ($defaultStart === null) { $nullableType = true; $typeHint .= $tokens[$i]['content']; $typeHintEndToken = $i; } break; - case 'T_CLOSE_PARENTHESIS': - case 'T_COMMA': + case T_PUBLIC: + case T_PROTECTED: + case T_PRIVATE: + if ($defaultStart === null) { + $visibilityToken = $i; + } + break; + case T_READONLY: + if ($defaultStart === null) { + $readonlyToken = $i; + } + break; + case T_CLOSE_PARENTHESIS: + case T_COMMA: // If it's null, then there must be no parameters for this // method. if ($currVar === null) { @@ -451,6 +372,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $vars[$paramCount]['default_equal_token'] = $equalToken; } + $vars[$paramCount]['has_attributes'] = $hasAttributes; $vars[$paramCount]['pass_by_reference'] = $passByReference; $vars[$paramCount]['reference_token'] = $referenceToken; $vars[$paramCount]['variable_length'] = $variableLength; @@ -460,6 +382,17 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $vars[$paramCount]['type_hint_end_token'] = $typeHintEndToken; $vars[$paramCount]['nullable_type'] = $nullableType; + if ($visibilityToken !== null) { + $vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content']; + $vars[$paramCount]['visibility_token'] = $visibilityToken; + $vars[$paramCount]['property_readonly'] = false; + } + + if ($readonlyToken !== null) { + $vars[$paramCount]['property_readonly'] = true; + $vars[$paramCount]['readonly_token'] = $readonlyToken; + } + if ($tokens[$i]['code'] === T_COMMA) { $vars[$paramCount]['comma_token'] = $i; } else { @@ -471,6 +404,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $paramStart = ($i + 1); $defaultStart = null; $equalToken = null; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; @@ -479,10 +413,12 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) $typeHintToken = false; $typeHintEndToken = false; $nullableType = false; + $visibilityToken = null; + $readonlyToken = null; - $paramCount++; + ++$paramCount; break; - case 'T_EQUAL': + case T_EQUAL: $defaultStart = $phpcsFile->findNext(Tokens::$emptyTokens, ($i + 1), null, true); $equalToken = $i; break; @@ -498,16 +434,19 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) * The format of the return value is: * ```php * array( - * 'scope' => 'public', // Public, private, or protected - * 'scope_specified' => true, // TRUE if the scope keyword was found. - * 'return_type' => '', // The return type of the method. - * 'return_type_token' => integer, // The stack pointer to the start of the return type - * // or FALSE if there is no return type. - * 'nullable_return_type' => false, // TRUE if the return type is nullable. - * 'is_abstract' => false, // TRUE if the abstract keyword was found. - * 'is_final' => false, // TRUE if the final keyword was found. - * 'is_static' => false, // TRUE if the static keyword was found. - * 'has_body' => false, // TRUE if the method has a body + * 'scope' => 'public', // Public, private, or protected + * 'scope_specified' => true, // TRUE if the scope keyword was found. + * 'return_type' => '', // The return type of the method. + * 'return_type_token' => integer, // The stack pointer to the start of the return type + * // or FALSE if there is no return type. + * 'return_type_end_token' => integer, // The stack pointer to the end of the return type + * // or FALSE if there is no return type. + * 'nullable_return_type' => false, // TRUE if the return type is preceded by + * // the nullability operator. + * 'is_abstract' => false, // TRUE if the abstract keyword was found. + * 'is_final' => false, // TRUE if the final keyword was found. + * 'is_static' => false, // TRUE if the static keyword was found. + * 'has_body' => false, // TRUE if the method has a body * ); * ``` * @@ -515,30 +454,12 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 0.0.5. - * - PHPCS 3.0.0: Removed the `"is_closure"` array index which was always `false` anyway. - * - PHPCS 3.0.0: The Exception thrown changed from a `PHP_CodeSniffer_Exception` to - * `\PHP_CodeSniffer\Exceptions\TokenizerException`. - * - PHPCS 3.3.0: New `"return_type"`, `"return_type_token"` and `"nullable_return_type"` array indexes. - * - The `"return_type"` index contains the return type of the function or closer, - * or a blank string if not specified. - * - If the return type is nullable, the return type will contain the leading `?`. - * - A `"nullable_return_type"` array index in the return value will also be set to `true`. - * - If the return type contains namespace information, it will be cleaned of - * whitespace and comments. - * - To access the original return value string, use the main tokens array. - * - PHPCS 3.4.0: New `"has_body"` array index. - * `false` if the method has no body (as with abstract and interface methods) - * or `true` otherwise. - * - PHPCS 3.5.0: The Exception thrown changed from a `\PHP_CodeSniffer\Exceptions\TokenizerException` - * to `\PHP_CodeSniffer\Exceptions\RuntimeException`. - * - PHPCS 3.5.3: Added support for PHP 7.4 `T_FN` arrow functions. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source. * @see \PHPCSUtils\Utils\FunctionDeclarations::getProperties() PHPCSUtils native improved version. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. - * @since 1.0.0-alpha3 Added support for PHP 8.0 static return type (expected in future PHPCS release). * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token to @@ -551,151 +472,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr) */ public static function getMethodProperties(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - $arrowOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $stackPtr); - - if ($tokens[$stackPtr]['code'] !== T_FUNCTION - && $tokens[$stackPtr]['code'] !== T_CLOSURE - && $arrowOpenClose === false - ) { - throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN'); - } - - if ($tokens[$stackPtr]['code'] === T_FUNCTION) { - $valid = [ - T_PUBLIC => T_PUBLIC, - T_PRIVATE => T_PRIVATE, - T_PROTECTED => T_PROTECTED, - T_STATIC => T_STATIC, - T_FINAL => T_FINAL, - T_ABSTRACT => T_ABSTRACT, - T_WHITESPACE => T_WHITESPACE, - T_COMMENT => T_COMMENT, - T_DOC_COMMENT => T_DOC_COMMENT, - ]; - } else { - $valid = [ - T_STATIC => T_STATIC, - T_WHITESPACE => T_WHITESPACE, - T_COMMENT => T_COMMENT, - T_DOC_COMMENT => T_DOC_COMMENT, - ]; - } - - $scope = 'public'; - $scopeSpecified = false; - $isAbstract = false; - $isFinal = false; - $isStatic = false; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (isset($valid[$tokens[$i]['code']]) === false) { - break; - } - - switch ($tokens[$i]['code']) { - case T_PUBLIC: - $scope = 'public'; - $scopeSpecified = true; - break; - case T_PRIVATE: - $scope = 'private'; - $scopeSpecified = true; - break; - case T_PROTECTED: - $scope = 'protected'; - $scopeSpecified = true; - break; - case T_ABSTRACT: - $isAbstract = true; - break; - case T_FINAL: - $isFinal = true; - break; - case T_STATIC: - $isStatic = true; - break; - } - } - - $returnType = ''; - $returnTypeToken = false; - $nullableReturnType = false; - $hasBody = true; - $returnTypeTokens = Collections::returnTypeTokensBC(); - - $parenthesisCloser = null; - if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { - $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; - } - - if (isset($parenthesisCloser) === true) { - $scopeOpener = null; - if (isset($tokens[$stackPtr]['scope_opener']) === true) { - $scopeOpener = $tokens[$stackPtr]['scope_opener']; - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - $scopeOpener = $arrowOpenClose['scope_opener']; - } - - for ($i = $parenthesisCloser; $i < $phpcsFile->numTokens; $i++) { - if (($scopeOpener === null && $tokens[$i]['code'] === T_SEMICOLON) - || ($scopeOpener !== null && $i === $scopeOpener) - ) { - // End of function definition. - break; - } - - if ($tokens[$i]['type'] === 'T_NULLABLE' - // Handle nullable tokens in PHPCS < 2.8.0. - || (defined('T_NULLABLE') === false && $tokens[$i]['code'] === T_INLINE_THEN) - // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. - || ($arrowOpenClose !== false && $tokens[$i]['code'] === T_INLINE_THEN - && version_compare(Helper::getVersion(), '2.9.1', '<') === true) - ) { - $nullableReturnType = true; - } - - if (isset($returnTypeTokens[$tokens[$i]['code']]) === true) { - if ($returnTypeToken === false) { - $returnTypeToken = $i; - } - - $returnType .= $tokens[$i]['content']; - } - } - - $bodyTokens = [T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET]; - if ($arrowOpenClose !== false) { - $bodyTokens = [T_DOUBLE_ARROW => T_DOUBLE_ARROW]; - if (defined('T_FN_ARROW') === true) { - // PHPCS 3.5.3+. - $bodyTokens[T_FN_ARROW] = T_FN_ARROW; - } - } - - $end = $phpcsFile->findNext(($bodyTokens + [T_SEMICOLON]), $parenthesisCloser); - $hasBody = ($end !== false && isset($bodyTokens[$tokens[$end]['code']])); - } - - if ($returnType !== '' && $nullableReturnType === true) { - $returnType = '?' . $returnType; - } - - return [ - 'scope' => $scope, - 'scope_specified' => $scopeSpecified, - 'return_type' => $returnType, - 'return_type_token' => $returnTypeToken, - 'nullable_return_type' => $nullableReturnType, - 'is_abstract' => $isAbstract, - 'is_final' => $isFinal, - 'is_static' => $isStatic, - 'has_body' => $hasBody, - ]; + return $phpcsFile->getMethodProperties($stackPtr); } /** @@ -707,12 +484,14 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) * 'scope' => string, // Public, private, or protected. * 'scope_specified' => boolean, // TRUE if the scope was explicitly specified. * 'is_static' => boolean, // TRUE if the static keyword was found. + * 'is_readonly' => boolean, // TRUE if the readonly keyword was found. * 'type' => string, // The type of the var (empty if no type specified). * 'type_token' => integer, // The stack pointer to the start of the type * // or FALSE if there is no type. * 'type_end_token' => integer, // The stack pointer to the end of the type * // or FALSE if there is no type. - * 'nullable_type' => boolean, // TRUE if the type is nullable. + * 'nullable_type' => boolean, // TRUE if the type is preceded by the + * // nullability operator. * ); * ``` * @@ -720,22 +499,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 0.0.5. - * - PHPCS 3.0.0: The Exception thrown changed from a `PHP_CodeSniffer_Exception` to - * `\PHP_CodeSniffer\Exceptions\TokenizerException`. - * - PHPCS 3.4.0: Fixed method params being recognized as properties, PHPCS#2214. - * - PHPCS 3.5.0: New `"type"`, `"type_token"`, `"type_end_token"` and `"nullable_type"` array indexes. - * - The `"type"` index contains the type of the member var, or a blank string - * if not specified. - * - If the type is nullable, `"type"` will contain the leading `?`. - * - If a type is specified, the position of the first token in the type will - * be set in a `"type_token"` array index. - * - If a type is specified, the position of the last token in the type will - * be set in a `"type_end_token"` array index. - * - If the type is nullable, a `"nullable_type"` array index will also be set to `true`. - * - If the type contains namespace information, it will be cleaned of whitespace - * and comments in the `"type"` value. - * - PHPCS 3.5.0: The Exception thrown changed from a `\PHP_CodeSniffer\Exceptions\TokenizerException` - * to `\PHP_CodeSniffer\Exceptions\RuntimeException`. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::getMemberProperties() Original source. * @see \PHPCSUtils\Utils\Variables::getMemberProperties() PHPCSUtils native improved version. @@ -754,135 +518,7 @@ public static function getMethodProperties(File $phpcsFile, $stackPtr) */ public static function getMemberProperties(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] !== T_VARIABLE) { - throw new RuntimeException('$stackPtr must be of type T_VARIABLE'); - } - - $conditions = array_keys($tokens[$stackPtr]['conditions']); - $ptr = array_pop($conditions); - if (isset($tokens[$ptr]) === false - || ($tokens[$ptr]['code'] !== T_CLASS - && $tokens[$ptr]['code'] !== T_ANON_CLASS - && $tokens[$ptr]['code'] !== T_TRAIT) - ) { - if (isset($tokens[$ptr]) === true - && $tokens[$ptr]['code'] === T_INTERFACE - ) { - // T_VARIABLEs in interfaces can actually be method arguments - // but they wont be seen as being inside the method because there - // are no scope openers and closers for abstract methods. If it is in - // parentheses, we can be pretty sure it is a method argument. - if (isset($tokens[$stackPtr]['nested_parenthesis']) === false - || empty($tokens[$stackPtr]['nested_parenthesis']) === true - ) { - $error = 'Possible parse error: interfaces may not include member vars'; - $phpcsFile->addWarning($error, $stackPtr, 'Internal.ParseError.InterfaceHasMemberVar'); - return []; - } - } else { - throw new RuntimeException('$stackPtr is not a class member var'); - } - } - - // Make sure it's not a method parameter. - if (empty($tokens[$stackPtr]['nested_parenthesis']) === false) { - $parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']); - $deepestOpen = array_pop($parenthesis); - if ($deepestOpen > $ptr - && isset($tokens[$deepestOpen]['parenthesis_owner']) === true - && $tokens[$tokens[$deepestOpen]['parenthesis_owner']]['code'] === T_FUNCTION - ) { - throw new RuntimeException('$stackPtr is not a class member var'); - } - } - - $valid = Collections::$propertyModifierKeywords; - $valid += Tokens::$emptyTokens; - - $scope = 'public'; - $scopeSpecified = false; - $isStatic = false; - - $startOfStatement = $phpcsFile->findPrevious( - [ - T_SEMICOLON, - T_OPEN_CURLY_BRACKET, - T_CLOSE_CURLY_BRACKET, - ], - ($stackPtr - 1) - ); - - for ($i = ($startOfStatement + 1); $i < $stackPtr; $i++) { - if (isset($valid[$tokens[$i]['code']]) === false) { - break; - } - - switch ($tokens[$i]['code']) { - case T_PUBLIC: - $scope = 'public'; - $scopeSpecified = true; - break; - case T_PRIVATE: - $scope = 'private'; - $scopeSpecified = true; - break; - case T_PROTECTED: - $scope = 'protected'; - $scopeSpecified = true; - break; - case T_STATIC: - $isStatic = true; - break; - } - } - - $type = ''; - $typeToken = false; - $typeEndToken = false; - $nullableType = false; - $propertyTypeTokens = Collections::propertyTypeTokensBC(); - - if ($i < $stackPtr) { - // We've found a type. - for ($i; $i < $stackPtr; $i++) { - if ($tokens[$i]['code'] === T_VARIABLE) { - // Hit another variable in a group definition. - break; - } - - if ($tokens[$i]['type'] === 'T_NULLABLE' - // Handle nullable property types in PHPCS < 3.5.0. - || $tokens[$i]['code'] === T_INLINE_THEN - ) { - $nullableType = true; - } - - if (isset($propertyTypeTokens[$tokens[$i]['code']]) === true) { - $typeEndToken = $i; - if ($typeToken === false) { - $typeToken = $i; - } - - $type .= $tokens[$i]['content']; - } - } - - if ($type !== '' && $nullableType === true) { - $type = '?' . $type; - } - } - - return [ - 'scope' => $scope, - 'scope_specified' => $scopeSpecified, - 'is_static' => $isStatic, - 'type' => $type, - 'type_token' => $typeToken, - 'type_end_token' => $typeEndToken, - 'nullable_type' => $nullableType, - ]; + return $phpcsFile->getMemberProperties($stackPtr); } /** @@ -900,10 +536,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 1.3.0. - * - PHPCS 3.0.0: The Exception thrown changed from a `PHP_CodeSniffer_Exception` to - * `\PHP_CodeSniffer\Exceptions\TokenizerException`. - * - PHPCS 3.5.0: The Exception thrown changed from a `\PHP_CodeSniffer\Exceptions\TokenizerException` - * to`\PHP_CodeSniffer\Exceptions\RuntimeException`. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::getClassProperties() Original source. * @see \PHPCSUtils\Utils\ObjectDeclarations::getClassProperties() PHPCSUtils native improved version. @@ -921,43 +554,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) */ public static function getClassProperties(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] !== T_CLASS) { - throw new RuntimeException('$stackPtr must be of type T_CLASS'); - } - - $valid = [ - T_FINAL => T_FINAL, - T_ABSTRACT => T_ABSTRACT, - T_WHITESPACE => T_WHITESPACE, - T_COMMENT => T_COMMENT, - T_DOC_COMMENT => T_DOC_COMMENT, - ]; - - $isAbstract = false; - $isFinal = false; - - for ($i = ($stackPtr - 1); $i > 0; $i--) { - if (isset($valid[$tokens[$i]['code']]) === false) { - break; - } - - switch ($tokens[$i]['code']) { - case T_ABSTRACT: - $isAbstract = true; - break; - - case T_FINAL: - $isFinal = true; - break; - } - } - - return [ - 'is_abstract' => $isAbstract, - 'is_final' => $isFinal, - ]; + return $phpcsFile->getClassProperties($stackPtr); } /** @@ -967,23 +564,12 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 0.0.5. - * - PHPCS 3.1.1: Bug fix: misidentification of reference vs bitwise operator, PHPCS#1604/#1609. - * - An array assignment of a calculated value with a bitwise and operator in it, - * was being misidentified as a reference. - * - A calculated default value for a function parameter with a bitwise and operator - * in it, was being misidentified as a reference. - * - New by reference was not recognized as a reference. - * - References to class properties with `self::`, `parent::`, `static::`, - * `namespace\ClassName::`, `classname::` were not recognized as references. - * - PHPCS 3.5.3: Added support for PHP 7.4 `T_FN` arrow functions returning by reference. - * - PHPCS 3.5.6: Bug fix: the reference operator for closures declared to return by reference was - * not recognized as a reference. PHPCS#2977. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::isReference() Original source. * @see \PHPCSUtils\Utils\Operators::isReference() PHPCSUtils native improved version. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the `T_BITWISE_AND` token. @@ -993,118 +579,7 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) */ public static function isReference(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - if ($tokens[$stackPtr]['code'] !== T_BITWISE_AND) { - return false; - } - - $tokenBefore = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - - if ($tokens[$tokenBefore]['code'] === T_FUNCTION - || $tokens[$tokenBefore]['code'] === T_CLOSURE - || FunctionDeclarations::isArrowFunction($phpcsFile, $tokenBefore) === true - ) { - // Function returns a reference. - return true; - } - - if ($tokens[$tokenBefore]['code'] === T_DOUBLE_ARROW) { - // Inside a foreach loop or array assignment, this is a reference. - return true; - } - - if ($tokens[$tokenBefore]['code'] === T_AS) { - // Inside a foreach loop, this is a reference. - return true; - } - - if (isset(BCTokens::assignmentTokens()[$tokens[$tokenBefore]['code']]) === true) { - // This is directly after an assignment. It's a reference. Even if - // it is part of an operation, the other tests will handle it. - return true; - } - - $tokenAfter = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); - - if ($tokens[$tokenAfter]['code'] === T_NEW) { - return true; - } - - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $brackets = $tokens[$stackPtr]['nested_parenthesis']; - $lastBracket = array_pop($brackets); - if (isset($tokens[$lastBracket]['parenthesis_owner']) === true) { - $owner = $tokens[$tokens[$lastBracket]['parenthesis_owner']]; - if ($owner['code'] === T_FUNCTION - || $owner['code'] === T_CLOSURE - ) { - $params = self::getMethodParameters($phpcsFile, $tokens[$lastBracket]['parenthesis_owner']); - foreach ($params as $param) { - $varToken = $tokenAfter; - if ($param['variable_length'] === true) { - $varToken = $phpcsFile->findNext( - (Tokens::$emptyTokens + [T_ELLIPSIS]), - ($stackPtr + 1), - null, - true - ); - } - - if ($param['token'] === $varToken - && $param['pass_by_reference'] === true - ) { - // Function parameter declared to be passed by reference. - return true; - } - } - } - } else { - $prev = false; - for ($t = ($tokens[$lastBracket]['parenthesis_opener'] - 1); $t >= 0; $t--) { - if ($tokens[$t]['code'] !== T_WHITESPACE) { - $prev = $t; - break; - } - } - - if ($prev !== false && $tokens[$prev]['code'] === T_USE) { - // Closure use by reference. - return true; - } - } - } - - // Pass by reference in function calls and assign by reference in arrays. - if ($tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS - || $tokens[$tokenBefore]['code'] === T_COMMA - || $tokens[$tokenBefore]['code'] === T_OPEN_SHORT_ARRAY - ) { - if ($tokens[$tokenAfter]['code'] === T_VARIABLE) { - return true; - } else { - $skip = Tokens::$emptyTokens; - $skip[] = T_NS_SEPARATOR; - $skip[] = T_SELF; - $skip[] = T_PARENT; - $skip[] = T_STATIC; - $skip[] = T_STRING; - $skip[] = T_NAMESPACE; - $skip[] = T_DOUBLE_COLON; - - $nextSignificantAfter = $phpcsFile->findNext( - $skip, - ($stackPtr + 1), - null, - true - ); - if ($tokens[$nextSignificantAfter]['code'] === T_VARIABLE) { - return true; - } - } - } - - return false; + return $phpcsFile->isReference($stackPtr); } /** @@ -1115,12 +590,7 @@ public static function isReference(File $phpcsFile, $stackPtr) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 0.0.5. - * - PHPCS 3.3.0: New `$origContent` parameter to optionally return original - * (non tab-replaced) content. - * - PHPCS 3.4.0: - * - Now throws a `RuntimeException` if the `$start` param is invalid. - * This stops an infinite loop when the function is passed invalid data. - * - If the `$length` param is invalid, an empty string will be returned. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::getTokensAsString() Original source. * @see \PHPCSUtils\Utils\GetTokensAsString Related set of functions. @@ -1139,33 +609,7 @@ public static function isReference(File $phpcsFile, $stackPtr) */ public static function getTokensAsString(File $phpcsFile, $start, $length, $origContent = false) { - $tokens = $phpcsFile->getTokens(); - - if (is_int($start) === false || isset($tokens[$start]) === false) { - throw new RuntimeException('The $start position for getTokensAsString() must exist in the token stack'); - } - - if (is_int($length) === false || $length <= 0) { - return ''; - } - - $str = ''; - $end = ($start + $length); - if ($end > $phpcsFile->numTokens) { - $end = $phpcsFile->numTokens; - } - - for ($i = $start; $i < $end; $i++) { - // If tabs are being converted to spaces by the tokeniser, the - // original content should be used instead of the converted content. - if ($origContent === true && isset($tokens[$i]['orig_content']) === true) { - $str .= $tokens[$i]['orig_content']; - } else { - $str .= $tokens[$i]['content']; - } - } - - return $str; + return $phpcsFile->getTokensAsString($start, $length, $origContent); } /** @@ -1175,13 +619,11 @@ public static function getTokensAsString(File $phpcsFile, $start, $length, $orig * * Changelog for the PHPCS native function: * - Introduced in PHPCS 2.1.0. - * - PHPCS 2.6.2: New optional `$ignore` parameter to selectively ignore stop points. - * - PHPCS 3.5.5: Added support for PHP 7.4 `T_FN` arrow functions. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::findStartOfStatement() Original source. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $start The position to start searching from in the token stack. @@ -1191,58 +633,7 @@ public static function getTokensAsString(File $phpcsFile, $start, $length, $orig */ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = null) { - $tokens = $phpcsFile->getTokens(); - - $endTokens = Tokens::$blockOpeners; - - $endTokens[T_COLON] = true; - $endTokens[T_COMMA] = true; - $endTokens[T_DOUBLE_ARROW] = true; - $endTokens[T_SEMICOLON] = true; - $endTokens[T_OPEN_TAG] = true; - $endTokens[T_CLOSE_TAG] = true; - $endTokens[T_OPEN_SHORT_ARRAY] = true; - - if ($ignore !== null) { - $ignore = (array) $ignore; - foreach ($ignore as $code) { - unset($endTokens[$code]); - } - } - - $lastNotEmpty = $start; - - for ($i = $start; $i >= 0; $i--) { - if (isset($endTokens[$tokens[$i]['code']]) === true) { - // Found the end of the previous statement. - return $lastNotEmpty; - } - - if (isset($tokens[$i]['scope_opener']) === true - && $i === $tokens[$i]['scope_closer'] - && $tokens[$i]['code'] !== T_CLOSE_PARENTHESIS - ) { - // Found the end of the previous scope block. - return $lastNotEmpty; - } - - // Skip nested statements. - if (isset($tokens[$i]['bracket_opener']) === true - && $i === $tokens[$i]['bracket_closer'] - ) { - $i = $tokens[$i]['bracket_opener']; - } elseif (isset($tokens[$i]['parenthesis_opener']) === true - && $i === $tokens[$i]['parenthesis_closer'] - ) { - $i = $tokens[$i]['parenthesis_opener']; - } - - if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) { - $lastNotEmpty = $i; - } - } - - return 0; + return $phpcsFile->findStartOfStatement($start, $ignore); } /** @@ -1252,18 +643,11 @@ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = n * * Changelog for the PHPCS native function: * - Introduced in PHPCS 2.1.0. - * - PHPCS 2.6.2: New optional `$ignore` parameter to selectively ignore stop points. - * - PHPCS 2.7.1: Improved handling of short arrays, PHPCS #1203. - * - PHPCS 3.3.0: Bug fix: end of statement detection when passed a scope opener, PHPCS #1863. - * - PHPCS 3.5.0: Improved handling of group use statements. - * - PHPCS 3.5.3: Added support for PHP 7.4 `T_FN` arrow functions. - * - PHPCS 3.5.4: Improved support for PHP 7.4 `T_FN` arrow functions. - * - PHPCS 3.5.5: Improved support for PHP 7.4 `T_FN` arrow functions, PHPCS #2895. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::findEndOfStatement() Original source. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $start The position to start searching from in the token stack. @@ -1273,98 +657,7 @@ public static function findStartOfStatement(File $phpcsFile, $start, $ignore = n */ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = null) { - $tokens = $phpcsFile->getTokens(); - - $endTokens = [ - T_COLON => true, - T_COMMA => true, - T_DOUBLE_ARROW => true, - T_SEMICOLON => true, - T_CLOSE_PARENTHESIS => true, - T_CLOSE_SQUARE_BRACKET => true, - T_CLOSE_CURLY_BRACKET => true, - T_CLOSE_SHORT_ARRAY => true, - T_OPEN_TAG => true, - T_CLOSE_TAG => true, - ]; - - if ($ignore !== null) { - $ignore = (array) $ignore; - foreach ($ignore as $code) { - unset($endTokens[$code]); - } - } - - $lastNotEmpty = $start; - for ($i = $start; $i < $phpcsFile->numTokens; $i++) { - if ($i !== $start && isset($endTokens[$tokens[$i]['code']]) === true) { - // Found the end of the statement. - if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS - || $tokens[$i]['code'] === T_CLOSE_SQUARE_BRACKET - || $tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET - || $tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY - || $tokens[$i]['code'] === T_OPEN_TAG - || $tokens[$i]['code'] === T_CLOSE_TAG - ) { - return $lastNotEmpty; - } - - return $i; - } - - // Skip nested statements. - if (isset($tokens[$i]['scope_closer']) === true - && ($i === $tokens[$i]['scope_opener'] - || $i === $tokens[$i]['scope_condition']) - ) { - if ($tokens[$i]['type'] === 'T_FN') { - $lastNotEmpty = $tokens[$i]['scope_closer']; - - // Minus 1 as the closer can be shared. - $i = ($tokens[$i]['scope_closer'] - 1); - continue; - } - - if ($i === $start && isset(Tokens::$scopeOpeners[$tokens[$i]['code']]) === true) { - return $tokens[$i]['scope_closer']; - } - - $i = $tokens[$i]['scope_closer']; - } elseif (isset($tokens[$i]['bracket_closer']) === true - && $i === $tokens[$i]['bracket_opener'] - ) { - $i = $tokens[$i]['bracket_closer']; - } elseif (isset($tokens[$i]['parenthesis_closer']) === true - && $i === $tokens[$i]['parenthesis_opener'] - ) { - $i = $tokens[$i]['parenthesis_closer']; - } elseif ($tokens[$i]['code'] === T_OPEN_USE_GROUP) { - $end = $phpcsFile->findNext(T_CLOSE_USE_GROUP, ($i + 1)); - if ($end !== false) { - $i = $end; - } - } elseif (isset(Collections::arrowFunctionTokensBC()[$tokens[$i]['code']]) === true) { - // Potentially a PHP 7.4 arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/3.5.4. - $arrowFunctionOpenClose = FunctionDeclarations::getArrowFunctionOpenClose($phpcsFile, $i); - if ($arrowFunctionOpenClose !== false) { - if ($i === $start) { - return $arrowFunctionOpenClose['scope_closer']; - } - - $lastNotEmpty = $arrowFunctionOpenClose['scope_closer']; - - // Minus 1 as the closer can be shared. - $i = ($arrowFunctionOpenClose['scope_closer'] - 1); - continue; - } - } - - if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) { - $lastNotEmpty = $i; - } - } - - return ($phpcsFile->numTokens - 1); + return $phpcsFile->findEndOfStatement($start, $ignore); } /** @@ -1374,7 +667,7 @@ public static function findEndOfStatement(File $phpcsFile, $start, $ignore = nul * * Changelog for the PHPCS native function: * - Introduced in PHPCS 0.0.5. - * - This method has received no significant code updates since PHPCS 2.6.0. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::hasCondition() Original source. * @see \PHPCSUtils\Utils\Conditions::hasCondition() PHPCSUtils native alternative. @@ -1399,14 +692,12 @@ public static function hasCondition(File $phpcsFile, $stackPtr, $types) * * Changelog for the PHPCS native function: * - Introduced in PHPCS 1.3.0. - * - PHPCS 3.5.4: New `$first` parameter which allows for the closest matching token to be returned. - * By default, it continues to return the first matched token found from the top of the file. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::getCondition() Original source. * @see \PHPCSUtils\Utils\Conditions::getCondition() More versatile alternative. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added support for the PHPCS 3.5.4 `$first` parameter. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. @@ -1421,30 +712,7 @@ public static function hasCondition(File $phpcsFile, $stackPtr, $types) */ public static function getCondition(File $phpcsFile, $stackPtr, $type, $first = true) { - $tokens = $phpcsFile->getTokens(); - - // Check for the existence of the token. - if (isset($tokens[$stackPtr]) === false) { - return false; - } - - // Make sure the token has conditions. - if (isset($tokens[$stackPtr]['conditions']) === false) { - return false; - } - - $conditions = $tokens[$stackPtr]['conditions']; - if ($first === false) { - $conditions = array_reverse($conditions, true); - } - - foreach ($conditions as $token => $condition) { - if ($condition === $type) { - return $token; - } - } - - return false; + return $phpcsFile->getCondition($stackPtr, $type, $first); } /** @@ -1455,10 +723,7 @@ public static function getCondition(File $phpcsFile, $stackPtr, $type, $first = * * Changelog for the PHPCS native function: * - Introduced in PHPCS 1.2.0. - * - PHPCS 2.8.0: Now supports anonymous classes. - * - PHPCS 3.1.0: Now supports interfaces extending interfaces (incorrectly, only supporting - * single interface extension). - * - PHPCS 3.3.2: Fixed bug causing bleed through with nested classes, PHPCS#2127. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::findExtendedClassName() Original source. * @see \PHPCSUtils\Utils\ObjectDeclarations::findExtendedClassName() PHPCSUtils native improved version. @@ -1473,55 +738,17 @@ public static function getCondition(File $phpcsFile, $stackPtr, $type, $first = */ public static function findExtendedClassName(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - // Check for the existence of the token. - if (isset($tokens[$stackPtr]) === false) { - return false; - } - - if ($tokens[$stackPtr]['code'] !== T_CLASS - && $tokens[$stackPtr]['code'] !== T_ANON_CLASS - && $tokens[$stackPtr]['code'] !== T_INTERFACE - ) { - return false; - } - - if (isset($tokens[$stackPtr]['scope_opener']) === false) { - return false; - } - - $classOpenerIndex = $tokens[$stackPtr]['scope_opener']; - $extendsIndex = $phpcsFile->findNext(T_EXTENDS, $stackPtr, $classOpenerIndex); - if ($extendsIndex === false) { - return false; - } - - $find = [ - T_NS_SEPARATOR, - T_STRING, - T_WHITESPACE, - ]; - - $end = $phpcsFile->findNext($find, ($extendsIndex + 1), ($classOpenerIndex + 1), true); - $name = $phpcsFile->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1)); - $name = trim($name); - - if ($name === '') { - return false; - } - - return $name; + return $phpcsFile->findExtendedClassName($stackPtr); } /** - * Returns the names of the interfaces that the specified class implements. + * Returns the names of the interfaces that the specified class or enum implements. * * PHPCS cross-version compatible version of the `File::findImplementedInterfaceNames()` method. * * Changelog for the PHPCS native function: * - Introduced in PHPCS 2.7.0. - * - PHPCS 2.8.0: Now supports anonymous classes. + * - The upstream method has received no significant updates since PHPCS 3.7.1. * * @see \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames() Original source. * @see \PHPCSUtils\Utils\ObjectDeclarations::findImplementedInterfaceNames() PHPCSUtils native improved version. @@ -1529,53 +756,13 @@ public static function findExtendedClassName(File $phpcsFile, $stackPtr) * @since 1.0.0 * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The stack position of the class. + * @param int $stackPtr The stack position of the class or enum token. * * @return array|false Array with names of the implemented interfaces or `FALSE` on * error or if there are no implemented interface names. */ public static function findImplementedInterfaceNames(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - // Check for the existence of the token. - if (isset($tokens[$stackPtr]) === false) { - return false; - } - - if ($tokens[$stackPtr]['code'] !== T_CLASS - && $tokens[$stackPtr]['code'] !== T_ANON_CLASS - ) { - return false; - } - - if (isset($tokens[$stackPtr]['scope_closer']) === false) { - return false; - } - - $classOpenerIndex = $tokens[$stackPtr]['scope_opener']; - $implementsIndex = $phpcsFile->findNext(T_IMPLEMENTS, $stackPtr, $classOpenerIndex); - if ($implementsIndex === false) { - return false; - } - - $find = [ - T_NS_SEPARATOR, - T_STRING, - T_WHITESPACE, - T_COMMA, - ]; - - $end = $phpcsFile->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true); - $name = $phpcsFile->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1)); - $name = trim($name); - - if ($name === '') { - return false; - } else { - $names = explode(',', $name); - $names = array_map('trim', $names); - return $names; - } + return $phpcsFile->findImplementedInterfaceNames($stackPtr); } } diff --git a/PHPCSUtils/BackCompat/BCTokens.php b/PHPCSUtils/BackCompat/BCTokens.php index ee430758..52aed62a 100644 --- a/PHPCSUtils/BackCompat/BCTokens.php +++ b/PHPCSUtils/BackCompat/BCTokens.php @@ -11,6 +11,8 @@ namespace PHPCSUtils\BackCompat; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Exceptions\InvalidTokenArray; +use PHPCSUtils\Tokens\Collections; /** * Token arrays related utility methods. @@ -40,76 +42,40 @@ * the token arrays returned by this class. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. * - * @method static array blockOpeners() Tokens that open code blocks. - * @method static array booleanOperators() Tokens that perform boolean operations. - * @method static array bracketTokens() Tokens that represent brackets and parenthesis. - * @method static array castTokens() Tokens that represent type casting. - * @method static array commentTokens() Tokens that are comments. - * @method static array emptyTokens() Tokens that don't represent code. - * @method static array equalityTokens() Tokens that represent equality comparisons. - * @method static array heredocTokens() Tokens that make up a heredoc string. - * @method static array includeTokens() Tokens that include files. - * @method static array methodPrefixes() Tokens that can prefix a method name. - * @method static array scopeModifiers() Tokens that represent scope modifiers. - * @method static array scopeOpeners() Tokens that are allowed to open scopes. - * @method static array stringTokens() Tokens that represent strings. - * Note that `T_STRINGS` are NOT represented in this list as this list - * is about _text_ strings. + * @method static array arithmeticTokens() Tokens that represent arithmetic operators. + * @method static array assignmentTokens() Tokens that represent assignments. + * @method static array blockOpeners() Tokens that open code blocks. + * @method static array booleanOperators() Tokens that perform boolean operations. + * @method static array bracketTokens() Tokens that represent brackets and parenthesis. + * @method static array castTokens() Tokens that represent type casting. + * @method static array commentTokens() Tokens that are comments. + * @method static array comparisonTokens() Tokens that represent comparison operator. + * @method static array contextSensitiveKeywords() Tokens representing context sensitive keywords in PHP. + * @method static array emptyTokens() Tokens that don't represent code. + * @method static array equalityTokens() Tokens that represent equality comparisons. + * @method static array heredocTokens() Tokens that make up a heredoc string. + * @method static array includeTokens() Tokens that include files. + * @method static array magicConstants() Tokens representing PHP magic constants. + * @method static array methodPrefixes() Tokens that can prefix a method name. + * @method static array ooScopeTokens() Tokens that open class and object scopes. + * @method static array operators() Tokens that perform operations. + * @method static array parenthesisOpeners() Token types that open parenthesis. + * @method static array phpcsCommentTokens() Tokens that are comments containing PHPCS instructions. + * @method static array scopeModifiers() Tokens that represent scope modifiers. + * @method static array scopeOpeners() Tokens that are allowed to open scopes. + * @method static array stringTokens() Tokens that represent strings. + * Note that `T_STRING`s are NOT represented in this list as this list + * is about _text_ strings. + * @method static array textStringTokens() Tokens that represent text strings. */ -class BCTokens +final class BCTokens { - /** - * Token types that are comments containing PHPCS instructions. - * - * @since 1.0.0 - * @since 1.0.0-alpha3 Visibility changed from `protected` to `private`. - * - * @var string[] - */ - private static $phpcsCommentTokensTypes = [ - 'T_PHPCS_ENABLE', - 'T_PHPCS_DISABLE', - 'T_PHPCS_SET', - 'T_PHPCS_IGNORE', - 'T_PHPCS_IGNORE_FILE', - ]; - - /** - * Tokens that open class and object scopes. - * - * @since 1.0.0 - * @since 1.0.0-alpha3 Visibility changed from `protected` to `private`. - * - * @var array => - */ - private static $ooScopeTokens = [ - \T_CLASS => \T_CLASS, - \T_ANON_CLASS => \T_ANON_CLASS, - \T_INTERFACE => \T_INTERFACE, - \T_TRAIT => \T_TRAIT, - ]; - - /** - * Tokens that represent text strings. - * - * @since 1.0.0 - * @since 1.0.0-alpha3 Visibility changed from `protected` to `private`. - * - * @var array => - */ - private static $textStringTokens = [ - \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, - \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, - \T_INLINE_HTML => \T_INLINE_HTML, - \T_HEREDOC => \T_HEREDOC, - \T_NOWDOC => \T_NOWDOC, - ]; - /** * Handle calls to (undeclared) methods for token arrays which haven't received any - * changes since PHPCS 2.6.0. + * changes since PHPCS 3.7.1. * * @since 1.0.0 * @@ -118,6 +84,8 @@ class BCTokens * Unused as none of the methods take arguments. * * @return array => Token array + * + * @throws \PHPCSUtils\Exceptions\InvalidTokenArray When an invalid token array is requested. */ public static function __callStatic($name, $args) { @@ -125,228 +93,8 @@ public static function __callStatic($name, $args) return Tokens::${$name}; } - // Default to an empty array. - return []; - } - - /** - * Tokens that represent assignment operators. - * - * Retrieve the PHPCS assignment tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.0.5. - * - PHPCS 2.9.0: The PHP 7.4 `T_COALESCE_EQUAL` token was added to the array. - * The `T_COALESCE_EQUAL` token was introduced in PHPCS 2.8.1. - * - PHPCS 3.2.0: The JS `T_ZSR_EQUAL` token was added to the array. - * The `T_ZSR_EQUAL` token was introduced in PHPCS 2.8.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$assignmentTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function assignmentTokens() - { - $tokens = Tokens::$assignmentTokens; - - /* - * The `T_COALESCE_EQUAL` token may be available pre-PHPCS 2.8.1 depending on - * the PHP version used to run PHPCS. - */ - if (\defined('T_COALESCE_EQUAL')) { - $tokens[\T_COALESCE_EQUAL] = \T_COALESCE_EQUAL; - } - - if (\defined('T_ZSR_EQUAL')) { - $tokens[\T_ZSR_EQUAL] = \T_ZSR_EQUAL; - } - - return $tokens; - } - - /** - * Tokens that represent comparison operators. - * - * Retrieve the PHPCS comparison tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.5.0. - * - PHPCS 2.9.0: The PHP 7.0 `T_COALESCE` token was added to the array. - * The `T_COALESCE` token was introduced in PHPCS 2.6.1. - * - PHPCS 2.9.0: The PHP 7.0 `T_SPACESHIP` token was added to the array. - * The `T_SPACESHIP` token was introduced in PHPCS 2.5.1. - * - * @see \PHP_CodeSniffer\Util\Tokens::$comparisonTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function comparisonTokens() - { - $tokens = Tokens::$comparisonTokens + [\T_SPACESHIP => \T_SPACESHIP]; - - if (\defined('T_COALESCE')) { - $tokens[\T_COALESCE] = \T_COALESCE; - } - - return $tokens; - } - - /** - * Tokens that represent arithmetic operators. - * - * Retrieve the PHPCS arithmetic tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.5.0. - * - PHPCS 2.9.0: The PHP 5.6 `T_POW` token was added to the array. - * The `T_POW` token was introduced in PHPCS 2.4.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$arithmeticTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array or an empty array for PHPCS versions in - * which the PHPCS native comment tokens did not exist yet. - */ - public static function arithmeticTokens() - { - return Tokens::$arithmeticTokens + [\T_POW => \T_POW]; - } - - /** - * Tokens that perform operations. - * - * Retrieve the PHPCS operator tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.0.5. - * - PHPCS 2.6.1: The PHP 7.0 `T_COALESCE` token was backfilled and added to the array. - * - PHPCS 2.8.1: The PHP 7.4 `T_COALESCE_EQUAL` token was backfilled and (incorrectly) - * added to the array. - * - PHPCS 2.9.0: The `T_COALESCE_EQUAL` token was removed from the array. - * - * @see \PHP_CodeSniffer\Util\Tokens::$operators Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function operators() - { - $tokens = Tokens::$operators; - - /* - * The `T_COALESCE` token may be available pre-PHPCS 2.6.1 depending on the PHP version - * used to run PHPCS. - */ - if (\defined('T_COALESCE')) { - $tokens[\T_COALESCE] = \T_COALESCE; - } - - if (\defined('T_COALESCE_EQUAL')) { - unset($tokens[\T_COALESCE_EQUAL]); - } - - return $tokens; - } - - /** - * Token types that open parentheses. - * - * Retrieve the PHPCS parenthesis openers tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 0.0.5. - * - PHPCS 3.5.0: `T_LIST` and `T_ANON_CLASS` added to the array. - * - * Note: While `T_LIST` and `T_ANON_CLASS` will be included in the return value for this - * method, the associated parentheses will not have the `'parenthesis_owner'` index set - * until PHPCS 3.5.0. Use the {@see \PHPCSUtils\Utils\Parentheses::getOwner()} - * or {@see \PHPCSUtils\Utils\Parentheses::hasOwner()} methods if you need to check for - * a `T_LIST` or `T_ANON_CLASS` parentheses owner. - * - * @see \PHP_CodeSniffer\Util\Tokens::$parenthesisOpeners Original array. - * @see \PHPCSUtils\Utils\Parentheses Class holding utility methods for - * working with the `'parenthesis_...'` - * index keys in a token array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function parenthesisOpeners() - { - $tokens = Tokens::$parenthesisOpeners; - $tokens[\T_LIST] = \T_LIST; - $tokens[\T_ANON_CLASS] = \T_ANON_CLASS; - - return $tokens; - } - - /** - * Tokens that are comments containing PHPCS instructions. - * - * Retrieve the PHPCS comment tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 3.2.3. The PHPCS comment tokens, however, were introduced in - * PHPCS 3.2.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$phpcsCommentTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array or an empty array for PHPCS - * versions in which the PHPCS native annotation - * tokens did not exist yet. - */ - public static function phpcsCommentTokens() - { - static $tokenArray = []; - - if (isset(Tokens::$phpcsCommentTokens)) { - return Tokens::$phpcsCommentTokens; - } - - if (\defined('T_PHPCS_IGNORE')) { - // PHPCS 3.2.0 - 3.2.2. - if (empty($tokenArray)) { - foreach (self::$phpcsCommentTokensTypes as $type) { - $tokenArray[\constant($type)] = \constant($type); - } - } - - return $tokenArray; - } - - return []; - } - - /** - * Tokens that represent text strings. - * - * Retrieve the PHPCS text string tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 2.9.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$textStringTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function textStringTokens() - { - if (isset(Tokens::$textStringTokens)) { - return Tokens::$textStringTokens; - } - - return self::$textStringTokens; + // Unknown token array requested. + throw InvalidTokenArray::create($name); } /** @@ -356,7 +104,8 @@ public static function textStringTokens() * * Changelog for the PHPCS native array: * - Introduced in PHPCS 2.3.3. - * - PHPCS 3.1.0: `T_SELF` and `T_STATIC` added to the array. + * - PHPCS 3.7.2: `T_PARENT` added to the array. + * - PHPCS 4.0.0: `T_NAME_QUALIFIED`, `T_NAME_FULLY_QUALIFIED` and `T_NAME_RELATIVE` added to the array. * * @see \PHP_CodeSniffer\Util\Tokens::$functionNameTokens Original array. * @@ -366,33 +115,10 @@ public static function textStringTokens() */ public static function functionNameTokens() { - $tokens = Tokens::$functionNameTokens; - $tokens[\T_SELF] = \T_SELF; - $tokens[\T_STATIC] = \T_STATIC; + $tokens = Tokens::$functionNameTokens; + $tokens += Collections::ooHierarchyKeywords(); + $tokens += Collections::nameTokens(); return $tokens; } - - /** - * Tokens that open class and object scopes. - * - * Retrieve the OO scope tokens array in a cross-version compatible manner. - * - * Changelog for the PHPCS native array: - * - Introduced in PHPCS 3.1.0. - * - * @see \PHP_CodeSniffer\Util\Tokens::$ooScopeTokens Original array. - * - * @since 1.0.0 - * - * @return array => Token array. - */ - public static function ooScopeTokens() - { - if (isset(Tokens::$ooScopeTokens)) { - return Tokens::$ooScopeTokens; - } - - return self::$ooScopeTokens; - } } diff --git a/PHPCSUtils/BackCompat/Helper.php b/PHPCSUtils/BackCompat/Helper.php index 20bd8829..bab4f694 100644 --- a/PHPCSUtils/BackCompat/Helper.php +++ b/PHPCSUtils/BackCompat/Helper.php @@ -10,23 +10,20 @@ namespace PHPCSUtils\BackCompat; +use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; /** * Utility methods to retrieve (configuration) information from PHP_CodeSniffer. * - * PHP_CodeSniffer cross-version compatibility helper for PHPCS 2.x vs PHPCS 3.x. + * PHP_CodeSniffer cross-version compatibility helper. * - * A number of PHPCS classes were split up into several classes in PHPCS 3.x - * Those classes cannot be aliased as they don't represent the same object. - * This class provides helper methods for functions which were contained in - * one of these classes and which are commonly used by external standards. - * - * @since 1.0.0 The initial methods in this class have been ported over from - * the external PHPCompatibility & WPCS standards. + * @since 1.0.0 The initial methods in this class have been ported over from + * the external PHPCompatibility & WPCS standards. + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Helper +final class Helper { /** @@ -47,13 +44,7 @@ class Helper */ public static function getVersion() { - if (\defined('\PHP_CodeSniffer\Config::VERSION') === false) { - // PHPCS 2.x. - return \PHP_CodeSniffer::VERSION; - } - - // PHPCS 3.x. - return \PHP_CodeSniffer\Config::VERSION; + return Config::VERSION; } /** @@ -76,11 +67,6 @@ public static function getVersion() */ public static function setConfigData($key, $value, $temp = false, $config = null) { - if (\method_exists('\PHP_CodeSniffer\Config', 'setConfigData') === false) { - // PHPCS 2.x. - return \PHP_CodeSniffer::setConfigData($key, $value, $temp); - } - if (isset($config) === true) { // PHPCS 3.x and 4.x. return $config->setConfigData($key, $value, $temp); @@ -91,7 +77,7 @@ public static function setConfigData($key, $value, $temp = false, $config = null } // PHPCS 3.x. - return \PHP_CodeSniffer\Config::setConfigData($key, $value, $temp); + return Config::setConfigData($key, $value, $temp); } /** @@ -108,13 +94,7 @@ public static function setConfigData($key, $value, $temp = false, $config = null */ public static function getConfigData($key) { - if (\method_exists('\PHP_CodeSniffer\Config', 'getConfigData') === false) { - // PHPCS 2.x. - return \PHP_CodeSniffer::getConfigData($key); - } - - // PHPCS 3.x. - return \PHP_CodeSniffer\Config::getConfigData($key); + return Config::getConfigData($key); } /** @@ -132,18 +112,8 @@ public static function getConfigData($key) */ public static function getCommandLineData(File $phpcsFile, $key) { - if (\class_exists('\PHP_CodeSniffer\Config') === false) { - // PHPCS 2.x. - $config = $phpcsFile->phpcs->cli->getCommandLineValues(); - if (isset($config[$key])) { - return $config[$key]; - } - } else { - // PHPCS 3.x. - $config = $phpcsFile->config; - if (isset($config->{$key})) { - return $config->{$key}; - } + if (isset($phpcsFile->config->{$key})) { + return $phpcsFile->config->{$key}; } return null; @@ -178,19 +148,11 @@ public static function getTabWidth(File $phpcsFile) * @param \PHP_CodeSniffer\Files\File|null $phpcsFile Optional. The current file being processed. * * @return string Encoding. Defaults to the PHPCS native default, which is 'utf-8' - * for PHPCS 3.x and was 'iso-8859-1' for PHPCS 2.x. + * for PHPCS 3.x. */ public static function getEncoding(File $phpcsFile = null) { - static $default; - - if (isset($default) === false) { - $default = 'utf-8'; - if (\version_compare(self::getVersion(), '2.99.99', '<=') === true) { - // In PHPCS 2.x, the default encoding is `iso-8859-1`. - $default = 'iso-8859-1'; - } - } + $default = 'utf-8'; if ($phpcsFile instanceof File) { // Most reliable. @@ -222,17 +184,11 @@ public static function getEncoding(File $phpcsFile = null) */ public static function ignoreAnnotations(File $phpcsFile = null) { - if (\class_exists('\PHP_CodeSniffer\Config') === false) { - // PHPCS 2.x does not support `--ignore-annotations`. - return false; - } - - // PHPCS 3.x. if (isset($phpcsFile, $phpcsFile->config->annotations)) { return ! $phpcsFile->config->annotations; } - $annotations = \PHP_CodeSniffer\Config::getConfigData('annotations'); + $annotations = Config::getConfigData('annotations'); if (isset($annotations)) { return ! $annotations; } diff --git a/PHPCSUtils/Exceptions/InvalidTokenArray.php b/PHPCSUtils/Exceptions/InvalidTokenArray.php new file mode 100644 index 00000000..8fcc5121 --- /dev/null +++ b/PHPCSUtils/Exceptions/InvalidTokenArray.php @@ -0,0 +1,44 @@ +> Format: $cache[$loop][$fileName][$key][$id] = mixed $value; + */ + private static $cache = []; + + /** + * Check whether a result has been cached for a certain utility function. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param string $key The key to identify a particular set of results. + * It is recommended to pass __METHOD__ to this parameter. + * @param int|string $id Unique identifier for these results. + * Generally speaking this will be the $stackPtr passed + * to the utility function, but it can also something else, + * like a serialization of args passed to a function or an + * md5 hash of an input. + * + * @return bool + */ + public static function isCached(File $phpcsFile, $key, $id) + { + if (self::$enabled === false) { + return false; + } + + $fileName = $phpcsFile->getFilename(); + $loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0; + + return isset(self::$cache[$loop][$fileName][$key]) + && \array_key_exists($id, self::$cache[$loop][$fileName][$key]); + } + + /** + * Retrieve a previously cached result for a certain utility function. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param string $key The key to identify a particular set of results. + * It is recommended to pass __METHOD__ to this parameter. + * @param int|string $id Unique identifier for these results. + * Generally speaking this will be the $stackPtr passed + * to the utility function, but it can also something else, + * like a serialization of args passed to a function or an + * md5 hash of an input. + * + * @return mixed + */ + public static function get(File $phpcsFile, $key, $id) + { + if (self::$enabled === false) { + return null; + } + + $fileName = $phpcsFile->getFilename(); + $loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0; + + if (isset(self::$cache[$loop][$fileName][$key]) + && \array_key_exists($id, self::$cache[$loop][$fileName][$key]) + ) { + return self::$cache[$loop][$fileName][$key][$id]; + } + + return null; + } + + /** + * Retrieve all previously cached results for a certain utility function and a certain file. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param string $key The key to identify a particular set of results. + * It is recommended to pass __METHOD__ to this parameter. + * + * @return array + */ + public static function getForFile(File $phpcsFile, $key) + { + if (self::$enabled === false) { + return []; + } + + $fileName = $phpcsFile->getFilename(); + $loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0; + + if (isset(self::$cache[$loop][$fileName]) + && \array_key_exists($key, self::$cache[$loop][$fileName]) + ) { + return self::$cache[$loop][$fileName][$key]; + } + + return []; + } + + /** + * Cache the result for a certain utility function. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param string $key The key to identify a particular set of results. + * It is recommended to pass __METHOD__ to this parameter. + * @param int|string $id Unique identifier for these results. + * Generally speaking this will be the $stackPtr passed + * to the utility function, but it can also something else, + * like a serialization of args passed to a function or an + * md5 hash of an input. + * @param mixed $value An arbitrary value to write to the cache. + * + * @return mixed + */ + public static function set(File $phpcsFile, $key, $id, $value) + { + if (self::$enabled === false) { + return; + } + + $fileName = $phpcsFile->getFilename(); + $loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0; + + /* + * If this is a phpcbf run and we've reached the next loop, clear the cache + * of all previous loops to free up memory. + */ + if (isset(self::$cache[$loop]) === false + && empty(self::$cache) === false + ) { + self::clear(); + } + + self::$cache[$loop][$fileName][$key][$id] = $value; + } + + /** + * Clear the cache. + * + * @return void + */ + public static function clear() + { + self::$cache = []; + } +} diff --git a/PHPCSUtils/Internal/IsShortArrayOrList.php b/PHPCSUtils/Internal/IsShortArrayOrList.php new file mode 100644 index 00000000..e881e746 --- /dev/null +++ b/PHPCSUtils/Internal/IsShortArrayOrList.php @@ -0,0 +1,700 @@ + => + */ + private $openBrackets; + + /** + * Constructor. + * + * @since 1.0.0-alpha4 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the short array opener token. + * + * @return void + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the token passed is not one of the + * accepted types or doesn't exist. + */ + public function __construct(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $openBrackets = Collections::shortArrayListOpenTokensBC(); + + if (isset($tokens[$stackPtr]) === false + || isset($openBrackets[$tokens[$stackPtr]['code']]) === false + ) { + throw new RuntimeException( + 'The IsShortArrayOrList class expects to be passed a T_OPEN_SHORT_ARRAY or T_OPEN_SQUARE_BRACKET token.' + ); + } + + $this->phpcsFile = $phpcsFile; + $this->tokens = $tokens; + $this->opener = $stackPtr; + + $this->closer = $stackPtr; + if (isset($this->tokens[$stackPtr]['bracket_closer'])) { + $this->closer = $this->tokens[$stackPtr]['bracket_closer']; + } + + $this->beforeOpener = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($this->opener - 1), null, true); + $this->afterCloser = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($this->closer + 1), null, true); + + $this->phpcsVersion = Helper::getVersion(); + $this->openBrackets = $openBrackets; + } + + /** + * Determine whether the bracket is a short array, short list or real square bracket. + * + * @since 1.0.0-alpha4 + * + * @return string Either 'short array', 'short list' or 'square brackets'. + */ + public function solve() + { + if ($this->isSquareBracket() === true) { + return self::SQUARE_BRACKETS; + } + + if ($this->afterCloser === false) { + // Live coding. Short array until told differently. + return self::SHORT_ARRAY; + } + + // If the bracket closer is followed by an equals sign, it's always a short list. + if ($this->tokens[$this->afterCloser]['code'] === \T_EQUAL) { + return self::SHORT_LIST; + } + + // Attributes can only contain constant expressions, i.e. lists not allowed. + if (Context::inAttribute($this->phpcsFile, $this->opener) === true) { + return self::SHORT_ARRAY; + } + + $type = $this->isInForeach(); + if ($type !== false) { + return $type; + } + + /* + * Check if this can be a nested set of brackets used as a value. + * That's the only "confusing" syntax left. In all other cases, it will be a short array. + */ + $hasRiskyTokenBeforeOpener = false; + if (isset($this->openBrackets[$this->tokens[$this->beforeOpener]['code']]) === true + || $this->tokens[$this->beforeOpener]['code'] === \T_COMMA + || $this->tokens[$this->beforeOpener]['code'] === \T_DOUBLE_ARROW + ) { + $hasRiskyTokenBeforeOpener = true; + } + + $hasRiskyTokenAfterCloser = false; + if ($this->tokens[$this->afterCloser]['code'] === \T_COMMA + || $this->tokens[$this->afterCloser]['code'] === \T_CLOSE_SHORT_ARRAY + || $this->tokens[$this->afterCloser]['code'] === \T_CLOSE_SQUARE_BRACKET + ) { + $hasRiskyTokenAfterCloser = true; + } + + if ($hasRiskyTokenBeforeOpener === false || $hasRiskyTokenAfterCloser === false) { + return self::SHORT_ARRAY; + } + + /* + * Check if this is the first/last item in a "parent" set of brackets. + * If so, skip straight to the parent and determine the type of that, the type + * of the inner set of brackets will be the same (as all other options have + * already been eliminated). + */ + if (isset($this->openBrackets[$this->tokens[$this->beforeOpener]['code']]) === true) { + return IsShortArrayOrListWithCache::getType($this->phpcsFile, $this->beforeOpener); + } + + $nextEffectiveAfterCloser = $this->afterCloser; + if ($this->tokens[$this->afterCloser]['code'] === \T_COMMA) { + // Skip over potential trailing commas. + $nextEffectiveAfterCloser = $this->phpcsFile->findNext( + Tokens::$emptyTokens, + ($this->afterCloser + 1), + null, + true + ); + } + + if ($this->tokens[$nextEffectiveAfterCloser]['code'] === \T_CLOSE_SHORT_ARRAY + || $this->tokens[$nextEffectiveAfterCloser]['code'] === \T_CLOSE_SQUARE_BRACKET + ) { + return IsShortArrayOrListWithCache::getType($this->phpcsFile, $nextEffectiveAfterCloser); + } + + /* + * Okay, so as of here, we know this set of brackets is preceded by a comma or double arrow + * and followed by a comma. This is the only ambiguous syntax left. + */ + + /* + * Check if this could be a (nested) short list at all. + * A list must have at least one variable inside and can not be empty. + * An array, however, cannot contain empty items. + */ + $type = $this->walkInside($this->opener); + if ($type !== false) { + return $type; + } + + // Last resort: walk up in the file to see if we can find a set of parent brackets... + $type = $this->walkOutside(); + if ($type !== false) { + return $type; + } + + // If everything failed, this will be a short array (shouldn't be possible). + return self::SHORT_ARRAY; // @codeCoverageIgnore + } + + /** + * Check if the brackets are in actual fact real square brackets. + * + * @since 1.0.0-alpha4 + * + * @return bool TRUE if these are real square brackets; FALSE otherwise. + */ + private function isSquareBracket() + { + if ($this->opener === $this->closer) { + // Parse error (unclosed bracket) or live coding. Bow out. + return true; + } + + // Check if this is a bracket we need to examine or a mistokenization. + return ($this->isShortArrayBracket() === false); + } + + /** + * Verify that the current set of brackets is not affected by known PHPCS cross-version tokenizer issues. + * + * List of current tokenizer issues which affect the short array/short list tokenization: + * - {@link https://github.com/squizlabs/PHP_CodeSniffer/pull/3632 PHPCS#3632} (PHPCS < 3.7.2) + * + * List of previous tokenizer issues which affected the short array/short list tokenization for reference: + * - {@link https://github.com/squizlabs/PHP_CodeSniffer/issues/1284 PHPCS#1284} (PHPCS < 2.8.1) + * - {@link https://github.com/squizlabs/PHP_CodeSniffer/issues/1381 PHPCS#1381} (PHPCS < 2.9.0) + * - {@link https://github.com/squizlabs/PHP_CodeSniffer/issues/1971 PHPCS#1971} (PHPCS 2.8.0 - 3.2.3) + * - {@link https://github.com/squizlabs/PHP_CodeSniffer/pull/3013 PHPCS#3013} (PHPCS < 3.5.6) + * - {@link https://github.com/squizlabs/PHP_CodeSniffer/pull/3172 PHPCS#3172} (PHPCS < 3.6.0) + * + * @since 1.0.0-alpha4 + * + * @return bool TRUE if this is actually a short array bracket which needs to be examined, + * FALSE if it is an (incorrectly tokenized) square bracket. + */ + private function isShortArrayBracket() + { + if ($this->tokens[$this->opener]['code'] === \T_OPEN_SQUARE_BRACKET) { + if (\version_compare($this->phpcsVersion, '3.7.2', '>=') === true) { + // These will just be properly tokenized, plain square brackets. No need for further checks. + return false; + } + + /* + * BC: Work around a bug in the tokenizer of PHPCS < 3.7.2, where a `[` would be + * tokenized as T_OPEN_SQUARE_BRACKET instead of T_OPEN_SHORT_ARRAY if it was + * preceded by the close parenthesis of a non-braced control structure. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3632 + */ + if ($this->tokens[$this->beforeOpener]['code'] === \T_CLOSE_PARENTHESIS + && isset($this->tokens[$this->beforeOpener]['parenthesis_owner']) === true + // phpcs:ignore Generic.Files.LineLength.TooLong + && isset(Tokens::$scopeOpeners[$this->tokens[$this->tokens[$this->beforeOpener]['parenthesis_owner']]['code']]) === true + ) { + return true; + } + + // These are really just plain square brackets. + return false; + } + + return true; + } + + /** + * Check is this set of brackets is used within a foreach expression. + * + * @since 1.0.0-alpha4 + * + * @return string|false The determined type or FALSE if undetermined. + */ + private function isInForeach() + { + $inForeach = Context::inForeachCondition($this->phpcsFile, $this->opener); + if ($inForeach === false) { + return false; + } + + switch ($inForeach) { + case 'beforeAs': + if ($this->tokens[$this->afterCloser]['code'] === \T_AS) { + return self::SHORT_ARRAY; + } + + break; + + case 'afterAs': + if ($this->tokens[$this->afterCloser]['code'] === \T_CLOSE_PARENTHESIS) { + $owner = Parentheses::getOwner($this->phpcsFile, $this->afterCloser); + if ($owner !== false && $this->tokens[$owner]['code'] === \T_FOREACH) { + return self::SHORT_LIST; + } + } + + break; + } + + /* + * Everything else will be a nested set of brackets (provided we're talking valid PHP), + * so disregard as it can not be determined yet. + */ + return false; + } + + /** + * Walk the first part of the contents between the brackets to see if we can determine if this + * is a short array or short list based on its contents. + * + * Short lists can only have another (nested) list or variable assignments, including property assignments + * and array index assignment, as the value inside the brackets. + * + * This won't walk the complete contents as that could be a huge performance drain. Just the first x items. + * + * @since 1.0.0-alpha4 + * + * @param int $opener The position of the short array open bracket token. + * @param int $recursions Optional. Keep track of how often we've recursed into this methd. + * Prevent infinite loops for extremely deeply nested arrays. + * Defaults to 0. + * + * @return string|false The determined type or FALSE if undetermined. + */ + private function walkInside($opener, $recursions = 0) + { + // Get the first 5 "parameters" and ignore the "is short array" check. + $items = PassedParameters::getParameters($this->phpcsFile, $opener, self::ITEM_LIMIT, true); + + if ($items === []) { + /* + * A list can not be empty, so this must be an array, however as this is a nested + * set of brackets, let the outside brackets be the decider as it may be + * a coding error which a sniff needs to flag. + */ + return false; + } + + // Make sure vars assigned by reference are handled correctly. + $skip = Tokens::$emptyTokens; + $skip[] = \T_BITWISE_AND; + + $skipNames = Collections::namespacedNameTokens() + Collections::$OOHierarchyKeywords; + + foreach ($items as $item) { + /* + * If we encounter a completely empty item, this must be a short list as arrays cannot contain + * empty items. + */ + if ($item['raw'] === '') { + return self::SHORT_LIST; + } + + /* + * If the "value" part of the entry doesn't start with a variable, a (nested) short list/array, + * or a static property assignment, we know for sure that the outside brackets will be an array. + */ + $arrow = Arrays::getDoubleArrowPtr($this->phpcsFile, $item['start'], $item['end']); + if ($arrow === false) { + $firstNonEmptyInValue = $this->phpcsFile->findNext($skip, $item['start'], ($item['end'] + 1), true); + } else { + $firstNonEmptyInValue = $this->phpcsFile->findNext($skip, ($arrow + 1), ($item['end'] + 1), true); + } + + if ($this->tokens[$firstNonEmptyInValue]['code'] !== \T_VARIABLE + && isset(Collections::namespacedNameTokens()[$this->tokens[$firstNonEmptyInValue]['code']]) === false + && isset(Collections::ooHierarchyKeywords()[$this->tokens[$firstNonEmptyInValue]['code']]) === false + && isset($this->openBrackets[$this->tokens[$firstNonEmptyInValue]['code']]) === false + ) { + return self::SHORT_ARRAY; + } + + /* + * Check if this is a potential list assignment to a static variable. + * If not, again, we can be sure it will be a short array. + */ + if (isset(Collections::namespacedNameTokens()[$this->tokens[$firstNonEmptyInValue]['code']]) === true + || isset(Collections::ooHierarchyKeywords()[$this->tokens[$firstNonEmptyInValue]['code']]) === true + ) { + $nextAfter = $this->phpcsFile->findNext($skipNames, ($firstNonEmptyInValue + 1), null, true); + + if ($this->tokens[$nextAfter]['code'] !== \T_DOUBLE_COLON) { + return self::SHORT_ARRAY; + } else { + /* + * Double colon, so make sure there is a variable after it. + * If not, it's constant or function call, i.e. a short array. + */ + $nextNextAfter = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($nextAfter + 1), null, true); + if ($this->tokens[$nextNextAfter]['code'] !== \T_VARIABLE) { + return self::SHORT_ARRAY; + } + } + + continue; + } + + if (isset($this->openBrackets[$this->tokens[$firstNonEmptyInValue]['code']]) === true) { + /* + * If the "value" part starts with an open bracket, but has other tokens after it, the current, + * outside set of brackets will always be an array (the brackets in the value can still be both, + * but that's not the concern of the current determination). + */ + $lastNonEmptyInValue = $this->phpcsFile->findPrevious( + Tokens::$emptyTokens, + $item['end'], + $item['start'], + true + ); + if (isset($this->tokens[$firstNonEmptyInValue]['bracket_closer']) === true + && $this->tokens[$firstNonEmptyInValue]['bracket_closer'] !== $lastNonEmptyInValue + ) { + return self::SHORT_ARRAY; + } + + /* + * Recursively check the inner set of brackets for contents indicating this is not a short list. + */ + if ($recursions < self::RECURSION_LIMIT) { + $innerType = $this->walkInside($firstNonEmptyInValue, ($recursions + 1)); + if ($innerType !== false) { + return $innerType; + } + } + } + } + + // Undetermined. + return false; + } + + /** + * Walk up in the file to try and find an "outer" set of brackets for an ambiguous, potentially + * nested set of brackets. + * + * This should really be the last resort, if all else fails to determine the type of the brackets. + * + * @since 1.0.0-alpha4 + * + * @return string|false The determined type or FALSE if undetermined. + */ + private function walkOutside() + { + $stopPoints = Collections::phpOpenTags(); + $stopPoints[\T_SEMICOLON] = \T_SEMICOLON; + + for ($i = ($this->opener - 1); $i >= 0; $i--) { + // Skip over block comments (just in case). + if ($this->tokens[$i]['code'] === \T_DOC_COMMENT_CLOSE_TAG) { + $i = $this->tokens[$i]['comment_opener']; + continue; + } + + if (isset(Tokens::$emptyTokens[$this->tokens[$i]['code']]) === true) { + continue; + } + + // Stop on an end of statement. + if (isset($stopPoints[$this->tokens[$i]['code']]) === true) { + // End of previous statement or start of document. + return self::SHORT_ARRAY; + } + + if (isset($this->tokens[$i]['scope_opener'], $this->tokens[$i]['scope_closer']) === true) { + if ($i === $this->tokens[$i]['scope_opener'] + && $this->tokens[$i]['scope_closer'] > $this->closer + ) { + // Found a scope wrapping this set of brackets before finding a outer set of brackets. + // This will be a short array. + return self::SHORT_ARRAY; + } + + if ($i === $this->tokens[$i]['scope_closer'] + && isset($this->tokens[$i]['scope_condition']) === true + ) { + $i = $this->tokens[$i]['scope_condition']; + continue; + } + + // Scope opener without scope condition shouldn't be possible, but just in case. + // @codeCoverageIgnoreStart + $i = $this->tokens[$i]['scope_opener']; + continue; + // @codeCoverageIgnoreEnd + } + + if (isset($this->tokens[$i]['parenthesis_opener'], $this->tokens[$i]['parenthesis_closer']) === true) { + if ($i === $this->tokens[$i]['parenthesis_opener'] + && $this->tokens[$i]['parenthesis_closer'] > $this->closer + ) { + // Found parentheses wrapping this set of brackets before finding a outer set of brackets. + // This will be a short array. + return self::SHORT_ARRAY; + } + + if ($i === $this->tokens[$i]['parenthesis_closer']) { + if (isset($this->tokens[$i]['parenthesis_owner']) === true) { + $i = $this->tokens[$i]['parenthesis_owner']; + continue; + } + } + + // Parenthesis closer without owner (function call and such). + $i = $this->tokens[$i]['parenthesis_opener']; + continue; + } + + /* + * Skip over attributes. + * No special handling needed, brackets within attributes won't reach this + * method as they are already handled within the solve() method. + */ + if (isset($this->tokens[$i]['attribute_opener'], $this->tokens[$i]['attribute_closer']) === true + && $i === $this->tokens[$i]['attribute_closer'] + ) { + $i = $this->tokens[$i]['attribute_opener']; + continue; + } + + /* + * This is a close bracket, but it's not the outer wrapper. + * As we skip over parentheses and curlies above, we *know* this will be a + * set of brackets at the same bracket "nesting level" as the set we are examining. + */ + if (isset($this->tokens[$i]['bracket_opener'], $this->tokens[$i]['bracket_closer']) === true + && $i === $this->tokens[$i]['bracket_closer'] + ) { + /* + * Now, if the set of brackets follows the same code pattern (comma or double arrow before, + * comma after), this will be an adjacent set of potentially nested brackets. + * If so, check if the type of the previous set of brackets has already been determined + * as adjacent sets of brackets will have the same type. + */ + $adjOpener = $this->tokens[$i]['bracket_opener']; + $prevNonEmpty = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($adjOpener - 1), null, true); + $nextNonEmpty = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($i + 1), null, true); + + if ($this->tokens[$prevNonEmpty]['code'] === $this->tokens[$this->beforeOpener]['code'] + && $this->tokens[$nextNonEmpty]['code'] === $this->tokens[$this->afterCloser]['code'] + && Cache::isCached($this->phpcsFile, IsShortArrayOrListWithCache::CACHE_KEY, $adjOpener) === true + ) { + return Cache::get($this->phpcsFile, IsShortArrayOrListWithCache::CACHE_KEY, $adjOpener); + } + + // If not, skip over it. + $i = $this->tokens[$i]['bracket_opener']; + continue; + } + + // Open bracket. + if (isset($this->openBrackets[$this->tokens[$i]['code']]) === true) { + if (isset($this->tokens[$i]['bracket_closer']) === false + || $this->tokens[$i]['code'] === \T_OPEN_SQUARE_BRACKET + ) { + /* + * If the type of the unclosed "outer" brackets cannot be determined or + * they are identified as plain square brackets, the inner brackets + * we are examining should be regarded as a short array. + */ + return self::SHORT_ARRAY; + } + + if ($this->tokens[$i]['bracket_closer'] > $this->closer) { + // This is one we have to examine further as an outer set of brackets. + // As all the other checks have already failed to get a result, we know that + // whatever the outer set is, the inner set will be the same. + return IsShortArrayOrListWithCache::getType($this->phpcsFile, $i); + } + } + } + + // Reached the start of the file without finding an outer set of brackets. + // Shouldn't be possible, but just in case. + return false; // @codeCoverageIgnore + } +} diff --git a/PHPCSUtils/Internal/IsShortArrayOrListWithCache.php b/PHPCSUtils/Internal/IsShortArrayOrListWithCache.php new file mode 100644 index 00000000..18c6d27a --- /dev/null +++ b/PHPCSUtils/Internal/IsShortArrayOrListWithCache.php @@ -0,0 +1,269 @@ +process(); + } + + /** + * Constructor. + * + * @since 1.0.0-alpha4 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the short array bracket token. + * + * @return void + */ + private function __construct(File $phpcsFile, $stackPtr) + { + $this->phpcsFile = $phpcsFile; + $this->tokens = $phpcsFile->getTokens(); + $this->stackPtr = $stackPtr; + } + + /** + * Determine whether a T_[OPEN|CLOSE}_[SHORT_ARRAY|SQUARE_BRACKET] token is a short array + * or short list construct using previously cached results whenever possible. + * + * @since 1.0.0-alpha4 + * + * @return string|false The type of construct this bracket was determined to be. + * Either 'short array', 'short list' or 'square brackets'. + * Or FALSE is this was not a bracket token. + */ + private function process() + { + if ($this->isValidStackPtr() === false) { + return false; + } + + $this->opener = $this->getOpener(); + + /* + * Check the cache in case we've seen this token before. + */ + $type = $this->getFromCache(); + if ($type !== false) { + return $type; + } + + /* + * If we've not seen the token before, try and solve it and cache the results. + * + * Make sure to safeguard against unopened/unclosed square brackets (parse error), + * which should always be regarded as real square brackets. + */ + $type = IsShortArrayOrList::SQUARE_BRACKETS; + if (isset($this->tokens[$this->stackPtr]['bracket_opener'], $this->tokens[$this->stackPtr]['bracket_closer'])) { + $solver = new IsShortArrayOrList($this->phpcsFile, $this->opener); + $type = $solver->solve(); + } + + $this->updateCache($type); + + return $type; + } + + /** + * Verify the passed token could potentially be a short array or short list token. + * + * @since 1.0.0-alpha4 + * + * @return bool + */ + private function isValidStackPtr() + { + return (isset($this->tokens[$this->stackPtr]) === true + && isset(Collections::shortArrayTokensBC()[$this->tokens[$this->stackPtr]['code']]) === true); + } + + /** + * Get the stack pointer to the short array/list opener. + * + * @since 1.0.0-alpha4 + * + * @return int + */ + private function getOpener() + { + $opener = $this->stackPtr; + if (isset($this->tokens[$this->stackPtr]['bracket_opener'])) { + $opener = $this->tokens[$this->stackPtr]['bracket_opener']; + } + + return $opener; + } + + /** + * Retrieve the bracket "type" of a token from the cache. + * + * @since 1.0.0-alpha4 + * + * @return string|false The previously determined type (which could be an empty string) + * or FALSE if no cache entry was found for this token. + */ + private function getFromCache() + { + if (Cache::isCached($this->phpcsFile, self::CACHE_KEY, $this->opener) === true) { + return Cache::get($this->phpcsFile, self::CACHE_KEY, $this->opener); + } + + return false; + } + + /** + * Update the cache with information about a particular bracket token. + * + * @since 1.0.0-alpha4 + * + * @param string $type The type this bracket has been determined to be. + * Either 'short array', 'short list' or 'square brackets'. + * + * @return void + */ + private function updateCache($type) + { + Cache::set($this->phpcsFile, self::CACHE_KEY, $this->opener, $type); + } +} diff --git a/PHPCSUtils/Internal/NoFileCache.php b/PHPCSUtils/Internal/NoFileCache.php new file mode 100644 index 00000000..9844e011 --- /dev/null +++ b/PHPCSUtils/Internal/NoFileCache.php @@ -0,0 +1,150 @@ +> Format: $cache[$key][$id] = mixed $value; + */ + private static $cache = []; + + /** + * Check whether a result has been cached for a certain utility function. + * + * @param string $key The key to identify a particular set of results. + * It is recommended to pass `__METHOD__` to this parameter. + * @param int|string $id Unique identifier for these results. + * It is recommended for this to be a serialization of arguments passed + * to the function or an md5 hash of an input. + * + * @return bool + */ + public static function isCached($key, $id) + { + return self::$enabled === true && isset(self::$cache[$key]) && \array_key_exists($id, self::$cache[$key]); + } + + /** + * Retrieve a previously cached result for a certain utility function. + * + * @param string $key The key to identify a particular set of results. + * It is recommended to pass `__METHOD__` to this parameter. + * @param int|string $id Unique identifier for these results. + * It is recommended for this to be a serialization of arguments passed + * to the function or an md5 hash of an input. + * + * @return mixed + */ + public static function get($key, $id) + { + if (self::$enabled === true && isset(self::$cache[$key]) && \array_key_exists($id, self::$cache[$key])) { + return self::$cache[$key][$id]; + } + + return null; + } + + /** + * Retrieve all previously cached results for a certain utility function. + * + * @param string $key The key to identify a particular set of results. + * It is recommended to pass `__METHOD__` to this parameter. + * + * @return array + */ + public static function getForKey($key) + { + if (self::$enabled === true && \array_key_exists($key, self::$cache)) { + return self::$cache[$key]; + } + + return []; + } + + /** + * Cache the result for a certain utility function. + * + * @param string $key The key to identify a particular set of results. + * It is recommended to pass `__METHOD__` to this parameter. + * @param int|string $id Unique identifier for these results. + * It is recommended for this to be a serialization of arguments passed + * to the function or an md5 hash of an input. + * @param mixed $value An arbitrary value to write to the cache. + * + * @return mixed + */ + public static function set($key, $id, $value) + { + if (self::$enabled === false) { + return; + } + + self::$cache[$key][$id] = $value; + } + + /** + * Clear the cache. + * + * @return void + */ + public static function clear() + { + self::$cache = []; + } +} diff --git a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php index a5b7449f..1ce85036 100644 --- a/PHPCSUtils/TestUtils/UtilityMethodTestCase.php +++ b/PHPCSUtils/TestUtils/UtilityMethodTestCase.php @@ -10,18 +10,22 @@ namespace PHPCSUtils\TestUtils; -use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Exceptions\TokenizerException; +use PHP_CodeSniffer\Files\File; use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Exceptions\TestFileNotFound; +use PHPCSUtils\Exceptions\TestMarkerNotFound; +use PHPCSUtils\Exceptions\TestTargetNotFound; use PHPUnit\Framework\TestCase; use ReflectionClass; /** * Base class for use when testing utility methods for PHP_CodeSniffer. * - * This class is compatible with PHP_CodeSniffer 2.x as well as 3.x. + * This class is compatible with PHP_CodeSniffer 3.x and contains preliminary compatibility with 4.x + * based on its currently known state/roadmap. * - * This class is compatible with {@link http://phpunit.de/ PHPUnit} 4.5 - 9.x providing the PHPCSUtils + * This class is compatible with {@link https://phpunit.de/ PHPUnit} 4.5 - 9.x providing the PHPCSUtils * autoload file is included in the test bootstrap. For more information about that, please consult * the project's {@link https://github.com/PHPCSStandards/PHPCSUtils/blob/develop/README.md README}. * @@ -96,6 +100,7 @@ * for the PHPCSUtils utility functions themselves. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ abstract class UtilityMethodTestCase extends TestCase { @@ -204,59 +209,39 @@ public static function setUpTestFile() $contents = \file_get_contents($caseFile); - if (\version_compare(self::$phpcsVersion, '2.99.99', '>')) { - // PHPCS 3.x. - $config = new \PHP_CodeSniffer\Config(); + $config = new \PHP_CodeSniffer\Config(); - /* - * We just need to provide a standard so PHPCS will tokenize the file. - * The standard itself doesn't actually matter for testing utility methods, - * so use the smallest one to get the fastest results. - */ - $config->standards = ['PSR1']; + /* + * We just need to provide a standard so PHPCS will tokenize the file. + * The standard itself doesn't actually matter for testing utility methods, + * so use the smallest one to get the fastest results. + */ + $config->standards = ['PSR1']; - /* - * Limiting the run to just one sniff will make it, yet again, slightly faster. - * Picked the simplest/fastest sniff available which is registered in PSR1. - */ - $config->sniffs = static::$selectedSniff; + /* + * Limiting the run to just one sniff will make it, yet again, slightly faster. + * Picked the simplest/fastest sniff available which is registered in PSR1. + */ + $config->sniffs = static::$selectedSniff; - // Disable caching. - $config->cache = false; + // Disable caching. + $config->cache = false; - // Also set a tab-width to enable testing tab-replaced vs `orig_content`. - $config->tabWidth = static::$tabWidth; + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. + $config->tabWidth = static::$tabWidth; - $ruleset = new \PHP_CodeSniffer\Ruleset($config); + $ruleset = new \PHP_CodeSniffer\Ruleset($config); - // Make sure the file gets parsed correctly based on the file type. - $contents = 'phpcs_input_file: ' . $caseFile . \PHP_EOL . $contents; + // Make sure the file gets parsed correctly based on the file type. + $contents = 'phpcs_input_file: ' . $caseFile . \PHP_EOL . $contents; - self::$phpcsFile = new \PHP_CodeSniffer\Files\DummyFile($contents, $ruleset, $config); + self::$phpcsFile = new \PHP_CodeSniffer\Files\DummyFile($contents, $ruleset, $config); - // Only tokenize the file, do not process it. - try { - self::$phpcsFile->parse(); - } catch (TokenizerException $e) { - // PHPCS 3.5.0 and higher. - } catch (RuntimeException $e) { - // PHPCS 3.0.0 < 3.5.0. - } - } else { - // PHPCS 2.x. - $phpcs = new \PHP_CodeSniffer(null, static::$tabWidth); - self::$phpcsFile = new \PHP_CodeSniffer_File( - $caseFile, - [], - [], - $phpcs - ); - - /* - * Using error silencing to drown out "undefined index" notices for tokenizer - * issues in PHPCS 2.x which won't get fixed anymore anyway. - */ - @self::$phpcsFile->start($contents); + // Only tokenize the file, do not process it. + try { + self::$phpcsFile->parse(); + } catch (TokenizerException $e) { + // PHPCS 3.5.0 and higher. This is handled below. } // Fail the test if the case file failed to tokenize. @@ -295,7 +280,7 @@ public function skipJSCSSTestsOnPHPCS4() } /** - * Clean up after finished test. + * Clean up after finished test by resetting all static properties to their default values. * * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()} * method. @@ -308,7 +293,33 @@ public function skipJSCSSTestsOnPHPCS4() */ public static function resetTestFile() { - self::$phpcsFile = null; + self::$phpcsVersion = '0'; + self::$fileExtension = 'inc'; + self::$caseFile = ''; + self::$tabWidth = 4; + self::$phpcsFile = null; + self::$selectedSniff = ['Dummy.Dummy.Dummy']; + } + + /** + * Check whether or not the PHP 8.0 identifier name tokens will be in use. + * + * The expected token positions/token counts for certain tokens will differ depending + * on whether the PHP 8.0 identifier name tokenization is used or the PHP < 8.0 + * identifier name tokenization. + * + * Tests can use this method to determine which flavour of tokenization to expect and + * to set test expectations accordingly. + * + * @codeCoverageIgnore Nothing to test. + * + * @since 1.0.0 + * + * @return bool + */ + public static function usesPhp8NameTokens() + { + return \version_compare(Helper::getVersion(), '3.99.99', '>='); } /** @@ -317,9 +328,10 @@ public static function resetTestFile() * Note: the test delimiter comment MUST start with `/* test` to allow this function to * distinguish between comments used *in* a test and test delimiters. * - * If the delimiter comment is not found, the test will automatically be failed. - * * @since 1.0.0 + * @since 1.0.0-alpha4 Will throw an exception whether the delimiter comment or the target + * token is not found. + * @since 1.0.0-alpha4 This method is now `static`, which allows for it to be used in "set up before class". * * @param string $commentString The complete delimiter comment to look for as a string. * This string should include the comment opener and closer. @@ -327,9 +339,16 @@ public static function resetTestFile() * @param string $tokenContent Optional. The token content for the target token. * * @return int + * + * @throws \PHPCSUtils\Exceptions\TestMarkerNotFound When the delimiter comment for the test was not found. + * @throws \PHPCSUtils\Exceptions\TestTargetNotFound When the target token cannot be found. */ - public function getTargetToken($commentString, $tokenType, $tokenContent = null) + public static function getTargetToken($commentString, $tokenType, $tokenContent = null) { + if ((self::$phpcsFile instanceof File) === false) { + throw new TestFileNotFound(); + } + $start = (self::$phpcsFile->numTokens - 1); $comment = self::$phpcsFile->findPrevious( \T_COMMENT, @@ -339,6 +358,10 @@ public function getTargetToken($commentString, $tokenType, $tokenContent = null) $commentString ); + if ($comment === false) { + throw TestMarkerNotFound::create($commentString, self::$phpcsFile->getFilename()); + } + $tokens = self::$phpcsFile->getTokens(); $end = ($start + 1); @@ -363,12 +386,7 @@ public function getTargetToken($commentString, $tokenType, $tokenContent = null) ); if ($target === false) { - $msg = 'Failed to find test target token for comment string: ' . $commentString; - if ($tokenContent !== null) { - $msg .= ' With token content: ' . $tokenContent; - } - - $this->fail($msg); + throw TestTargetNotFound::create($commentString, $tokenContent, self::$phpcsFile->getFilename()); } return $target; diff --git a/PHPCSUtils/Tokens/Collections.php b/PHPCSUtils/Tokens/Collections.php index 04924c34..d61b91aa 100644 --- a/PHPCSUtils/Tokens/Collections.php +++ b/PHPCSUtils/Tokens/Collections.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tokens; -use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Exceptions\InvalidTokenArray; /** * Collections of related tokens as often used and needed for sniffs. @@ -22,15 +22,49 @@ * @see \PHPCSUtils\BackCompat\BCTokens Backward compatible version of the PHPCS native token groups. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. + * @since 1.0.0-alpha4 Direct property access is deprecated for forward-compatibility reasons. + * Use the methods of the same name as the property instead. + * + * @method static array arrayOpenTokensBC() Tokens which can open an array (PHPCS cross-version compatible). + * @method static array arrayTokens() Tokens which are used to create arrays. + * @method static array arrayTokensBC() Tokens which are used to create arrays + * (PHPCS cross-version compatible). + * @method static array classModifierKeywords() Modifier keywords which can be used for a class declaration. + * @method static array closedScopes() List of tokens which represent "closed" scopes. + * @method static array controlStructureTokens() Control structure tokens. + * @method static array functionDeclarationTokens() Tokens which represent a keyword which starts + * a function declaration. + * @method static array incrementDecrementOperators() Increment/decrement operator tokens. + * @method static array listTokens() Tokens which are used to create lists. + * @method static array listTokensBC() Tokens which are used to create lists + * (PHPCS cross-version compatible) + * @method static array namespaceDeclarationClosers() List of tokens which can end a namespace declaration statement. + * @method static array nameTokens() Tokens used for "names", be it namespace, OO, function + * or constant names. + * @method static array objectOperators() Object operator tokens. + * @method static array phpOpenTags() Tokens which open PHP. + * @method static array propertyModifierKeywords() Modifier keywords which can be used for a property declaration. + * @method static array shortArrayListOpenTokensBC() Tokens which can open a short array or short list + * (PHPCS cross-version compatible). + * @method static array shortArrayTokens() Tokens which are used for short arrays. + * @method static array shortArrayTokensBC() Tokens which are used for short arrays + * (PHPCS cross-version compatible). + * @method static array shortListTokens() Tokens which are used for short lists. + * @method static array shortListTokensBC() Tokens which are used for short lists + * (PHPCS cross-version compatible). */ -class Collections +final class Collections { /** - * Control structures which can use the alternative control structure syntax. + * DEPRECATED: Tokens for control structures which can use the alternative control structure syntax. * * @since 1.0.0-alpha2 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::alternativeControlStructureSyntaxes()} + * method instead. + * * @var array => */ public static $alternativeControlStructureSyntaxTokens = [ @@ -45,10 +79,13 @@ class Collections ]; /** - * Alternative control structure syntax closer keyword tokens. + * DEPRECATED: Tokens representing alternative control structure syntax closer keywords. * * @since 1.0.0-alpha2 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::alternativeControlStructureSyntaxClosers()} + * method instead. + * * @var array => */ public static $alternativeControlStructureSyntaxCloserTokens = [ @@ -61,12 +98,40 @@ class Collections ]; /** - * Tokens which are used to create arrays. + * Tokens which can open an array (PHPCS cross-version compatible). + * + * Includes `T_OPEN_SQUARE_BRACKET` to allow for handling intermittent tokenizer issues related + * to the retokenization to `T_OPEN_SHORT_ARRAY`. + * Should only be used selectively. * - * @see \PHPCSUtils\Tokens\Collections::$shortArrayTokens Related property containing only tokens used - * for short arrays. + * @see \PHPCSUtils\Tokens\Collections::arrayTokensBC() Related method to retrieve tokens used + * for arrays (PHPCS cross-version). + * @see \PHPCSUtils\Tokens\Collections::shortArrayTokensBC() Related method to retrieve only tokens used + * for short arrays (PHPCS cross-version). * - * @since 1.0.0 + * @since 1.0.0-alpha4 Use the {@see Collections::arrayOpenTokensBC()} method for access. + * + * @return array => + */ + private static $arrayOpenTokensBC = [ + \T_ARRAY => \T_ARRAY, + \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, + \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, + ]; + + /** + * DEPRECATED: Tokens which are used to create arrays. + * + * @see \PHPCSUtils\Tokens\Collections::arrayOpenTokensBC() Related method to retrieve only the "open" tokens + * used for arrays (PHPCS cross-version compatible). + * @see \PHPCSUtils\Tokens\Collections::arrayTokensBC() Related method to retrieve tokens used + * for arrays (PHPCS cross-version compatible). + * @see \PHPCSUtils\Tokens\Collections::shortArrayTokens() Related method to retrieve only tokens used + * for short arrays. + * + * @since 1.0.0-alpha1 + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::arrayTokens()} method instead. * * @var array => */ @@ -77,15 +142,20 @@ class Collections ]; /** - * Tokens which are used to create arrays. + * DEPRECATED: Tokens which are used to create arrays (PHPCS cross-version compatible). * - * List which is backward-compatible with PHPCS < 3.3.0. + * Includes `T_OPEN_SQUARE_BRACKET` and `T_CLOSE_SQUARE_BRACKET` to allow for handling + * intermittent tokenizer issues related to the retokenization to `T_OPEN_SHORT_ARRAY`. * Should only be used selectively. * - * @see \PHPCSUtils\Tokens\Collections::$shortArrayTokensBC Related property containing only tokens used - * for short arrays (cross-version). + * @see \PHPCSUtils\Tokens\Collections::arrayOpenTokensBC() Related method to retrieve only the "open" tokens + * used for arrays (PHPCS cross-version compatible). + * @see \PHPCSUtils\Tokens\Collections::shortArrayTokensBC() Related method to retrieve only tokens used + * for short arrays (PHPCS cross-version compatible). + * + * @since 1.0.0-alpha1 * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::arrayTokensBC()} method instead. * * @var array => */ @@ -98,19 +168,23 @@ class Collections ]; /** - * Modifier keywords which can be used for a class declaration. + * DEPRECATED: Modifier keywords which can be used for a class declaration. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the T_READONLY token for PHP 8.2 readonly classes. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::classModifierKeywords()} method instead. * * @var array => */ public static $classModifierKeywords = [ \T_FINAL => \T_FINAL, \T_ABSTRACT => \T_ABSTRACT, + \T_READONLY => \T_READONLY, ]; /** - * List of tokens which represent "closed" scopes. + * DEPRECATED: List of tokens which represent "closed" scopes. * * I.e. anything declared within that scope - except for other closed scopes - is * outside of the global namespace. @@ -118,7 +192,10 @@ class Collections * This list doesn't contain the `T_NAMESPACE` token on purpose as variables declared * within a namespace scope are still global and not limited to that namespace. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the PHP 8.1 T_ENUM token. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::closedScopes()} method instead. * * @var array => */ @@ -127,14 +204,18 @@ class Collections \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, \T_TRAIT => \T_TRAIT, + \T_ENUM => \T_ENUM, \T_FUNCTION => \T_FUNCTION, \T_CLOSURE => \T_CLOSURE, ]; /** - * Control structure tokens. + * DEPRECATED: Control structure tokens. * * @since 1.0.0-alpha2 + * @since 1.0.0-alpha4 Added the T_MATCH token for PHP 8.0 match expressions. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::controlStructureTokens()} method instead. * * @var array => */ @@ -148,13 +229,29 @@ class Collections \T_DO => \T_DO, \T_WHILE => \T_WHILE, \T_DECLARE => \T_DECLARE, + \T_MATCH => \T_MATCH, + ]; + + /** + * Tokens which represent a keyword which starts a function declaration. + * + * @since 1.0.0-alpha4 Use the {@see Collections::functionDeclarationTokens()} method for access. + * + * @return array => + */ + private static $functionDeclarationTokens = [ + \T_FUNCTION => \T_FUNCTION, + \T_CLOSURE => \T_CLOSURE, + \T_FN => \T_FN, ]; /** - * Increment/decrement operator tokens. + * DEPRECATED: Increment/decrement operator tokens. * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::incrementDecrementOperators()} method instead. + * * @var array => */ public static $incrementDecrementOperators = [ @@ -163,12 +260,16 @@ class Collections ]; /** - * Tokens which are used to create lists. + * DEPRECATED: Tokens which are used to create lists. + * + * @see \PHPCSUtils\Tokens\Collections::listTokensBC() Related method to retrieve tokens used + * for lists (PHPCS cross-version). + * @see \PHPCSUtils\Tokens\Collections::shortListTokens() Related method to retrieve only tokens used + * for short lists. * - * @see \PHPCSUtils\Tokens\Collections::$shortListTokens Related property containing only tokens used - * for short lists. + * @since 1.0.0-alpha1 * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::listTokens()} method instead. * * @var array => */ @@ -179,15 +280,18 @@ class Collections ]; /** - * Tokens which are used to create lists. + * DEPRECATED: Tokens which are used to create lists (PHPCS cross-version compatible). * - * List which is backward-compatible with PHPCS < 3.3.0. + * Includes `T_OPEN_SQUARE_BRACKET` and `T_CLOSE_SQUARE_BRACKET` to allow for handling + * intermittent tokenizer issues related to the retokenization to `T_OPEN_SHORT_ARRAY`. * Should only be used selectively. * - * @see \PHPCSUtils\Tokens\Collections::$shortListTokensBC Related property containing only tokens used - * for short lists (cross-version). + * @see \PHPCSUtils\Tokens\Collections::shortListTokensBC() Related method to retrieve only tokens used + * for short lists (cross-version). * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::listTokensBC()} method instead. * * @var array => */ @@ -200,12 +304,13 @@ class Collections ]; /** - * Tokens for the PHP magic constants. - * - * @link https://www.php.net/language.constants.predefined PHP Manual on magic constants + * DEPRECATED: Tokens for the PHP magic constants. * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see \PHP_CodeSniffer\Util\Tokens::$magicConstants} property + * or the {@see \PHPCSUtils\BackCompat\BCTokens::magicConstants()} method instead. + * * @var array => */ public static $magicConstants = [ @@ -220,9 +325,11 @@ class Collections ]; /** - * List of tokens which can end a namespace declaration statement. + * DEPRECATED: List of tokens which can end a namespace declaration statement. + * + * @since 1.0.0-alpha1 * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::namespaceDeclarationClosers()} method instead. * * @var array => */ @@ -233,21 +340,49 @@ class Collections ]; /** - * Object operators. + * Tokens used for "names", be it namespace, OO, function or constant names. + * + * Includes the tokens introduced in PHP 8.0 for "Namespaced names as single token". + * + * Note: the PHP 8.0 namespaced name tokens are backfilled in PHPCS since PHPCS 3.5.7, + * but are not used yet (the PHP 8.0 tokenization is "undone" in PHPCS). + * As of PHPCS 4.0.0, these tokens _will_ be used and the PHP 8.0 tokenization is respected. + * + * @link https://wiki.php.net/rfc/namespaced_names_as_token PHP RFC on namespaced names as single token + * + * @since 1.0.0-alpha4 Use the {@see Collections::nameTokens()} method for access. + * + * @return array => + */ + private static $nameTokens = [ + \T_STRING => \T_STRING, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + ]; + + /** + * DEPRECATED: Object operator tokens. * * @since 1.0.0-alpha3 + * @since 1.0.0-alpha4 Added the PHP 8.0 T_NULLSAFE_OBJECT_OPERATOR token. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::objectOperators()} method instead. * * @var array => */ public static $objectOperators = [ - \T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR, - \T_DOUBLE_COLON => \T_DOUBLE_COLON, + \T_DOUBLE_COLON => \T_DOUBLE_COLON, + \T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR, + \T_NULLSAFE_OBJECT_OPERATOR => \T_NULLSAFE_OBJECT_OPERATOR, ]; /** - * OO structures which can use the "extends" keyword. + * DEPRECATED: OO structures which can use the "extends" keyword. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::ooCanExtend()} method instead. * * @var array => */ @@ -258,23 +393,31 @@ class Collections ]; /** - * OO structures which can use the "implements" keyword. + * DEPRECATED: OO structures which can use the "implements" keyword. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the PHP 8.1 T_ENUM token. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::ooCanImplement()} method instead. * * @var array => */ public static $OOCanImplement = [ \T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, + \T_ENUM => \T_ENUM, ]; /** - * OO scopes in which constants can be declared. + * DEPRECATED: OO scopes in which constants can be declared. * - * Note: traits can not declare constants. + * Note: traits can only declare constants since PHP 8.2. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the PHP 8.1 T_ENUM token. + * @since 1.0.0-alpha4 Added the T_TRAIT token for PHP 8.2 constants in traits. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::ooConstantScopes()} method instead. * * @var array => */ @@ -282,15 +425,19 @@ class Collections \T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, + \T_ENUM => \T_ENUM, + \T_TRAIT => \T_TRAIT, ]; /** - * Tokens types used for "forwarding" calls within OO structures. + * DEPRECATED: Tokens types used for "forwarding" calls within OO structures. * * @link https://www.php.net/language.oop5.paamayim-nekudotayim PHP Manual on OO forwarding calls * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::ooHierarchyKeywords()} method instead. + * * @var array => */ public static $OOHierarchyKeywords = [ @@ -300,15 +447,12 @@ class Collections ]; /** - * Tokens types which can be encountered in the fully/partially qualified name of an OO structure. - * - * Example: - * ```php - * echo namespace\Sub\ClassName::method(); - * ``` + * DEPRECATED: Tokens types which can be encountered in the fully/partially qualified name of an OO structure. * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::namespacedNameTokens()} method instead. + * * @var array => */ public static $OONameTokens = [ @@ -318,11 +462,13 @@ class Collections ]; /** - * OO scopes in which properties can be declared. + * DEPRECATED: OO scopes in which properties can be declared. * * Note: interfaces can not declare properties. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::ooPropertyScopes()} method instead. * * @var array => */ @@ -333,37 +479,49 @@ class Collections ]; /** - * Token types which can be encountered in a parameter type declaration. - * - * Sister-property to the {@see Collections::parameterTypeTokensBC()} method. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. + * DEPRECATED: Token types which can be encountered in a parameter type declaration. * - * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. - * This token constant will no longer exist in PHPCS 4.x. + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. + * @since 1.0.0-alpha4 Added the T_TRUE token for PHP 8.2 true type support. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. - * - * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() Related method (cross-version). - * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::parameterTypeTokens()} method instead. * * @var array => */ public static $parameterTypeTokens = [ - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_STRING => \T_STRING, - \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, + \T_TRUE => \T_TRUE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, ]; /** - * Modifier keywords which can be used for a property declaration. + * Tokens which open PHP. * - * @since 1.0.0 + * @since 1.0.0-alpha4 Use the {@see Collections::phpOpenTags()} method for access. + * + * @return array => + */ + private static $phpOpenTags = [ + \T_OPEN_TAG => \T_OPEN_TAG, + \T_OPEN_TAG_WITH_ECHO => \T_OPEN_TAG_WITH_ECHO, + ]; + + /** + * DEPRECATED: Modifier keywords which can be used for a property declaration. + * + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the T_READONLY token for PHP 8.1 readonly properties. + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::propertyModifierKeywords()} method instead. * * @var array => */ @@ -373,72 +531,84 @@ class Collections \T_PROTECTED => \T_PROTECTED, \T_STATIC => \T_STATIC, \T_VAR => \T_VAR, + \T_READONLY => \T_READONLY, ]; /** - * Token types which can be encountered in a property type declaration. + * DEPRECATED: Token types which can be encountered in a property type declaration. * - * Sister-property to the {@see Collections::propertyTypeTokensBC()} method. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. + * @since 1.0.0-alpha4 Added the T_TRUE token for PHP 8.2 true type support. * - * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. - * This token constant will no longer exist in PHPCS 4.x. - * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. - * - * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC() Related method (cross-version). - * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::propertyTypeTokens()} method instead. * * @var array => */ public static $propertyTypeTokens = [ - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_STRING => \T_STRING, - \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, + \T_TRUE => \T_TRUE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, ]; /** - * Token types which can be encountered in a return type declaration. + * DEPRECATED: Token types which can be encountered in a return type declaration. * - * Sister-property to the {@see Collections::returnTypeTokensBC()} method. - * The property supports PHPCS 3.5.4 and up. - * The method supports PHPCS 2.6.0 and up. + * @since 1.0.0-alpha1 + * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. + * @since 1.0.0-alpha4 Added the T_TRUE token for PHP 8.2 true type support. * - * Notable differences: - * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. - * These token constants will no longer exist in PHPCS 4.x. - * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. + * @deprecated 1.0.0-alpha4 Use the {@see Collections::returnTypeTokens()} method instead. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.5.4. + * @var array => + */ + public static $returnTypeTokens = [ + \T_CALLABLE => \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STATIC => \T_STATIC, + \T_FALSE => \T_FALSE, + \T_TRUE => \T_TRUE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, + ]; + + /** + * Tokens which can open a short array or short list (PHPCS cross-version compatible). * - * @see \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() Related method (cross-version). + * Includes `T_OPEN_SQUARE_BRACKET` to allow for handling intermittent tokenizer issues related + * to the retokenization to `T_OPEN_SHORT_ARRAY`. + * Should only be used selectively. * - * @since 1.0.0 + * @since 1.0.0-alpha4 Use the {@see Collections::shortArrayListOpenTokensBC()} method for access. * - * @var array => + * @return array => */ - public static $returnTypeTokens = [ - \T_STRING => \T_STRING, - \T_CALLABLE => \T_CALLABLE, - \T_SELF => \T_SELF, - \T_PARENT => \T_PARENT, - \T_STATIC => \T_STATIC, - \T_NS_SEPARATOR => \T_NS_SEPARATOR, + private static $shortArrayListOpenTokensBC = [ + \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, + \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, ]; /** - * Tokens which are used for short arrays. + * DEPRECATED: Tokens which are used for short arrays. * - * @see \PHPCSUtils\Tokens\Collections::$arrayTokens Related property containing all tokens used for arrays. + * @see \PHPCSUtils\Tokens\Collections::arrayTokens() Related method to retrieve all tokens used for arrays. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::shortArrayTokens()} method instead. * * @var array => */ @@ -448,15 +618,18 @@ class Collections ]; /** - * Tokens which are used for short arrays. + * DEPRECATED: Tokens which are used for short arrays (PHPCS cross-version compatible). * - * List which is backward-compatible with PHPCS < 3.3.0. + * Includes `T_OPEN_SQUARE_BRACKET` and `T_CLOSE_SQUARE_BRACKET` to allow for handling + * intermittent tokenizer issues related to the retokenization to `T_OPEN_SHORT_ARRAY`. * Should only be used selectively. * - * @see \PHPCSUtils\Tokens\Collections::$arrayTokensBC Related property containing all tokens used for arrays - * (cross-version). + * @see \PHPCSUtils\Tokens\Collections::arrayTokensBC() Related method to retrieve all tokens used for arrays + * (cross-version). + * + * @since 1.0.0-alpha1 * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::shortArrayTokensBC()} method instead. * * @var array => */ @@ -468,11 +641,13 @@ class Collections ]; /** - * Tokens which are used for short lists. + * DEPRECATED: Tokens which are used for short lists. * - * @see \PHPCSUtils\Tokens\Collections::$listTokens Related property containing all tokens used for lists. + * @see \PHPCSUtils\Tokens\Collections::listTokens() Related method to retrieve all tokens used for lists. * - * @since 1.0.0 + * @since 1.0.0-alpha1 + * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::shortListTokens()} method instead. * * @var array => */ @@ -482,15 +657,18 @@ class Collections ]; /** - * Tokens which are used for short lists. + * DEPRECATED: Tokens which are used for short lists (PHPCS cross-version compatible). * - * List which is backward-compatible with PHPCS < 3.3.0. + * Includes `T_OPEN_SQUARE_BRACKET` and `T_CLOSE_SQUARE_BRACKET` to allow for handling + * intermittent tokenizer issues related to the retokenization to `T_OPEN_SHORT_ARRAY`. * Should only be used selectively. * - * @see \PHPCSUtils\Tokens\Collections::$listTokensBC Related property containing all tokens used for lists - * (cross-version). + * @see \PHPCSUtils\Tokens\Collections::listTokensBC() Related method to retrieve all tokens used for lists + * (cross-version). + * + * @since 1.0.0-alpha1 * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::shortListTokensBC()} method instead. * * @var array => */ @@ -502,9 +680,11 @@ class Collections ]; /** - * Tokens which can start a - potentially multi-line - text string. + * DEPRECATED: Tokens which can start a - potentially multi-line - text string. + * + * @since 1.0.0-alpha1 * - * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the {@see Collections::textStringStartTokens()} method instead. * * @var array => */ @@ -516,202 +696,388 @@ class Collections ]; /** - * Tokens which can represent the arrow function keyword. + * Handle calls to (undeclared) methods for token arrays which don't need special handling. * - * Note: this is a method, not a property as the `T_FN` token for arrow functions may not exist. + * @since 1.0.0-alpha4 + * + * @param string $name The name of the method which has been called. + * @param array $args Any arguments passed to the method. + * Unused as none of the methods take arguments. + * + * @return array => Token array + * + * @throws \PHPCSUtils\Exceptions\InvalidTokenArray When an invalid token array is requested. + */ + public static function __callStatic($name, $args) + { + if (isset(self::${$name})) { + return self::${$name}; + } + + // Unknown token array requested. + throw InvalidTokenArray::create($name); + } + + /** + * Throw a deprecation notice with a standardized deprecation message. + * + * @since 1.0.0-alpha4 + * + * @param string $method The name of the method which is deprecated. + * @param string $version The version since which the method is deprecated. + * @param string $replacement What to use instead. + * + * @return void + */ + private static function triggerDeprecation($method, $version, $replacement) + { + \trigger_error( + \sprintf( + 'The %1$s::%2$s() method is deprecated since PHPCSUtils %3$s.' + . ' Use %4$s instead.', + __CLASS__, + $method, + $version, + $replacement + ), + \E_USER_DEPRECATED + ); + } + + /** + * Tokens for control structures which can use the alternative control structure syntax. + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$alternativeControlStructureSyntaxTokens} + * property. + * + * @return array => + */ + public static function alternativeControlStructureSyntaxes() + { + return self::$alternativeControlStructureSyntaxTokens; + } + + /** + * Tokens representing alternative control structure syntax closer keywords. + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$alternativeControlStructureSyntaxCloserTokens} + * property. + * + * @return array => + */ + public static function alternativeControlStructureSyntaxClosers() + { + return self::$alternativeControlStructureSyntaxCloserTokens; + } + + /** + * DEPRECATED: Tokens which can represent the arrow function keyword. * * @since 1.0.0-alpha2 * + * @deprecated 1.0.0-alpha4 Use the `T_FN` token constant instead. + * * @return array => */ public static function arrowFunctionTokensBC() { - $tokens = [ - \T_STRING => \T_STRING, - ]; + self::triggerDeprecation(__FUNCTION__, '1.0.0-alpha4', 'the `T_FN` token'); - if (\defined('T_FN') === true) { - // PHP 7.4 or PHPCS 3.5.3+. - $tokens[\T_FN] = \T_FN; - } + return [\T_FN => \T_FN]; + } + + /** + * Tokens which can represent function calls and function-call-like language constructs. + * + * @see \PHPCSUtils\Tokens\Collections::parameterPassingTokens() Related method. + * + * @since 1.0.0-alpha4 + * + * @return array => + */ + public static function functionCallTokens() + { + // Function calls and class instantiation. + $tokens = self::$nameTokens; + $tokens[\T_VARIABLE] = \T_VARIABLE; + + // Class instantiation only. + $tokens[\T_ANON_CLASS] = \T_ANON_CLASS; + $tokens += self::$OOHierarchyKeywords; return $tokens; } /** - * Tokens which can represent a keyword which starts a function declaration. + * DEPRECATED: Tokens which represent a keyword which starts a function declaration. * - * Note: this is a method, not a property as the `T_FN` token for arrow functions may not exist. + * @since 1.0.0-alpha3 * - * Sister-method to the {@see Collections::functionDeclarationTokensBC()} method. - * This method supports PHPCS 3.5.3 and up. - * The {@see Collections::functionDeclarationTokensBC()} method supports PHPCS 2.6.0 and up. + * @deprecated 1.0.0-alpha4 Use the {@see Collections::functionDeclarationTokens()} method instead. * - * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokensBC() Related method (PHPCS 2.6.0+). + * @return array => + */ + public static function functionDeclarationTokensBC() + { + self::triggerDeprecation( + __FUNCTION__, + '1.0.0-alpha4', + \sprintf('the %s::functionDeclarationTokens() method', __CLASS__) + ); + + return self::$functionDeclarationTokens; + } + + /** + * Tokens types which can be encountered in a fully, partially or unqualified name. * - * @since 1.0.0-alpha3 + * Example: + * ```php + * echo namespace\Sub\ClassName::method(); + * ``` + * + * @since 1.0.0-alpha4 * * @return array => */ - public static function functionDeclarationTokens() + public static function namespacedNameTokens() { $tokens = [ - \T_FUNCTION => \T_FUNCTION, - \T_CLOSURE => \T_CLOSURE, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_NAMESPACE => \T_NAMESPACE, ]; - if (\defined('T_FN') === true) { - // PHP 7.4 or PHPCS 3.5.3+. - $tokens[\T_FN] = \T_FN; - } + $tokens += self::$nameTokens; return $tokens; } /** - * Tokens which can represent a keyword which starts a function declaration. + * OO structures which can use the "extends" keyword. * - * Note: this is a method, not a property as the `T_FN` token for arrow functions may not exist. + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$OOCanExtend} property. * - * Sister-method to the {@see Collections::functionDeclarationTokens()} method. - * The {@see Collections::functionDeclarationTokens()} method supports PHPCS 3.5.3 and up. - * This method supports PHPCS 2.6.0 and up. + * @return array => + */ + public static function ooCanExtend() + { + return self::$OOCanExtend; + } + + /** + * OO structures which can use the "implements" keyword. * - * Notable difference: - * - This method accounts for when the `T_FN` token doesn't exist. + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$OOCanImplement} property. + * @since 1.0.0-alpha4 Added the PHP 8.1 T_ENUM token. * - * Note: if this method is used, the {@see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction()} - * method needs to be used on arrow function tokens to verify whether it really is an arrow function - * declaration or not. + * @return array => + */ + public static function ooCanImplement() + { + return self::$OOCanImplement; + } + + /** + * OO scopes in which constants can be declared. * - * It is recommended to use the {@see Collections::functionDeclarationTokens()} method instead of - * this method if a standard supports does not need to support PHPCS < 3.5.3. + * Note: traits can only declare constants since PHP 8.2. * - * @see \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() Related method (PHPCS 3.5.3+). - * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Arrow function verification. + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$OOConstantScopes} property. + * @since 1.0.0-alpha4 Added the PHP 8.1 T_ENUM token. + * @since 1.0.0-alpha4 Added the T_TRAIT token for PHP 8.2 constants in traits. * - * @since 1.0.0-alpha3 + * @return array => + */ + public static function ooConstantScopes() + { + return self::$OOConstantScopes; + } + + /** + * Tokens types used for "forwarding" calls within OO structures. + * + * @link https://www.php.net/language.oop5.paamayim-nekudotayim PHP Manual on OO forwarding calls + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$OOHierarchyKeywords} property. * * @return array => */ - public static function functionDeclarationTokensBC() + public static function ooHierarchyKeywords() { - $tokens = [ - \T_FUNCTION => \T_FUNCTION, - \T_CLOSURE => \T_CLOSURE, - ]; + return self::$OOHierarchyKeywords; + } + + /** + * OO scopes in which properties can be declared. + * + * Note: interfaces can not declare properties. + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$OOPropertyScopes} property. + * + * @return array => + */ + public static function ooPropertyScopes() + { + return self::$OOPropertyScopes; + } - $tokens += self::arrowFunctionTokensBC(); + /** + * Tokens which can be passed to the methods in the PassedParameter class. + * + * @see \PHPCSUtils\Utils\PassedParameters + * + * @since 1.0.0-alpha4 + * + * @return array => + */ + public static function parameterPassingTokens() + { + // Function call and class instantiation tokens. + $tokens = self::functionCallTokens(); + + // Function-look-a-like language constructs which can take multiple "parameters". + $tokens[\T_ISSET] = \T_ISSET; + $tokens[\T_UNSET] = \T_UNSET; + + // Array tokens. + $tokens += self::$arrayOpenTokensBC; return $tokens; } /** - * Token types which can be encountered in a parameter type declaration (cross-version). - * - * Sister-method to the {@see Collections::$parameterTypeTokens} property. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. + * Token types which can be encountered in a parameter type declaration. * - * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. - * This token constant will no longer exist in PHPCS 4.x. + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$parameterTypeTokens} property. + * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. + * @since 1.0.0-alpha4 Added the T_TRUE token for PHP 8.2 true type support. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. + * @return array => + */ + public static function parameterTypeTokens() + { + $tokens = self::$parameterTypeTokens; + $tokens += self::namespacedNameTokens(); + + return $tokens; + } + + /** + * DEPRECATED: Token types which can be encountered in a parameter type declaration (cross-version). * - * @see \PHPCSUtils\Tokens\Collections::$parameterTypeTokens Related property (PHPCS 3.3.0+). + * @see \PHPCSUtils\Tokens\Collections::parameterTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::parameterTypeTokens()} method instead. + * * @return array => */ public static function parameterTypeTokensBC() { - $tokens = self::$parameterTypeTokens; - - // PHPCS < 4.0; Needed for support of PHPCS < 3.3.0. For PHPCS 3.3.0+ the constant is no longer used. - if (\defined('T_ARRAY_HINT') === true) { - $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; - } + self::triggerDeprecation( + __FUNCTION__, + '1.0.0-alpha4', + \sprintf('the %s::parameterTypeTokens() method', __CLASS__) + ); - return $tokens; + return self::parameterTypeTokens(); } /** - * Token types which can be encountered in a property type declaration (cross-version). - * - * Sister-method to the {@see Collections::$propertyTypeTokens} property. - * The property supports PHPCS 3.3.0 and up. - * The method supports PHPCS 2.6.0 and up. + * Token types which can be encountered in a property type declaration. * - * Notable difference: - * - The method will include the `T_ARRAY_HINT` token when used with PHPCS 2.x and 3.x. - * This token constant will no longer exist in PHPCS 4.x. + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$propertyTypeTokens} property. + * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. + * @since 1.0.0-alpha4 Added the T_TRUE token for PHP 8.2 true type support. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.3.0. + * @return array => + */ + public static function propertyTypeTokens() + { + $tokens = self::$propertyTypeTokens; + $tokens += self::namespacedNameTokens(); + + return $tokens; + } + + /** + * DEPRECATED: Token types which can be encountered in a property type declaration (cross-version). * - * @see \PHPCSUtils\Tokens\Collections::$propertyTypeTokens Related property (PHPCS 3.3.0+). + * @see \PHPCSUtils\Tokens\Collections::propertyTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::propertyTypeTokens()} method instead. + * * @return array => */ public static function propertyTypeTokensBC() { - return self::parameterTypeTokensBC(); + self::triggerDeprecation( + __FUNCTION__, + '1.0.0-alpha4', + \sprintf('the %s::propertyTypeTokens() method', __CLASS__) + ); + + return self::propertyTypeTokens(); } /** - * Token types which can be encountered in a return type declaration (cross-version). - * - * Sister-property to the {@see Collections::returnTypeTokensBC()} method. - * The property supports PHPCS 3.5.4 and up. - * The method supports PHPCS 2.6.0 and up. + * Token types which can be encountered in a return type declaration. * - * Notable differences: - * - The method will include the `T_ARRAY_HINT` and the `T_RETURN_TYPE` tokens when used with PHPCS 2.x and 3.x. - * These token constants will no longer exist in PHPCS 4.x. - * - The method will include the `T_ARRAY` token which is needed for select arrow functions in PHPCS < 3.5.4. + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$returnTypeTokens} property. + * @since 1.0.0-alpha4 Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokens. + * @since 1.0.0-alpha4 Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support. + * @since 1.0.0-alpha4 Added the T_TRUE token for PHP 8.2 true type support. * - * It is recommended to use the property instead of the method if a standard supports does - * not need to support PHPCS < 3.5.4. + * @return array => + */ + public static function returnTypeTokens() + { + $tokens = self::$returnTypeTokens; + $tokens += self::$OOHierarchyKeywords; + $tokens += self::namespacedNameTokens(); + + return $tokens; + } + + /** + * DEPRECATED: Token types which can be encountered in a return type declaration (cross-version). * - * @see \PHPCSUtils\Tokens\Collections::$returnTypeTokens Related property (PHPCS 3.5.4+). + * @see \PHPCSUtils\Tokens\Collections::returnTypeTokens() Related method (PHPCS 3.3.0+). * * @since 1.0.0-alpha3 * + * @deprecated 1.0.0-alpha4 Use the {@see Collections::returnTypeTokens()} method instead. + * * @return array => */ public static function returnTypeTokensBC() { - $tokens = self::$returnTypeTokens; - - /* - * PHPCS < 4.0. Needed for support of PHPCS 2.4.0 < 3.3.0. - * For PHPCS 3.3.0+ the constant is no longer used. - */ - if (\defined('T_RETURN_TYPE') === true) { - $tokens[\T_RETURN_TYPE] = \T_RETURN_TYPE; - } + self::triggerDeprecation( + __FUNCTION__, + '1.0.0-alpha4', + \sprintf('the %s::returnTypeTokens() method', __CLASS__) + ); - /* - * PHPCS < 4.0. Needed for support of PHPCS < 2.8.0 / PHPCS < 3.5.3 for arrow functions. - * For PHPCS 3.5.3+ the constant is no longer used. - */ - if (\defined('T_ARRAY_HINT') === true) { - $tokens[\T_ARRAY_HINT] = \T_ARRAY_HINT; - } - - /* - * PHPCS < 3.5.4. Needed for support of PHPCS < 3.5.4 for select arrow functions. - * For PHPCS 3.5.4+ the constant is no longer used in return type tokenization. - */ - if (\version_compare(Helper::getVersion(), '3.5.4', '<')) { - $tokens[\T_ARRAY] = \T_ARRAY; - } + return self::returnTypeTokens(); + } - return $tokens; + /** + * Tokens which can start a - potentially multi-line - text string. + * + * @since 1.0.0-alpha4 This method replaces the {@see Collections::$textStingStartTokens} property. + * + * @return array => + */ + public static function textStringStartTokens() + { + return self::$textStingStartTokens; } } diff --git a/PHPCSUtils/Tokens/TokenHelper.php b/PHPCSUtils/Tokens/TokenHelper.php new file mode 100644 index 00000000..f3a2e2ea --- /dev/null +++ b/PHPCSUtils/Tokens/TokenHelper.php @@ -0,0 +1,55 @@ += 9.3 (which uses PHP-Parser), + * this logic breaks because PHP-Parser also polyfills tokens. + * This method takes potentially polyfilled tokens from PHP-Parser into account and will regard the token + * as undefined if it was declared by PHP-Parser. + * + * Note: this method only _needs_ to be used for PHP native tokens, not for PHPCS specific tokens. + * Also, realistically, it only needs to be used for tokens introduced in PHP in recent versions (PHP 7.4 and up). + * Having said that, the method _will_ also work correctly when a name of a PHPCS native token is passed or + * of an older PHP native token. + * + * {@internal PHP native tokens have a positive integer value. PHPCS polyfilled tokens are strings. + * PHP-Parser polyfilled tokens will always have a negative integer value < 0, which is how + * these are filtered out.} + * + * @link https://github.com/sebastianbergmann/php-code-coverage/issues/798 PHP-Code-Coverage#798 + * @link https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/Lexer.php PHP-Parser Lexer code + * + * @since 1.0.0-alpha4 + * + * @param string $name The token name. + * + * @return bool + */ + public static function tokenExists($name) + { + return (\defined($name) && (\is_int(\constant($name)) === false || \constant($name) > 0)); + } +} diff --git a/PHPCSUtils/Utils/Arrays.php b/PHPCSUtils/Utils/Arrays.php index ae292b16..328e3291 100644 --- a/PHPCSUtils/Utils/Arrays.php +++ b/PHPCSUtils/Utils/Arrays.php @@ -12,35 +12,37 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Internal\Cache; +use PHPCSUtils\Internal\IsShortArrayOrListWithCache; use PHPCSUtils\Tokens\Collections; -use PHPCSUtils\Utils\FunctionDeclarations; -use PHPCSUtils\Utils\Lists; /** * Utility functions for use when examining arrays. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Arrays +final class Arrays { /** * The tokens to target to find the double arrow in an array item. * - * Note: this array does not contain the `T_FN` token as it may or may not exist. - * If it exists, it will be added in the `getDoubleArrowPtr()` function. - * * @since 1.0.0 * * @var array => */ private static $doubleArrowTargets = [ \T_DOUBLE_ARROW => \T_DOUBLE_ARROW, + + // Nested arrays. \T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, - \T_STRING => \T_STRING, // BC for T_FN token in PHPCS < 3.5.3 icw PHP < 7.4. + + // Inline function, control structures and other things to skip over. + \T_FN => \T_FN, + \T_MATCH => \T_MATCH, + \T_ATTRIBUTE => \T_ATTRIBUTE, ]; /** @@ -62,115 +64,7 @@ class Arrays */ public static function isShortArray(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - // Is this one of the tokens this function handles ? - if (isset($tokens[$stackPtr]) === false - || isset(Collections::$shortArrayTokensBC[$tokens[$stackPtr]['code']]) === false - ) { - return false; - } - - // All known tokenizer bugs are in PHPCS versions before 3.3.0. - $phpcsVersion = Helper::getVersion(); - - /* - * Deal with square brackets which may be incorrectly tokenized short arrays. - */ - if (isset(Collections::$shortArrayTokens[$tokens[$stackPtr]['code']]) === false) { - if (\version_compare($phpcsVersion, '3.3.0', '>=')) { - // These will just be properly tokenized, plain square brackets. No need for further checks. - return false; - } - - $opener = $stackPtr; - if ($tokens[$stackPtr]['code'] === \T_CLOSE_SQUARE_BRACKET) { - $opener = $tokens[$stackPtr]['bracket_opener']; - } - - if (isset($tokens[$opener]['bracket_closer']) === false) { - return false; - } - - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), null, true); - - if (\version_compare($phpcsVersion, '2.8.0', '>=')) { - /* - * BC: Work around a bug in the tokenizer of PHPCS 2.8.0 - 3.2.3 where a `[` would be - * tokenized as T_OPEN_SQUARE_BRACKET instead of T_OPEN_SHORT_ARRAY if it was - * preceded by a PHP open tag at the very start of the file. - * - * If we have square brackets which are not that specific situation, they are just plain - * square brackets. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/1971 - */ - if ($prevNonEmpty !== 0 || $tokens[$prevNonEmpty]['code'] !== \T_OPEN_TAG) { - return false; - } - } - - if (\version_compare($phpcsVersion, '2.8.0', '<')) { - /* - * BC: Work around a bug in the tokenizer of PHPCS < 2.8.0 where a `[` would be - * tokenized as T_OPEN_SQUARE_BRACKET instead of T_OPEN_SHORT_ARRAY if it was - * preceded by a close curly of a control structure. - * - * If we have square brackets which are not that specific situation, they are just plain - * square brackets. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/1284 - */ - if ($tokens[$prevNonEmpty]['code'] !== \T_CLOSE_CURLY_BRACKET - || isset($tokens[$prevNonEmpty]['scope_condition']) === false - ) { - return false; - } - } - } else { - /* - * Deal with short array brackets which may be incorrectly tokenized plain square brackets. - */ - if (\version_compare($phpcsVersion, '2.9.0', '<')) { - $opener = $stackPtr; - if ($tokens[$stackPtr]['code'] === \T_CLOSE_SHORT_ARRAY) { - $opener = $tokens[$stackPtr]['bracket_opener']; - } - - /* - * BC: Work around a bug in the tokenizer of PHPCS < 2.9.0 where array dereferencing - * of short array and string literals would be incorrectly tokenized as short array. - * I.e. the square brackets in `'PHP'[0]` would be tokenized as short array. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/1381 - */ - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), null, true); - if ($tokens[$prevNonEmpty]['code'] === \T_CLOSE_SHORT_ARRAY - || $tokens[$prevNonEmpty]['code'] === \T_CONSTANT_ENCAPSED_STRING - ) { - return false; - } - - /* - * BC: Work around a bug in the tokenizer of PHPCS 2.8.0 and 2.8.1 where array dereferencing - * of a variable variable would be incorrectly tokenized as short array. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/1284 - */ - if (\version_compare($phpcsVersion, '2.8.0', '>=') - && $tokens[$prevNonEmpty]['code'] === \T_CLOSE_CURLY_BRACKET - ) { - $openCurly = $tokens[$prevNonEmpty]['bracket_opener']; - $beforeCurlies = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openCurly - 1), null, true); - if ($tokens[$beforeCurlies]['code'] === \T_DOLLAR) { - return false; - } - } - } - } - - // In all other circumstances, make sure this isn't a short list instead of a short array. - return (Lists::isShortList($phpcsFile, $stackPtr) === false); + return IsShortArrayOrListWithCache::isShortArray($phpcsFile, $stackPtr); } /** @@ -208,7 +102,7 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortArray = // Is this one of the tokens this function handles ? if (isset($tokens[$stackPtr]) === false - || isset(Collections::$arrayTokensBC[$tokens[$stackPtr]['code']]) === false + || isset(Collections::arrayTokensBC()[$tokens[$stackPtr]['code']]) === false ) { return false; } @@ -251,6 +145,8 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortArray = * * @since 1.0.0 * @since 1.0.0-alpha2 Now allows for arrow functions in arrays. + * @since 1.0.0-alpha4 Now allows for match expressions in arrays. + * @since 1.0.0-alpha4 Now allows for attributes in arrays. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being examined. * @param int $start Stack pointer to the start of the array item. @@ -271,11 +167,16 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) ); } + $cacheId = "$start-$end"; + if (Cache::isCached($phpcsFile, __METHOD__, $cacheId) === true) { + return Cache::get($phpcsFile, __METHOD__, $cacheId); + } + $targets = self::$doubleArrowTargets; - $targets += Collections::$closedScopes; - $targets += Collections::arrowFunctionTokensBC(); + $targets += Collections::closedScopes(); $doubleArrow = ($start - 1); + $returnValue = false; ++$end; do { $doubleArrow = $phpcsFile->findNext( @@ -289,38 +190,33 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end) } if ($tokens[$doubleArrow]['code'] === \T_DOUBLE_ARROW) { - return $doubleArrow; - } - - /* - * BC: work-around a bug in PHPCS 3.5.4 where the double arrow is incorrectly tokenized as T_STRING. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2865 - */ - if ($tokens[$doubleArrow]['code'] === \T_STRING && $tokens[$doubleArrow]['content'] === '=>') { - return $doubleArrow; + $returnValue = $doubleArrow; + break; } // Skip over closed scopes which may contain foreach structures or generators. - if (isset(Collections::$closedScopes[$tokens[$doubleArrow]['code']]) === true + if ((isset(Collections::closedScopes()[$tokens[$doubleArrow]['code']]) === true + || $tokens[$doubleArrow]['code'] === \T_FN + || $tokens[$doubleArrow]['code'] === \T_MATCH) && isset($tokens[$doubleArrow]['scope_closer']) === true ) { $doubleArrow = $tokens[$doubleArrow]['scope_closer']; continue; } - // BC for PHP 7.4 arrow functions with PHPCS < 3.5.3. - if (isset(Collections::arrowFunctionTokensBC()[$tokens[$doubleArrow]['code']]) === true - && FunctionDeclarations::isArrowFunction($phpcsFile, $doubleArrow) === false + // Skip over attributes which may contain arrays as a passed parameters. + if ($tokens[$doubleArrow]['code'] === \T_ATTRIBUTE + && isset($tokens[$doubleArrow]['attribute_closer']) ) { - // Not an arrow function, continue looking. + $doubleArrow = $tokens[$doubleArrow]['attribute_closer']; continue; } - // Start of nested long/short array or arrow function. + // Start of nested long/short array. break; } while ($doubleArrow < $end); - return false; + Cache::set($phpcsFile, __METHOD__, $cacheId, $returnValue); + return $returnValue; } } diff --git a/PHPCSUtils/Utils/Conditions.php b/PHPCSUtils/Utils/Conditions.php index e63eedd1..6650a4c2 100644 --- a/PHPCSUtils/Utils/Conditions.php +++ b/PHPCSUtils/Utils/Conditions.php @@ -20,7 +20,7 @@ * PHPCS native `PHP_CodeSniffer\Files\File` class. * Also see {@see \PHPCSUtils\BackCompat\BCFile}. */ -class Conditions +final class Conditions { /** diff --git a/PHPCSUtils/Utils/Context.php b/PHPCSUtils/Utils/Context.php new file mode 100644 index 00000000..1f640d20 --- /dev/null +++ b/PHPCSUtils/Utils/Context.php @@ -0,0 +1,232 @@ +getTokens(); + + // Check for the existence of the token. + if (isset($tokens[$stackPtr]) === false) { + return false; + } + + if (isset($tokens[$stackPtr]['attribute_opener'], $tokens[$stackPtr]['attribute_closer']) === false) { + return false; + } + + return ($stackPtr !== $tokens[$stackPtr]['attribute_opener'] + && $stackPtr !== $tokens[$stackPtr]['attribute_closer']); + } + + /** + * Check whether an arbitrary token is in a foreach condition and if so, in which part: + * before or after the "as". + * + * @since 1.0.0-alpha4 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the token we are checking. + * + * @return string|false String `'beforeAs'`, `'as'` or `'afterAs'` when the token is within + * a `foreach` condition. + * `FALSE` in all other cases, including for parse errors. + */ + public static function inForeachCondition(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check for the existence of the token. + if (isset($tokens[$stackPtr]) === false) { + return false; + } + + $foreach = Parentheses::getLastOwner($phpcsFile, $stackPtr, \T_FOREACH); + if ($foreach === false) { + return false; + } + + if ($tokens[$stackPtr]['code'] === \T_AS) { + return 'as'; + } + + $asPtr = $phpcsFile->findNext( + \T_AS, + ($tokens[$foreach]['parenthesis_opener'] + 1), + $tokens[$foreach]['parenthesis_closer'] + ); + + if ($asPtr === false) { + // Parse error or live coding. + return false; + } + + if ($stackPtr < $asPtr) { + return 'beforeAs'; + } + + return 'afterAs'; + } + + /** + * Check whether an arbitrary token is in a for condition and if so, in which part: + * the first, second or third expression. + * + * Note: the semicolons separating the conditions are regarded as belonging with the + * expression before it. + * + * @since 1.0.0-alpha4 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the token we are checking. + * + * @return string|false String `'expr1'`, `'expr2'` or `'expr3'` when the token is within + * a `for` condition. + * `FALSE` in all other cases, including for parse errors. + */ + public static function inForCondition(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Check for the existence of the token. + if (isset($tokens[$stackPtr]) === false) { + return false; + } + + $for = Parentheses::getLastOwner($phpcsFile, $stackPtr, \T_FOR); + if ($for === false) { + return false; + } + + $semicolons = []; + $count = 0; + $opener = $tokens[$for]['parenthesis_opener']; + $closer = $tokens[$for]['parenthesis_closer']; + $level = $tokens[$for]['level']; + $parens = 1; + + if (isset($tokens[$for]['nested_parenthesis'])) { + $parens = (\count($tokens[$for]['nested_parenthesis']) + 1); + } + + for ($i = ($opener + 1); $i < $closer; $i++) { + if ($tokens[$i]['code'] !== \T_SEMICOLON) { + continue; + } + + if ($tokens[$i]['level'] !== $level + || \count($tokens[$i]['nested_parenthesis']) !== $parens + ) { + // Disregard semi-colons at lower nesting/condition levels. + continue; + } + + ++$count; + $semicolons[$count] = $i; + } + + if ($count !== 2) { + return false; + } + + foreach ($semicolons as $key => $ptr) { + if ($stackPtr <= $ptr) { + return 'expr' . $key; + } + } + + return 'expr3'; + } +} diff --git a/PHPCSUtils/Utils/ControlStructures.php b/PHPCSUtils/Utils/ControlStructures.php index 085a1c3f..fbe94cdb 100644 --- a/PHPCSUtils/Utils/ControlStructures.php +++ b/PHPCSUtils/Utils/ControlStructures.php @@ -19,8 +19,9 @@ * Utility functions for use when examining control structures. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class ControlStructures +final class ControlStructures { /** @@ -36,6 +37,7 @@ class ControlStructures * regarded as empty. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.0 match control structures. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. @@ -53,7 +55,7 @@ public static function hasBody(File $phpcsFile, $stackPtr, $allowEmpty = true) // Check for the existence of the token. if (isset($tokens[$stackPtr]) === false - || isset(Collections::$controlStructureTokens[$tokens[$stackPtr]['code']]) === false + || isset(Collections::controlStructureTokens()[$tokens[$stackPtr]['code']]) === false ) { return false; } @@ -66,16 +68,6 @@ public static function hasBody(File $phpcsFile, $stackPtr, $allowEmpty = true) } } - // Deal with declare alternative syntax without scope opener. - if ($tokens[$stackPtr]['code'] === \T_DECLARE && isset($tokens[$stackPtr]['scope_opener']) === false) { - $declareOpenClose = self::getDeclareScopeOpenClose($phpcsFile, $stackPtr); - if ($declareOpenClose !== false) { - // Set the opener + closer in the tokens array. This will only affect our local copy. - $tokens[$stackPtr]['scope_opener'] = $declareOpenClose['opener']; - $tokens[$stackPtr]['scope_closer'] = $declareOpenClose['closer']; - } - } - /* * The scope markers are set. This is the simplest situation. */ @@ -209,15 +201,12 @@ public static function isElseIf(File $phpcsFile, $stackPtr) * In the first case, the statement - correctly - won't have a scope opener/closer. * In the second case, the statement will have the scope opener/closer indexes. * In the last case, due to a bug in the PHPCS Tokenizer, it won't have the scope opener/closer indexes, - * while it really should. This bug is fixed in PHPCS 3.5.4. - * - * In other words, if a sniff needs to support PHPCS < 3.5.4 and needs to take the alternative - * control structure syntax into account, this method can be used to retrieve the - * scope opener/closer for the declare statement. + * while it really should. This bug was fixed in PHPCS 3.5.4. * * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/2843 PHPCS PR #2843 * - * @since 1.0.0 + * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Check the scope_opener/scope_closer instead. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. @@ -234,6 +223,15 @@ public static function isElseIf(File $phpcsFile, $stackPtr) */ public static function getDeclareScopeOpenClose(File $phpcsFile, $stackPtr) { + \trigger_error( + \sprintf( + 'The %s() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.', + __METHOD__ + ), + \E_USER_DEPRECATED + ); + $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false @@ -249,99 +247,6 @@ public static function getDeclareScopeOpenClose(File $phpcsFile, $stackPtr) ]; } - $declareCount = 0; - $opener = null; - $closer = null; - - for ($i = $stackPtr; $i < $phpcsFile->numTokens; $i++) { - if ($tokens[$i]['code'] !== \T_DECLARE && $tokens[$i]['code'] !== \T_ENDDECLARE) { - continue; - } - - if ($tokens[$i]['code'] === \T_ENDDECLARE) { - --$declareCount; - - if ($declareCount !== 0) { - continue; - } - - // OK, we reached the target enddeclare. - $closer = $i; - break; - } - - if ($tokens[$i]['code'] === \T_DECLARE) { - ++$declareCount; - - // Find the scope opener - if (isset($tokens[$i]['parenthesis_closer']) === false) { - // Parse error or live coding, nothing to do. - return false; - } - - $scopeOpener = $phpcsFile->findNext( - Tokens::$emptyTokens, - ($tokens[$i]['parenthesis_closer'] + 1), - null, - true - ); - - if ($scopeOpener === false) { - // Live coding, nothing to do. - return false; - } - - // Remember the scope opener for our target declare. - if ($declareCount === 1) { - $opener = $scopeOpener; - } - - $i = $scopeOpener; - - switch ($tokens[$scopeOpener]['code']) { - case \T_COLON: - // Nothing particular to do. Just continue the loop. - break; - - case \T_OPEN_CURLY_BRACKET: - /* - * Live coding or nested declare statement with curlies. - */ - - if (isset($tokens[$scopeOpener]['scope_closer']) === false) { - // Live coding, nothing to do. - return false; - } - - // Jump over the statement. - $i = $tokens[$scopeOpener]['scope_closer']; - --$declareCount; - - break; - - case \T_SEMICOLON: - // Nested single line declare statement. - --$declareCount; - break; - - default: - // This is an unexpected token. Most likely a parse error. Bow out. - return false; - } - } - - if ($declareCount === 0) { - break; - } - } - - if (isset($opener, $closer)) { - return [ - 'opener' => $opener, - 'closer' => $closer, - ]; - } - return false; } @@ -349,6 +254,7 @@ public static function getDeclareScopeOpenClose(File $phpcsFile, $stackPtr) * Retrieve the exception(s) being caught in a CATCH condition. * * @since 1.0.0-alpha3 + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the token we are checking. @@ -396,7 +302,7 @@ public static function getCaughtExceptions(File $phpcsFile, $stackPtr) continue; } - if (isset(Collections::$OONameTokens[$tokens[$i]['code']]) === false) { + if (isset(Collections::namespacedNameTokens()[$tokens[$i]['code']]) === false) { // Add the current exception to the result array. $exceptions[] = [ 'type' => $foundName, diff --git a/PHPCSUtils/Utils/FunctionDeclarations.php b/PHPCSUtils/Utils/FunctionDeclarations.php index 54eab74f..74f87c4c 100644 --- a/PHPCSUtils/Utils/FunctionDeclarations.php +++ b/PHPCSUtils/Utils/FunctionDeclarations.php @@ -13,8 +13,7 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\BackCompat\BCTokens; -use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\GetTokensAsString; use PHPCSUtils\Utils\ObjectDeclarations; @@ -24,14 +23,15 @@ /** * Utility functions for use when examining function declaration statements. * - * @since 1.0.0 The `FunctionDeclarations::getProperties()` and the - * `FunctionDeclarations::getParameters()` methods are based on and - * inspired by respectively the `getMethodProperties()` - * and `getMethodParameters()` methods in the PHPCS native - * `PHP_CodeSniffer\Files\File` class. - * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * @since 1.0.0 The `FunctionDeclarations::getProperties()` and the + * `FunctionDeclarations::getParameters()` methods are based on and + * inspired by respectively the `getMethodProperties()` + * and `getMethodParameters()` methods in the PHPCS native + * `PHP_CodeSniffer\Files\File` class. + * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class FunctionDeclarations +final class FunctionDeclarations { /** @@ -112,25 +112,6 @@ class FunctionDeclarations '__soapcall' => 'SOAPClient', ]; - /** - * Tokens which can be the end token of an arrow function. - * - * @since 1.0.0 - * - * @var array => - */ - private static $arrowFunctionEndTokens = [ - \T_COLON => true, - \T_COMMA => true, - \T_SEMICOLON => true, - \T_CLOSE_PARENTHESIS => true, - \T_CLOSE_SQUARE_BRACKET => true, - \T_CLOSE_CURLY_BRACKET => true, - \T_CLOSE_SHORT_ARRAY => true, - \T_OPEN_TAG => true, - \T_CLOSE_TAG => true, - ]; - /** * Returns the declaration name for a function. * @@ -167,16 +148,18 @@ public static function getName(File $phpcsFile, $stackPtr) * parse errors or live coding. * - Defensive coding against incorrect calls to this method. * - More efficient checking whether a function has a body. - * - New `"return_type_end_token"` (int|false) array index. - * - To allow for backward compatible handling of arrow functions, this method will also accept - * `T_STRING` tokens and examine them to check if these are arrow functions. + * - Support for PHP 8.0 identifier name tokens in return types, cross-version PHP & PHPCS. + * - Support for the PHP 8.2 `true` type. * * @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMethodProperties() Cross-version compatible version of the original. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. * @since 1.0.0-alpha3 Added support for PHP 8.0 static return type. + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. + * @since 1.0.0-alpha4 Added support for PHP 8.1 intersection types. + * @since 1.0.0-alpha4 Added support for PHP 8.2 true type. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token to @@ -193,7 +176,8 @@ public static function getName(File $phpcsFile, $stackPtr) * // or FALSE if there is no return type. * 'return_type_end_token' => integer, // The stack pointer to the end of the return type * // or FALSE if there is no return type. - * 'nullable_return_type' => false, // TRUE if the return type is nullable. + * 'nullable_return_type' => false, // TRUE if the return type is preceded + * // by the nullability operator. * 'is_abstract' => false, // TRUE if the abstract keyword was found. * 'is_final' => false, // TRUE if the final keyword was found. * 'is_static' => false, // TRUE if the static keyword was found. @@ -206,13 +190,10 @@ public static function getName(File $phpcsFile, $stackPtr) */ public static function getProperties(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - $arrowOpenClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); + $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false - || ($tokens[$stackPtr]['code'] !== \T_FUNCTION - && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $arrowOpenClose === false) + || isset(Collections::functionDeclarationTokens()[$tokens[$stackPtr]['code']]) === false ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or an arrow function'); } @@ -266,23 +247,23 @@ public static function getProperties(File $phpcsFile, $stackPtr) $returnTypeEndToken = false; $nullableReturnType = false; $hasBody = false; - $returnTypeTokens = Collections::returnTypeTokensBC(); + $returnTypeTokens = Collections::returnTypeTokens(); + + /* + * BC PHPCS < 3.x.x: The union type separator is not (yet) retokenized correctly + * for union types containing the `true` type. + */ + $returnTypeTokens[\T_BITWISE_OR] = \T_BITWISE_OR; $parenthesisCloser = null; if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) { $parenthesisCloser = $tokens[$stackPtr]['parenthesis_closer']; - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - $parenthesisCloser = $arrowOpenClose['parenthesis_closer']; } if (isset($parenthesisCloser) === true) { $scopeOpener = null; if (isset($tokens[$stackPtr]['scope_opener']) === true) { $scopeOpener = $tokens[$stackPtr]['scope_opener']; - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3. - $scopeOpener = $arrowOpenClose['scope_opener']; } for ($i = $parenthesisCloser; $i < $phpcsFile->numTokens; $i++) { @@ -297,13 +278,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) break; } - if ($tokens[$i]['type'] === 'T_NULLABLE' - // Handle nullable tokens in PHPCS < 2.8.0. - || (\defined('T_NULLABLE') === false && $tokens[$i]['code'] === \T_INLINE_THEN) - // Handle nullable tokens with arrow functions in PHPCS 2.8.0 - 2.9.0. - || ($arrowOpenClose !== false && $tokens[$i]['code'] === \T_INLINE_THEN - && \version_compare(Helper::getVersion(), '2.9.1', '<') === true) - ) { + if ($tokens[$i]['code'] === \T_NULLABLE) { $nullableReturnType = true; } @@ -348,6 +323,7 @@ public static function getProperties(File $phpcsFile, $stackPtr) * 'name' => '$var', // The variable name. * 'token' => integer, // The stack pointer to the variable name. * 'content' => string, // The full content of the variable definition. + * 'has_attributes' => boolean, // Does the parameter have one or more attributes attached ? * 'pass_by_reference' => boolean, // Is the variable passed by reference? * 'reference_token' => integer, // The stack pointer to the reference operator * // or FALSE if the param is not passed by reference. @@ -359,7 +335,8 @@ public static function getProperties(File $phpcsFile, $stackPtr) * // or FALSE if there is no type hint. * 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint * // or FALSE if there is no type hint. - * 'nullable_type' => boolean, // TRUE if the var type is nullable. + * 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability + * // operator. * 'comma_token' => integer, // The stack pointer to the comma after the param * // or FALSE if this is the last param. * ) @@ -372,19 +349,35 @@ public static function getProperties(File $phpcsFile, $stackPtr) * 'default_equal_token' => integer, // The stack pointer to the equals sign. * ``` * + * Parameters declared using PHP 8 constructor property promotion, have these additional array indexes: + * ```php + * 'property_visibility' => string, // The property visibility as declared. + * 'visibility_token' => integer, // The stack pointer to the visibility modifier token. + * 'property_readonly' => bool, // TRUE if the readonly keyword was found. + * 'readonly_token' => integer, // The stack pointer to the readonly modifier token. + * ``` + * * Main differences with the PHPCS version: * - Defensive coding against incorrect calls to this method. * - More efficient and more stable checking whether a `T_USE` token is a closure use. * - More efficient and more stable looping of the default value. * - Clearer exception message when a non-closure use token was passed to the function. - * - To allow for backward compatible handling of arrow functions, this method will also accept - * `T_STRING` tokens and examine them to check if these are arrow functions. + * - Support for PHP 8.0 identifier name tokens in parameter types, cross-version PHP & PHPCS. + * - Support for the PHP 8.2 `true` type. + * - The results of this function call are cached during a PHPCS run for faster response times. * * @see \PHP_CodeSniffer\Files\File::getMethodParameters() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMethodParameters() Cross-version compatible version of the original. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. + * @since 1.0.0-alpha4 Added support for PHP 8.0 constructor property promotion. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. + * @since 1.0.0-alpha4 Added support for PHP 8.0 parameter attributes. + * @since 1.0.0-alpha4 Added support for PHP 8.1 readonly keyword for constructor property promotion. + * @since 1.0.0-alpha4 Added support for PHP 8.1 intersection types. + * @since 1.0.0-alpha4 Added support for PHP 8.2 true type. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the function token @@ -400,19 +393,17 @@ public static function getProperties(File $phpcsFile, $stackPtr) */ public static function getParameters(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - $arrowOpenClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); + $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false - || ($tokens[$stackPtr]['code'] !== \T_FUNCTION - && $tokens[$stackPtr]['code'] !== \T_CLOSURE - && $tokens[$stackPtr]['code'] !== \T_USE - && $arrowOpenClose === false) + || (isset(Collections::functionDeclarationTokens()[$tokens[$stackPtr]['code']]) === false + && $tokens[$stackPtr]['code'] !== \T_USE) ) { throw new RuntimeException('$stackPtr must be of type T_FUNCTION, T_CLOSURE or T_USE or an arrow function'); } if ($tokens[$stackPtr]['code'] === \T_USE) { + // This will work PHPCS 3.x/4.x cross-version without much overhead. $opener = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); if ($opener === false || $tokens[$opener]['code'] !== \T_OPEN_PARENTHESIS @@ -420,9 +411,6 @@ public static function getParameters(File $phpcsFile, $stackPtr) ) { throw new RuntimeException('$stackPtr was not a valid closure T_USE'); } - } elseif ($arrowOpenClose !== false) { - // Arrow function in combination with PHP < 7.4 or PHPCS < 3.5.3/4/5. - $opener = $arrowOpenClose['parenthesis_opener']; } else { if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) { // Live coding or syntax error, so no params to find. @@ -437,6 +425,10 @@ public static function getParameters(File $phpcsFile, $stackPtr) return []; } + if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) { + return Cache::get($phpcsFile, __METHOD__, $stackPtr); + } + $closer = $tokens[$opener]['parenthesis_closer']; $vars = []; @@ -445,6 +437,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) $defaultStart = null; $equalToken = null; $paramCount = 0; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; @@ -453,48 +446,75 @@ public static function getParameters(File $phpcsFile, $stackPtr) $typeHintToken = false; $typeHintEndToken = false; $nullableType = false; + $visibilityToken = null; + $readonlyToken = null; + + $parameterTypeTokens = Collections::parameterTypeTokens(); + + /* + * BC PHPCS < 3.x.x: The union type separator is not (yet) retokenized correctly + * for union types containing the `true` type. + */ + $parameterTypeTokens[\T_BITWISE_OR] = \T_BITWISE_OR; for ($i = $paramStart; $i <= $closer; $i++) { - // Changed from checking 'code' to 'type' to allow for T_NULLABLE not existing in PHPCS < 2.8.0. - switch ($tokens[$i]['type']) { - case 'T_BITWISE_AND': + if (isset($parameterTypeTokens[$tokens[$i]['code']]) === true + /* + * Self and parent are valid, static invalid, but was probably intended as type declaration. + * Note: constructor property promotion does not support static properties, so this should + * still be a valid assumption. + */ + || $tokens[$i]['code'] === \T_STATIC + ) { + if ($typeHintToken === false) { + $typeHintToken = $i; + } + + $typeHint .= $tokens[$i]['content']; + $typeHintEndToken = $i; + continue; + } + + switch ($tokens[$i]['code']) { + case \T_ATTRIBUTE: + $hasAttributes = true; + + // Skip to the end of the attribute. + $i = $tokens[$i]['attribute_closer']; + break; + + case \T_BITWISE_AND: $passByReference = true; $referenceToken = $i; break; - case 'T_VARIABLE': + case \T_VARIABLE: $currVar = $i; break; - case 'T_ELLIPSIS': + case \T_ELLIPSIS: $variableLength = true; $variadicToken = $i; break; - case 'T_ARRAY_HINT': // PHPCS < 3.3.0. - case 'T_CALLABLE': - case 'T_SELF': - case 'T_PARENT': - case 'T_STATIC': // Self and parent are valid, static invalid, but was probably intended as type hint. - case 'T_STRING': - case 'T_NS_SEPARATOR': - if ($typeHintToken === false) { - $typeHintToken = $i; - } - + case \T_NULLABLE: + $nullableType = true; $typeHint .= $tokens[$i]['content']; $typeHintEndToken = $i; break; - case 'T_NULLABLE': - case 'T_INLINE_THEN': // PHPCS < 2.8.0. - $nullableType = true; - $typeHint .= $tokens[$i]['content']; - $typeHintEndToken = $i; + case \T_PUBLIC: + case \T_PROTECTED: + case \T_PRIVATE: + $visibilityToken = $i; break; - case 'T_CLOSE_PARENTHESIS': - case 'T_COMMA': + case \T_READONLY: + $readonlyToken = $i; + break; + + case \T_CLOSE_PARENTHESIS: + case \T_COMMA: // If it's null, then there must be no parameters for this // method. if ($currVar === null) { @@ -516,6 +536,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) $vars[$paramCount]['default_equal_token'] = $equalToken; } + $vars[$paramCount]['has_attributes'] = $hasAttributes; $vars[$paramCount]['pass_by_reference'] = $passByReference; $vars[$paramCount]['reference_token'] = $referenceToken; $vars[$paramCount]['variable_length'] = $variableLength; @@ -525,6 +546,17 @@ public static function getParameters(File $phpcsFile, $stackPtr) $vars[$paramCount]['type_hint_end_token'] = $typeHintEndToken; $vars[$paramCount]['nullable_type'] = $nullableType; + if ($visibilityToken !== null) { + $vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content']; + $vars[$paramCount]['visibility_token'] = $visibilityToken; + $vars[$paramCount]['property_readonly'] = false; + } + + if ($readonlyToken !== null) { + $vars[$paramCount]['property_readonly'] = true; + $vars[$paramCount]['readonly_token'] = $readonlyToken; + } + if ($tokens[$i]['code'] === \T_COMMA) { $vars[$paramCount]['comma_token'] = $i; } else { @@ -536,6 +568,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) $paramStart = ($i + 1); $defaultStart = null; $equalToken = null; + $hasAttributes = false; $passByReference = false; $referenceToken = false; $variableLength = false; @@ -544,11 +577,13 @@ public static function getParameters(File $phpcsFile, $stackPtr) $typeHintToken = false; $typeHintEndToken = false; $nullableType = false; + $visibilityToken = null; + $readonlyToken = null; - $paramCount++; + ++$paramCount; break; - case 'T_EQUAL': + case \T_EQUAL: $defaultStart = $phpcsFile->findNext(Tokens::$emptyTokens, ($i + 1), null, true); $equalToken = $i; @@ -582,6 +617,7 @@ public static function getParameters(File $phpcsFile, $stackPtr) } } + Cache::set($phpcsFile, __METHOD__, $stackPtr, $vars); return $vars; } @@ -589,26 +625,12 @@ public static function getParameters(File $phpcsFile, $stackPtr) * Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function. * * Helper function for cross-version compatibility with both PHP as well as PHPCS. - * - PHP 7.4+ will tokenize most tokens with the content "fn" as `T_FN`, even when it isn't an arrow function. - * - PHPCS < 3.5.3 will tokenize arrow functions keywords as `T_STRING`. - * - PHPCS 3.5.3/3.5.4 will tokenize the keyword differently depending on which PHP version is used - * and similar to PHP will tokenize most tokens with the content "fn" as `T_FN`, even when it's not an - * arrow function. - * > Note: the tokens tokenized by PHPCS 3.5.3 - 3.5.4 as `T_FN` are not 100% the same as those tokenized - * by PHP 7.4+ as `T_FN`. - * - * Either way, the `T_FN` token is not a reliable search vector for finding or examining - * arrow functions, at least not until PHPCS 3.5.5. - * This function solves that and will give reliable results in the same way as this is now - * solved in PHPCS 3.5.5. - * - * > Note: Bugs are still being found and reported about how PHPCS tokenizes the arrow functions. - * This method will keep up with upstream changes and backport them, in as far possible, to allow - * for sniffing arrow functions in PHPCS < current. + * As of PHPCS 3.5.6, this function is no longer be needed. * * @see \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose() Related function. * - * @since 1.0.0 + * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the T_FN token constant instead. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The token to check. Typically a T_FN or @@ -620,28 +642,25 @@ public static function getParameters(File $phpcsFile, $stackPtr) */ public static function isArrowFunction(File $phpcsFile, $stackPtr) { + \trigger_error( + \sprintf( + 'The %s() function is deprecated since PHPCSUtils 1.0.0-alpha4. Use the `T_FN` token instead.', + __METHOD__ + ), + \E_USER_DEPRECATED + ); + $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false) { return false; } - if ($tokens[$stackPtr]['type'] === 'T_FN' + if ($tokens[$stackPtr]['code'] === \T_FN && isset($tokens[$stackPtr]['scope_closer']) === true ) { return true; } - if (isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === false - || \strtolower($tokens[$stackPtr]['content']) !== 'fn' - ) { - return false; - } - - $openClose = self::getArrowFunctionOpenClose($phpcsFile, $stackPtr); - if ($openClose !== false && isset($openClose['scope_closer'])) { - return true; - } - return false; } @@ -650,13 +669,12 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr) * for an arrow function. * * Helper function for cross-version compatibility with both PHP as well as PHPCS. - * In PHPCS versions prior to PHPCS 3.5.3/3.5.4, the `T_FN` token is not yet backfilled - * and does not have parenthesis opener/closer nor scope opener/closer indexes assigned - * in the `$tokens` array. + * As of PHPCS 3.5.6, this function is no longer be needed. * * @see \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() Related function. * - * @since 1.0.0 + * @since 1.0.0 + * @deprecated 1.0.0-alpha4 Use the T_FN token constant instead. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The token to retrieve the openers/closers for. @@ -676,19 +694,23 @@ public static function isArrowFunction(File $phpcsFile, $stackPtr) */ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) { + \trigger_error( + \sprintf( + 'The %s() function is deprecated since PHPCSUtils 1.0.0-alpha4. Use the `T_FN` token instead.', + __METHOD__ + ), + \E_USER_DEPRECATED + ); + $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false - || isset(Collections::arrowFunctionTokensBC()[$tokens[$stackPtr]['code']]) === false - || \strtolower($tokens[$stackPtr]['content']) !== 'fn' + || $tokens[$stackPtr]['code'] !== \T_FN ) { return false; } - if ($tokens[$stackPtr]['type'] === 'T_FN' - && isset($tokens[$stackPtr]['scope_closer']) === true - && \version_compare(Helper::getVersion(), '3.5.4', '>') === true - ) { + if (isset($tokens[$stackPtr]['scope_closer']) === true) { // The keys will either all be set or none will be set, so no additional checks needed. return [ 'parenthesis_opener' => $tokens[$stackPtr]['parenthesis_opener'], @@ -698,125 +720,7 @@ public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) ]; } - /* - * This is either a T_STRING token pre-PHP 7.4, or T_FN on PHP 7.4 in combination - * with PHPCS < 3.5.3/4/5. - * - * Now see about finding the relevant arrow function tokens. - */ - $returnValue = []; - - $nextNonEmpty = $phpcsFile->findNext( - (Tokens::$emptyTokens + [\T_BITWISE_AND]), - ($stackPtr + 1), - null, - true - ); - if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] !== \T_OPEN_PARENTHESIS) { - return false; - } - - $returnValue['parenthesis_opener'] = $nextNonEmpty; - if (isset($tokens[$nextNonEmpty]['parenthesis_closer']) === false) { - return false; - } - - $returnValue['parenthesis_closer'] = $tokens[$nextNonEmpty]['parenthesis_closer']; - - $ignore = Tokens::$emptyTokens; - $ignore += Collections::returnTypeTokensBC(); - $ignore[\T_COLON] = \T_COLON; - $ignore[\T_INLINE_ELSE] = \T_INLINE_ELSE; // Return type colon on PHPCS < 2.9.1. - $ignore[\T_INLINE_THEN] = \T_INLINE_THEN; // Nullable type indicator on PHPCS < 2.9.1. - - if (\defined('T_NULLABLE') === true) { - $ignore[\T_NULLABLE] = \T_NULLABLE; - } - - $arrow = $phpcsFile->findNext( - $ignore, - ($tokens[$nextNonEmpty]['parenthesis_closer'] + 1), - null, - true - ); - - if ($arrow === false - || ($tokens[$arrow]['code'] !== \T_DOUBLE_ARROW && $tokens[$arrow]['type'] !== 'T_FN_ARROW') - ) { - return false; - } - - $returnValue['scope_opener'] = $arrow; - $inTernary = false; - $lastEndToken = null; - - for ($scopeCloser = ($arrow + 1); $scopeCloser < $phpcsFile->numTokens; $scopeCloser++) { - if (isset(self::$arrowFunctionEndTokens[$tokens[$scopeCloser]['code']]) === true - // BC for misidentified ternary else in some PHPCS versions. - && ($tokens[$scopeCloser]['code'] !== \T_COLON || $inTernary === false) - ) { - if ($lastEndToken !== null - && $tokens[$scopeCloser]['code'] === \T_CLOSE_PARENTHESIS - && $tokens[$scopeCloser]['parenthesis_opener'] < $arrow - ) { - $scopeCloser = $lastEndToken; - } - - break; - } - - if (isset(Collections::arrowFunctionTokensBC()[$tokens[$scopeCloser]['code']]) === true) { - $nested = self::getArrowFunctionOpenClose($phpcsFile, $scopeCloser); - if ($nested !== false && isset($nested['scope_closer'])) { - // We minus 1 here in case the closer can be shared with us. - $scopeCloser = ($nested['scope_closer'] - 1); - continue; - } - } - - if (isset($tokens[$scopeCloser]['scope_closer']) === true - && $tokens[$scopeCloser]['code'] !== \T_INLINE_ELSE - && $tokens[$scopeCloser]['code'] !== \T_END_HEREDOC - && $tokens[$scopeCloser]['code'] !== \T_END_NOWDOC - ) { - // We minus 1 here in case the closer can be shared with us. - $scopeCloser = ($tokens[$scopeCloser]['scope_closer'] - 1); - continue; - } - - if (isset($tokens[$scopeCloser]['parenthesis_closer']) === true) { - $scopeCloser = $tokens[$scopeCloser]['parenthesis_closer']; - $lastEndToken = $scopeCloser; - continue; - } - - if (isset($tokens[$scopeCloser]['bracket_closer']) === true) { - $scopeCloser = $tokens[$scopeCloser]['bracket_closer']; - $lastEndToken = $scopeCloser; - continue; - } - - if ($tokens[$scopeCloser]['code'] === \T_INLINE_THEN) { - $inTernary = true; - continue; - } - - if ($tokens[$scopeCloser]['code'] === \T_INLINE_ELSE) { - if ($inTernary === false) { - break; - } - - $inTernary = false; - } - } - - if ($scopeCloser === $phpcsFile->numTokens) { - return false; - } - - $returnValue['scope_closer'] = $scopeCloser; - - return $returnValue; + return []; } /** @@ -933,7 +837,7 @@ public static function isPHPDoubleUnderscoreMethod(File $phpcsFile, $stackPtr) return false; } - $scopePtr = Scopes::validDirectScope($phpcsFile, $stackPtr, BCTokens::ooScopeTokens()); + $scopePtr = Scopes::validDirectScope($phpcsFile, $stackPtr, Tokens::$ooScopeTokens); if ($scopePtr === false) { return false; } diff --git a/PHPCSUtils/Utils/GetTokensAsString.php b/PHPCSUtils/Utils/GetTokensAsString.php index b0ea65d5..f18b0c03 100644 --- a/PHPCSUtils/Utils/GetTokensAsString.php +++ b/PHPCSUtils/Utils/GetTokensAsString.php @@ -26,22 +26,14 @@ * PHPCS native `File` class. * Also see {@see \PHPCSUtils\BackCompat\BCFile::getTokensAsString()}. */ -class GetTokensAsString +final class GetTokensAsString { /** * Retrieve the tab-replaced content of the tokens from the specified start position in * the token stack to the specified end position (inclusive). * - * This is the default behaviour for PHPCS. - * - * If the `tabWidth` is set, either via a (custom) ruleset, the config file or by passing it - * on the command-line, PHPCS will automatically replace tabs with spaces. - * The `'content'` index key in the `$tokens` array will contain the tab-replaced content. - * The `'orig_content'` index key in the `$tokens` array will contain the original content. - * - * @see \PHP_CodeSniffer\Files\File::getTokensAsString() Similar length-based function. - * @see \PHPCSUtils\BackCompat\BCFile::getTokensAsString() Cross-version compatible version of the original. + * Alias for the {@see \PHPCSUtils\Utils\GetTokensAsString::tabReplaced()} method. * * @since 1.0.0 * @@ -55,14 +47,22 @@ class GetTokensAsString */ public static function normal(File $phpcsFile, $start, $end) { - return self::getString($phpcsFile, $start, $end); + return self::tabReplaced($phpcsFile, $start, $end); } /** * Retrieve the tab-replaced content of the tokens from the specified start position in * the token stack to the specified end position (inclusive). * - * Alias for the {@see \PHPCSUtils\Utils\GetTokensAsString::normal()} method. + * This is the default behaviour for PHPCS. + * + * If the `tabWidth` is set, either via a (custom) ruleset, the config file or by passing it + * on the command-line, PHPCS will automatically replace tabs with spaces. + * The `'content'` index key in the `$tokens` array will contain the tab-replaced content. + * The `'orig_content'` index key in the `$tokens` array will contain the original content. + * + * @see \PHP_CodeSniffer\Files\File::getTokensAsString() Similar length-based function. + * @see \PHPCSUtils\BackCompat\BCFile::getTokensAsString() Cross-version compatible version of the original. * * @since 1.0.0 * @@ -76,14 +76,14 @@ public static function normal(File $phpcsFile, $start, $end) */ public static function tabReplaced(File $phpcsFile, $start, $end) { - return self::normal($phpcsFile, $start, $end); + return self::getString($phpcsFile, $start, $end); } /** * Retrieve the original content of the tokens from the specified start position in * the token stack to the specified end position (inclusive). * - * In contrast to the {@see GetTokensAsString::normal()} method, this method will return + * In contrast to the {@see GetTokensAsString::tabReplaced()} method, this method will return * the original token content for the specified tokens. * That means that if the original content contained tabs, the return value of this function * will also contain tabs. @@ -135,7 +135,7 @@ public static function noComments(File $phpcsFile, $start, $end) * Retrieve the code-tokens only content of the tokens from the specified start position * in the token stack to the specified end position (inclusive) without whitespace or comments. * - * This is, for instance, useful to retrieve a namespace name without stray whitespace or comments. + * This is useful, for instance, to retrieve a namespace name without stray whitespace or comments. * Use this function selectively and with care! * * @see \PHP_CodeSniffer\Files\File::getTokensAsString() Loosely related function. diff --git a/PHPCSUtils/Utils/Lists.php b/PHPCSUtils/Utils/Lists.php index ff64db64..0c768763 100644 --- a/PHPCSUtils/Utils/Lists.php +++ b/PHPCSUtils/Utils/Lists.php @@ -13,16 +13,18 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Internal\Cache; +use PHPCSUtils\Internal\IsShortArrayOrListWithCache; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\GetTokensAsString; -use PHPCSUtils\Utils\Parentheses; /** * Utility functions to retrieve information when working with lists. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Lists +final class Lists { /** @@ -64,106 +66,7 @@ class Lists */ public static function isShortList(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - - // Is this one of the tokens this function handles ? - if (isset($tokens[$stackPtr]) === false - || isset(Collections::$shortListTokensBC[$tokens[$stackPtr]['code']]) === false - ) { - return false; - } - - /* - * BC: Work around a bug in the tokenizer of PHPCS 2.8.0 - 3.2.3 where a `[` would be - * tokenized as T_OPEN_SQUARE_BRACKET instead of T_OPEN_SHORT_ARRAY if it was - * preceded by a PHP open tag at the very start of the file. - * - * In that case, we also know for sure that it is a short list as long as the close - * bracket is followed by an `=` sign. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/1971 - * - * Also work around a bug in the tokenizer of PHPCS < 2.8.0 where a `[` would be - * tokenized as T_OPEN_SQUARE_BRACKET instead of T_OPEN_SHORT_ARRAY if it was - * preceded by a closing curly belonging to a control structure. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/1284 - */ - if ($tokens[$stackPtr]['code'] === \T_OPEN_SQUARE_BRACKET - || $tokens[$stackPtr]['code'] === \T_CLOSE_SQUARE_BRACKET - ) { - $opener = $stackPtr; - if ($tokens[$stackPtr]['code'] === \T_CLOSE_SQUARE_BRACKET) { - $opener = $tokens[$stackPtr]['bracket_opener']; - } - - if (isset($tokens[$opener]['bracket_closer']) === false) { - // Definitely not a short list. - return false; - } - - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), null, true); - if ((($prevNonEmpty === 0 && $tokens[$prevNonEmpty]['code'] === \T_OPEN_TAG) // Bug #1971. - || ($tokens[$prevNonEmpty]['code'] === \T_CLOSE_CURLY_BRACKET - && isset($tokens[$prevNonEmpty]['scope_condition']))) // Bug #1284. - ) { - $closer = $tokens[$opener]['bracket_closer']; - $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($closer + 1), null, true); - if ($nextNonEmpty !== false && $tokens[$nextNonEmpty]['code'] === \T_EQUAL) { - return true; - } - } - - return false; - } - - switch ($tokens[$stackPtr]['code']) { - case \T_OPEN_SHORT_ARRAY: - $opener = $stackPtr; - $closer = $tokens[$stackPtr]['bracket_closer']; - break; - - case \T_CLOSE_SHORT_ARRAY: - $opener = $tokens[$stackPtr]['bracket_opener']; - $closer = $stackPtr; - break; - } - - $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($closer + 1), null, true); - if ($nextNonEmpty !== false && $tokens[$nextNonEmpty]['code'] === \T_EQUAL) { - return true; - } - - // Check for short list in foreach, i.e. `foreach($array as [$a, $b])`. - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), null, true); - if ($prevNonEmpty !== false - && ($tokens[$prevNonEmpty]['code'] === \T_AS - || $tokens[$prevNonEmpty]['code'] === \T_DOUBLE_ARROW) - && Parentheses::lastOwnerIn($phpcsFile, $prevNonEmpty, \T_FOREACH) !== false - ) { - return true; - } - - // Maybe this is a short list syntax nested inside another short list syntax ? - $parentOpen = $opener; - do { - $parentOpen = $phpcsFile->findPrevious( - [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET], // BC: PHPCS#1971. - ($parentOpen - 1), - null, - false, - null, - true - ); - - if ($parentOpen === false) { - return false; - } - } while (isset($tokens[$parentOpen]['bracket_closer']) === true - && $tokens[$parentOpen]['bracket_closer'] < $opener - ); - - return self::isShortList($phpcsFile, $parentOpen); + return IsShortArrayOrListWithCache::isShortList($phpcsFile, $stackPtr); } /** @@ -201,7 +104,7 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortList = n // Is this one of the tokens this function handles ? if (isset($tokens[$stackPtr]) === false - || isset(Collections::$listTokensBC[$tokens[$stackPtr]['code']]) === false + || isset(Collections::listTokensBC()[$tokens[$stackPtr]['code']]) === false ) { return false; } @@ -209,20 +112,11 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortList = n switch ($tokens[ $stackPtr ]['code']) { case \T_LIST: if (isset($tokens[$stackPtr]['parenthesis_opener'])) { - // PHPCS 3.5.0. $opener = $tokens[$stackPtr]['parenthesis_opener']; - } else { - // PHPCS < 3.5.0. - $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($nextNonEmpty !== false - && $tokens[$nextNonEmpty]['code'] === \T_OPEN_PARENTHESIS - ) { - $opener = $nextNonEmpty; - } - } - if (isset($opener, $tokens[$opener]['parenthesis_closer'])) { - $closer = $tokens[$opener]['parenthesis_closer']; + if (isset($tokens[$opener]['parenthesis_closer'])) { + $closer = $tokens[$opener]['parenthesis_closer']; + } } break; @@ -314,6 +208,10 @@ public static function getAssignments(File $phpcsFile, $stackPtr) throw new RuntimeException('The Lists::getAssignments() method expects a long/short list token.'); } + if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) { + return Cache::get($phpcsFile, __METHOD__, $stackPtr); + } + $opener = $openClose['opener']; $closer = $openClose['closer']; @@ -431,6 +329,7 @@ public static function getAssignments(File $phpcsFile, $stackPtr) } } + Cache::set($phpcsFile, __METHOD__, $stackPtr, $vars); return $vars; } } diff --git a/PHPCSUtils/Utils/MessageHelper.php b/PHPCSUtils/Utils/MessageHelper.php new file mode 100644 index 00000000..1749ed38 --- /dev/null +++ b/PHPCSUtils/Utils/MessageHelper.php @@ -0,0 +1,145 @@ +addError($message, $stackPtr, $code, $data, $severity); + } + + return $phpcsFile->addWarning($message, $stackPtr, $code, $data, $severity); + } + + /** + * Add a PHPCS message to the output stack as either a fixable warning or a fixable error. + * + * @since 1.0.0-alpha4 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param string $message The message. + * @param int $stackPtr The position of the token + * the message relates to. + * @param bool $isError Whether to report the message as an + * 'error' or 'warning'. + * Defaults to true (error). + * @param string $code The error code for the message. + * Defaults to 'Found'. + * @param array $data Optional input for the data replacements. + * @param int $severity Optional. Severity level. Defaults to 0 which will + * translate to the PHPCS default severity level. + * + * @return bool + */ + public static function addFixableMessage( + File $phpcsFile, + $message, + $stackPtr, + $isError = true, + $code = 'Found', + array $data = [], + $severity = 0 + ) { + if ($isError === true) { + return $phpcsFile->addFixableError($message, $stackPtr, $code, $data, $severity); + } + + return $phpcsFile->addFixableWarning($message, $stackPtr, $code, $data, $severity); + } + + /** + * Convert an arbitrary text string to an alphanumeric string with underscores. + * + * Pre-empt issues in XML and PHP when arbitrary strings are being used as error codes. + * + * @since 1.0.0-alpha4 + * + * @param string $text Arbitrary text string intended to be used in an error code. + * @param bool $strtolower Whether or not to convert the text string to lowercase. + * + * @return string + */ + public static function stringToErrorcode($text, $strtolower = false) + { + $text = \preg_replace('`[^a-z0-9_]`i', '_', $text); + + if ($strtolower === true) { + $text = \strtolower($text); + } + + return $text; + } + + /** + * Make the whitespace escape codes used in an arbitrary text string visible. + * + * At times, it is useful to show a code snippet in an error message. + * If such a code snippet contains new lines and/or tab or space characters, those would be + * displayed as-is in the command-line report, often breaking the layout of the report + * or making the report harder to read. + * + * This method will convert these characters to their escape codes, making them visible in the + * display string without impacting the report layout. + * + * @see \PHPCSUtils\Utils\GetTokensToString Methods to retrieve a multi-token code snippet. + * @see \PHP_CodeSniffer\Util\Common\prepareForOutput() Similar PHPCS native method. + * + * @since 1.0.0-alpha4 + * + * @param string $text Arbitrary text string. + * + * @return string + */ + public static function showEscapeChars($text) + { + $search = ["\n", "\r", "\t"]; + $replace = ['\n', '\r', '\t']; + + return \str_replace($search, $replace, $text); + } +} diff --git a/PHPCSUtils/Utils/Namespaces.php b/PHPCSUtils/Utils/Namespaces.php index 47458ce2..2cdcabb3 100644 --- a/PHPCSUtils/Utils/Namespaces.php +++ b/PHPCSUtils/Utils/Namespaces.php @@ -14,7 +14,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCFile; -use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Conditions; use PHPCSUtils\Utils\GetTokensAsString; @@ -27,14 +27,16 @@ * @link https://www.php.net/language.namespaces PHP Manual on namespaces. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Namespaces +final class Namespaces { /** * Determine what a T_NAMESPACE token is used for. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the `T_NAMESPACE` token. @@ -56,17 +58,16 @@ public static function getType(File $phpcsFile, $stackPtr) * Set up array of tokens which can only be used in combination with the keyword as operator * and which cannot be confused with other keywords. */ - $findAfter = BCTokens::assignmentTokens() - + BCTokens::comparisonTokens() - + BCTokens::operators() + $findAfter = Tokens::$assignmentTokens + + Tokens::$comparisonTokens + + Tokens::$operators + Tokens::$castTokens + Tokens::$blockOpeners - + Collections::$incrementDecrementOperators - + Collections::$objectOperators; + + Collections::incrementDecrementOperators() + + Collections::objectOperators() + + Collections::shortArrayListOpenTokensBC(); - $findAfter[\T_OPEN_CURLY_BRACKET] = \T_OPEN_CURLY_BRACKET; - $findAfter[\T_OPEN_SQUARE_BRACKET] = \T_OPEN_SQUARE_BRACKET; - $findAfter[\T_OPEN_SHORT_ARRAY] = \T_OPEN_SHORT_ARRAY; + $findAfter[\T_OPEN_CURLY_BRACKET] = \T_OPEN_CURLY_BRACKET; } $tokens = $phpcsFile->getTokens(); @@ -98,12 +99,14 @@ public static function getType(File $phpcsFile, $stackPtr) $start = BCFile::findStartOfStatement($phpcsFile, $stackPtr); if ($start === $stackPtr && ($tokens[$next]['code'] === \T_STRING + || $tokens[$next]['code'] === \T_NAME_QUALIFIED || $tokens[$next]['code'] === \T_OPEN_CURLY_BRACKET) ) { return 'declaration'; } - if ($tokens[$next]['code'] === \T_NS_SEPARATOR + if (($tokens[$next]['code'] === \T_NS_SEPARATOR + || $tokens[$next]['code'] === \T_NAME_FULLY_QUALIFIED) // PHP 8.0 parse error. && ($start !== $stackPtr || $phpcsFile->findNext($findAfter, ($stackPtr + 1), null, false, null, true) !== false) ) { @@ -185,7 +188,7 @@ public static function getDeclaredName(File $phpcsFile, $stackPtr, $clean = true return false; } - $endOfStatement = $phpcsFile->findNext(Collections::$namespaceDeclarationClosers, ($stackPtr + 1)); + $endOfStatement = $phpcsFile->findNext(Collections::namespaceDeclarationClosers(), ($stackPtr + 1)); if ($endOfStatement === false) { // Live coding or parse error. return false; @@ -257,6 +260,9 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) * - and that namespace declarations can't be nested in anything, so we can skip over any * nesting structures. */ + if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) { + return Cache::get($phpcsFile, __METHOD__, $stackPtr); + } // Start by breaking out of any scoped structures this token is in. $prev = $stackPtr; @@ -271,14 +277,16 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) $prev = $firstParensOpener; } - $find = [ + $find = [ \T_NAMESPACE, \T_CLOSE_CURLY_BRACKET, \T_CLOSE_PARENTHESIS, \T_CLOSE_SHORT_ARRAY, \T_CLOSE_SQUARE_BRACKET, \T_DOC_COMMENT_CLOSE_TAG, + \T_ATTRIBUTE_END, ]; + $returnValue = false; do { $prev = $phpcsFile->findPrevious($find, ($prev - 1)); @@ -290,12 +298,6 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) // Stop if we encounter a scoped namespace declaration as we already know we're not in one. if (isset($tokens[$prev]['scope_condition']) === true && $tokens[$tokens[$prev]['scope_condition']]['code'] === \T_NAMESPACE - /* - * BC: Work around a bug where curlies for variable variables received an incorrect - * and irrelevant scope condition in PHPCS < 3.3.0. - * {@link https://github.com/squizlabs/PHP_CodeSniffer/issues/1882} - */ - && self::isDeclaration($phpcsFile, $tokens[$prev]['scope_condition']) === true ) { break; } @@ -304,7 +306,8 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) if (isset($tokens[$prev]['scope_condition']) === true) { $prev = $tokens[$prev]['scope_condition']; } elseif (isset($tokens[$prev]['scope_opener']) === true) { - $prev = $tokens[$prev]['scope_opener']; + // Shouldn't be possible, but just in case. + $prev = $tokens[$prev]['scope_opener']; // @codeCoverageIgnore } continue; @@ -324,6 +327,12 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) continue; } + // Skip over potentially large attributes. + if (isset($tokens[$prev]['attribute_opener'])) { + $prev = $tokens[$prev]['attribute_opener']; + continue; + } + // Skip over potentially large docblocks. if (isset($tokens[$prev]['comment_opener'])) { $prev = $tokens[$prev]['comment_opener']; @@ -335,16 +344,19 @@ public static function findNamespacePtr(File $phpcsFile, $stackPtr) && self::isDeclaration($phpcsFile, $prev) === true ) { // Now make sure the token was not part of the declaration. - $endOfStatement = $phpcsFile->findNext(Collections::$namespaceDeclarationClosers, ($prev + 1)); + $endOfStatement = $phpcsFile->findNext(Collections::namespaceDeclarationClosers(), ($prev + 1)); if ($endOfStatement > $stackPtr) { - return false; + // Token is part of the declaration, return false. + break; } - return $prev; + $returnValue = $prev; + break; } } while (true); - return false; + Cache::set($phpcsFile, __METHOD__, $stackPtr, $returnValue); + return $returnValue; } /** diff --git a/PHPCSUtils/Utils/NamingConventions.php b/PHPCSUtils/Utils/NamingConventions.php index aebf6919..241e2a67 100644 --- a/PHPCSUtils/Utils/NamingConventions.php +++ b/PHPCSUtils/Utils/NamingConventions.php @@ -16,15 +16,16 @@ * Identifier names in PHP are: * - {@link https://www.php.net/language.namespaces.definition namespace} names; * - {@link https://www.php.net/language.oop5.basic class}, - * {@link https://www.php.net/language.oop5.traits trait} and - * {@link https://www.php.net/language.oop5.interfaces interface} names; + * {@link https://www.php.net/language.oop5.traits trait}, + * {@link https://www.php.net/language.oop5.interfaces interface} and + * {@link https://www.php.net/language.types.enumerations enum} names; * - {@link https://www.php.net/functions.user-defined function and method} names; * - {@link https://www.php.net/language.variables.basics variable} names; * - {@link https://www.php.net/language.constants constant} names. * * @since 1.0.0-alpha3 */ -class NamingConventions +final class NamingConventions { /** diff --git a/PHPCSUtils/Utils/Numbers.php b/PHPCSUtils/Utils/Numbers.php index e209093d..4065c0ac 100644 --- a/PHPCSUtils/Utils/Numbers.php +++ b/PHPCSUtils/Utils/Numbers.php @@ -12,27 +12,30 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; -use PHPCSUtils\BackCompat\Helper; /** * Utility functions for working with integer/float tokens. * - * PHP 7.4 introduced numeric literal separators which break number tokenization in older PHP versions. - * PHPCS backfills this since PHPCS 3.5.3/4. + * PHP 7.4 introduced numeric literal separators. PHPCS backfills this since PHPCS 3.5.3/4. + * PHP 8.1 introduced an explicit octal notation. This is backfilled in PHPCS since PHPCS 3.7.0. * - * In other words, if an external standard intends to support PHPCS < 3.5.4 and PHP < 7.4, working - * with number tokens has suddenly become a challenge. - * - * The functions in this class have been put in place to ease that pain and it is - * *strongly* recommended to always use these functions when sniffing for and examining the + * While there are currently no unsupported numeric syntaxes, the methods in this class + * can still be useful for external standards which need to examine the * contents of `T_LNUMBER` or `T_DNUMBER` tokens. * * @link https://www.php.net/migration74.new-features.php#migration74.new-features.core.numeric-literal-separator * PHP Manual on numeric literal separators. + * @link https://www.php.net/manual/en/migration81.new-features.php#migration81.new-features.core.octal-literal-prefix + * PHP Manual on the introduction of the integer octal literal prefix. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. + * @since 1.0.0-alpha4 Removed the following class constants: + * - `Numbers::REGEX_NUMLIT_STRING` + * - `Numbers::REGEX_HEX_NUMLIT_STRING` + * - `Numbers::UNSUPPORTED_PHPCS_VERSION` */ -class Numbers +final class Numbers { /** @@ -51,7 +54,7 @@ class Numbers * * @var string */ - const REGEX_OCTAL_INT = '`^0[0-7]+$`D'; + const REGEX_OCTAL_INT = '`^0[o]?[0-7]+$`iD'; /** * Regex to determine whether the contents of an arbitrary string represents a binary integer. @@ -98,67 +101,10 @@ class Numbers `ixD'; /** - * Regex to determine if a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence. - * - * Cross-version compatibility helper for PHP 7.4 numeric literals with underscore separators. - * - * @since 1.0.0 - * - * @var string - */ - const REGEX_NUMLIT_STRING = '`^((? true, - \T_DNUMBER => true, - \T_STRING => true, - ]; - - /** - * Retrieve information about a number token in a cross-version compatible manner. - * - * Helper function to deal with numeric literals, potentially with underscore separators. - * - * PHP < 7.4 does not tokenize numeric literals containing underscores correctly. - * As of PHPCS 3.5.3, PHPCS contains a backfill, but this backfill was buggy in the initial - * implementation. A fix for this broken backfill is included in PHPCS 3.5.4. - * - * Either way, this function can be used with all PHPCS/PHP combinations and will, if necessary, - * provide a backfill for PHPCS/PHP combinations where PHP 7.4 numbers with underscore separators - * are tokenized incorrectly - with the exception of PHPCS 3.5.3 as the buggyness of the original - * backfill implementation makes it impossible to provide reliable results. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2546 PHPCS issue #2546 - * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/2771 PHPCS PR #2771 + * Helper function to deal with numeric literals, potentially with underscore separators + * and/or explicit octal notation. * * @since 1.0.0 * @@ -169,10 +115,8 @@ class Numbers * The format of the array return value is: * ```php * array( - * 'orig_content' => string, // The (potentially concatenated) original - * // content of the tokens; - * 'content' => string, // The (potentially concatenated) content, - * // underscore(s) removed; + * 'orig_content' => string, // The original content of the token(s); + * 'content' => string, // The content, underscore(s) removed; * 'code' => int, // The token code of the number, either * // T_LNUMBER or T_DNUMBER. * 'type' => string, // The token type, either 'T_LNUMBER' @@ -180,21 +124,17 @@ class Numbers * 'decimal' => string, // The decimal value of the number; * 'last_token' => int, // The stackPtr to the last token which was * // part of the number. - * // This will be the same as the original - * // stackPtr if it is not a PHP 7.4 number - * // with underscores. + * // At this time, this will be always be the original + * // stackPtr. This may change in the future if + * // new numeric syntaxes would be added to PHP. * ) * ``` * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified token is not of type * `T_LNUMBER` or `T_DNUMBER`. - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If this function is called in combination - * with an unsupported PHPCS version. */ public static function getCompleteNumber(File $phpcsFile, $stackPtr) { - static $php74, $phpcsVersion, $phpcsWithBackfill; - $tokens = $phpcsFile->getTokens(); if (isset($tokens[$stackPtr]) === false @@ -205,24 +145,8 @@ public static function getCompleteNumber(File $phpcsFile, $stackPtr) ); } - if (isset($php74, $phpcsVersion, $phpcsWithBackfill) === false) { - $php74 = \version_compare(\PHP_VERSION_ID, '70399', '>'); - $phpcsVersion = Helper::getVersion(); - $phpcsWithBackfill = \version_compare($phpcsVersion, self::UNSUPPORTED_PHPCS_VERSION, '>'); - } - - /* - * Bow out for PHPCS version(s) with broken tokenization of PHP 7.4 numeric literals with - * separators, including for PHP 7.4, as the backfill kicks in for PHP 7.4 while it shouldn't. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2546 - */ - if (\version_compare($phpcsVersion, self::UNSUPPORTED_PHPCS_VERSION, '==') === true) { - throw new RuntimeException('The ' . __METHOD__ . '() method does not support PHPCS ' . $phpcsVersion); - } - $content = $tokens[$stackPtr]['content']; - $result = [ + return [ 'orig_content' => $content, 'content' => \str_replace('_', '', $content), 'code' => $tokens[$stackPtr]['code'], @@ -230,118 +154,27 @@ public static function getCompleteNumber(File $phpcsFile, $stackPtr) 'decimal' => self::getDecimalValue($content), 'last_token' => $stackPtr, ]; - - // When things are already correctly tokenized, there's not much to do. - if ($php74 === true - || $phpcsWithBackfill === true - || isset($tokens[($stackPtr + 1)]) === false - || $tokens[($stackPtr + 1)]['code'] !== \T_STRING - || $tokens[($stackPtr + 1)]['content'][0] !== '_' - ) { - return $result; - } - - $hex = false; - if (\strpos($content, '0x') === 0) { - $hex = true; - } - - $lastChar = \substr($content, -1); - if (\preg_match('`[0-9]`', $lastChar) !== 1) { - if ($hex === false || \preg_match('`[A-F]`i', $lastChar) !== 1) { - // Last character not valid for numeric literal sequence with underscores. - // No need to look any further. - return $result; - } - } - - /* - * OK, so this could potentially be a PHP 7.4 number with an underscore separator with PHPCS - * being run on PHP < 7.4. - */ - - $regex = self::REGEX_NUMLIT_STRING; - if ($hex === true) { - $regex = self::REGEX_HEX_NUMLIT_STRING; - } - - $next = $stackPtr; - $lastToken = $stackPtr; - - while (isset($tokens[++$next], self::$numericLiteralAcceptedTokens[$tokens[$next]['code']]) === true) { - if ($tokens[$next]['code'] === \T_STRING - && \preg_match($regex, $tokens[$next]['content']) !== 1 - ) { - break; - } - - $content .= $tokens[$next]['content']; - $lastToken = $next; - $lastChar = \substr(\strtolower($content), -1); - - // Support floats. - if ($lastChar === 'e' - && isset($tokens[($next + 1)], $tokens[($next + 2)]) === true - && ($tokens[($next + 1)]['code'] === \T_MINUS - || $tokens[($next + 1)]['code'] === \T_PLUS) - && $tokens[($next + 2)]['code'] === \T_LNUMBER - ) { - $content .= $tokens[($next + 1)]['content']; - $content .= $tokens[($next + 2)]['content']; - $next += 2; - $lastToken = $next; - } - - // Don't look any further if the last char is not valid before a separator. - if (\preg_match('`[0-9]`', $lastChar) !== 1) { - if ($hex === false || \preg_match('`[a-f]`i', $lastChar) !== 1) { - break; - } - } - } - - // OK, so we now have `content` including potential underscores. Let's strip them out. - $result['orig_content'] = $content; - $result['content'] = \str_replace('_', '', $content); - $result['decimal'] = self::getDecimalValue($result['content']); - $result['last_token'] = $lastToken; - - // Determine actual token type. - $type = $result['type']; - if ($type === 'T_LNUMBER') { - if ($hex === false - && (\strpos($result['content'], '.') !== false - || \stripos($result['content'], 'e') !== false) - ) { - $type = 'T_DNUMBER'; - } elseif (($result['decimal'] + 0) > \PHP_INT_MAX) { - $type = 'T_DNUMBER'; - } - } - - $result['code'] = \constant($type); - $result['type'] = $type; - - return $result; } /** * Get the decimal number value of a numeric string. * - * Takes PHP 7.4 numeric literal separators in numbers into account. + * Takes PHP 7.4 numeric literal separators and explicit octal literals in numbers into account. * * @since 1.0.0 * - * @param string $string Arbitrary token content string. + * @param string $textString Arbitrary text string. + * This text string should be the (combined) token content of + * one or more tokens which together represent a number in PHP. * * @return string|false Decimal number as a string or `FALSE` if the passed parameter * was not a numeric string. * > Note: floating point numbers with exponent will not be expanded, * but returned as-is. */ - public static function getDecimalValue($string) + public static function getDecimalValue($textString) { - if (\is_string($string) === false || $string === '') { + if (\is_string($textString) === false || $textString === '') { return false; } @@ -352,26 +185,26 @@ public static function getDecimalValue($string) * here to allow the hexdec(), bindec() functions to work correctly and for * the decimal/float to return a cross-version compatible decimal value.} */ - $string = \str_replace('_', '', $string); + $textString = \str_replace('_', '', $textString); - if (self::isDecimalInt($string) === true) { - return $string; + if (self::isDecimalInt($textString) === true) { + return $textString; } - if (self::isHexidecimalInt($string) === true) { - return (string) \hexdec($string); + if (self::isHexidecimalInt($textString) === true) { + return (string) \hexdec($textString); } - if (self::isBinaryInt($string) === true) { - return (string) \bindec($string); + if (self::isBinaryInt($textString) === true) { + return (string) \bindec($textString); } - if (self::isOctalInt($string) === true) { - return (string) \octdec($string); + if (self::isOctalInt($textString) === true) { + return (string) \octdec($textString); } - if (self::isFloat($string) === true) { - return $string; + if (self::isFloat($textString) === true) { + return $textString; } return false; @@ -384,20 +217,20 @@ public static function getDecimalValue($string) * * @since 1.0.0 * - * @param string $string Arbitrary string. + * @param string $textString Arbitrary string. * * @return bool */ - public static function isDecimalInt($string) + public static function isDecimalInt($textString) { - if (\is_string($string) === false || $string === '') { + if (\is_string($textString) === false || $textString === '') { return false; } // Remove potential PHP 7.4 numeric literal separators. - $string = \str_replace('_', '', $string); + $textString = \str_replace('_', '', $textString); - return (\preg_match(self::REGEX_DECIMAL_INT, $string) === 1); + return (\preg_match(self::REGEX_DECIMAL_INT, $textString) === 1); } /** @@ -407,20 +240,20 @@ public static function isDecimalInt($string) * * @since 1.0.0 * - * @param string $string Arbitrary string. + * @param string $textString Arbitrary string. * * @return bool */ - public static function isHexidecimalInt($string) + public static function isHexidecimalInt($textString) { - if (\is_string($string) === false || $string === '') { + if (\is_string($textString) === false || $textString === '') { return false; } // Remove potential PHP 7.4 numeric literal separators. - $string = \str_replace('_', '', $string); + $textString = \str_replace('_', '', $textString); - return (\preg_match(self::REGEX_HEX_INT, $string) === 1); + return (\preg_match(self::REGEX_HEX_INT, $textString) === 1); } /** @@ -430,43 +263,43 @@ public static function isHexidecimalInt($string) * * @since 1.0.0 * - * @param string $string Arbitrary string. + * @param string $textString Arbitrary string. * * @return bool */ - public static function isBinaryInt($string) + public static function isBinaryInt($textString) { - if (\is_string($string) === false || $string === '') { + if (\is_string($textString) === false || $textString === '') { return false; } // Remove potential PHP 7.4 numeric literal separators. - $string = \str_replace('_', '', $string); + $textString = \str_replace('_', '', $textString); - return (\preg_match(self::REGEX_BINARY_INT, $string) === 1); + return (\preg_match(self::REGEX_BINARY_INT, $textString) === 1); } /** * Verify whether the contents of an arbitrary string represents an octal integer. * - * Takes PHP 7.4 numeric literal separators in numbers into account. + * Takes PHP 7.4 numeric literal separators and explicit octal literals in numbers into account. * * @since 1.0.0 * - * @param string $string Arbitrary string. + * @param string $textString Arbitrary string. * * @return bool */ - public static function isOctalInt($string) + public static function isOctalInt($textString) { - if (\is_string($string) === false || $string === '') { + if (\is_string($textString) === false || $textString === '') { return false; } // Remove potential PHP 7.4 numeric literal separators. - $string = \str_replace('_', '', $string); + $textString = \str_replace('_', '', $textString); - return (\preg_match(self::REGEX_OCTAL_INT, $string) === 1); + return (\preg_match(self::REGEX_OCTAL_INT, $textString) === 1); } /** @@ -476,19 +309,19 @@ public static function isOctalInt($string) * * @since 1.0.0 * - * @param string $string Arbitrary string. + * @param string $textString Arbitrary string. * * @return bool */ - public static function isFloat($string) + public static function isFloat($textString) { - if (\is_string($string) === false || $string === '') { + if (\is_string($textString) === false || $textString === '') { return false; } // Remove potential PHP 7.4 numeric literal separators. - $string = \str_replace('_', '', $string); + $textString = \str_replace('_', '', $textString); - return (\preg_match(self::REGEX_FLOAT, $string) === 1); + return (\preg_match(self::REGEX_FLOAT, $textString) === 1); } } diff --git a/PHPCSUtils/Utils/ObjectDeclarations.php b/PHPCSUtils/Utils/ObjectDeclarations.php index 83ddee06..f52cb590 100644 --- a/PHPCSUtils/Utils/ObjectDeclarations.php +++ b/PHPCSUtils/Utils/ObjectDeclarations.php @@ -19,18 +19,19 @@ /** * Utility functions for use when examining object declaration statements. * - * @since 1.0.0 The `ObjectDeclarations::get(Declaration)Name()`, - * `ObjectDeclarations::getClassProperties()`, `ObjectDeclarations::findExtendedClassName()` - * and `ObjectDeclarations::findImplementedInterfaceNames()` methods are based on and - * inspired by the methods of the same name in the PHPCS native - * `PHP_CodeSniffer\Files\File` class. - * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * @since 1.0.0 The `ObjectDeclarations::get(Declaration)Name()`, + * `ObjectDeclarations::getClassProperties()`, `ObjectDeclarations::findExtendedClassName()` + * and `ObjectDeclarations::findImplementedInterfaceNames()` methods are based on and + * inspired by the methods of the same name in the PHPCS native + * `PHP_CodeSniffer\Files\File` class. + * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class ObjectDeclarations +final class ObjectDeclarations { /** - * Retrieves the declaration name for classes, interfaces, traits, and functions. + * Retrieves the declaration name for classes, interfaces, traits, enums and functions. * * Main differences with the PHPCS version: * - Defensive coding against incorrect calls to this method. @@ -43,27 +44,24 @@ class ObjectDeclarations * Using this version of the utility method, either the complete name (invalid or not) will * be returned or `null` in case of no name (parse error). * - * Note: - * - For ES6 classes in combination with PHPCS 2.x, passing a `T_STRING` token to - * this method will be accepted for JS files. - * - Support for JS ES6 method syntax has not been back-filled for PHPCS < 3.0.0. - * * @see \PHP_CodeSniffer\Files\File::getDeclarationName() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getDeclarationName() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.1 enums. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the declaration token * which declared the class, interface, - * trait, or function. + * trait, enum or function. * - * @return string|null The name of the class, interface, trait, or function; + * @return string|null The name of the class, interface, trait, enum, or function; * or `NULL` if the passed token doesn't exist, the function or * class is anonymous or in case of a parse error/live coding. * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified token is not of type - * `T_FUNCTION`, `T_CLASS`, `T_TRAIT`, or `T_INTERFACE`. + * `T_FUNCTION`, `T_CLASS`, `T_ANON_CLASS`, + * `T_CLOSURE`, `T_TRAIT`, `T_ENUM` or `T_INTERFACE`. */ public static function getName(File $phpcsFile, $stackPtr) { @@ -77,24 +75,15 @@ public static function getName(File $phpcsFile, $stackPtr) $tokenCode = $tokens[$stackPtr]['code']; - /* - * BC: Work-around JS ES6 classes not being tokenized as T_CLASS in PHPCS < 3.0.0. - */ - if (isset($phpcsFile->tokenizerType) - && $phpcsFile->tokenizerType === 'JS' - && $tokenCode === \T_STRING - && $tokens[$stackPtr]['content'] === 'class' - ) { - $tokenCode = \T_CLASS; - } - if ($tokenCode !== \T_FUNCTION && $tokenCode !== \T_CLASS && $tokenCode !== \T_INTERFACE && $tokenCode !== \T_TRAIT + && $tokenCode !== \T_ENUM ) { throw new RuntimeException( - 'Token type "' . $tokens[$stackPtr]['type'] . '" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT' + 'Token type "' . $tokens[$stackPtr]['type'] + . '" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM' ); } @@ -123,6 +112,7 @@ public static function getName(File $phpcsFile, $stackPtr) $exclude[] = \T_OPEN_PARENTHESIS; $exclude[] = \T_OPEN_CURLY_BRACKET; $exclude[] = \T_BITWISE_AND; + $exclude[] = \T_COLON; // Backed enums. $nameStart = $phpcsFile->findNext($exclude, ($stackPtr + 1), $stopPoint, true); if ($nameStart === false) { @@ -133,17 +123,7 @@ public static function getName(File $phpcsFile, $stackPtr) $tokenAfterNameEnd = $phpcsFile->findNext($exclude, $nameStart, $stopPoint); if ($tokenAfterNameEnd === false) { - $content = null; - - /* - * BC: In PHPCS 2.6.0, in case of live coding, the last token in a file will be tokenized - * as T_STRING, but won't have the `content` index set. - */ - if (isset($tokens[$nameStart]['content'])) { - $content = $tokens[$nameStart]['content']; - } - - return $content; + return $tokens[$nameStart]['content']; } // Name starts with number, so is composed of multiple tokens. @@ -157,13 +137,14 @@ public static function getName(File $phpcsFile, $stackPtr) * - Bugs fixed: * - Handling of PHPCS annotations. * - Handling of unorthodox docblock placement. - * - A class cannot both be abstract as well as final, so this utility should not allow for that. * - Defensive coding against incorrect calls to this method. + * - Support for PHP 8.2 readonly classes. * * @see \PHP_CodeSniffer\Files\File::getClassProperties() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getClassProperties() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for the PHP 8.2 readonly keyword. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the `T_CLASS` @@ -175,6 +156,7 @@ public static function getName(File $phpcsFile, $stackPtr) * array( * 'is_abstract' => false, // TRUE if the abstract keyword was found. * 'is_final' => false, // TRUE if the final keyword was found. + * 'is_readonly' => false, // TRUE if the readonly keyword was found. * ); * ``` * @@ -189,10 +171,11 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) throw new RuntimeException('$stackPtr must be of type T_CLASS'); } - $valid = Collections::$classModifierKeywords + Tokens::$emptyTokens; + $valid = Collections::classModifierKeywords() + Tokens::$emptyTokens; $properties = [ 'is_abstract' => false, 'is_final' => false, + 'is_readonly' => false, ]; for ($i = ($stackPtr - 1); $i > 0; $i--) { @@ -203,11 +186,15 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) switch ($tokens[$i]['code']) { case \T_ABSTRACT: $properties['is_abstract'] = true; - break 2; + break; case \T_FINAL: $properties['is_final'] = true; - break 2; + break; + + case \T_READONLY: + $properties['is_readonly'] = true; + break; } } @@ -226,8 +213,10 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) * - Bugs fixed: * - Handling of PHPCS annotations. * - Handling of comments. + * - Handling of the namespace keyword used as operator. * - Improved handling of parse errors. * - The returned name will be clean of superfluous whitespace and/or comments. + * - Support for PHP 8.0 tokenization of identifier/namespaced names, cross-version PHP & PHPCS. * * @see \PHP_CodeSniffer\Files\File::findExtendedClassName() Original source. * @see \PHPCSUtils\BackCompat\BCFile::findExtendedClassName() Cross-version compatible version of @@ -244,7 +233,7 @@ public static function getClassProperties(File $phpcsFile, $stackPtr) */ public static function findExtendedClassName(File $phpcsFile, $stackPtr) { - $names = self::findNames($phpcsFile, $stackPtr, \T_EXTENDS, Collections::$OOCanExtend); + $names = self::findNames($phpcsFile, $stackPtr, \T_EXTENDS, Collections::ooCanExtend()); if ($names === false) { return false; } @@ -254,30 +243,33 @@ public static function findExtendedClassName(File $phpcsFile, $stackPtr) } /** - * Retrieves the names of the interfaces that the specified class implements. + * Retrieves the names of the interfaces that the specified class or enum implements. * * Main differences with the PHPCS version: * - Bugs fixed: * - Handling of PHPCS annotations. * - Handling of comments. + * - Handling of the namespace keyword used as operator. * - Improved handling of parse errors. * - The returned name(s) will be clean of superfluous whitespace and/or comments. + * - Support for PHP 8.0 tokenization of identifier/namespaced names, cross-version PHP & PHPCS. * * @see \PHP_CodeSniffer\Files\File::findImplementedInterfaceNames() Original source. * @see \PHPCSUtils\BackCompat\BCFile::findImplementedInterfaceNames() Cross-version compatible version of * the original. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.1 enums. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. - * @param int $stackPtr The stack position of the class. + * @param int $stackPtr The stack position of the class or enum token. * * @return array|false Array with names of the implemented interfaces or `FALSE` on * error or if there are no implemented interface names. */ public static function findImplementedInterfaceNames(File $phpcsFile, $stackPtr) { - return self::findNames($phpcsFile, $stackPtr, \T_IMPLEMENTS, Collections::$OOCanImplement); + return self::findNames($phpcsFile, $stackPtr, \T_IMPLEMENTS, Collections::ooCanImplement()); } /** @@ -308,6 +300,7 @@ public static function findExtendedInterfaceNames(File $phpcsFile, $stackPtr) * interfaces that the specific class/interface declaration extends/implements. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The stack position of the @@ -320,7 +313,7 @@ public static function findExtendedInterfaceNames(File $phpcsFile, $stackPtr) * @return array|false Returns an array of names or `FALSE` on error or when the object * being declared does not extend/implement another object. */ - private static function findNames(File $phpcsFile, $stackPtr, $keyword, $allowedFor) + private static function findNames(File $phpcsFile, $stackPtr, $keyword, array $allowedFor) { $tokens = $phpcsFile->getTokens(); @@ -337,12 +330,7 @@ private static function findNames(File $phpcsFile, $stackPtr, $keyword, $allowed return false; } - $find = [ - \T_NS_SEPARATOR, - \T_STRING, - ]; - $find += Tokens::$emptyTokens; - + $find = Collections::namespacedNameTokens() + Tokens::$emptyTokens; $names = []; $end = $keywordPtr; do { diff --git a/PHPCSUtils/Utils/Operators.php b/PHPCSUtils/Utils/Operators.php index cc472aa4..7378052d 100644 --- a/PHPCSUtils/Utils/Operators.php +++ b/PHPCSUtils/Utils/Operators.php @@ -12,7 +12,6 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; use PHPCSUtils\Utils\Parentheses; @@ -22,13 +21,14 @@ * * @link https://www.php.net/language.operators PHP manual on operators. * - * @since 1.0.0 The `isReference()` method is based on and inspired by - * the method of the same name in the PHPCS native `File` class. - * Also see {@see \PHPCSUtils\BackCompat\BCFile}. - * The `isUnaryPlusMinus()` method is, in part, inspired by the - * `Squiz.WhiteSpace.OperatorSpacing` sniff. + * @since 1.0.0 The `isReference()` method is based on and inspired by + * the method of the same name in the PHPCS native `File` class. + * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * The `isUnaryPlusMinus()` method is, in part, inspired by the + * `Squiz.WhiteSpace.OperatorSpacing` sniff. + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Operators +final class Operators { /** @@ -41,6 +41,9 @@ class Operators private static $extraUnaryIndicators = [ \T_STRING_CONCAT => true, \T_RETURN => true, + \T_EXIT => true, + \T_CONTINUE => true, + \T_BREAK => true, \T_ECHO => true, \T_PRINT => true, \T_YIELD => true, @@ -53,6 +56,8 @@ class Operators \T_INLINE_THEN => true, \T_INLINE_ELSE => true, \T_CASE => true, + \T_FN_ARROW => true, + \T_MATCH_ARROW => true, ]; /** @@ -60,13 +65,13 @@ class Operators * * Main differences with the PHPCS version: * - Defensive coding against incorrect calls to this method. - * - Improved handling of select tokenizer errors involving short lists/short arrays. * * @see \PHP_CodeSniffer\Files\File::isReference() Original source. * @see \PHPCSUtils\BackCompat\BCFile::isReference() Cross-version compatible version of the original. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the `T_BITWISE_AND` token. @@ -84,10 +89,7 @@ public static function isReference(File $phpcsFile, $stackPtr) $tokenBefore = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - if ($tokens[$tokenBefore]['code'] === \T_FUNCTION - || $tokens[$tokenBefore]['code'] === T_CLOSURE - || FunctionDeclarations::isArrowFunction($phpcsFile, $tokenBefore) === true - ) { + if (isset(Collections::functionDeclarationTokens()[$tokens[$tokenBefore]['code']]) === true) { // Function returns a reference. return true; } @@ -102,7 +104,7 @@ public static function isReference(File $phpcsFile, $stackPtr) return true; } - if (isset(BCTokens::assignmentTokens()[$tokens[$tokenBefore]['code']]) === true) { + if (isset(Tokens::$assignmentTokens[$tokens[$tokenBefore]['code']]) === true) { // This is directly after an assignment. It's a reference. Even if // it is part of an operation, the other tests will handle it. return true; @@ -116,43 +118,36 @@ public static function isReference(File $phpcsFile, $stackPtr) $lastOpener = Parentheses::getLastOpener($phpcsFile, $stackPtr); if ($lastOpener !== false) { - $lastOwner = Parentheses::lastOwnerIn($phpcsFile, $stackPtr, [\T_FUNCTION, \T_CLOSURE]); - if ($lastOwner !== false) { + $lastOwner = Parentheses::getOwner($phpcsFile, $lastOpener); + + if (isset(Collections::functionDeclarationTokens()[$tokens[$lastOwner]['code']]) === true + // As of PHPCS 4.x, `T_USE` is a parenthesis owner. + || $tokens[$lastOwner]['code'] === \T_USE + ) { $params = FunctionDeclarations::getParameters($phpcsFile, $lastOwner); foreach ($params as $param) { - if ($param['pass_by_reference'] === true) { + if ($param['reference_token'] === $stackPtr) { // Function parameter declared to be passed by reference. return true; } } - } elseif (isset($tokens[$lastOpener]['parenthesis_owner']) === false) { - $prev = false; - for ($t = ($lastOpener - 1); $t >= 0; $t--) { - if ($tokens[$t]['code'] !== \T_WHITESPACE) { - $prev = $t; - break; - } - } - - if ($prev !== false && $tokens[$prev]['code'] === \T_USE) { - // Closure use by reference. - return true; - } } } - // Pass by reference in function calls and assign by reference in arrays. + /* + * Pass by reference in function calls, assign by reference in arrays and + * closure use by reference in PHPCS 3.x. + */ if ($tokens[$tokenBefore]['code'] === \T_OPEN_PARENTHESIS || $tokens[$tokenBefore]['code'] === \T_COMMA || $tokens[$tokenBefore]['code'] === \T_OPEN_SHORT_ARRAY - || $tokens[$tokenBefore]['code'] === \T_OPEN_SQUARE_BRACKET // PHPCS 2.8.0 < 3.3.0. ) { if ($tokens[$tokenAfter]['code'] === \T_VARIABLE) { return true; } else { $skip = Tokens::$emptyTokens; - $skip += Collections::$OONameTokens; - $skip += Collections::$OOHierarchyKeywords; + $skip += Collections::namespacedNameTokens(); + $skip += Collections::ooHierarchyKeywords(); $skip[] = \T_DOUBLE_COLON; $nextSignificantAfter = $phpcsFile->findNext( @@ -199,7 +194,7 @@ public static function isUnaryPlusMinus(File $phpcsFile, $stackPtr) return false; } - if (isset(BCTokens::operators()[$tokens[$next]['code']]) === true) { + if (isset(Tokens::$operators[$tokens[$next]['code']]) === true) { // Next token is an operator, so this is not a unary. return false; } @@ -209,24 +204,16 @@ public static function isUnaryPlusMinus(File $phpcsFile, $stackPtr) /* * Check the preceeding token for an indication that this is not an arithmetic operation. */ - if (isset(BCTokens::operators()[$tokens[$prev]['code']]) === true - || isset(BCTokens::comparisonTokens()[$tokens[$prev]['code']]) === true + if (isset(Tokens::$operators[$tokens[$prev]['code']]) === true + || isset(Tokens::$comparisonTokens[$tokens[$prev]['code']]) === true || isset(Tokens::$booleanOperators[$tokens[$prev]['code']]) === true - || isset(BCTokens::assignmentTokens()[$tokens[$prev]['code']]) === true + || isset(Tokens::$assignmentTokens[$tokens[$prev]['code']]) === true || isset(Tokens::$castTokens[$tokens[$prev]['code']]) === true || isset(self::$extraUnaryIndicators[$tokens[$prev]['code']]) === true ) { return true; } - /* - * BC for PHPCS < 3.1.0 in which the PHP 5.5 T_YIELD token was not yet backfilled. - * Note: not accounting for T_YIELD_FROM as that would be a parse error anyway. - */ - if ($tokens[$prev]['code'] === \T_STRING && $tokens[$prev]['content'] === 'yield') { - return true; - } - return false; } diff --git a/PHPCSUtils/Utils/Orthography.php b/PHPCSUtils/Utils/Orthography.php index 3bafca1d..cd9f35b1 100644 --- a/PHPCSUtils/Utils/Orthography.php +++ b/PHPCSUtils/Utils/Orthography.php @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class Orthography +final class Orthography { /** @@ -43,21 +43,21 @@ class Orthography * * @since 1.0.0 * - * @param string $string The text string to examine. - * This can be the contents of a text string token, - * but also, for instance, a comment text. - * Potential text delimiter quotes should be stripped - * off a text string before passing it to this method. - * Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}. + * @param string $textString The text string to examine. + * This can be the contents of a text string token, + * but also, for instance, a comment text. + * Potential text delimiter quotes should be stripped + * off a text string before passing it to this method. + * Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}. * * @return bool `TRUE` when the first character is a capital letter or a letter * which doesn't have a concept of capitalization. * `FALSE` otherwise, including for non-letter characters. */ - public static function isFirstCharCapitalized($string) + public static function isFirstCharCapitalized($textString) { - $string = \ltrim($string); - return (\preg_match('`^[\p{Lu}\p{Lt}\p{Lo}]`u', $string) > 0); + $textString = \ltrim($textString); + return (\preg_match('`^[\p{Lu}\p{Lt}\p{Lo}]`u', $textString) > 0); } /** @@ -65,21 +65,21 @@ public static function isFirstCharCapitalized($string) * * @since 1.0.0 * - * @param string $string The text string to examine. - * This can be the contents of a text string token, - * but also, for instance, a comment text. - * Potential text delimiter quotes should be stripped - * off a text string before passing it to this method. - * Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}. + * @param string $textString The text string to examine. + * This can be the contents of a text string token, + * but also, for instance, a comment text. + * Potential text delimiter quotes should be stripped + * off a text string before passing it to this method. + * Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}. * * @return bool `TRUE` when the first character is a lowercase letter. * `FALSE` otherwise, including for letters which don't have a concept of * capitalization and for non-letter characters. */ - public static function isFirstCharLowercase($string) + public static function isFirstCharLowercase($textString) { - $string = \ltrim($string); - return (\preg_match('`^\p{Ll}`u', $string) > 0); + $textString = \ltrim($textString); + return (\preg_match('`^\p{Ll}`u', $textString) > 0); } /** @@ -87,7 +87,7 @@ public static function isFirstCharLowercase($string) * * @since 1.0.0 * - * @param string $string The text string to examine. + * @param string $textString The text string to examine. * This can be the contents of a text string token, * but also, for instance, a comment text. * Potential text delimiter quotes should be stripped @@ -100,19 +100,15 @@ public static function isFirstCharLowercase($string) * * @return bool */ - public static function isLastCharPunctuation($string, $allowedChars = self::TERMINAL_POINTS) + public static function isLastCharPunctuation($textString, $allowedChars = self::TERMINAL_POINTS) { - static $encoding; + $encoding = Helper::getEncoding(); + $textString = \rtrim($textString); - if (isset($encoding) === false) { - $encoding = Helper::getEncoding(); - } - - $string = \rtrim($string); if (\function_exists('iconv_substr') === true) { - $lastChar = \iconv_substr($string, -1, 1, $encoding); + $lastChar = \iconv_substr($textString, -1, 1, $encoding); } else { - $lastChar = \substr($string, -1); + $lastChar = \substr($textString, -1); } if (\function_exists('iconv_strpos') === true) { diff --git a/PHPCSUtils/Utils/Parentheses.php b/PHPCSUtils/Utils/Parentheses.php index 0e68b3b4..e5d78f41 100644 --- a/PHPCSUtils/Utils/Parentheses.php +++ b/PHPCSUtils/Utils/Parentheses.php @@ -12,24 +12,46 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\BackCompat\Helper; -use PHPCSUtils\Tokens\Collections; -use PHPCSUtils\Utils\FunctionDeclarations; /** - * Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped in - * parentheses. + * Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped + * in parentheses. + * + * In contrast to PHPCS natively, `isset()`, `unset()`, `empty()`, `exit()`, `die()` and `eval()` + * will be considered parentheses owners by the functions in this class. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for `isset()`, `unset()`, `empty()`, `exit()`, `die()` + * and `eval()` as parentheses owners to all applicable functions. + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Parentheses +final class Parentheses { /** - * Get the pointer to the parentheses owner of an open/close parenthesis. + * Extra tokens which should be considered parentheses owners. + * + * - `T_ISSET`, `T_UNSET`, `T_EMPTY`, `T_EXIT` and `T_EVAL` are not PHPCS native parentheses + * owners, but are considered such for the purposes of this class. + * Also see {@link https://github.com/squizlabs/PHP_CodeSniffer/issues/3118 PHPCS#3118}. + * + * @since 1.0.0-alpha4 + * + * @var array => + */ + private static $extraParenthesesOwners = [ + \T_ISSET => \T_ISSET, + \T_UNSET => \T_UNSET, + \T_EMPTY => \T_EMPTY, + \T_EXIT => \T_EXIT, + \T_EVAL => \T_EVAL, + ]; + + /** + * Get the stack pointer to the parentheses owner of an open/close parenthesis. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position of `T_OPEN/CLOSE_PARENTHESIS` token. @@ -47,18 +69,9 @@ public static function getOwner(File $phpcsFile, $stackPtr) } /* - * `T_LIST` and `T_ANON_CLASS` only became parentheses owners in PHPCS 3.5.0. - * `T_FN` was only backfilled in PHPCS 3.5.3/4/5. - * - On PHP 7.4 with PHPCS < 3.5.3, T_FN will not yet be a parentheses owner. - * - On PHP < 7.4 with PHPCS < 3.5.3, T_FN will be tokenized as T_STRING and not yet be a parentheses owner. - * - * {@internal As the 'parenthesis_owner' index is only set on parentheses, we didn't need to do any - * input validation before, but now we do.} + * As the 'parenthesis_owner' index is only set on parentheses, we didn't need to do any + * input validation before, but now we do. */ - if (\version_compare(Helper::getVersion(), '3.5.4', '>=') === true) { - return false; - } - if (isset($tokens[$stackPtr]) === false || ($tokens[$stackPtr]['code'] !== \T_OPEN_PARENTHESIS && $tokens[$stackPtr]['code'] !== \T_CLOSE_PARENTHESIS) @@ -72,12 +85,7 @@ public static function getOwner(File $phpcsFile, $stackPtr) $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($prevNonEmpty !== false - && ($tokens[$prevNonEmpty]['code'] === \T_LIST - || $tokens[$prevNonEmpty]['code'] === \T_ANON_CLASS - // Work-around: anon classes were, in certain circumstances, tokenized as T_CLASS prior to PHPCS 3.4.0. - || $tokens[$prevNonEmpty]['code'] === \T_CLASS - // Possibly an arrow function. - || FunctionDeclarations::isArrowFunction($phpcsFile, $prevNonEmpty) === true) + && isset(self::$extraParenthesesOwners[$tokens[$prevNonEmpty]['code']]) === true ) { return $prevNonEmpty; } @@ -90,7 +98,7 @@ public static function getOwner(File $phpcsFile, $stackPtr) * set of valid owners. * * @since 1.0.0 - * @since 1.0.0-alpha2 Added BC support for PHP 7.4 arrow functions. + * @since 1.0.0-alpha2 Added support for PHP 7.4 arrow functions. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position of `T_OPEN/CLOSE_PARENTHESIS` token. @@ -110,23 +118,6 @@ public static function isOwnerIn(File $phpcsFile, $stackPtr, $validOwners) $tokens = $phpcsFile->getTokens(); $validOwners = (array) $validOwners; - /* - * Work around tokenizer bug where anon classes were, in certain circumstances, tokenized - * as `T_CLASS` prior to PHPCS 3.4.0. - * As `T_CLASS` is normally not an parenthesis owner, we can safely add it to the array - * without doing a version check. - */ - if (\in_array(\T_ANON_CLASS, $validOwners, true)) { - $validOwners[] = \T_CLASS; - } - - /* - * Allow for T_FN token being tokenized as T_STRING before PHPCS 3.5.3. - */ - if (\defined('T_FN') && \in_array(\T_FN, $validOwners, true)) { - $validOwners += Collections::arrowFunctionTokensBC(); - } - return \in_array($tokens[$owner]['code'], $validOwners, true); } @@ -148,11 +139,12 @@ public static function hasOwner(File $phpcsFile, $stackPtr, $validOwners) } /** - * Retrieve the position of the opener to the first (outer) set of parentheses an arbitrary - * token is wrapped in, where the parentheses owner is within the set of valid owners. + * Retrieve the stack pointer to the parentheses opener of the first (outer) set of parentheses + * an arbitrary token is wrapped in. * - * If no `$validOwners` are specified, the opener to the first set of parentheses surrounding - * the token will be returned. + * If the optional `$validOwners` parameter is passed, the stack pointer to the opener to + * the first set of parentheses, which has an owner which is in the list of valid owners, + * will be returned. This may be a nested set of parentheses. * * @since 1.0.0 * @@ -171,11 +163,12 @@ public static function getFirstOpener(File $phpcsFile, $stackPtr, $validOwners = } /** - * Retrieve the position of the closer to the first (outer) set of parentheses an arbitrary - * token is wrapped in, where the parentheses owner is within the set of valid owners. + * Retrieve the stack pointer to the parentheses closer of the first (outer) set of parentheses + * an arbitrary token is wrapped in. * - * If no `$validOwners` are specified, the closer to the first set of parentheses surrounding - * the token will be returned. + * If the optional `$validOwners` parameter is passed, the stack pointer to the closer to + * the first set of parentheses, which has an owner which is in the list of valid owners, + * will be returned. This may be a nested set of parentheses. * * @since 1.0.0 * @@ -200,11 +193,12 @@ public static function getFirstCloser(File $phpcsFile, $stackPtr, $validOwners = } /** - * Retrieve the position of the parentheses owner to the first (outer) set of parentheses an - * arbitrary token is wrapped in, where the parentheses owner is within the set of valid owners. + * Retrieve the stack pointer to the parentheses owner of the first (outer) set of parentheses + * an arbitrary token is wrapped in. * - * If no `$validOwners` are specified, the owner to the first set of parentheses surrounding - * the token will be returned or `false` if the first set of parentheses does not have an owner. + * If the optional `$validOwners` parameter is passed, the stack pointer to the owner of + * the first set of parentheses, which has an owner which is in the list of valid owners, + * will be returned. This may be a nested set of parentheses. * * @since 1.0.0 * @@ -228,11 +222,12 @@ public static function getFirstOwner(File $phpcsFile, $stackPtr, $validOwners = } /** - * Retrieve the position of the opener to the last (inner) set of parentheses an arbitrary - * token is wrapped in, where the parentheses owner is within the set of valid owners. + * Retrieve the stack pointer to the parentheses opener of the last (inner) set of parentheses + * an arbitrary token is wrapped in. * - * If no `$validOwners` are specified, the opener to the last set of parentheses surrounding - * the token will be returned. + * If the optional `$validOwners` parameter is passed, the stack pointer to the opener to + * the last set of parentheses, which has an owner which is in the list of valid owners, + * will be returned. This may be a set of parentheses higher up. * * @since 1.0.0 * @@ -251,11 +246,12 @@ public static function getLastOpener(File $phpcsFile, $stackPtr, $validOwners = } /** - * Retrieve the position of the closer to the last (inner) set of parentheses an arbitrary - * token is wrapped in, where the parentheses owner is within the set of valid owners. + * Retrieve the stack pointer to the parentheses closer of the last (inner) set of parentheses + * an arbitrary token is wrapped in. * - * If no `$validOwners` are specified, the closer to the last set of parentheses surrounding - * the token will be returned. + * If the optional `$validOwners` parameter is passed, the stack pointer to the closer to + * the last set of parentheses, which has an owner which is in the list of valid owners, + * will be returned. This may be a set of parentheses higher up. * * @since 1.0.0 * @@ -280,11 +276,12 @@ public static function getLastCloser(File $phpcsFile, $stackPtr, $validOwners = } /** - * Retrieve the position of the parentheses owner to the last (inner) set of parentheses an - * arbitrary token is wrapped in where the parentheses owner is within the set of valid owners. + * Retrieve the stack pointer to the parentheses owner of the last (inner) set of parentheses + * an arbitrary token is wrapped in. * - * If no `$validOwners` are specified, the owner to the last set of parentheses surrounding - * the token will be returned or `false` if the last set of parentheses does not have an owner. + * If the optional `$validOwners` parameter is passed, the stack pointer to the owner of + * the last set of parentheses, which has an owner which is in the list of valid owners, + * will be returned. This may be a set of parentheses higher up. * * @since 1.0.0 * @@ -308,7 +305,7 @@ public static function getLastOwner(File $phpcsFile, $stackPtr, $validOwners = [ } /** - * Check whether the owner of a outermost wrapping set of parentheses of an arbitrary token + * Check whether the owner of the outermost wrapping set of parentheses of an arbitrary token * is within a limited set of acceptable token types. * * @since 1.0.0 @@ -336,7 +333,7 @@ public static function firstOwnerIn(File $phpcsFile, $stackPtr, $validOwners) } /** - * Check whether the owner of a innermost wrapping set of parentheses of an arbitrary token + * Check whether the owner of the innermost wrapping set of parentheses of an arbitrary token * is within a limited set of acceptable token types. * * @since 1.0.0 diff --git a/PHPCSUtils/Utils/PassedParameters.php b/PHPCSUtils/Utils/PassedParameters.php index c813f6df..79a92685 100644 --- a/PHPCSUtils/Utils/PassedParameters.php +++ b/PHPCSUtils/Utils/PassedParameters.php @@ -13,38 +13,21 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Internal\Cache; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Arrays; use PHPCSUtils\Utils\GetTokensAsString; /** * Utility functions to retrieve information about parameters passed to function calls, - * array declarations, isset and unset constructs. + * class instantiations, array declarations, isset and unset constructs. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class PassedParameters +final class PassedParameters { - /** - * The token types these methods can handle. - * - * @since 1.0.0 - * - * @var array => - */ - private static $allowedConstructs = [ - \T_STRING => true, - \T_VARIABLE => true, - \T_SELF => true, - \T_STATIC => true, - \T_ARRAY => true, - \T_OPEN_SHORT_ARRAY => true, - \T_ISSET => true, - \T_UNSET => true, - // BC for various short array tokenizer issues. See the Arrays class for more details. - \T_OPEN_SQUARE_BRACKET => true, - ]; - /** * Tokens which are considered stop point, either because they are the end * of the parameter (comma) or because we need to skip over them. @@ -59,43 +42,59 @@ class PassedParameters \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_OPEN_PARENTHESIS => \T_OPEN_PARENTHESIS, \T_DOC_COMMENT_OPEN_TAG => \T_DOC_COMMENT_OPEN_TAG, + \T_ATTRIBUTE => \T_ATTRIBUTE, ]; /** * Checks if any parameters have been passed. * - * - If passed a `T_STRING` or `T_VARIABLE` stack pointer, it will treat it as a function call. + * - If passed a `T_STRING`, `T_NAME_FULLY_QUALIFIED`, `T_NAME_RELATIVE`, `T_NAME_QUALIFIED` + * or `T_VARIABLE` stack pointer, it will treat it as a function call. * If a `T_STRING` or `T_VARIABLE` which is *not* a function call is passed, the behaviour is * undetermined. - * - If passed a `T_SELF` or `T_STATIC` stack pointer, it will accept it as a - * function call when used like `new self()`. + * - If passed a `T_ANON_CLASS` stack pointer, it will accept it as a class instantiation. + * - If passed a `T_SELF`, `T_STATIC` or `T_PARENT` stack pointer, it will accept it as a + * class instantiation function call when used like `new self()`. * - If passed a `T_ARRAY` or `T_OPEN_SHORT_ARRAY` stack pointer, it will detect * whether the array has values or is empty. + * For purposes of backward-compatibility with older PHPCS versions, `T_OPEN_SQUARE_BRACKET` + * tokens will also be accepted and will be checked whether they are in reality + * a short array opener. * - If passed a `T_ISSET` or `T_UNSET` stack pointer, it will detect whether those * language constructs have "parameters". * * @since 1.0.0 + * @since 1.0.0-alpha4 Added the `$isShortArray` parameter. + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. + * @since 1.0.0-alpha4 Added defensive coding against PHP 8.1 first class callables + * being passed as if they were function calls. * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of the `T_STRING`, `T_VARIABLE`, `T_ARRAY`, - * `T_OPEN_SHORT_ARRAY`, `T_ISSET`, or `T_UNSET` token. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param int $stackPtr The position of function call name, + * language construct or array open token. + * @param true|null $isShortArray Optional. Short-circuit the short array check for + * `T_OPEN_SHORT_ARRAY` tokens if it isn't necessary. + * Efficiency tweak for when this has already been established, + * Use with EXTREME care. * * @return bool * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the token passed is not one of the * accepted types or doesn't exist. */ - public static function hasParameters(File $phpcsFile, $stackPtr) + public static function hasParameters(File $phpcsFile, $stackPtr, $isShortArray = null) { $tokens = $phpcsFile->getTokens(); - if (isset($tokens[$stackPtr], self::$allowedConstructs[$tokens[$stackPtr]['code']]) === false) { + if (isset($tokens[$stackPtr]) === false + || isset(Collections::parameterPassingTokens()[$tokens[$stackPtr]['code']]) === false + ) { throw new RuntimeException( 'The hasParameters() method expects a function call, array, isset or unset token to be passed.' ); } - if ($tokens[$stackPtr]['code'] === \T_SELF || $tokens[$stackPtr]['code'] === \T_STATIC) { + if (isset(Collections::ooHierarchyKeywords()[$tokens[$stackPtr]['code']]) === true) { $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($tokens[$prev]['code'] !== \T_NEW) { throw new RuntimeException( @@ -104,8 +103,8 @@ public static function hasParameters(File $phpcsFile, $stackPtr) } } - if (($tokens[$stackPtr]['code'] === \T_OPEN_SHORT_ARRAY - || $tokens[$stackPtr]['code'] === \T_OPEN_SQUARE_BRACKET) + if (isset(Collections::shortArrayListOpenTokensBC()[$tokens[$stackPtr]['code']]) === true + && $isShortArray !== true && Arrays::isShortArray($phpcsFile, $stackPtr) === false ) { throw new RuntimeException( @@ -119,9 +118,7 @@ public static function hasParameters(File $phpcsFile, $stackPtr) } // Deal with short array syntax. - if ($tokens[$stackPtr]['code'] === \T_OPEN_SHORT_ARRAY - || $tokens[$stackPtr]['code'] === \T_OPEN_SQUARE_BRACKET - ) { + if (isset(Collections::shortArrayListOpenTokensBC()[$tokens[$stackPtr]['code']]) === true) { if ($next === $tokens[$stackPtr]['bracket_closer']) { // No parameters. return false; @@ -140,8 +137,11 @@ public static function hasParameters(File $phpcsFile, $stackPtr) return false; } + $ignore = Tokens::$emptyTokens; + $ignore[\T_ELLIPSIS] = \T_ELLIPSIS; // Prevent PHP 8.1 first class callables from being seen as function calls. + $closeParenthesis = $tokens[$next]['parenthesis_closer']; - $nextNextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($next + 1), ($closeParenthesis + 1), true); + $nextNextNonEmpty = $phpcsFile->findNext($ignore, ($next + 1), ($closeParenthesis + 1), true); if ($nextNextNonEmpty === $closeParenthesis) { // No parameters. @@ -157,12 +157,24 @@ public static function hasParameters(File $phpcsFile, $stackPtr) * See {@see PassedParameters::hasParameters()} for information on the supported constructs. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added the `$limit` and `$isShortArray` parameters. + * @since 1.0.0-alpha4 Added support for PHP 8.0 function calls with named arguments by introducing + * the `'name'` and `'name_token'` index keys as well as using the name + * as the index for the top-level array for named parameters. * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of the `T_STRING`, `T_VARIABLE`, `T_ARRAY`, - * `T_OPEN_SHORT_ARRAY`, `T_ISSET`, or `T_UNSET` token. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param int $stackPtr The position of function call name, + * language construct or array open token. + * @param int $limit Optional. Limit the parameter retrieval to the first # + * parameters/array entries. + * Use with care on function calls, as this can break + * support for named parameters! + * @param true|null $isShortArray Optional. Short-circuit the short array check for + * `T_OPEN_SHORT_ARRAY` tokens if it isn't necessary. + * Efficiency tweak for when this has already been established, + * Use with EXTREME care. * - * @return array A multi-dimentional array information on each parameter/array item. + * @return array A multi-dimentional array with information on each parameter/array item. * The information gathered about each parameter/array item is in the following format: * ```php * 1 => array( @@ -172,25 +184,45 @@ public static function hasParameters(File $phpcsFile, $stackPtr) * 'clean' => string, // Same as `raw`, but all comment tokens have been stripped out. * ) * ``` - * _Note: The array starts at index 1._ + * If a named parameter is encountered in a function call, the top-level index will not be + * the parameter _position_, but the _parameter name_ and the array will include two extra keys: + * ```php + * 'parameter_name' => array( + * 'name' => string, // The parameter name (without the colon). + * 'name_token' => int, // The stack pointer to the parameter name token. + * ... + * ) + * ``` + * The `'start'`, `'end'`, `'raw'` and `'clean'` indexes will always contain just and only + * information on the parameter value. + * _Note: The array starts at index 1 for positional parameters._ + * _The key for named parameters will be the parameter name._ * If no parameters/array items are found, an empty array will be returned. * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the token passed is not one of the * accepted types or doesn't exist. */ - public static function getParameters(File $phpcsFile, $stackPtr) + public static function getParameters(File $phpcsFile, $stackPtr, $limit = 0, $isShortArray = null) { - if (self::hasParameters($phpcsFile, $stackPtr) === false) { + if (self::hasParameters($phpcsFile, $stackPtr, $isShortArray) === false) { return []; } + $effectiveLimit = (\is_int($limit) && $limit > 0) ? $limit : 0; + + if (Cache::isCached($phpcsFile, __METHOD__, "$stackPtr-$effectiveLimit") === true) { + return Cache::get($phpcsFile, __METHOD__, "$stackPtr-$effectiveLimit"); + } + + if ($effectiveLimit !== 0 && Cache::isCached($phpcsFile, __METHOD__, "$stackPtr-0") === true) { + return \array_slice(Cache::get($phpcsFile, __METHOD__, "$stackPtr-0"), 0, $effectiveLimit, true); + } + // Ok, we know we have a valid token with parameters and valid open & close brackets/parenthesis. $tokens = $phpcsFile->getTokens(); // Mark the beginning and end tokens. - if ($tokens[$stackPtr]['code'] === \T_OPEN_SHORT_ARRAY - || $tokens[$stackPtr]['code'] === \T_OPEN_SQUARE_BRACKET - ) { + if (isset(Collections::shortArrayListOpenTokensBC()[$tokens[$stackPtr]['code']]) === true) { $opener = $stackPtr; $closer = $tokens[$stackPtr]['bracket_closer']; } else { @@ -198,6 +230,8 @@ public static function getParameters(File $phpcsFile, $stackPtr) $closer = $tokens[$opener]['parenthesis_closer']; } + $mayHaveNames = (isset(Collections::functionCallTokens()[$tokens[$stackPtr]['code']]) === true); + $parameters = []; $nextComma = $opener; $paramStart = ($opener + 1); @@ -238,19 +272,54 @@ public static function getParameters(File $phpcsFile, $stackPtr) continue; } + // Skip over attributes. + if ($tokens[$nextComma]['code'] === \T_ATTRIBUTE + && isset($tokens[$nextComma]['attribute_closer']) + ) { + $nextComma = $tokens[$nextComma]['attribute_closer']; + continue; + } + if ($tokens[$nextComma]['code'] !== \T_COMMA && $tokens[$nextComma]['code'] !== $tokens[$closer]['code'] ) { // Just in case. - continue; + continue; // @codeCoverageIgnore } // Ok, we've reached the end of the parameter. - $paramEnd = ($nextComma - 1); - $parameters[$cnt]['start'] = $paramStart; - $parameters[$cnt]['end'] = $paramEnd; - $parameters[$cnt]['raw'] = \trim(GetTokensAsString::normal($phpcsFile, $paramStart, $paramEnd)); - $parameters[$cnt]['clean'] = \trim(GetTokensAsString::noComments($phpcsFile, $paramStart, $paramEnd)); + $paramEnd = ($nextComma - 1); + $key = $cnt; + + if ($mayHaveNames === true) { + $firstNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, $paramStart, ($paramEnd + 1), true); + if ($firstNonEmpty !== $paramEnd) { + $secondNonEmpty = $phpcsFile->findNext( + Tokens::$emptyTokens, + ($firstNonEmpty + 1), + ($paramEnd + 1), + true + ); + + if ($tokens[$secondNonEmpty]['code'] === \T_COLON + && $tokens[$firstNonEmpty]['code'] === \T_PARAM_NAME + ) { + if (isset($parameters[$tokens[$firstNonEmpty]['content']]) === false) { + // Set the key to be the name, but only if we've not seen this name before. + $key = $tokens[$firstNonEmpty]['content']; + } + + $parameters[$key]['name'] = $tokens[$firstNonEmpty]['content']; + $parameters[$key]['name_token'] = $firstNonEmpty; + $paramStart = ($secondNonEmpty + 1); + } + } + } + + $parameters[$key]['start'] = $paramStart; + $parameters[$key]['end'] = $paramEnd; + $parameters[$key]['raw'] = \trim(GetTokensAsString::normal($phpcsFile, $paramStart, $paramEnd)); + $parameters[$key]['clean'] = \trim(GetTokensAsString::noComments($phpcsFile, $paramStart, $paramEnd)); // Check if there are more tokens before the closing parenthesis. // Prevents function calls with trailing comma's from setting an extra parameter: @@ -262,12 +331,26 @@ public static function getParameters(File $phpcsFile, $stackPtr) true ); if ($hasNextParam === false) { + // Reached the end, so for the purpose of caching, this should be saved as if no limit was set. + $effectiveLimit = 0; + break; + } + + // Stop if there is a valid limit and the limit has been reached. + if ($effectiveLimit !== 0 && $cnt === $effectiveLimit) { break; } // Prepare for the next parameter. $paramStart = ($nextComma + 1); - $cnt++; + ++$cnt; + } + + if ($effectiveLimit !== 0 && $cnt === $effectiveLimit) { + Cache::set($phpcsFile, __METHOD__, "$stackPtr-$effectiveLimit", $parameters); + } else { + // Limit is 0 or total items is less than effective limit. + Cache::set($phpcsFile, __METHOD__, "$stackPtr-0", $parameters); } return $parameters; @@ -278,37 +361,65 @@ public static function getParameters(File $phpcsFile, $stackPtr) * * See {@see PassedParameters::hasParameters()} for information on the supported constructs. * + * @see PassedParameters::getParameterFromStack() For when the parameter stack of a function call is + * already retrieved. + * * @since 1.0.0 + * @since 1.0.0-alpha4 Added the `$paramNames` parameter. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of the `T_STRING`, `T_VARIABLE`, `T_ARRAY`, - * `T_OPEN_SHORT_ARRAY`, `T_ISSET` or `T_UNSET` token. + * @param int $stackPtr The position of function call name, + * language construct or array open token. * @param int $paramOffset The 1-based index position of the parameter to retrieve. + * @param string|string[] $paramNames Optional. Either the name of the target parameter + * to retrieve as a string or an array of names for the + * same target parameter. + * Only relevant for function calls. + * An arrays of names is supported to allow for functions + * for which the parameter names have undergone name + * changes over time. + * When specified, the name will take precedence over the + * offset. + * For PHP 8 support, it is STRONGLY recommended to + * always pass both the offset as well as the parameter + * name when examining function calls. * - * @return array|false Array with information on the parameter/array item at the specified offset. + * @return array|false Array with information on the parameter/array item at the specified offset, + * or with the specified name. * Or `FALSE` if the specified parameter/array item is not found. - * The format of the return value is: - * ```php - * array( - * 'start' => int, // The stack pointer to the first token in the parameter/array item. - * 'end' => int, // The stack pointer to the last token in the parameter/array item. - * 'raw' => string, // A string with the contents of all tokens between `start` and `end`. - * 'clean' => string, // Same as `raw`, but all comment tokens have been stripped out. - * ) - * ``` + * See {@see PassedParameters::getParameters()} for the format of the returned + * (single-dimensional) array. * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the token passed is not one of the * accepted types or doesn't exist. + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If a function call parameter is requested and + * the `$paramName` parameter is not passed. */ - public static function getParameter(File $phpcsFile, $stackPtr, $paramOffset) + public static function getParameter(File $phpcsFile, $stackPtr, $paramOffset, $paramNames = []) { - $parameters = self::getParameters($phpcsFile, $stackPtr); + $tokens = $phpcsFile->getTokens(); + + if (empty($paramNames) === true) { + $parameters = self::getParameters($phpcsFile, $stackPtr, $paramOffset); + } else { + $parameters = self::getParameters($phpcsFile, $stackPtr); + } + + /* + * Non-function calls. + */ + if (isset(Collections::functionCallTokens()[$tokens[$stackPtr]['code']]) === false) { + if (isset($parameters[$paramOffset]) === true) { + return $parameters[$paramOffset]; + } - if (isset($parameters[$paramOffset]) === false) { return false; } - return $parameters[$paramOffset]; + /* + * Function calls. + */ + return self::getParameterFromStack($parameters, $paramOffset, $paramNames); } /** @@ -319,8 +430,8 @@ public static function getParameter(File $phpcsFile, $stackPtr, $paramOffset) * @since 1.0.0 * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. - * @param int $stackPtr The position of the `T_STRING`, `T_VARIABLE`, `T_ARRAY`, - * `T_OPEN_SHORT_ARRAY`, `T_ISSET` or `T_UNSET` token. + * @param int $stackPtr The position of function call name, + * language construct or array open token. * * @return int * @@ -335,4 +446,67 @@ public static function getParameterCount(File $phpcsFile, $stackPtr) return \count(self::getParameters($phpcsFile, $stackPtr)); } + + /** + * Get information on a specific function call parameter passed. + * + * This is an efficiency method to correctly handle positional versus named parameters + * for function calls when multiple parameters need to be examined. + * + * See {@see PassedParameters::hasParameters()} for information on the supported constructs. + * + * @since 1.0.0-alpha4 + * + * @param array $parameters The output of a previous call to {@see PassedParameters::getParameters()}. + * @param int $paramOffset The 1-based index position of the parameter to retrieve. + * @param string|string[] $paramNames Either the name of the target parameter to retrieve + * as a string or an array of names for the same target parameter. + * An array of names is supported to allow for functions + * for which the parameter names have undergone name + * changes over time. + * The name will take precedence over the offset. + * + * @return array|false Array with information on the parameter at the specified offset, + * or with the specified name. + * Or `FALSE` if the specified parameter is not found. + * See {@see PassedParameters::getParameters()} for the format of the returned + * (single-dimensional) array. + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the `$paramNames` parameter is not passed + * and the requested parameter was not passed + * as a positional parameter in the function call + * being examined. + */ + public static function getParameterFromStack(array $parameters, $paramOffset, $paramNames) + { + if (empty($parameters) === true) { + return false; + } + + // First check for a named parameter. + if (empty($paramNames) === false) { + $paramNames = (array) $paramNames; + foreach ($paramNames as $name) { + // Note: parameter names are case-sensitive!. + if (isset($parameters[$name]) === true) { + return $parameters[$name]; + } + } + } + + // Next check for positional parameters. + if (isset($parameters[$paramOffset]) === true + && isset($parameters[$paramOffset]['name']) === false + ) { + return $parameters[$paramOffset]; + } + + if (empty($paramNames) === true) { + throw new RuntimeException( + 'To allow for support for PHP 8 named parameters, the $paramNames parameter must be passed.' + ); + } + + return false; + } } diff --git a/PHPCSUtils/Utils/Scopes.php b/PHPCSUtils/Utils/Scopes.php index 518a910e..2854aae6 100644 --- a/PHPCSUtils/Utils/Scopes.php +++ b/PHPCSUtils/Utils/Scopes.php @@ -11,7 +11,7 @@ namespace PHPCSUtils\Utils; use PHP_CodeSniffer\Files\File; -use PHPCSUtils\BackCompat\BCTokens; +use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Conditions; use PHPCSUtils\Utils\Parentheses; @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class Scopes +final class Scopes { /** @@ -56,9 +56,11 @@ public static function validDirectScope(File $phpcsFile, $stackPtr, $validScopes } /** - * Check whether a T_CONST token is a class/interface constant declaration. + * Check whether a T_CONST token is a class/interface/trait/enum constant declaration. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.1 enums. + * @since 1.0.0-alpha4 Added support for PHP 8.2 constants in traits. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position in the stack of the @@ -74,7 +76,7 @@ public static function isOOConstant(File $phpcsFile, $stackPtr) return false; } - if (self::validDirectScope($phpcsFile, $stackPtr, Collections::$OOConstantScopes) !== false) { + if (self::validDirectScope($phpcsFile, $stackPtr, Collections::ooConstantScopes()) !== false) { return true; } @@ -100,7 +102,7 @@ public static function isOOProperty(File $phpcsFile, $stackPtr) return false; } - $scopePtr = self::validDirectScope($phpcsFile, $stackPtr, Collections::$OOPropertyScopes); + $scopePtr = self::validDirectScope($phpcsFile, $stackPtr, Collections::ooPropertyScopes()); if ($scopePtr !== false) { // Make sure it's not a method parameter. $deepestOpen = Parentheses::getLastOpener($phpcsFile, $stackPtr); @@ -116,9 +118,10 @@ public static function isOOProperty(File $phpcsFile, $stackPtr) } /** - * Check whether a T_FUNCTION token is a class/interface/trait method declaration. + * Check whether a T_FUNCTION token is a class/interface/trait/enum method declaration. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.1 enums. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position in the stack of the @@ -134,7 +137,7 @@ public static function isOOMethod(File $phpcsFile, $stackPtr) return false; } - if (self::validDirectScope($phpcsFile, $stackPtr, BCTokens::ooScopeTokens()) !== false) { + if (self::validDirectScope($phpcsFile, $stackPtr, Tokens::$ooScopeTokens) !== false) { return true; } diff --git a/PHPCSUtils/Utils/TextStrings.php b/PHPCSUtils/Utils/TextStrings.php index c8a3bc96..d6ac1408 100644 --- a/PHPCSUtils/Utils/TextStrings.php +++ b/PHPCSUtils/Utils/TextStrings.php @@ -12,16 +12,40 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Util\Tokens; +use PHPCSUtils\Internal\Cache; +use PHPCSUtils\Internal\NoFileCache; use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Utils\GetTokensAsString; /** * Utility functions for working with text string tokens. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class TextStrings +final class TextStrings { + /** + * Regex to match the start of an embedded variable/expression. + * + * Prevents matching escaped variables/expressions. + * + * @var string + */ + const START_OF_EMBED = '`(?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(?:\??->(?P>varname)|\[[^\]\'"\s]+\])?`'; + /** * Get the complete contents of a - potentially multi-line - text string. * @@ -43,7 +67,7 @@ class TextStrings * quotes off the resulting text string. * Defaults to `true`. * - * @return string The complete text string. + * @return string The contents of the complete text string. * * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a * valid text string token. @@ -51,41 +75,83 @@ class TextStrings * token in a text string. */ public static function getCompleteTextString(File $phpcsFile, $stackPtr, $stripQuotes = true) + { + $tokens = $phpcsFile->getTokens(); + $end = self::getEndOfCompleteTextString($phpcsFile, $stackPtr); + + $stripNewline = false; + if ($tokens[$stackPtr]['code'] === \T_START_HEREDOC || $tokens[$stackPtr]['code'] === \T_START_NOWDOC) { + $stripQuotes = false; + $stripNewline = true; + $stackPtr = ($stackPtr + 1); + } + + $contents = GetTokensAsString::normal($phpcsFile, $stackPtr, $end); + + if ($stripNewline === true) { + // Heredoc/nowdoc: strip the new line at the end of the string to emulate how PHP sees the string. + $contents = \rtrim($contents, "\r\n"); + } + + if ($stripQuotes === true) { + return self::stripQuotes($contents); + } + + return $contents; + } + + /** + * Get the stack pointer to the end of a - potentially multi-line - text string. + * + * @see \PHPCSUtils\Utils\TextStrings::getCompleteTextString() Retrieve the contents of a complete - potentially + * multi-line - text string. + * + * @since 1.0.0-alpha4 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. + * @param int $stackPtr Pointer to the first text string token + * of a - potentially multi-line - text string + * or to a Nowdoc/Heredoc opener. + * + * @return int Stack pointer to the last token in the text string. + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified position is not a + * valid text string token. + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified token is not the _first_ + * token in a text string. + */ + public static function getEndOfCompleteTextString(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); // Must be the start of a text string token. - if (isset($tokens[$stackPtr], Collections::$textStingStartTokens[$tokens[$stackPtr]['code']]) === false) { + if (isset($tokens[$stackPtr], Collections::textStringStartTokens()[$tokens[$stackPtr]['code']]) === false) { throw new RuntimeException( '$stackPtr must be of type T_START_HEREDOC, T_START_NOWDOC, T_CONSTANT_ENCAPSED_STRING' . ' or T_DOUBLE_QUOTED_STRING' ); } - if ($tokens[$stackPtr]['code'] === \T_CONSTANT_ENCAPSED_STRING - || $tokens[$stackPtr]['code'] === \T_DOUBLE_QUOTED_STRING - ) { + if (isset(Tokens::$stringTokens[$tokens[$stackPtr]['code']]) === true) { $prev = $phpcsFile->findPrevious(\T_WHITESPACE, ($stackPtr - 1), null, true); if ($tokens[$stackPtr]['code'] === $tokens[$prev]['code']) { throw new RuntimeException('$stackPtr must be the start of the text string'); } } - $stripNewline = false; + if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) { + return Cache::get($phpcsFile, __METHOD__, $stackPtr); + } switch ($tokens[$stackPtr]['code']) { case \T_START_HEREDOC: - $stripQuotes = false; - $stripNewline = true; - $targetType = \T_HEREDOC; - $current = ($stackPtr + 1); + $targetType = \T_HEREDOC; + $current = ($stackPtr + 1); break; case \T_START_NOWDOC: - $stripQuotes = false; - $stripNewline = true; - $targetType = \T_NOWDOC; - $current = ($stackPtr + 1); + $targetType = \T_NOWDOC; + $current = ($stackPtr + 1); break; default: @@ -94,40 +160,169 @@ public static function getCompleteTextString(File $phpcsFile, $stackPtr, $stripQ break; } - $string = ''; - do { - $string .= $tokens[$current]['content']; + while (isset($tokens[$current]) && $tokens[$current]['code'] === $targetType) { ++$current; - } while (isset($tokens[$current]) && $tokens[$current]['code'] === $targetType); - - if ($stripNewline === true) { - // Heredoc/nowdoc: strip the new line at the end of the string to emulate how PHP sees the string. - $string = \rtrim($string, "\r\n"); } - if ($stripQuotes === true) { - return self::stripQuotes($string); - } + $lastPtr = ($current - 1); - return $string; + Cache::set($phpcsFile, __METHOD__, $stackPtr, $lastPtr); + return $lastPtr; } /** - * Strip text delimiter quotes from an arbitrary string. + * Strip text delimiter quotes from an arbitrary text string. * - * Intended for use with the "contents" of a `T_CONSTANT_ENCAPSED_STRING` / `T_DOUBLE_QUOTED_STRING`. + * Intended for use with the "content" of a `T_CONSTANT_ENCAPSED_STRING` / `T_DOUBLE_QUOTED_STRING`. * * - Prevents stripping mis-matched quotes. - * - Prevents stripping quotes from the textual content of the string. + * - Prevents stripping quotes from the textual content of the text string. * * @since 1.0.0 * - * @param string $string The raw string. + * @param string $textString The raw text string. * - * @return string String without quotes around it. + * @return string Text string without quotes around it. */ - public static function stripQuotes($string) + public static function stripQuotes($textString) { - return \preg_replace('`^([\'"])(.*)\1$`Ds', '$2', $string); + return \preg_replace('`^([\'"])(.*)\1$`Ds', '$2', $textString); + } + + /** + * Get the embedded variables/expressions from an arbitrary string. + * + * Note: this function gets the complete variables/expressions _as they are embedded_, + * i.e. including potential curly brace wrappers, array access, method calls etc. + * + * @since 1.0.0-alpha4 + * + * @param string $text The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. + * + * @return array Array of encountered variable names/expressions with the offset at which + * the variable/expression was found in the string, as the key. + */ + public static function getEmbeds($text) + { + return self::getStripEmbeds($text)['embeds']; + } + + /** + * Strip embedded variables/expressions from an arbitrary string. + * + * @since 1.0.0-alpha4 + * + * @param string $text The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. + * + * @return string String without variables/expressions in it. + */ + public static function stripEmbeds($text) + { + return self::getStripEmbeds($text)['remaining']; + } + + /** + * Split an arbitrary text string into embedded variables/expressions and remaining text. + * + * PHP contains four types of embedding syntaxes: + * 1. Directly embedding variables ("$foo"); + * 2. Braces outside the variable ("{$foo}"); + * 3. Braces after the dollar sign ("${foo}"); + * 4. Variable variables ("${expr}", equivalent to (string) ${expr}). + * + * Type 3 and 4 are deprecated as of PHP 8.2 and will be removed in PHP 9.0. + * + * This method handles all types of embeds, including recognition of whether an embed is escaped or not. + * + * @link https://www.php.net/language.types.string#language.types.string.parsing PHP Manual on string parsing + * @link https://wiki.php.net/rfc/deprecate_dollar_brace_string_interpolation PHP RFC on deprecating select + * string interpolation syntaxes + * + * @since 1.0.0-alpha4 + * + * @param string $text The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token. + * + * @return array Array containing two values: + * 1. An array containing a string representation of each embed encountered. + * The keys in this array are the integer offset within the original string + * where the embed was found. + * 2. The textual contents, embeds stripped out of it. + * The format of the array return value is: + * ```php + * array( + * 'embeds' => array, + * 'remaining' => string, + * ) + * ``` + */ + public static function getStripEmbeds($text) + { + if (\strpos($text, '$') === false) { + return [ + 'embeds' => [], + 'remaining' => $text, + ]; + } + + $textHash = \md5($text); + if (NoFileCache::isCached(__METHOD__, $textHash) === true) { + return NoFileCache::get(__METHOD__, $textHash); + } + + $offset = 0; + $strLen = \strlen($text); // Use iconv ? + $stripped = ''; + $variables = []; + + while (\preg_match(self::START_OF_EMBED, $text, $matches, \PREG_OFFSET_CAPTURE, $offset) === 1) { + $stripped .= \substr($text, $offset, ($matches[2][1] - $offset)); + + $matchedExpr = $matches[2][0]; + $matchedOffset = $matches[2][1]; + $braces = \substr_count($matchedExpr, '{'); + $newOffset = $matchedOffset + \strlen($matchedExpr); + + if ($braces === 0) { + /* + * Type 1: simple variable embed. + * Regex will always return a match due to the look ahead in the above regex. + */ + \preg_match(self::TYPE1_EMBED_AFTER_DOLLAR, $text, $endMatch, 0, $newOffset); + $matchedExpr .= $endMatch[0]; + $variables[$matchedOffset] = $matchedExpr; + $offset = $newOffset + \strlen($endMatch[0]); + continue; + } + + for (; $newOffset < $strLen; $newOffset++) { + if ($text[$newOffset] === '{') { + ++$braces; + continue; + } + + if ($text[$newOffset] === '}') { + --$braces; + if ($braces === 0) { + $matchedExpr = \substr($text, $matchedOffset, (1 + $newOffset - $matchedOffset)); + $variables[$matchedOffset] = $matchedExpr; + $offset = ($newOffset + 1); + break; + } + } + } + } + + if ($offset < $strLen) { + // Add the end of the string. + $stripped .= \substr($text, $offset); + } + + $returnValue = [ + 'embeds' => $variables, + 'remaining' => $stripped, + ]; + + NoFileCache::set(__METHOD__, $textHash, $returnValue); + return $returnValue; } } diff --git a/PHPCSUtils/Utils/UseStatements.php b/PHPCSUtils/Utils/UseStatements.php index 24fd5fa6..ad53bd19 100644 --- a/PHPCSUtils/Utils/UseStatements.php +++ b/PHPCSUtils/Utils/UseStatements.php @@ -13,7 +13,7 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\Utils\Conditions; use PHPCSUtils\Utils\Parentheses; @@ -21,8 +21,9 @@ * Utility functions for examining use statements. * * @since 1.0.0 + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class UseStatements +final class UseStatements { /** @@ -58,6 +59,13 @@ public static function getType(File $phpcsFile, $stackPtr) return ''; } + // More efficient & simpler check for closure use in PHPCS 4.x. + if (isset($tokens[$stackPtr]['parenthesis_owner']) + && $tokens[$stackPtr]['parenthesis_owner'] === $stackPtr + ) { + return 'closure'; + } + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($prev !== false && $tokens[$prev]['code'] === \T_CLOSE_PARENTHESIS && Parentheses::isOwnerIn($phpcsFile, $prev, \T_CLOSURE) === true @@ -71,8 +79,8 @@ public static function getType(File $phpcsFile, $stackPtr) return 'import'; } - $traitScopes = BCTokens::ooScopeTokens(); - // Only classes and traits can import traits. + $traitScopes = Tokens::$ooScopeTokens; + // Only classes, traits and enums can import traits. unset($traitScopes[\T_INTERFACE]); if (isset($traitScopes[$tokens[$lastCondition]['code']]) === true) { @@ -145,6 +153,7 @@ public static function isTraitUse(File $phpcsFile, $stackPtr) * Handles single import, multi-import and group-import use statements. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. * @param int $stackPtr The position in the stack of the `T_USE` token. @@ -204,7 +213,11 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) return $statements; } - $endOfStatement++; + if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) { + return Cache::get($phpcsFile, __METHOD__, $stackPtr); + } + + ++$endOfStatement; $start = true; $useGroup = false; @@ -221,25 +234,6 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) } $tokenCode = $tokens[$i]['code']; - - /* - * BC: Work round a tokenizer bug related to a parse error. - * - * If `function` or `const` is used as the alias, the semi-colon after it would - * be tokenized as T_STRING. - * For `function` this was fixed in PHPCS 2.8.0. For `const` the issue still exists - * in PHPCS 3.5.2. - * - * Along the same lines, the `}` T_CLOSE_USE_GROUP would also be tokenized as T_STRING. - */ - if ($tokenCode === \T_STRING) { - if ($tokens[$i]['content'] === ';') { - $tokenCode = \T_SEMICOLON; - } elseif ($tokens[$i]['content'] === '}') { - $tokenCode = \T_CLOSE_USE_GROUP; - } - } - switch ($tokenCode) { case \T_STRING: // Only when either at the start of the statement or at the start of a new sub within a group. @@ -269,6 +263,27 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) $alias = $tokens[$i]['content']; break; + case \T_NAME_QUALIFIED: + case \T_NAME_FULLY_QUALIFIED: // This would be a parse error, but handle it anyway. + /* + * PHPCS 4.x. + * + * These tokens can only be encountered when either at the start of the statement + * or at the start of a new sub within a group. + */ + if ($start === true && $fixedType === false) { + $type = 'name'; + } + + $start = false; + + if ($hasAlias === false) { + $name .= $tokens[$i]['content']; + } + + $alias = \substr($tokens[$i]['content'], (\strrpos($tokens[$i]['content'], '\\') + 1)); + break; + case \T_AS: $hasAlias = true; break; @@ -309,42 +324,14 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) $name .= $tokens[$i]['content']; break; - case \T_FUNCTION: - case \T_CONST: - /* - * BC: Work around tokenizer bug in PHPCS < 3.4.1. - * - * `function`/`const` in `use function`/`use const` tokenized as T_FUNCTION/T_CONST - * instead of T_STRING when there is a comment between the keywords. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2431 - */ - if ($start === true && $fixedType === false) { - $type = \strtolower($tokens[$i]['content']); - $start = false; - if ($useGroup === false) { - $fixedType = true; - } - - break; - } - - $start = false; - - if ($hasAlias === false) { - $name .= $tokens[$i]['content']; - } - - $alias = $tokens[$i]['content']; - break; - /* * Fall back in case reserved keyword is (illegally) used in name. * Parse error, but not our concern. */ default: if ($hasAlias === false) { - $name .= $tokens[$i]['content']; + // Defensive coding, just in case. Should no longer be possible since PHPCS 3.7.0. + $name .= $tokens[$i]['content']; // @codeCoverageIgnore } $alias = $tokens[$i]['content']; @@ -352,6 +339,7 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) } } + Cache::set($phpcsFile, __METHOD__, $stackPtr, $statements); return $statements; } @@ -367,6 +355,7 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) * * @see \PHPCSUtils\AbstractSniffs\AbstractFileContextSniff * @see \PHPCSUtils\Utils\UseStatements::splitImportUseStatement() + * @see \PHPCSUtils\Utils\UseStatements::mergeImportUseStatements() * * @since 1.0.0-alpha3 * @@ -383,30 +372,62 @@ public static function splitImportUseStatement(File $phpcsFile, $stackPtr) * the previously collected `use` statement information. * See {@see UseStatements::splitImportUseStatement()} for more details about the array format. */ - public static function splitAndMergeImportUseStatement(File $phpcsFile, $stackPtr, $previousUseStatements) + public static function splitAndMergeImportUseStatement(File $phpcsFile, $stackPtr, array $previousUseStatements) { try { - $useStatements = self::splitImportUseStatement($phpcsFile, $stackPtr); - - if (isset($previousUseStatements['name']) === false) { - $previousUseStatements['name'] = $useStatements['name']; - } else { - $previousUseStatements['name'] += $useStatements['name']; - } - if (isset($previousUseStatements['function']) === false) { - $previousUseStatements['function'] = $useStatements['function']; - } else { - $previousUseStatements['function'] += $useStatements['function']; - } - if (isset($previousUseStatements['const']) === false) { - $previousUseStatements['const'] = $useStatements['const']; - } else { - $previousUseStatements['const'] += $useStatements['const']; - } + $useStatements = self::splitImportUseStatement($phpcsFile, $stackPtr); + $previousUseStatements = self::mergeImportUseStatements($previousUseStatements, $useStatements); } catch (RuntimeException $e) { // Not an import use statement. } return $previousUseStatements; } + + /** + * Merge two import use statement arrays. + * + * Beware: this method should only be used to combine the import use statements found in *one* file. + * Do NOT combine the statements of multiple files as the result will be inaccurate and unreliable. + * + * @see \PHPCSUtils\Utils\UseStatements::splitImportUseStatement() + * + * @since 1.0.0-alpha4 + * + * @param array $previousUseStatements The import `use` statements collected so far. + * This should be either the output of a + * previous call to this method or the output of + * an earlier call to the + * {@see UseStatements::splitImportUseStatement()} + * method. + * @param array $currentUseStatement The parsed import `use` statements to merge with + * the previously collected use statements. + * This should be the output of a call to the + * {@see UseStatements::splitImportUseStatement()} + * method. + * + * @return array A multi-level array containing information about the current `use` statement combined with + * the previously collected `use` statement information. + * See {@see UseStatements::splitImportUseStatement()} for more details about the array format. + */ + public static function mergeImportUseStatements(array $previousUseStatements, array $currentUseStatement) + { + if (isset($previousUseStatements['name']) === false) { + $previousUseStatements['name'] = $currentUseStatement['name']; + } else { + $previousUseStatements['name'] += $currentUseStatement['name']; + } + if (isset($previousUseStatements['function']) === false) { + $previousUseStatements['function'] = $currentUseStatement['function']; + } else { + $previousUseStatements['function'] += $currentUseStatement['function']; + } + if (isset($previousUseStatements['const']) === false) { + $previousUseStatements['const'] = $currentUseStatement['const']; + } else { + $previousUseStatements['const'] += $currentUseStatement['const']; + } + + return $previousUseStatements; + } } diff --git a/PHPCSUtils/Utils/Variables.php b/PHPCSUtils/Utils/Variables.php index e24c0056..5fc346a6 100644 --- a/PHPCSUtils/Utils/Variables.php +++ b/PHPCSUtils/Utils/Variables.php @@ -20,11 +20,12 @@ /** * Utility functions for use when examining variables. * - * @since 1.0.0 The `Variables::getMemberProperties()` method is based on and inspired by - * the method of the same name in the PHPCS native `PHP_CodeSniffer\Files\File` class. - * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * @since 1.0.0 The `Variables::getMemberProperties()` method is based on and inspired by + * the method of the same name in the PHPCS native `PHP_CodeSniffer\Files\File` class. + * Also see {@see \PHPCSUtils\BackCompat\BCFile}. + * @since 1.0.0-alpha4 Dropped support for PHPCS < 3.7.1. */ -class Variables +final class Variables { /** @@ -36,9 +37,9 @@ class Variables * The variables names are set without the leading dollar sign to allow this array * to be used with array index keys as well. Think: `'_GET'` in `$GLOBALS['_GET']`.} * - * @since 1.0.0 + * @link https://php.net/reserved.variables PHP Manual on reserved variables * - * @link http://php.net/reserved.variables PHP Manual on reserved variables + * @since 1.0.0 * * @var array => */ @@ -80,11 +81,18 @@ class Variables * This will now throw the same _"$stackPtr is not a class member var"_ runtime exception as * other non-property variables passed to the method. * - Defensive coding against incorrect calls to this method. + * - Support PHP 8.0 identifier name tokens in property types, cross-version PHP & PHPCS. + * - Support for the PHP 8.2 `true` type. * * @see \PHP_CodeSniffer\Files\File::getMemberProperties() Original source. * @see \PHPCSUtils\BackCompat\BCFile::getMemberProperties() Cross-version compatible version of the original. * * @since 1.0.0 + * @since 1.0.0-alpha4 Added support for PHP 8.0 union types. + * @since 1.0.0-alpha4 No longer gets confused by PHP 8.0 property attributes. + * @since 1.0.0-alpha4 Added support for PHP 8.1 readonly properties. + * @since 1.0.0-alpha4 Added support for PHP 8.1 intersection types. + * @since 1.0.0-alpha4 Added support for PHP 8.2 true type. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position in the stack of the `T_VARIABLE` token @@ -97,12 +105,14 @@ class Variables * 'scope' => string, // Public, private, or protected. * 'scope_specified' => boolean, // TRUE if the scope was explicitly specified. * 'is_static' => boolean, // TRUE if the static keyword was found. + * 'is_readonly' => boolean, // TRUE if the readonly keyword was found. * 'type' => string, // The type of the var (empty if no type specified). * 'type_token' => integer, // The stack pointer to the start of the type * // or FALSE if there is no type. * 'type_end_token' => integer, // The stack pointer to the end of the type * // or FALSE if there is no type. - * 'nullable_type' => boolean, // TRUE if the type is nullable. + * 'nullable_type' => boolean, // TRUE if the type is preceded by the + * // nullability operator. * ); * ``` * @@ -123,17 +133,19 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) throw new RuntimeException('$stackPtr is not a class member var'); } - $valid = Collections::$propertyModifierKeywords + Tokens::$emptyTokens; + $valid = Collections::propertyModifierKeywords() + Tokens::$emptyTokens; $scope = 'public'; $scopeSpecified = false; $isStatic = false; + $isReadonly = false; $startOfStatement = $phpcsFile->findPrevious( [ \T_SEMICOLON, \T_OPEN_CURLY_BRACKET, \T_CLOSE_CURLY_BRACKET, + \T_ATTRIBUTE_END, ], ($stackPtr - 1) ); @@ -159,6 +171,9 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) case \T_STATIC: $isStatic = true; break; + case \T_READONLY: + $isReadonly = true; + break; } } @@ -166,7 +181,13 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) $typeToken = false; $typeEndToken = false; $nullableType = false; - $propertyTypeTokens = Collections::propertyTypeTokensBC(); + $propertyTypeTokens = Collections::propertyTypeTokens(); + + /* + * BC PHPCS < 3.x.x: The union type separator is not (yet) retokenized correctly + * for union types containing the `true` type. + */ + $propertyTypeTokens[\T_BITWISE_OR] = \T_BITWISE_OR; if ($i < $stackPtr) { // We've found a type. @@ -176,10 +197,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) break; } - if ($tokens[$i]['type'] === 'T_NULLABLE' - // Handle nullable types in PHPCS < 3.5.0 and for PHP-4 style `var` properties in PHPCS < 3.5.4. - || $tokens[$i]['code'] === \T_INLINE_THEN - ) { + if ($tokens[$i]['code'] === \T_NULLABLE) { $nullableType = true; } @@ -202,6 +220,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr) 'scope' => $scope, 'scope_specified' => $scopeSpecified, 'is_static' => $isStatic, + 'is_readonly' => $isReadonly, 'type' => $type, 'type_token' => $typeToken, 'type_end_token' => $typeEndToken, diff --git a/README.md b/README.md index 6fa86e87..81dda22c 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,114 @@ -PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer -===================================================== +# PHPCSUtils: A suite of utility functions for use with PHP_CodeSniffer -[![Latest Stable Version](https://poser.pugx.org/phpcsstandards/phpcsutils/v/stable)](https://packagist.org/packages/phpcsstandards/phpcsutils) -[![Travis Build Status](https://travis-ci.com/PHPCSStandards/PHPCSUtils.svg?branch=master)](https://travis-ci.com/PHPCSStandards/PHPCSUtils/branches) -[![Release Date of the Latest Version](https://img.shields.io/github/release-date/PHPCSStandards/PHPCSUtils.svg?maxAge=1800)](https://github.com/PHPCSStandards/PHPCSUtils/releases) + * [Features](#features) * [Minimum Requirements](#minimum-requirements) * [Integrating PHPCSUtils in your external PHPCS standard](#integrating-phpcsutils-in-your-external-phpcs-standard) - + [Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0](#composer-based-with-a-minimum-phpcs-requirement-of-phpcs-310) - + [Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0](#composer-based-with-a-minimum-phpcs-requirement-of-phpcs-260) - + [Non-Composer based integration](#non-composer-based-integration) + - [Composer-based](#composer-based) + - [Non-Composer based integration](#non-composer-based-integration) * [Frequently Asked Questions](#frequently-asked-questions) * [Potential Support Questions from your End-Users](#potential-support-questions-from-your-end-users) * [Contributing](#contributing) * [License](#license) -Features -------------------------------------------- +## Features -[PHPCSUtils](https://github.com/PHPCSStandards/PHPCSUtils) is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) (or "PHPCS" for short). +[PHPCSUtils][phpcsutils-repo] is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer] (or "PHPCS" for short). This package offers the following features:
-### Use the latest version of PHP_CodeSniffer native utility functions. - -Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard. +### An ever-growing number of utility functions for use with PHP_CodeSniffer -Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 2.6.0 and up. +Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a DocBlock, PHPCSUtils has got you covered! -### Several abstract sniff classes which your sniffs can extend. +Includes improved versions of the PHPCS native utility functions and plenty of new utility functions. -These classes take most of the heavy lifting away for some frequently occurring sniff types. +These functions are compatible with PHPCS 3.7.1 up to PHPCS `master`. -### A collection of static properties and methods for often-used token groups. +### A collection of static properties and methods for often-used token groups Collections of related tokens often-used and needed for sniffs. These are additional "token groups" to compliment the ones available through the PHPCS native `PHP_CodeSniffer\Util\Tokens` class. -### An ever-growing number of utility functions for use with PHP_CodeSniffer. - -Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a DocBlock, PHPCSUtils has got you covered! - -Includes improved versions of the PHPCS native utility functions and plenty of new utility functions. +### Several abstract sniff classes which your sniffs can extend -These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS `master`. +These classes take most of the heavy lifting away for some frequently occurring sniff types. ### Test utilities An abstract `UtilityMethodTestCase` class to support testing of your utility methods written for PHP_CodeSniffer. -Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x. +Supports PHPUnit 4.x up to 9.x. -### Backward compatibility layer +### Use the latest version of PHP_CodeSniffer native utility functions -A `PHPCS23Utils` standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a few helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x. +Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard. + +Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 3.7.1 and up. ### Fully documented -To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation](https://phpcsutils.com/). +To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation][phpcsutils-web].
-Minimum Requirements -------------------------------------------- + +## Minimum Requirements * PHP 5.4 or higher. -* [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3). +* [PHP_CodeSniffer] 3.7.1+. * Recommended PHP extensions for optimal functionality: - PCRE with Unicode support (normally enabled by default) -Integrating PHPCSUtils in your external PHPCS standard -------------------------------------------- +## Integrating PHPCSUtils in your external PHPCS standard -### Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0 +### Composer-based -If your external PHP_CodeSniffer standard only supports Composer-based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward. +If your external PHP_CodeSniffer standard only supports Composer-based installs, integrating PHPCSUtils is pretty straight forward. Run the following from the root of your external PHPCS standard's project: + ```bash +composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true composer require phpcsstandards/phpcsutils:^1.0 ``` No further action needed. You can start using all the utility functions, abstract sniff classes and other features of PHPCSUtils straight away. -> :information_source: The PHPCSUtils package includes the [DealerDirect Composer PHPCS plugin](https://github.com/Dealerdirect/phpcodesniffer-composer-installer). +> :information_source: The PHPCSUtils package includes the [Composer PHPCS plugin]. > > This plugin will automatically register PHPCSUtils (and your own external standard) with PHP_CodeSniffer, so you and your users don't have to worry about this anymore. > > :warning: Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the `--config-set installed_paths` command, you can remove those instructions as they are no longer needed. +> +> :information_source: As of Composer 2.2, Composer will [ask for permission](https://blog.packagist.com/composer-2-2/#more-secure-plugin-execution) to allow the Composer PHPCS plugin to execute code. For the plugin to be functional, permission needs to be granted. +> This can be done ahead of time by instructing your users to run the following command before installing your standard: +> +> ```bash +> composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true +> ``` #### Running your unit tests @@ -114,25 +119,6 @@ If you have your own unit test suite to test your sniffs, make sure to load the If you intend to use the test utilities provided in the `PHPCSUtils/TestUtils` directory, make sure you also load the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file in your PHPUnit bootstrap file. -### Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0 - -Follow the above instructions for use with PHPCS 3.x. - -In addition to that, add the following to the `ruleset.xml` file of your standard(s): -```xml - - -``` - -> :information_source: The `PHPCS23Utils` "standard" does not add any real sniffs, it only makes sure that the Utility functions will work in PHPCS 2.x as well. - -#### Running your unit tests - -If your standard supports both PHPCS 2.x as well as 3.x, you are bound to already have a PHPUnit `bootstrap.php` file in place. - -To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the Composer `vendor/autoload.php` file, as well as the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file. - - ### Non-Composer based integration In this case, more than anything, you will need to update the non-Composer installation instructions for your end-users. @@ -141,28 +127,34 @@ To use a non-Composer based installation for your sniff development environment, Your installation instructions for a non-Composer based installation will probably look similar to this: -> * Install [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) via [your preferred method](https://github.com/squizlabs/PHP_CodeSniffer#installation). +> * Install [PHP_CodeSniffer] via [your preferred method](https://github.com/squizlabs/PHP_CodeSniffer#installation). > * Register the path to PHPCS in your system `$PATH` environment variable to make the `phpcs` command available from anywhere in your file system. -> * Download the [latest _YourStandardName_ release] and unzip/untar it into an arbitrary directory. +> * Download the \[latest _YourStandardName_ release\] and unzip/untar it into an arbitrary directory. > You can also choose to clone the repository using git. > * Add the path to the directory in which you placed your copy of the _YourStandardName_ repo to the PHP_CodeSniffer configuration using the below command: +> > ```bash > phpcs --config-set installed_paths /path/to/YourStandardName > ``` +> > **Warning**: :warning: The `installed_paths` command overwrites any previously set `installed_paths`. If you have previously set `installed_paths` for other external standards, run `phpcs --config-show` first and then run the `installed_paths` command with all the paths you need separated by comma's, i.e.: +> > ```bash > phpcs --config-set installed_paths /path/1,/path/2,/path/3 > ``` For things to continue working when you add PHPCSUtils to your standard, you need to replace the last bullet with this: -> * **Next, download the [latest PHPCSUtils release](https://github.com/PHPCSStandards/PHPCSUtils/releases) and unzip/untar it into an arbitrary directory.** +> * **Next, download the [latest PHPCSUtils release][phpcsutils-releases] and unzip/untar it into an arbitrary directory.** > You can also choose to clone the repository using git. > * Add the path to the **directories** in which you placed your copy of the _YourStandardName_ repo **and the PHPCSUtils repo** to the PHP_CodeSniffer configuration using the below command: +> > ```bash > phpcs --config-set installed_paths /path/to/YourStandardName,/path/to/PHPCSUtils > ``` +> > **Warning**: :warning: The `installed_paths` command overwrites any previously set `installed_paths`. If you have previously set `installed_paths` for other external standards, run `phpcs --config-show` first and then run the `installed_paths` command with all the paths you need separated by comma's, i.e.: +> > ```bash > phpcs --config-set installed_paths /path/1,/path/2,/path/3 > ``` @@ -186,7 +178,7 @@ if ($phpcsUtilDir === false && file_exists(__DIR__ . '/vendor/autoload.php')) { // Load the Composer autoload file. require_once $vendorDir . '/autoload.php'; - // This snippet is only needed when you use the PHPCSUtils TestUtils or if your standard still supports PHPCS 2.x. + // This snippet is only needed when you use the PHPCSUtils TestUtils. if (file_exists($phpcsUtilDir . '/phpcsutils-autoload.php')) { require_once $phpcsUtilDir . '/phpcsutils-autoload.php'; } @@ -209,9 +201,11 @@ pointing to the PHPCS directory. -Once that's done, you will need to make a small tweak to your own dev environment to get the unit tests runnning for a non-Composer based install: +Once that's done, you will need to make a small tweak to your own dev environment to get the unit tests running for a non-Composer based install: + * Copy your project's `phpunit.xml.dist` file to `phpunit.xml`. * Add the following to the `phpunit.xml` file within the `` tags, replacing `/path/to/PHPCSUtils` with the path in which you installed PHPCSUtils on your local system: + ```xml @@ -219,85 +213,84 @@ Once that's done, you will need to make a small tweak to your own dev environmen ``` -Frequently Asked Questions -------- +## Frequently Asked Questions -
+
-#### Q: How does this all work without an external standard needing to register an autoloader? +### Q: How does this all work without an external standard needing to register an autoloader? A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes used from PHPCSUtils. -#### Q: What does the `PHPCS23Utils` standard do? - -A: All the `PHPCS23Utils` standard does is load the `phpcsutils-autoload.php` file. - -PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The `phpcsutils-autoload.php` file creates `class_alias`-es for the most commonly used PHPCS classes, including all PHPCS classes used by PHPCSUtils. That way, both your external standard as well as PHPCSUtils can refer to the PHPCS 3.x class names and the code will still work in PHPCS 2.x. - -#### Q: Why is PHP_CodeSniffer 3.5.3 not supported? - -A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer 3.5.3 is broken and there is no way to reliably provide support for anything to do with numbers or `T_STRING` tokens when using PHP_CodeSniffer 3.5.3 as the tokens returned by the tokenizer are unpredictable and unreliable. - -The backfill was fixed in PHP_CodeSniffer 3.5.4. - -#### Q: Any other problematic PHPCS versions? - -A: Well, the arrow function backfill which was added in PHPCS 3.5.3 is still causing problems. In a very limited set of circumstances, it will even hang the Tokenizer. A fix for [one particular such problem](https://github.com/squizlabs/php_codesniffer/issues/2926) has been committed to `master`, but is not (yet) in a released version. It is expected to be released in PHP_CodeSniffer 3.5.6. - -As the Tokenizer hanging is a problem unrelated to PHPCSUtils and not something which can be mitigated from within PHPCSUtils in any conceivable way, PHPCSUtils won't block installation in combination with PHPCS 3.5.4 and 3.5.5. - -There are several other issues which can not be worked around, like scope closers being set incorrectly and throwing the scope setting off for the rest of the file, so not withstanding that PHPCSUtils can work around a lot of issues, it is still highly recommended to advise your end-users to always use the latest version of PHPCS for the most reliable results. - -#### Q: Does using PHPCSUtils have any effect on the PHPCS native sniffs? +### Q: Does using PHPCSUtils have any effect on the PHPCS native sniffs? A: No. PHPCSUtils will only work for those sniffs which explicitly use the PHPCSUtils functionality. If your standard includes both PHPCS native sniffs as well as your own sniffs, your own sniffs can benefit from the back-compat layer offered by PHPCSUtils, as well as from the additional utility functions. However, the PHPCS native sniffs will not receive those benefits, as PHPCS itself does not use PHPCSUtils. -#### Q: Do the utilities work with javascript/CSS files? +### Q: Do the utilities work with javascript/CSS files? -A: JS/CSS support will be removed from PHP_CodeSniffer in PHPCS 4.x. -While at this time, some of the utilies _may_ work with JS/CSS files, PHPCSUtils does not offer formal support for JS/CSS sniffing with PHP_CodeSniffer and will stop any existing support once PHPCS 4.x has been released. +A: JS/CSS support will be removed from `PHP_CodeSniffer` in PHPCS 4.x. +While at this time, some of the utilities _may_ work with JS/CSS files, PHPCSUtils does not offer formal support for JS/CSS sniffing with `PHP_CodeSniffer` and will stop any existing support once PHPCS 4.x has been released. -#### Q: Are all file encodings supported? +### Q: Are all file encodings supported? A: No. The UTF-8 file encoding is the only officially supported encoding. Support for other encodings may incidentally work, but is not officially supported. > **It is recommended to advise your users to save their files as UTF-8 encoded for the best results.** -PHP_CodeSniffer 3.x will default to UTF-8 as the expected file encoding. -If your standard supports PHP_CodeSniffer 2.x, it is recommended to set the expected encoding in the ruleset to `utf-8`, like so: `` or to advise users to use the CLI option `--encoding=utf-8`. +Note: `PHP_CodeSniffer` 3.x defaults to UTF-8 as the expected file encoding. + +
+ +## Potential Support Questions from your End-Users -Potential Support Questions from your End-Users -------- +
-#### Q: A user reports a fatal "class not found" error for a class from PHPCSUtils. +### Q: A user reports a fatal "class not found" error for a class from PHPCSUtils 1. Check that the version of PHPCSUtils the user has installed complies with the minimum version of PHPCSUtils your standard requires. If not, they will need to upgrade. 2. If the version is correct, this indicates that the end-user does not have PHPCSUtils installed and/or registered with PHP_CodeSniffer. - Please review your standard's installation instructions to make sure that PHPCSUtils will be installed when those are followed. - Inform the user to install PHPCSUtils and register it with PHP_CodeSniffer. +--- + > :bulb: **Pro-tip**: if you want to prevent the fatal error and show a _friendlier_ error message instead, add `` to your standard's `ruleset.xml` file. > -> With that in place, PHP_CodeSniffer will show a _"ERROR: the "PHPCSUtils" coding standard is not installed."_ message if PHPCSUtils is missing as soon as the ruleset loading is finished. +> With that in place, `PHP_CodeSniffer` will show a _"ERROR: the "PHPCSUtils" coding standard is not installed."_ message if PHPCSUtils is missing as soon as the ruleset loading is finished. + +--- > :bulb: **Pro-tip**: provide upgrade instructions for your end-users. For Composer-based installs, those should look like this: +> > ```bash -> composer update your/cs-package --with-dependencies +> composer update your/cs-package --with-[all-]dependencies > ``` +> > That way, when the user updates your coding standards package, they will automatically also update PHPCSUtils. +--- +
-Contributing -------- +## Contributing + Contributions to this project are welcome. Clone the repo, branch off from `develop`, make your changes, commit them and send in a pull request. If you are unsure whether the changes you are proposing would be welcome, please open an issue first to discuss your proposal. -License -------- -This code is released under the [GNU Lesser General Public License (LGPLv3)](http://www.gnu.org/copyleft/lesser.html). + +## License + +This code is released under the [GNU Lesser General Public License (LGPLv3)](https://www.gnu.org/copyleft/lesser.html). + + +[PHP_CodeSniffer]: https://github.com/squizlabs/PHP_CodeSniffer +[Composer PHPCS plugin]: https://github.com/PHPCSStandards/composer-installer +[phpcsutils-repo]: https://github.com/PHPCSStandards/PHPCSUtils +[phpcsutils-web]: https://phpcsutils.com/ +[phpcsutils-packagist]: https://packagist.org/packages/phpcsstandards/phpcsutils +[phpcsutils-releases]: https://github.com/PHPCSStandards/PHPCSUtils/releases +[phpcsutils-tests-gha]: https://github.com/PHPCSStandards/PHPCSUtils/actions/workflows/test.yml diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php index 1ea377ca..300e1173 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/AbstractArrayDeclarationSniffTest.php @@ -10,8 +10,8 @@ namespace PHPCSUtils\Tests\AbstractSniffs\AbstractArrayDeclaration; -use PHPCSUtils\Tests\AssertAttributeSame; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; +use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff class. @@ -22,10 +22,8 @@ * * @since 1.0.0 */ -class AbstractArrayDeclarationSniffTest extends UtilityMethodTestCase +final class AbstractArrayDeclarationSniffTest extends PolyfilledTestCase { - // Backfill for the assertAttributeSame() method on PHPUnit 9.x. - use AssertAttributeSame; /** * List of methods in the abstract which should be mocked. @@ -51,10 +49,7 @@ class AbstractArrayDeclarationSniffTest extends UtilityMethodTestCase */ public function testShortList() { - $target = $this->getTargetToken( - '/* testShortList */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortList */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -89,10 +84,7 @@ public function testShortList() */ public function testEmptyArray() { - $target = $this->getTargetToken( - '/* testEmptyArray */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testEmptyArray */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -129,7 +121,7 @@ public function testSingleLineShortArrayNoKeysNoTrailingComma() { $target = $this->getTargetToken( '/* testSingleLineShortArrayNoKeysNoTrailingComma */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] + Collections::arrayOpenTokensBC() ); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') @@ -196,7 +188,7 @@ public function testMultiLineLongArrayKeysTrailingComma() { $target = $this->getTargetToken( '/* testMultiLineLongArrayKeysTrailingComma */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] + Collections::arrayOpenTokensBC() ); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') @@ -293,7 +285,7 @@ public function testMultiLineShortArrayMixedKeysNoKeys() { $target = $this->getTargetToken( '/* testMultiLineShortArrayMixedKeysNoKeys */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] + Collections::arrayOpenTokensBC() ); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') @@ -386,10 +378,7 @@ public function testMultiLineShortArrayMixedKeysNoKeys() */ public function testEmptyArrayItem() { - $target = $this->getTargetToken( - '/* testEmptyArrayItem */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testEmptyArrayItem */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -420,10 +409,7 @@ public function testEmptyArrayItem() */ public function testShortCircuitOnProcessOpenClose() { - $target = $this->getTargetToken( - '/* testShortCircuit */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortCircuit */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -458,10 +444,7 @@ public function testShortCircuitOnProcessOpenClose() */ public function testShortCircuitOnProcessKey() { - $target = $this->getTargetToken( - '/* testShortCircuit */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortCircuit */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -496,10 +479,7 @@ public function testShortCircuitOnProcessKey() */ public function testShortCircuitOnProcessNoKey() { - $target = $this->getTargetToken( - '/* testShortCircuit */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortCircuit */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -534,10 +514,7 @@ public function testShortCircuitOnProcessNoKey() */ public function testShortCircuitOnProcessArrow() { - $target = $this->getTargetToken( - '/* testShortCircuit */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortCircuit */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -572,10 +549,7 @@ public function testShortCircuitOnProcessArrow() */ public function testShortCircuitOnProcessValue() { - $target = $this->getTargetToken( - '/* testShortCircuit */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortCircuit */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) @@ -610,10 +584,7 @@ public function testShortCircuitOnProcessValue() */ public function testShortCircuitOnProcessComma() { - $target = $this->getTargetToken( - '/* testShortCircuit */', - [\T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] - ); + $target = $this->getTargetToken('/* testShortCircuit */', Collections::arrayOpenTokensBC()); $mockObj = $this->getMockBuilder('\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff') ->setMethods($this->methodsToMock) diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php index 207810a4..b006753c 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/ArrayDeclarationSniffTestDouble.php @@ -18,7 +18,7 @@ * * @since 1.0.0 */ -class ArrayDeclarationSniffTestDouble extends AbstractArrayDeclarationSniff +final class ArrayDeclarationSniffTestDouble extends AbstractArrayDeclarationSniff { /** diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.inc b/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.inc index f13f3af8..ab29b362 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.inc +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.inc @@ -15,6 +15,14 @@ my $var text EOD => 'excluded', $var['key']{1} => 'excluded', + << 'excluded', + << 'excluded', ]; /* testAllEmptyString */ @@ -112,3 +120,19 @@ NOW => 6, "abc" => 7, ]; + +/* testHeredocWithEscapedVarInKey */ +$heredocStringKeyWithEscapedVar = [ + << 1, + << 2, + << 3, +]; diff --git a/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php b/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php index 3e2390c8..ed3b2fe4 100644 --- a/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php +++ b/Tests/AbstractSniffs/AbstractArrayDeclaration/GetActualArrayKeyTest.php @@ -24,7 +24,7 @@ * * @since 1.0.0 */ -class GetActualArrayKeyTest extends UtilityMethodTestCase +final class GetActualArrayKeyTest extends UtilityMethodTestCase { /** @@ -75,35 +75,69 @@ public function dataGetActualArrayKey() { return [ 'unsupported-key-types' => [ - '/* testAllVoid */', - null, - 0, + 'testMarker' => '/* testAllVoid */', + 'expected' => null, + 'expectedFrom' => 0, ], 'keys-all-empty-string' => [ - '/* testAllEmptyString */', - '', - 0, + 'testMarker' => '/* testAllEmptyString */', + 'expected' => '', + 'expectedFrom' => 0, ], 'keys-all-integer-zero' => [ - '/* testAllZero */', - 0, - 0, + 'testMarker' => '/* testAllZero */', + 'expected' => 0, + 'expectedFrom' => 0, ], 'keys-all-integer-one' => [ - '/* testAllOne */', - 1, - 1, + 'testMarker' => '/* testAllOne */', + 'expected' => 1, + 'expectedFrom' => 1, ], 'keys-all-integer-eleven' => [ - '/* testAllEleven */', - 11, - 0, + 'testMarker' => '/* testAllEleven */', + 'expected' => 11, + 'expectedFrom' => 0, ], 'keys-all-string-abc' => [ - '/* testAllStringAbc */', - 'abc', - 0, + 'testMarker' => '/* testAllStringAbc */', + 'expected' => 'abc', + 'expectedFrom' => 0, ], ]; } + + /** + * Test retrieving the actual array key from a heredoc when the key could contain interpolation, but doesn't, + * as the interpolation is escaped. + * + * @return void + */ + public function testGetActualArrayKeyFromHeredocWithEscapedVarInKey() + { + $testObj = new ArrayDeclarationSniffTestDouble(); + $testObj->tokens = self::$phpcsFile->getTokens(); + + $stackPtr = $this->getTargetToken('/* testHeredocWithEscapedVarInKey */', [\T_ARRAY, \T_OPEN_SHORT_ARRAY]); + $arrayItems = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + + $expected = [ + 1 => 'a{$b}c', + 2 => 'a$bc', + 3 => '$\{abc}', + ]; + + $this->assertCount(\count($expected), $arrayItems); + + foreach ($arrayItems as $itemNr => $arrayItem) { + $arrowPtr = Arrays::getDoubleArrowPtr(self::$phpcsFile, $arrayItem['start'], $arrayItem['end']); + $result = $testObj->getActualArrayKey(self::$phpcsFile, $arrayItem['start'], ($arrowPtr - 1)); + $this->assertSame( + $expected[$itemNr], + $result, + 'Failed: actual key ' . $result . ' is not the same as the expected key ' . $expected[$itemNr] + . ' for item number ' . $itemNr + ); + } + } } diff --git a/Tests/AssertAttributeSame.php b/Tests/AssertAttributeSame.php index 6bc8c914..d8f7bfd2 100644 --- a/Tests/AssertAttributeSame.php +++ b/Tests/AssertAttributeSame.php @@ -58,27 +58,27 @@ public function assertAttributeValueSame($expected, $attributeName, $actualObjec * Retrieve the value of an object's attribute. * This also works for attributes that are declared protected or private. * - * @param object|string $object The object or class on which to check the property value. - * @param string $attributeName The name of the property to check. + * @param object|string $objectUnderTest The object or class on which to check the property value. + * @param string $attributeName The name of the property to check. * * @return mixed Property value. * * @throws \Exception */ - public static function getObjectAttributeValue($object, $attributeName) + public static function getObjectAttributeValue($objectUnderTest, $attributeName) { - $reflector = new ReflectionObject($object); + $reflector = new ReflectionObject($objectUnderTest); do { try { $attribute = $reflector->getProperty($attributeName); if (!$attribute || $attribute->isPublic()) { - return $object->$attributeName; + return $objectUnderTest->$attributeName; } $attribute->setAccessible(true); - $value = $attribute->getValue($object); + $value = $attribute->getValue($objectUnderTest); $attribute->setAccessible(false); return $value; diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc b/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc index 921e7996..83516798 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.inc @@ -39,17 +39,67 @@ $a = [ /* testStaticArrowFunction */ static fn ($a) => $a; +return 0; + /* testArrowFunctionReturnValue */ fn(): array => [a($a, $b)]; +/* testArrowFunctionAsArgument */ $foo = foo( - /* testArrowFunctionAsArgument */ fn() => bar() ); +/* testArrowFunctionWithArrayAsArgument */ $foo = foo( - /* testArrowFunctionWithArrayAsArgument */ fn() => [$row[0], $row[3]] ); -return 0; +$match = match ($a) { + /* testMatchCase */ + 1 => 'foo', + /* testMatchDefault */ + default => 'bar' +}; + +$match = match ($a) { + /* testMatchMultipleCase */ + 1, 2, => $a * $b, + /* testMatchDefaultComma */ + default, => 'something' +}; + +match ($pressedKey) { + /* testMatchFunctionCall */ + Key::RETURN_ => save($value, $user) +}; + +$result = match (true) { + /* testMatchFunctionCallArm */ + str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en', + str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr', + default => 'pl' +}; + +/* testMatchClosure */ +$result = match ($key) { + 1 => function($a, $b) {}, + 2 => function($b, $c) {}, +}; + +/* testMatchArray */ +$result = match ($key) { + 1 => [1,2,3], + 2 => [1 => one(), 2 => two()], +}; + +/* testNestedMatch */ +$result = match ($key) { + 1 => match ($key) { + 1 => 'one', + 2 => 'two', + }, + 2 => match ($key) { + 1 => 'two', + 2 => 'one', + }, +}; diff --git a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php index e144d598..1f42fd45 100644 --- a/Tests/BackCompat/BCFile/FindEndOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindEndOfStatementTest.php @@ -24,7 +24,6 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::findEndOfStatement method. @@ -33,7 +32,7 @@ * * @since 1.0.0 */ -class FindEndOfStatementTest extends UtilityMethodTestCase +final class FindEndOfStatementTest extends UtilityMethodTestCase { /** @@ -163,7 +162,9 @@ public function testUseGroup() $start = $this->getTargetToken('/* testUseGroup */', T_USE); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); - $this->assertSame(($start + 23), $found); + $expected = parent::usesPhp8NameTokens() ? ($start + 21) : ($start + 23); + + $this->assertSame($expected, $found); } /** @@ -173,7 +174,7 @@ public function testUseGroup() */ public function testArrowFunctionArrayValue() { - $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', Collections::arrowFunctionTokensBC()); + $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_FN); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); $this->assertSame(($start + 9), $found); @@ -187,7 +188,7 @@ public function testArrowFunctionArrayValue() public function testStaticArrowFunction() { $static = $this->getTargetToken('/* testStaticArrowFunction */', T_STATIC); - $fn = $this->getTargetToken('/* testStaticArrowFunction */', Collections::arrowFunctionTokensBC()); + $fn = $this->getTargetToken('/* testStaticArrowFunction */', T_FN); $endOfStatementStatic = BCFile::findEndOfStatement(self::$phpcsFile, $static); $endOfStatementFn = BCFile::findEndOfStatement(self::$phpcsFile, $fn); @@ -202,7 +203,7 @@ public function testStaticArrowFunction() */ public function testArrowFunctionReturnValue() { - $start = $this->getTargetToken('/* testArrowFunctionReturnValue */', Collections::arrowFunctionTokensBC()); + $start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_FN); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); $this->assertSame(($start + 18), $found); @@ -215,7 +216,7 @@ public function testArrowFunctionReturnValue() */ public function testArrowFunctionAsArgument() { - $start = $this->getTargetToken('/* testArrowFunctionAsArgument */', Collections::arrowFunctionTokensBC()); + $start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); $this->assertSame(($start + 8), $found); @@ -228,12 +229,166 @@ public function testArrowFunctionAsArgument() */ public function testArrowFunctionWithArrayAsArgument() { - $start = $this->getTargetToken( - '/* testArrowFunctionWithArrayAsArgument */', - Collections::arrowFunctionTokensBC() - ); + $start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN); $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); $this->assertSame(($start + 17), $found); } + + /** + * Test simple match expression case. + * + * @return void + */ + public function testMatchCase() + { + $start = $this->getTargetToken('/* testMatchCase */', T_LNUMBER); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 5), $found); + + $start = $this->getTargetToken('/* testMatchCase */', T_CONSTANT_ENCAPSED_STRING); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 1), $found); + } + + /** + * Test simple match expression default case. + * + * @return void + */ + public function testMatchDefault() + { + $start = $this->getTargetToken('/* testMatchDefault */', T_MATCH_DEFAULT); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 4), $found); + + $start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame($start, $found); + } + + /** + * Test multiple comma-separated match expression case values. + * + * @return void + */ + public function testMatchMultipleCase() + { + $start = $this->getTargetToken('/* testMatchMultipleCase */', T_LNUMBER); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + $this->assertSame(($start + 13), $found); + + $start += 6; + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + $this->assertSame(($start + 7), $found); + } + + /** + * Test match expression default case with trailing comma. + * + * @return void + */ + public function testMatchDefaultComma() + { + $start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_DEFAULT); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 5), $found); + } + + /** + * Test match expression with function call. + * + * @return void + */ + public function testMatchFunctionCall() + { + $start = $this->getTargetToken('/* testMatchFunctionCall */', T_STRING); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 12), $found); + + $start += 8; + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 1), $found); + } + + /** + * Test match expression with function call in the arm. + * + * @return void + */ + public function testMatchFunctionCallArm() + { + // Check the first case. + $start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_STRING); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 21), $found); + + // Check the second case. + $start += 24; + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 21), $found); + } + + /** + * Test match expression with closure. + * + * @return void + */ + public function testMatchClosure() + { + $start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 14), $found); + + $start += 17; + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 14), $found); + } + + /** + * Test match expression with array declaration. + * + * @return void + */ + public function testMatchArray() + { + $start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 11), $found); + + $start += 14; + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 22), $found); + } + + /** + * Test nested match expressions. + * + * @return void + */ + public function testNestedMatch() + { + $start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER); + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 30), $found); + + $start += 21; + $found = BCFile::findEndOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start + 5), $found); + } } diff --git a/Tests/BackCompat/BCFile/FindExtendedClassNameTest.inc b/Tests/BackCompat/BCFile/FindExtendedClassNameTest.inc index dbe9ee38..58b73505 100644 --- a/Tests/BackCompat/BCFile/FindExtendedClassNameTest.inc +++ b/Tests/BackCompat/BCFile/FindExtendedClassNameTest.inc @@ -31,6 +31,9 @@ class testFECNNestedExtendedClass { } } +/* testNamespaceRelativeQualifiedClass */ +class testFECNQualifiedClass extends Core\File\RelativeClass {} + /* testClassThatExtendsAndImplements */ class testFECNClassThatExtendsAndImplements extends testFECNClass implements InterfaceA, InterfaceB {} @@ -44,7 +47,7 @@ $anon = new class( $a, $b ) extends testFECNExtendedAnonClass {}; interface Multi extends \Package\FooInterface, \BarInterface {}; /* testMissingExtendsName */ -class testMissingExtendsName extends { /* missing classname */ } // Internal parse error. +class testMissingExtendsName extends { /* missing classname */ } // Intentional parse error. // Intentional parse error. Has to be the last test in the file. /* testParseError */ diff --git a/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php b/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php index 279b4404..fb794dd5 100644 --- a/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php +++ b/Tests/BackCompat/BCFile/FindExtendedClassNameTest.php @@ -137,6 +137,10 @@ public function dataExtendedClass() '/* testNestedExtendedAnonClass */', 'testFECNAnonClass', ], + [ + '/* testNamespaceRelativeQualifiedClass */', + 'Core\File\RelativeClass', + ], [ '/* testClassThatExtendsAndImplements */', 'testFECNClass', diff --git a/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.inc b/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.inc index 4243fa3b..e1cc427a 100644 --- a/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.inc +++ b/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.inc @@ -20,17 +20,29 @@ class testFIINNamespacedClass implements \PHP_CodeSniffer\Tests\Core\File\testFI /* testNonImplementedClass */ class testFIINNonImplementedClass {} +/* testNamespaceRelativeQualifiedClass */ +class testFIINQualifiedClass implements Core\File\RelativeInterface {} + /* testClassThatExtendsAndImplements */ class testFECNClassThatExtendsAndImplements extends testFECNClass implements InterfaceA, \NameSpaced\Cat\InterfaceB {} /* testClassThatImplementsAndExtends */ class testFECNClassThatImplementsAndExtends implements \InterfaceA, InterfaceB extends testFECNClass {} +/* testBackedEnumWithoutImplements */ +enum Suit:string {} + +/* testEnumImplements */ +enum Suit implements Colorful {} + +/* testBackedEnumImplements */ +enum Suit: string implements Colorful, \Deck {} + /* testAnonClassImplements */ $anon = class() implements testFIINInterface {} /* testMissingImplementsName */ -class testMissingExtendsName implements { /* missing interface name */ } // Internal parse error. +class testMissingExtendsName implements { /* missing interface name */ } // Intentional parse error. // Intentional parse error. Has to be the last test in the file. /* testParseError */ diff --git a/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php b/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php index 602aab86..ef44e19f 100644 --- a/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php +++ b/Tests/BackCompat/BCFile/FindImplementedInterfaceNamesTest.php @@ -88,7 +88,7 @@ public function testFindImplementedInterfaceNames($identifier, $expected) { $testClass = static::TEST_CLASS; - $OOToken = $this->getTargetToken($identifier, [T_CLASS, T_ANON_CLASS, T_INTERFACE]); + $OOToken = $this->getTargetToken($identifier, [T_CLASS, T_ANON_CLASS, T_INTERFACE, T_ENUM]); $result = $testClass::findImplementedInterfaceNames(self::$phpcsFile, $OOToken); $this->assertSame($expected, $result); } @@ -126,6 +126,10 @@ public function dataImplementedInterface() '/* testInterface */', false, ], + [ + '/* testNamespaceRelativeQualifiedClass */', + ['Core\File\RelativeInterface'], + ], [ '/* testClassThatExtendsAndImplements */', [ @@ -140,6 +144,21 @@ public function dataImplementedInterface() 'InterfaceB', ], ], + [ + '/* testBackedEnumWithoutImplements */', + false, + ], + [ + '/* testEnumImplements */', + ['Colorful'], + ], + [ + '/* testBackedEnumImplements */', + [ + 'Colorful', + '\Deck', + ], + ], [ '/* testAnonClassImplements */', ['testFIINInterface'], diff --git a/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc b/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc index 366047b6..7061c473 100644 --- a/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc +++ b/Tests/BackCompat/BCFile/FindStartOfStatementTest.inc @@ -1,5 +1,136 @@ $foo + $bar, 'b' => true]; + +/* testUseGroup */ +use Vendor\Package\{ClassA as A, ClassB, ClassC as C}; + +$a = [ + /* testArrowFunctionArrayValue */ + 'a' => fn() => return 1, + 'b' => fn() => return 1, +]; + +/* testStaticArrowFunction */ +static fn ($a) => $a; + +/* testArrowFunctionReturnValue */ +fn(): array => [a($a, $b)]; + +/* testArrowFunctionAsArgument */ +$foo = foo( + fn() => bar() +); + +/* testArrowFunctionWithArrayAsArgument */ +$foo = foo( + fn() => [$row[0], $row[3]] +); + +$match = match ($a) { + /* testMatchCase */ + 1 => 'foo', + /* testMatchDefault */ + default => 'bar' +}; + +$match = match ($a) { + /* testMatchMultipleCase */ + 1, 2, => $a * $b, + /* testMatchDefaultComma */ + default, => 'something' +}; + +match ($pressedKey) { + /* testMatchFunctionCall */ + Key::RETURN_ => save($value, $user) +}; + +$result = match (true) { + /* testMatchFunctionCallArm */ + str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en', + str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr', + default => 'pl' +}; + +/* testMatchClosure */ +$result = match ($key) { + 1 => function($a, $b) {}, + 2 => function($b, $c) {}, +}; + +/* testMatchArray */ +$result = match ($key) { + 1 => [1,2,3], + 2 => [1 => one($a, $b), 2 => two($b, $c)], + 3 => [], +}; + +/* testNestedMatch */ +$result = match ($key) { + 1 => match ($key) { + 1 => 'one', + 2 => 'two', + }, + 2 => match ($key) { + 1 => 'two', + 2 => 'one', + }, +}; + +return 0; + +/* testOpenTag */ +?> +

Test

+', foo(), ''; + +/* testOpenTagWithEcho */ +?> +

Test

+', foo(), ''; + +?> $song->url()) @@ -10,3 +141,33 @@ $value = [ Text::make('Title') ]), ]; + +switch ($foo) { + /* testCaseStatement */ + case 1: + /* testInsideCaseStatement */ + $var = doSomething(); + /* testInsideCaseBreakStatement */ + break 2; + + case 2: + /* testInsideCaseContinueStatement */ + continue 2; + + case 3: + /* testInsideCaseReturnStatement */ + return false; + + case 4: + /* testInsideCaseExitStatement */ + exit(1); + + case 5: + /* testInsideCaseThrowStatement */ + throw new Exception(); + + /* testDefaultStatement */ + default: + /* testInsideDefaultContinueStatement */ + continue $var; +} diff --git a/Tests/BackCompat/BCFile/FindStartOfStatementTest.php b/Tests/BackCompat/BCFile/FindStartOfStatementTest.php index 966d5ec5..de3d91ec 100644 --- a/Tests/BackCompat/BCFile/FindStartOfStatementTest.php +++ b/Tests/BackCompat/BCFile/FindStartOfStatementTest.php @@ -20,13 +20,449 @@ * * @since 1.0.0 */ -class FindStartOfStatementTest extends UtilityMethodTestCase +final class FindStartOfStatementTest extends UtilityMethodTestCase { + /** + * Test a simple assignment. + * + * @return void + */ + public function testSimpleAssignment() + { + $start = $this->getTargetToken('/* testSimpleAssignment */', T_SEMICOLON); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 5), $found); + } + + /** + * Test a function call. + * + * @return void + */ + public function testFunctionCall() + { + $start = $this->getTargetToken('/* testFunctionCall */', T_CLOSE_PARENTHESIS); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 6), $found); + } + + /** + * Test a function call. + * + * @return void + */ + public function testFunctionCallArgument() + { + $start = $this->getTargetToken('/* testFunctionCallArgument */', T_VARIABLE, '$b'); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame($start, $found); + } + + /** + * Test a direct call to a control structure. + * + * @return void + */ + public function testControlStructure() + { + $start = $this->getTargetToken('/* testControlStructure */', T_CLOSE_CURLY_BRACKET); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 6), $found); + } + + /** + * Test the assignment of a closure. + * + * @return void + */ + public function testClosureAssignment() + { + $start = $this->getTargetToken('/* testClosureAssignment */', T_CLOSE_CURLY_BRACKET); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 12), $found); + } + + /** + * Test using a heredoc in a function argument. + * + * @return void + */ + public function testHeredocFunctionArg() + { + // Find the start of the function. + $start = $this->getTargetToken('/* testHeredocFunctionArg */', T_SEMICOLON); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 10), $found); + + // Find the start of the heredoc. + $start -= 4; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 4), $found); + + // Find the start of the last arg. + $start += 2; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame($start, $found); + } + + /** + * Test parts of a switch statement. + * + * @return void + */ + public function testSwitch() + { + // Find the start of the switch. + $start = $this->getTargetToken('/* testSwitch */', T_CLOSE_CURLY_BRACKET); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 47), $found); + + // Find the start of default case. + $start -= 5; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 6), $found); + + // Find the start of the second case. + $start -= 12; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 5), $found); + + // Find the start of the first case. + $start -= 13; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 8), $found); + + // Test inside the first case. + --$start; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 1), $found); + } + + /** + * Test statements that are array values. + * + * @return void + */ + public function testStatementAsArrayValue() + { + // Test short array syntax. + $start = $this->getTargetToken('/* testStatementAsArrayValue */', T_STRING, 'Datetime'); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 2), $found); + + // Test long array syntax. + $start += 12; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 2), $found); + + // Test same statement outside of array. + ++$start; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 9), $found); + + // Test with an array index. + $start += 17; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 5), $found); + } + + /** + * Test a use group. + * + * @return void + */ + public function testUseGroup() + { + $start = $this->getTargetToken('/* testUseGroup */', T_SEMICOLON); + $expected = parent::usesPhp8NameTokens() ? ($start - 21) : ($start - 23); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame($expected, $found); + } + + /** + * Test arrow function as array value. + * + * @return void + */ + public function testArrowFunctionArrayValue() + { + $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_COMMA); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 9), $found); + } + + /** + * Test static arrow function. + * + * @return void + */ + public function testStaticArrowFunction() + { + $start = $this->getTargetToken('/* testStaticArrowFunction */', T_SEMICOLON); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 11), $found); + } + + /** + * Test arrow function with return value. + * + * @return void + */ + public function testArrowFunctionReturnValue() + { + $start = $this->getTargetToken('/* testArrowFunctionReturnValue */', T_SEMICOLON); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 18), $found); + } + + /** + * Test arrow function used as a function argument. + * + * @return void + */ + public function testArrowFunctionAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionAsArgument */', T_FN); + $start += 8; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 8), $found); + } + + /** + * Test arrow function with arrays used as a function argument. + * + * @return void + */ + public function testArrowFunctionWithArrayAsArgument() + { + $start = $this->getTargetToken('/* testArrowFunctionWithArrayAsArgument */', T_FN); + $start += 17; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 17), $found); + } + + /** + * Test simple match expression case. + * + * @return void + */ + public function testMatchCase() + { + $start = $this->getTargetToken('/* testMatchCase */', T_COMMA); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 1), $found); + } + + /** + * Test simple match expression default case. + * + * @return void + */ + public function testMatchDefault() + { + $start = $this->getTargetToken('/* testMatchDefault */', T_CONSTANT_ENCAPSED_STRING, "'bar'"); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame($start, $found); + } + + /** + * Test multiple comma-separated match expression case values. + * + * @return void + */ + public function testMatchMultipleCase() + { + $start = $this->getTargetToken('/* testMatchMultipleCase */', T_MATCH_ARROW); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 6), $found); + + $start += 6; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 4), $found); + } + + /** + * Test match expression default case with trailing comma. + * + * @return void + */ + public function testMatchDefaultComma() + { + $start = $this->getTargetToken('/* testMatchDefaultComma */', T_MATCH_ARROW); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 3), $found); + + $start += 2; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame($start, $found); + } + + /** + * Test match expression with function call. + * + * @return void + */ + public function testMatchFunctionCall() + { + $start = $this->getTargetToken('/* testMatchFunctionCall */', T_CLOSE_PARENTHESIS); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 6), $found); + } + + /** + * Test match expression with function call in the arm. + * + * @return void + */ + public function testMatchFunctionCallArm() + { + // Check the first case. + $start = $this->getTargetToken('/* testMatchFunctionCallArm */', T_MATCH_ARROW); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 18), $found); + + // Check the second case. + $start += 24; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 18), $found); + } + + /** + * Test match expression with closure. + * + * @return void + */ + public function testMatchClosure() + { + $start = $this->getTargetToken('/* testMatchClosure */', T_LNUMBER); + $start += 14; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 10), $found); + + $start += 17; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 10), $found); + } + + /** + * Test match expression with array declaration. + * + * @return void + */ + public function testMatchArray() + { + // Start of first case statement. + $start = $this->getTargetToken('/* testMatchArray */', T_LNUMBER); + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + $this->assertSame($start, $found); + + // Comma after first statement. + $start += 11; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + $this->assertSame(($start - 7), $found); + + // Start of second case statement. + $start += 3; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + $this->assertSame($start, $found); + + // Comma after first statement. + $start += 30; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + $this->assertSame(($start - 26), $found); + } + + /** + * Test nested match expressions. + * + * @return void + */ + public function testNestedMatch() + { + $start = $this->getTargetToken('/* testNestedMatch */', T_LNUMBER); + $start += 30; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 26), $found); + + $start -= 4; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 1), $found); + + $start -= 3; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 2), $found); + } + + /** + * Test full PHP open tag. + * + * @return void + */ + public function testOpenTag() + { + $start = $this->getTargetToken('/* testOpenTag */', T_OPEN_TAG); + $start += 2; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 1), $found); + } + + /** + * Test PHP open tag with echo. + * + * @return void + */ + public function testOpenTagWithEcho() + { + $start = $this->getTargetToken('/* testOpenTagWithEcho */', T_OPEN_TAG_WITH_ECHO); + $start += 3; + $found = BCFile::findStartOfStatement(self::$phpcsFile, $start); + + $this->assertSame(($start - 1), $found); + } + /** * Test object call on result of static function call with arrow function as parameter and wrapped within an array. * - * @link https://github.com/squizlabs/php_codesniffer/issues/2849 + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2849 * @link https://github.com/squizlabs/PHP_CodeSniffer/commit/fbf67efc3fc0c2a355f5585d49f4f6fe160ff2f9 * * @return void @@ -40,4 +476,110 @@ public function testObjectCallPrecededByArrowFunctionAsFunctionCallParameterInAr $this->assertSame($expected, $found); } + + /** + * Test finding the start of a statement inside a switch control structure case/default statement. + * + * @link https://github.com/squizlabs/php_codesniffer/issues/3192 + * @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3186/commits/18a0e54735bb9b3850fec266e5f4c50dacf618ea + * + * @dataProvider dataFindStartInsideSwitchCaseDefaultStatements + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array|string|int $targets The token to search for after the test marker. + * @param string|int $expectedTarget Token code of the expected start of statement stack pointer. + * + * @return void + */ + public function testFindStartInsideSwitchCaseDefaultStatements($testMarker, $targets, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $targets); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = BCFile::findStartOfStatement(self::$phpcsFile, $testToken); + + $this->assertSame($expected, $found); + } + + /** + * Data provider. + * + * @return array + */ + public static function dataFindStartInsideSwitchCaseDefaultStatements() + { + return [ + 'Case keyword should be start of case statement - case itself' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => \T_CASE, + 'expectedTarget' => \T_CASE, + ], + 'Case keyword should be start of case statement - number (what\'s being compared)' => [ + 'testMarker' => '/* testCaseStatement */', + 'targets' => \T_LNUMBER, + 'expectedTarget' => \T_CASE, + ], + 'Variable should be start of arbitrary assignment statement - variable itself' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => \T_VARIABLE, + 'expectedTarget' => \T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - equal sign' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => \T_EQUAL, + 'expectedTarget' => \T_VARIABLE, + ], + 'Variable should be start of arbitrary assignment statement - function call' => [ + 'testMarker' => '/* testInsideCaseStatement */', + 'targets' => \T_STRING, + 'expectedTarget' => \T_VARIABLE, + ], + 'Break should be start for contents of the break statement - contents' => [ + 'testMarker' => '/* testInsideCaseBreakStatement */', + 'targets' => \T_LNUMBER, + 'expectedTarget' => \T_BREAK, + ], + 'Continue should be start for contents of the continue statement - contents' => [ + 'testMarker' => '/* testInsideCaseContinueStatement */', + 'targets' => \T_LNUMBER, + 'expectedTarget' => \T_CONTINUE, + ], + 'Return should be start for contents of the return statement - contents' => [ + 'testMarker' => '/* testInsideCaseReturnStatement */', + 'targets' => \T_FALSE, + 'expectedTarget' => \T_RETURN, + ], + 'Exit should be start for contents of the exit statement - close parenthesis' => [ + // Note: not sure if this is actually correct - should this be the open parenthesis ? + 'testMarker' => '/* testInsideCaseExitStatement */', + 'targets' => \T_CLOSE_PARENTHESIS, + 'expectedTarget' => \T_EXIT, + ], + 'Throw should be start for contents of the throw statement - new keyword' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => \T_NEW, + 'expectedTarget' => \T_THROW, + ], + 'Throw should be start for contents of the throw statement - exception name' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => \T_STRING, + 'expectedTarget' => \T_THROW, + ], + 'Throw should be start for contents of the throw statement - close parenthesis' => [ + 'testMarker' => '/* testInsideCaseThrowStatement */', + 'targets' => \T_CLOSE_PARENTHESIS, + 'expectedTarget' => \T_THROW, + ], + 'Default keyword should be start of default statement - default itself' => [ + 'testMarker' => '/* testDefaultStatement */', + 'targets' => \T_DEFAULT, + 'expectedTarget' => \T_DEFAULT, + ], + 'Return should be start for contents of the return statement (inside default) - variable' => [ + 'testMarker' => '/* testInsideDefaultContinueStatement */', + 'targets' => \T_VARIABLE, + 'expectedTarget' => \T_CONTINUE, + ], + ]; + } } diff --git a/Tests/BackCompat/BCFile/GetClassPropertiesTest.inc b/Tests/BackCompat/BCFile/GetClassPropertiesTest.inc index 9753d3ae..5ec030f6 100644 --- a/Tests/BackCompat/BCFile/GetClassPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetClassPropertiesTest.inc @@ -6,6 +6,9 @@ interface NotAClass {} /* testAnonClass */ $anon = new class() {}; +/* testEnum */ +enum NotAClassEither {} + /* testClassWithoutProperties */ class ClassWithoutProperties {} @@ -29,3 +32,10 @@ abstract * @phpcs:disable Standard.Cat.SniffName -- Just because. */ class ClassWithDocblock {} + +/* testParseErrorAbstractFinal */ +final /* comment */ + + abstract // Intentional parse error, class cannot both be final and abstract. + + class AbstractFinal {} diff --git a/Tests/BackCompat/BCFile/GetClassPropertiesTest.php b/Tests/BackCompat/BCFile/GetClassPropertiesTest.php index f21dea86..c575b57d 100644 --- a/Tests/BackCompat/BCFile/GetClassPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetClassPropertiesTest.php @@ -49,8 +49,8 @@ public function testNotAClassException($testMarker, $tokenType) $this->expectPhpcsException('$stackPtr must be of type T_CLASS'); $testClass = static::TEST_CLASS; - $interface = $this->getTargetToken($testMarker, $tokenType); - $testClass::getClassProperties(self::$phpcsFile, $interface); + $target = $this->getTargetToken($testMarker, $tokenType); + $testClass::getClassProperties(self::$phpcsFile, $target); } /** @@ -71,6 +71,10 @@ public function dataNotAClassException() '/* testAnonClass */', \T_ANON_CLASS, ], + 'enum' => [ + '/* testEnum */', + \T_ENUM, + ], ]; } @@ -138,6 +142,13 @@ public function dataGetClassProperties() 'is_final' => false, ], ], + 'abstract-final-parse-error' => [ + '/* testParseErrorAbstractFinal */', + [ + 'is_abstract' => true, + 'is_final' => true, + ], + ], ]; } } diff --git a/Tests/BackCompat/BCFile/GetConditionTest.php b/Tests/BackCompat/BCFile/GetConditionTest.php index e316eebf..077cddb6 100644 --- a/Tests/BackCompat/BCFile/GetConditionTest.php +++ b/Tests/BackCompat/BCFile/GetConditionTest.php @@ -192,8 +192,13 @@ public function testNonExistentToken() */ public function testNonConditionalToken() { + $targetType = \T_STRING; + if (parent::usesPhp8NameTokens() === true) { + $targetType = \T_NAME_QUALIFIED; + } + $testClass = static::TEST_CLASS; - $stackPtr = $this->getTargetToken('/* testStartPoint */', \T_STRING); + $stackPtr = $this->getTargetToken('/* testStartPoint */', $targetType); $result = $testClass::getCondition(self::$phpcsFile, $stackPtr, \T_IF); $this->assertFalse($result); diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php index 5e5e82e9..b34e2b70 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameJSTest.php @@ -39,7 +39,7 @@ class GetDeclarationNameJSTest extends UtilityMethodTestCase */ public function testInvalidTokenPassed() { - $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); + $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); $target = $this->getTargetToken('/* testInvalidTokenPassed */', \T_STRING); BCFile::getDeclarationName(self::$phpcsFile, $target); @@ -93,7 +93,7 @@ public function dataGetDeclarationNameNull() public function testGetDeclarationName($testMarker, $expected, $targetType = null) { if (isset($targetType) === false) { - $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]; + $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM, \T_FUNCTION]; } $target = $this->getTargetToken($testMarker, $targetType); @@ -134,10 +134,6 @@ public function dataGetDeclarationName() */ public function testGetDeclarationNameES6Method() { - if (\version_compare(static::$phpcsVersion, '3.0.0', '<') === true) { - $this->markTestSkipped('Support for JS ES6 method has not been backfilled for PHPCS 2.x (yet)'); - } - $target = $this->getTargetToken('/* testMethod */', [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]); $result = BCFile::getDeclarationName(self::$phpcsFile, $target); $this->assertSame('methodName', $result); diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc index fcb3ad05..d6d2ea42 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.inc @@ -28,7 +28,7 @@ $class = new class extends SomeClass { function functionName() {} /* testFunctionReturnByRef */ -function & functionNameByRef(); +function & functionNameByRef() {} /* testClass */ abstract class ClassName { @@ -69,6 +69,22 @@ class /* comment */ /* testFunctionFn */ function fn() {} +/* testPureEnum */ +enum Foo +{ + case SOME_CASE; +} + +/* testBackedEnumSpaceBetweenNameAndColon */ +enum Hoo : string +{ + case ONE = 'one'; + case TWO = 'two'; +} + +/* testBackedEnumNoSpaceBetweenNameAndColon */ +enum Suit: int implements Colorful, CardGame {} + /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. function // Comment. diff --git a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php index 95aa9981..43285e3c 100644 --- a/Tests/BackCompat/BCFile/GetDeclarationNameTest.php +++ b/Tests/BackCompat/BCFile/GetDeclarationNameTest.php @@ -32,7 +32,7 @@ class GetDeclarationNameTest extends UtilityMethodTestCase */ public function testInvalidTokenPassed() { - $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); + $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); $target = $this->getTargetToken('/* testInvalidTokenPassed */', \T_STRING); BCFile::getDeclarationName(self::$phpcsFile, $target); @@ -85,11 +85,6 @@ public function dataGetDeclarationNameNull() '/* testAnonClassExtendsWithoutParens */', \T_ANON_CLASS, ], - - /* - * Note: this particular test *will* throw tokenizer "undefined offset" notices on PHPCS 2.6.0, - * but the test will pass. - */ 'live-coding' => [ '/* testLiveCoding */', \T_FUNCTION, @@ -111,7 +106,7 @@ public function dataGetDeclarationNameNull() public function testGetDeclarationName($testMarker, $expected, $targetType = null) { if (isset($targetType) === false) { - $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]; + $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM, \T_FUNCTION]; } $target = $this->getTargetToken($testMarker, $targetType); @@ -185,6 +180,18 @@ public function dataGetDeclarationName() '/* testFunctionFn */', 'fn', ], + 'enum-pure' => [ + '/* testPureEnum */', + 'Foo', + ], + 'enum-backed-space-between-name-and-colon' => [ + '/* testBackedEnumSpaceBetweenNameAndColon */', + 'Hoo', + ], + 'enum-backed-no-space-between-name-and-colon' => [ + '/* testBackedEnumNoSpaceBetweenNameAndColon */', + 'Suit', + ], ]; } } diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc index b50f8a1a..48fde8c0 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc @@ -182,3 +182,136 @@ function_call( 'param', new class { /* testNestedMethodParam 2 */ public function __construct( $open, $post_id ) {} }, 10, 2 ); + +class PHP8Mixed { + /* testPHP8MixedTypeHint */ + public static miXed $mixed; + + /* testPHP8MixedTypeHintNullable */ + // Intentional fatal error - nullability is not allowed with mixed, but that's not the concern of the method. + private ?mixed $nullableMixed; +} + +class NSOperatorInType { + /* testNamespaceOperatorTypeHint */ + public ?namespace\Name $prop; +} + +$anon = class() { + /* testPHP8UnionTypesSimple */ + public int|float $unionTypeSimple; + + /* testPHP8UnionTypesTwoClasses */ + private MyClassA|\Package\MyClassB $unionTypesTwoClasses; + + /* testPHP8UnionTypesAllBaseTypes */ + protected array|bool|int|float|NULL|object|string $unionTypesAllBaseTypes; + + /* testPHP8UnionTypesAllPseudoTypes */ + // Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. + var false|mixed|self|parent|iterable|Resource $unionTypesAllPseudoTypes; + + /* testPHP8UnionTypesIllegalTypes */ + // Intentional fatal error - types which are not allowed for properties, but that's not the concern of the method. + public callable|static|void $unionTypesIllegalTypes; + + /* testPHP8UnionTypesNullable */ + // Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. + public ?int|float $unionTypesNullable; + + /* testPHP8PseudoTypeNull */ + // Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. + public null $pseudoTypeNull; + + /* testPHP8PseudoTypeFalse */ + // Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. + public false $pseudoTypeFalse; + + /* testPHP8PseudoTypeFalseAndBool */ + // Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. + public bool|FALSE $pseudoTypeFalseAndBool; + + /* testPHP8ObjectAndClass */ + // Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. + public object|ClassName $objectAndClass; + + /* testPHP8PseudoTypeIterableAndArray */ + // Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. + public iterable|array|Traversable $pseudoTypeIterableAndArray; + + /* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ + // Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. + public int |string| /*comment*/ INT $duplicateTypeInUnion; + + /* testPHP81Readonly */ + public readonly int $readonly; + + /* testPHP81ReadonlyWithNullableType */ + public readonly ?array $readonlyWithNullableType; + + /* testPHP81ReadonlyWithUnionType */ + public readonly string|int $readonlyWithUnionType; + + /* testPHP81ReadonlyWithUnionTypeWithNull */ + protected ReadOnly string|null $readonlyWithUnionTypeWithNull; + + /* testPHP81OnlyReadonlyWithUnionType */ + readonly string|int $onlyReadonly; + + /* testPHP81OnlyReadonlyWithUnionTypeMultiple */ + readonly \InterfaceA|\Sub\InterfaceB|false + $onlyReadonly; + + /* testPHP81ReadonlyAndStatic */ + readonly private static ?string $readonlyAndStatic; + + /* testPHP81ReadonlyMixedCase */ + public ReadONLY static $readonlyMixedCase; +}; + +$anon = class { + /* testPHP8PropertySingleAttribute */ + #[PropertyWithAttribute] + public string $foo; + + /* testPHP8PropertyMultipleAttributes */ + #[PropertyWithAttribute(foo: 'bar'), MyAttribute] + protected ?int|float $bar; + + /* testPHP8PropertyMultilineAttribute */ + #[ + PropertyWithAttribute(/* comment */ 'baz') + ] + private mixed $baz; +}; + +enum Suit +{ + /* testEnumProperty */ + protected $anonymous; +} + +enum Direction implements ArrayAccess +{ + case Up; + case Down; + + /* testEnumMethodParamNotProperty */ + public function offsetGet($val) { ... } +} + +$anon = class() { + /* testPHP81IntersectionTypes */ + public Foo&Bar $intersectionType; + + /* testPHP81MoreIntersectionTypes */ + public Foo&Bar&Baz $moreIntersectionTypes; + + /* testPHP81IllegalIntersectionTypes */ + // Intentional fatal error - types which are not allowed for intersection type, but that's not the concern of the method. + public int&string $illegalIntersectionType; + + /* testPHP81NullableIntersectionType */ + // Intentional fatal error - nullability is not allowed with intersection type, but that's not the concern of the method. + public ?Foo&Bar $nullableIntersectionType; +}; diff --git a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php index ce3d32bb..09c68526 100644 --- a/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMemberPropertiesTest.php @@ -82,503 +82,941 @@ public function testGetMemberProperties($identifier, $expected) */ public function dataGetMemberProperties() { + $php8Names = parent::usesPhp8NameTokens(); + return [ - [ + 'var-modifier' => [ '/* testVar */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'var-modifier-and-type' => [ '/* testVarType */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => '?int', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'public-modifier' => [ '/* testPublic */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'public-modifier-and-type' => [ '/* testPublicType */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'string', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'protected-modifier' => [ '/* testProtected */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'protected-modifier-and-type' => [ '/* testProtectedType */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'bool', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'private-modifier' => [ '/* testPrivate */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'private-modifier-and-type' => [ '/* testPrivateType */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'array', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'static-modifier' => [ '/* testStatic */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'static-modifier-and-type' => [ '/* testStaticType */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '?string', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'static-and-var-modifier' => [ '/* testStaticVar */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'var-and-static-modifier' => [ '/* testVarStatic */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'public-static-modifiers' => [ '/* testPublicStatic */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'protected-static-modifiers' => [ '/* testProtectedStatic */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'private-static-modifiers' => [ '/* testPrivateStatic */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'no-modifier' => [ '/* testNoPrefix */', [ 'scope' => 'public', 'scope_specified' => false, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'public-and-static-modifier-with-docblock' => [ '/* testPublicStaticWithDocblock */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'protected-and-static-modifier-with-docblock' => [ '/* testProtectedStaticWithDocblock */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'private-and-static-modifier-with-docblock' => [ '/* testPrivateStaticWithDocblock */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-simple-type-prop-1' => [ '/* testGroupType 1 */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'float', 'type_token' => -6, // Offset from the T_VARIABLE token. 'type_end_token' => -6, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'property-group-simple-type-prop-2' => [ '/* testGroupType 2 */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => 'float', 'type_token' => -13, // Offset from the T_VARIABLE token. 'type_end_token' => -13, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'property-group-nullable-type-prop-1' => [ '/* testGroupNullableType 1 */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '?string', 'type_token' => -6, // Offset from the T_VARIABLE token. 'type_end_token' => -6, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'property-group-nullable-type-prop-2' => [ '/* testGroupNullableType 2 */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '?string', 'type_token' => -17, // Offset from the T_VARIABLE token. 'type_end_token' => -17, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'property-group-protected-static-prop-1' => [ '/* testGroupProtectedStatic 1 */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-protected-static-prop-2' => [ '/* testGroupProtectedStatic 2 */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-protected-static-prop-3' => [ '/* testGroupProtectedStatic 3 */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-1' => [ '/* testGroupPrivate 1 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-2' => [ '/* testGroupPrivate 2 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-3' => [ '/* testGroupPrivate 3 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-4' => [ '/* testGroupPrivate 4 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-5' => [ '/* testGroupPrivate 5 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-6' => [ '/* testGroupPrivate 6 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-group-private-prop-7' => [ '/* testGroupPrivate 7 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'messy-nullable-type' => [ '/* testMessyNullableType */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?array', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'fqn-type' => [ '/* testNamespaceType */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '\MyNamespace\MyClass', - 'type_token' => -5, // Offset from the T_VARIABLE token. + 'type_token' => ($php8Names === true) ? -2 : -5, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'nullable-classname-type' => [ '/* testNullableNamespaceType 1 */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?ClassName', 'type_token' => -2, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'nullable-namespace-relative-class-type' => [ '/* testNullableNamespaceType 2 */', [ 'scope' => 'protected', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '?Folder\ClassName', - 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_token' => ($php8Names === true) ? -2 : -4, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => true, ], ], - [ + 'multiline-namespaced-type' => [ '/* testMultilineNamespaceType */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '\MyNamespace\MyClass\Foo', - 'type_token' => -18, // Offset from the T_VARIABLE token. + 'type_token' => ($php8Names === true) ? -15 : -18, // Offset from the T_VARIABLE token. 'type_end_token' => -2, // Offset from the T_VARIABLE token. 'nullable_type' => false, ], ], - [ + 'property-after-method' => [ '/* testPropertyAfterMethod */', [ 'scope' => 'private', 'scope_specified' => true, 'is_static' => true, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'invalid-property-in-interface' => [ '/* testInterfaceProperty */', [], ], - [ + 'property-in-nested-class-1' => [ '/* testNestedProperty 1 */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], - [ + 'property-in-nested-class-2' => [ '/* testNestedProperty 2 */', [ 'scope' => 'public', 'scope_specified' => true, 'is_static' => false, + 'is_readonly' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, 'nullable_type' => false, ], ], + 'php8-mixed-type' => [ + '/* testPHP8MixedTypeHint */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => false, + 'type' => 'miXed', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-nullable-mixed-type' => [ + '/* testPHP8MixedTypeHintNullable */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '?mixed', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'namespace-operator-type-declaration' => [ + '/* testNamespaceOperatorTypeHint */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '?namespace\Name', + 'type_token' => ($php8Names === true) ? -2 : -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8-union-types-simple' => [ + '/* testPHP8UnionTypesSimple */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int|float', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-two-classes' => [ + '/* testPHP8UnionTypesTwoClasses */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'MyClassA|\Package\MyClassB', + 'type_token' => ($php8Names === true) ? -4 : -7, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-all-base-types' => [ + '/* testPHP8UnionTypesAllBaseTypes */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'array|bool|int|float|NULL|object|string', + 'type_token' => -14, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-all-pseudo-types' => [ + '/* testPHP8UnionTypesAllPseudoTypes */', + [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'false|mixed|self|parent|iterable|Resource', + 'type_token' => -12, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-illegal-types' => [ + '/* testPHP8UnionTypesIllegalTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + // Missing static, but that's OK as not an allowed syntax. + 'type' => 'callable||void', + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-nullable' => [ + '/* testPHP8UnionTypesNullable */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '?int|float', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8-union-types-pseudo-type-null' => [ + '/* testPHP8PseudoTypeNull */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'null', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-pseudo-type-false' => [ + '/* testPHP8PseudoTypeFalse */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'false', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-pseudo-type-false-and-bool' => [ + '/* testPHP8PseudoTypeFalseAndBool */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'bool|FALSE', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-object-and-class' => [ + '/* testPHP8ObjectAndClass */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'object|ClassName', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-pseudo-type-iterable-and-array' => [ + '/* testPHP8PseudoTypeIterableAndArray */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'iterable|array|Traversable', + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-union-types-duplicate-type-with-whitespace-and-comments' => [ + '/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int|string|INT', + 'type_token' => -10, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property' => [ + '/* testPHP81Readonly */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'int', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-nullable-type' => [ + '/* testPHP81ReadonlyWithNullableType */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'type' => '?array', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8.1-readonly-property-with-union-type' => [ + '/* testPHP81ReadonlyWithUnionType */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'string|int', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-union-type-with-null' => [ + '/* testPHP81ReadonlyWithUnionTypeWithNull */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'string|null', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-union-type-no-visibility' => [ + '/* testPHP81OnlyReadonlyWithUnionType */', + [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'string|int', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-property-with-multi-union-type-no-visibility' => [ + '/* testPHP81OnlyReadonlyWithUnionTypeMultiple */', + [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'type' => '\InterfaceA|\Sub\InterfaceB|false', + 'type_token' => ($php8Names === true) ? -7 : -11, // Offset from the T_VARIABLE token. + 'type_end_token' => -3, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-readonly-and-static-property' => [ + '/* testPHP81ReadonlyAndStatic */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => true, + 'type' => '?string', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8.1-readonly-mixed-case-keyword' => [ + '/* testPHP81ReadonlyMixedCase */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8-property-with-single-attribute' => [ + '/* testPHP8PropertySingleAttribute */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'string', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8-property-with-multiple-attributes' => [ + '/* testPHP8PropertyMultipleAttributes */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '?int|float', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8-property-with-multiline-attribute' => [ + '/* testPHP8PropertyMultilineAttribute */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'mixed', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'invalid-property-in-enum' => [ + '/* testEnumProperty */', + [], + ], + 'php8.1-single-intersection-type' => [ + '/* testPHP81IntersectionTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'Foo&Bar', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-multi-intersection-type' => [ + '/* testPHP81MoreIntersectionTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'Foo&Bar&Baz', + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-illegal-intersection-type' => [ + '/* testPHP81IllegalIntersectionTypes */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int&string', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.1-nullable-intersection-type' => [ + '/* testPHP81NullableIntersectionType */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => '?Foo&Bar', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], ]; } @@ -617,6 +1055,7 @@ public function dataNotClassProperty() ['/* testGlobalVariable */'], ['/* testNestedMethodParam 1 */'], ['/* testNestedMethodParam 2 */'], + ['/* testEnumMethodParamNotProperty */'], ]; } diff --git a/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php b/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php index cd86d071..9c3358f8 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersParseError1Test.php @@ -12,6 +12,7 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodParameters method. @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class GetMethodParametersParseError1Test extends UtilityMethodTestCase +final class GetMethodParametersParseError1Test extends UtilityMethodTestCase { /** @@ -32,7 +33,7 @@ class GetMethodParametersParseError1Test extends UtilityMethodTestCase */ public function testParseError() { - $target = $this->getTargetToken('/* testParseError */', [\T_FUNCTION, \T_CLOSURE]); + $target = $this->getTargetToken('/* testParseError */', Collections::functionDeclarationTokens()); $result = BCFile::getMethodParameters(self::$phpcsFile, $target); $this->assertSame([], $result); diff --git a/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php b/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php index 08da2c2d..3324266f 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersParseError2Test.php @@ -12,6 +12,7 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodParameters method. @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class GetMethodParametersParseError2Test extends UtilityMethodTestCase +final class GetMethodParametersParseError2Test extends UtilityMethodTestCase { /** @@ -32,7 +33,7 @@ class GetMethodParametersParseError2Test extends UtilityMethodTestCase */ public function testParseError() { - $target = $this->getTargetToken('/* testParseError */', [\T_FUNCTION, \T_CLOSURE]); + $target = $this->getTargetToken('/* testParseError */', Collections::functionDeclarationTokens()); $result = BCFile::getMethodParameters(self::$phpcsFile, $target); $this->assertSame([], $result); diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc index 922c59fd..e2991b67 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.inc @@ -30,6 +30,15 @@ function passByReference(&$var) {} /* testArrayHint */ function arrayHint(array $var) {} +/* testVariable */ +function variable($var) {} + +/* testSingleDefaultValue */ +function defaultValue($var1=self::CONSTANT) {} + +/* testDefaultValues */ +function defaultValues($var1=1, $var2='value') {} + /* testTypeHint */ function typeHint(foo $var1, bar $var2) {} @@ -41,15 +50,6 @@ class MyClass { /* testNullableTypeHint */ function nullableTypeHint(?int $var1, ?\bar $var2) {} -/* testVariable */ -function variable($var) {} - -/* testSingleDefaultValue */ -function defaultValue($var1=self::CONSTANT) {} - -/* testDefaultValues */ -function defaultValues($var1=1, $var2='value') {} - /* testBitwiseAndConstantExpressionDefaultValue */ function myFunction($a = 10 & 20) {} @@ -125,23 +125,181 @@ function messyDeclaration( & /*test*/ ... /* phpcs:ignore */ $c ) {} +/* testPHP8MixedTypeHint */ +function mixedTypeHint(mixed &...$var1) {} + +/* testPHP8MixedTypeHintNullable */ +// Intentional fatal error - nullability is not allowed with mixed, but that's not the concern of the method. +function mixedTypeHintNullable(?Mixed $var1) {} + +/* testNamespaceOperatorTypeHint */ +function namespaceOperatorTypeHint(?namespace\Name $var1) {} + +/* testPHP8UnionTypesSimple */ +function unionTypeSimple(int|float $number, self|parent &...$obj) {} + +/* testPHP8UnionTypesWithSpreadOperatorAndReference */ +function globalFunctionWithSpreadAndReference(float|null &$paramA, string|int ...$paramB ) {} + +/* testPHP8UnionTypesSimpleWithBitwiseOrInDefault */ +$fn = fn(int|float $var = CONSTANT_A | CONSTANT_B) => $var; + +/* testPHP8UnionTypesTwoClasses */ +function unionTypesTwoClasses(MyClassA|\Package\MyClassB $var) {} + +/* testPHP8UnionTypesAllBaseTypes */ +function unionTypesAllBaseTypes(array|bool|callable|int|float|null|object|string $var) {} + +/* testPHP8UnionTypesAllPseudoTypes */ +// Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. +function unionTypesAllPseudoTypes(false|mixed|self|parent|iterable|Resource $var) {} + +/* testPHP8UnionTypesNullable */ +// Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. +$closure = function (?int|float $number) {}; + +/* testPHP8PseudoTypeNull */ +// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeNull(null $var = null) {} + +/* testPHP8PseudoTypeFalse */ +// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeFalse(false $var = false) {} + +/* testPHP8PseudoTypeFalseAndBool */ +// Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. +function pseudoTypeFalseAndBool(bool|false $var = false) {} + +/* testPHP8ObjectAndClass */ +// Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. +function objectAndClass(object|ClassName $var) {} + +/* testPHP8PseudoTypeIterableAndArray */ +// Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. +function pseudoTypeIterableAndArray(iterable|array|Traversable $var) {} + +/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ +// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. +function duplicateTypeInUnion( int | string /*comment*/ | INT $var) {} + +class ConstructorPropertyPromotionNoTypes { + /* testPHP8ConstructorPropertyPromotionNoTypes */ + public function __construct( + public $x = 0.0, + protected $y = '', + private $z = null, + ) {} +} + +class ConstructorPropertyPromotionWithTypes { + /* testPHP8ConstructorPropertyPromotionWithTypes */ + public function __construct(protected float|int $x, public ?string &$y = 'test', private mixed $z) {} +} + +class ConstructorPropertyPromotionAndNormalParams { + /* testPHP8ConstructorPropertyPromotionAndNormalParam */ + public function __construct(public int $promotedProp, ?int $normalArg) {} +} + +class ConstructorPropertyPromotionWithReadOnly { + /* testPHP81ConstructorPropertyPromotionWithReadOnly */ + public function __construct(public readonly ?int $promotedProp, ReadOnly private string|bool &$promotedToo) {} +} + +/* testPHP8ConstructorPropertyPromotionGlobalFunction */ +// Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method. +function globalFunction(private $x) {} + +abstract class ConstructorPropertyPromotionAbstractMethod { + /* testPHP8ConstructorPropertyPromotionAbstractMethod */ + // Intentional fatal error. + // 1. Property promotion not allowed in abstract method, but that's not the concern of this method. + // 2. Variadic arguments not allowed in property promotion, but that's not the concern of this method. + // 3. The callable type is not supported for properties, but that's not the concern of this method. + abstract public function __construct(public callable $y, private ...$x); +} + +/* testCommentsInParameter */ +function commentsInParams( + // Leading comment. + ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ 'default value' . /*-*/ 'second part' // Trailing comment. +) {} + +/* testParameterAttributesInFunctionDeclaration */ +class ParametersWithAttributes( + public function __construct( + #[\MyExample\MyAttribute] private string $constructorPropPromTypedParamSingleAttribute, + #[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute, + #[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute, + #[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes, + #[MyAttribute(array("key" => "value"))] + &...$otherParam, + ) {} +} + +/* testPHP8IntersectionTypes */ +function intersectionTypes(Foo&Bar $obj1, Boo&Bar $obj2) {} + +/* testPHP81IntersectionTypesWithSpreadOperatorAndReference */ +function globalFunctionWithSpreadAndReference(Boo&Bar &$paramA, Foo&Bar ...$paramB) {} + +/* testPHP81MoreIntersectionTypes */ +function moreIntersectionTypes(MyClassA&\Package\MyClassB&\Package\MyClassC $var) {} + +/* testPHP81IllegalIntersectionTypes */ +// Intentional fatal error - simple types are not allowed with intersection types, but that's not the concern of the method. +$closure = function (string&int $numeric_string) {}; + +/* testPHP81NullableIntersectionTypes */ +// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. +$closure = function (?Foo&Bar $object) {}; + +/* testPHP81NewInInitializers */ +function newInInitializers( + TypeA $new = new TypeA(self::CONST_VALUE), + \Package\TypeB $newToo = new \Package\TypeB(10, 'string'), +) {} + /* testFunctionCallFnPHPCS353-354 */ $value = $obj->fn(true); /* testClosureNoParams */ -function() {} +function() {}; /* testClosure */ -function( $a = 'test' ) {} +function( $a = 'test' ) {}; /* testClosureUseNoParams */ -function() use() {} +function() use() {}; /* testClosureUse */ -function() use( $foo, $bar ) {} +function() use( $foo, $bar ) {}; + +/* testFunctionParamListWithTrailingComma */ +function trailingComma( + ?string $foo /*comment*/ , + $bar = 0, +) {} + +/* testClosureParamListWithTrailingComma */ +function( + $foo, + $bar, +) {}; + +/* testArrowFunctionParamListWithTrailingComma */ +$fn = fn( ?int $a , ...$b, ) => $b; + +/* testClosureUseWithTrailingComma */ +function() use( + $foo /*comment*/ , + $bar, +) {}; /* testInvalidUse */ -function() use {} // Intentional parse error. +function() use {}; // Intentional parse error. /* testArrowFunctionLiveCoding */ // Intentional parse error. This has to be the last test in the file. diff --git a/Tests/BackCompat/BCFile/GetMethodParametersTest.php b/Tests/BackCompat/BCFile/GetMethodParametersTest.php index 302403fa..e47336aa 100644 --- a/Tests/BackCompat/BCFile/GetMethodParametersTest.php +++ b/Tests/BackCompat/BCFile/GetMethodParametersTest.php @@ -25,7 +25,6 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodParameters method. @@ -73,11 +72,11 @@ public function dataUnexpectedTokenException() ], 'function-call-fn-phpcs-3.5.3-3.5.4' => [ '/* testFunctionCallFnPHPCS353-354 */', - Collections::arrowFunctionTokensBC(), + [T_FN, T_STRING], ], 'fn-live-coding' => [ '/* testArrowFunctionLiveCoding */', - Collections::arrowFunctionTokensBC(), + [T_FN, T_STRING], ], ]; } @@ -123,11 +122,11 @@ public function dataInvalidUse() * * @param string $commentString The comment which preceeds the test. * @param array $targetTokenType Optional. The token type to search for after $commentString. - * Defaults to the function/closure tokens. + * Defaults to the function/closure/arrow tokens. * * @return void */ - public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_CLOSURE]) + public function testNoParams($commentString, $targetTokenType = [T_FUNCTION, T_CLOSURE, \T_FN]) { $target = $this->getTargetToken($commentString, $targetTokenType); $result = BCFile::getMethodParameters(self::$phpcsFile, $target); @@ -163,6 +162,7 @@ public function testPassByReference() 'token' => 5, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => '&$var', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 4, // Offset from the T_FUNCTION token. 'variable_length' => false, @@ -189,6 +189,7 @@ public function testArrayHint() 'token' => 6, // Offset from the T_FUNCTION token. 'name' => '$var', 'content' => 'array $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -204,39 +205,25 @@ public function testArrayHint() } /** - * Verify type hint parsing. + * Verify variable. * * @return void */ - public function testTypeHint() + public function testVariable() { $expected = []; $expected[0] = [ - 'token' => 6, // Offset from the T_FUNCTION token. - 'name' => '$var1', - 'content' => 'foo $var1', - 'pass_by_reference' => false, - 'reference_token' => false, - 'variable_length' => false, - 'variadic_token' => false, - 'type_hint' => 'foo', - 'type_hint_token' => 4, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. - 'nullable_type' => false, - 'comma_token' => 7, // Offset from the T_FUNCTION token. - ]; - - $expected[1] = [ - 'token' => 11, // Offset from the T_FUNCTION token. - 'name' => '$var2', - 'content' => 'bar $var2', + 'token' => 4, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => '$var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => 'bar', - 'type_hint_token' => 9, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 9, // Offset from the T_FUNCTION token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, 'nullable_type' => false, 'comma_token' => false, ]; @@ -245,24 +232,28 @@ public function testTypeHint() } /** - * Verify self type hint parsing. + * Verify default value parsing with a single function param. * * @return void */ - public function testSelfTypeHint() + public function testSingleDefaultValue() { $expected = []; $expected[0] = [ - 'token' => 6, // Offset from the T_FUNCTION token. - 'name' => '$var', - 'content' => 'self $var', + 'token' => 4, // Offset from the T_FUNCTION token. + 'name' => '$var1', + 'content' => '$var1=self::CONSTANT', + 'default' => 'self::CONSTANT', + 'default_token' => 6, // Offset from the T_FUNCTION token. + 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => 'self', - 'type_hint_token' => 4, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, 'nullable_type' => false, 'comma_token' => false, ]; @@ -271,40 +262,47 @@ public function testSelfTypeHint() } /** - * Verify nullable type hint parsing. + * Verify default value parsing. * * @return void */ - public function testNullableTypeHint() + public function testDefaultValues() { $expected = []; $expected[0] = [ - 'token' => 7, // Offset from the T_FUNCTION token. + 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$var1', - 'content' => '?int $var1', + 'content' => '$var1=1', + 'default' => '1', + 'default_token' => 6, // Offset from the T_FUNCTION token. + 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '?int', - 'type_hint_token' => 5, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. - 'nullable_type' => true, - 'comma_token' => 8, // Offset from the T_FUNCTION token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 7, // Offset from the T_FUNCTION token. ]; - $expected[1] = [ - 'token' => 14, // Offset from the T_FUNCTION token. + 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$var2', - 'content' => '?\bar $var2', + 'content' => "\$var2='value'", + 'default' => "'value'", + 'default_token' => 11, // Offset from the T_FUNCTION token. + 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '?\bar', - 'type_hint_token' => 11, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 12, // Offset from the T_FUNCTION token. - 'nullable_type' => true, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, 'comma_token' => false, ]; @@ -312,24 +310,41 @@ public function testNullableTypeHint() } /** - * Verify variable. + * Verify type hint parsing. * * @return void */ - public function testVariable() + public function testTypeHint() { $expected = []; $expected[0] = [ - 'token' => 4, // Offset from the T_FUNCTION token. - 'name' => '$var', - 'content' => '$var', + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var1', + 'content' => 'foo $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, + 'type_hint' => 'foo', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 7, // Offset from the T_FUNCTION token. + ]; + + $expected[1] = [ + 'token' => 11, // Offset from the T_FUNCTION token. + 'name' => '$var2', + 'content' => 'bar $var2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bar', + 'type_hint_token' => 9, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 9, // Offset from the T_FUNCTION token. 'nullable_type' => false, 'comma_token' => false, ]; @@ -338,27 +353,25 @@ public function testVariable() } /** - * Verify default value parsing with a single function param. + * Verify self type hint parsing. * * @return void */ - public function testSingleDefaultValue() + public function testSelfTypeHint() { $expected = []; $expected[0] = [ - 'token' => 4, // Offset from the T_FUNCTION token. - 'name' => '$var1', - 'content' => '$var1=self::CONSTANT', - 'default' => 'self::CONSTANT', - 'default_token' => 6, // Offset from the T_FUNCTION token. - 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'self $var', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, + 'type_hint' => 'self', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. 'nullable_type' => false, 'comma_token' => false, ]; @@ -367,45 +380,44 @@ public function testSingleDefaultValue() } /** - * Verify default value parsing. + * Verify nullable type hint parsing. * * @return void */ - public function testDefaultValues() + public function testNullableTypeHint() { + $php8Names = parent::usesPhp8NameTokens(); + $expected = []; $expected[0] = [ - 'token' => 4, // Offset from the T_FUNCTION token. + 'token' => 7, // Offset from the T_FUNCTION token. 'name' => '$var1', - 'content' => '$var1=1', - 'default' => '1', - 'default_token' => 6, // Offset from the T_FUNCTION token. - 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'content' => '?int $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, - 'nullable_type' => false, - 'comma_token' => 7, // Offset from the T_FUNCTION token. + 'type_hint' => '?int', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => 8, // Offset from the T_FUNCTION token. ]; + $expected[1] = [ - 'token' => 9, // Offset from the T_FUNCTION token. + 'token' => ($php8Names === true) ? 13 : 14, // Offset from the T_FUNCTION token. 'name' => '$var2', - 'content' => "\$var2='value'", - 'default' => "'value'", - 'default_token' => 11, // Offset from the T_FUNCTION token. - 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'content' => '?\bar $var2', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, - 'nullable_type' => false, + 'type_hint' => '?\bar', + 'type_hint_token' => 11, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 11 : 12, // Offset from the T_FUNCTION token. + 'nullable_type' => true, 'comma_token' => false, ]; @@ -427,6 +439,7 @@ public function testBitwiseAndConstantExpressionDefaultValue() 'default' => '10 & 20', 'default_token' => 8, // Offset from the T_FUNCTION token. 'default_equal_token' => 6, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -453,6 +466,7 @@ public function testArrowFunction() 'token' => 4, // Offset from the T_FN token. 'name' => '$a', 'content' => 'int $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -468,6 +482,7 @@ public function testArrowFunction() 'token' => 8, // Offset from the T_FN token. 'name' => '$b', 'content' => '...$b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -479,9 +494,7 @@ public function testArrowFunction() 'comma_token' => false, ]; - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** @@ -496,6 +509,7 @@ public function testArrowFunctionReturnByRef() 'token' => 6, // Offset from the T_FN token. 'name' => '$a', 'content' => '?string $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -507,9 +521,7 @@ public function testArrowFunctionReturnByRef() 'comma_token' => false, ]; - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** @@ -527,6 +539,7 @@ public function testArrayDefaultValues() 'default' => '[]', 'default_token' => 8, // Offset from the T_FUNCTION token. 'default_equal_token' => 6, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -544,6 +557,7 @@ public function testArrayDefaultValues() 'default' => 'array(1, 2, 3)', 'default_token' => 16, // Offset from the T_FUNCTION token. 'default_equal_token' => 14, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -570,6 +584,7 @@ public function testConstantDefaultValueSecondParam() 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$var1', 'content' => '$var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -587,6 +602,7 @@ public function testConstantDefaultValueSecondParam() 'default' => 'M_PI', 'default_token' => 11, // Offset from the T_FUNCTION token. 'default_equal_token' => 9, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -616,6 +632,7 @@ public function testScalarTernaryExpressionInDefault() 'default' => 'FOO ? \'bar\' : 10', 'default_token' => 9, // Offset from the T_FUNCTION token. 'default_equal_token' => 7, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -630,6 +647,7 @@ public function testScalarTernaryExpressionInDefault() 'token' => 24, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => '? bool $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -656,6 +674,7 @@ public function testVariadicFunction() 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => 'int ... $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -682,6 +701,7 @@ public function testVariadicByRefFunction() 'token' => 7, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '&...$a', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 5, // Offset from the T_FUNCTION token. 'variable_length' => true, @@ -708,6 +728,7 @@ public function testVariadicFunctionClassType() 'token' => 4, // Offset from the T_FUNCTION token. 'name' => '$unit', 'content' => '$unit', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -722,6 +743,7 @@ public function testVariadicFunctionClassType() 'token' => 10, // Offset from the T_FUNCTION token. 'name' => '$intervals', 'content' => 'DateInterval ...$intervals', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -743,32 +765,36 @@ public function testVariadicFunctionClassType() */ public function testNameSpacedTypeDeclaration() { + $php8Names = parent::usesPhp8NameTokens(); + $expected = []; $expected[0] = [ - 'token' => 12, // Offset from the T_FUNCTION token. + 'token' => ($php8Names === true) ? 7 : 12, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '\Package\Sub\ClassName $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, 'type_hint' => '\Package\Sub\ClassName', 'type_hint_token' => 5, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 10, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 5 : 10, // Offset from the T_FUNCTION token. 'nullable_type' => false, - 'comma_token' => 13, // Offset from the T_FUNCTION token. + 'comma_token' => ($php8Names === true) ? 8 : 13, // Offset from the T_FUNCTION token. ]; $expected[1] = [ - 'token' => 20, // Offset from the T_FUNCTION token. + 'token' => ($php8Names === true) ? 13 : 20, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => '?Sub\AnotherClass $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, 'type_hint' => '?Sub\AnotherClass', - 'type_hint_token' => 16, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 18, // Offset from the T_FUNCTION token. + 'type_hint_token' => ($php8Names === true) ? 11 : 16, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 11 : 18, // Offset from the T_FUNCTION token. 'nullable_type' => true, 'comma_token' => false, ]; @@ -788,6 +814,7 @@ public function testWithAllTypes() 'token' => 9, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '?ClassName $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -802,6 +829,7 @@ public function testWithAllTypes() 'token' => 15, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => 'self $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -816,6 +844,7 @@ public function testWithAllTypes() 'token' => 21, // Offset from the T_FUNCTION token. 'name' => '$c', 'content' => 'parent $c', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -830,6 +859,7 @@ public function testWithAllTypes() 'token' => 27, // Offset from the T_FUNCTION token. 'name' => '$d', 'content' => 'object $d', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -844,6 +874,7 @@ public function testWithAllTypes() 'token' => 34, // Offset from the T_FUNCTION token. 'name' => '$e', 'content' => '?int $e', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -858,6 +889,7 @@ public function testWithAllTypes() 'token' => 41, // Offset from the T_FUNCTION token. 'name' => '$f', 'content' => 'string &$f', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 40, // Offset from the T_FUNCTION token. 'variable_length' => false, @@ -872,6 +904,7 @@ public function testWithAllTypes() 'token' => 47, // Offset from the T_FUNCTION token. 'name' => '$g', 'content' => 'iterable $g', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -889,6 +922,7 @@ public function testWithAllTypes() 'default' => 'true', 'default_token' => 57, // Offset from the T_FUNCTION token. 'default_equal_token' => 55, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -906,6 +940,7 @@ public function testWithAllTypes() 'default' => "'is_null'", 'default_token' => 67, // Offset from the T_FUNCTION token. 'default_equal_token' => 65, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -923,6 +958,7 @@ public function testWithAllTypes() 'default' => '1.1', 'default_token' => 77, // Offset from the T_FUNCTION token. 'default_equal_token' => 75, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -937,6 +973,7 @@ public function testWithAllTypes() 'token' => 84, // Offset from the T_FUNCTION token. 'name' => '$k', 'content' => 'array ...$k', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -963,6 +1000,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 7, // Offset from the T_FN token. 'name' => '$a', 'content' => '?ClassName $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -977,6 +1015,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 13, // Offset from the T_FN token. 'name' => '$b', 'content' => 'self $b', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -991,6 +1030,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 19, // Offset from the T_FN token. 'name' => '$c', 'content' => 'parent $c', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1005,6 +1045,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 25, // Offset from the T_FN token. 'name' => '$d', 'content' => 'object $d', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1019,6 +1060,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 32, // Offset from the T_FN token. 'name' => '$e', 'content' => '?int $e', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1033,6 +1075,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 39, // Offset from the T_FN token. 'name' => '$f', 'content' => 'string &$f', + 'has_attributes' => false, 'pass_by_reference' => true, 'reference_token' => 38, // Offset from the T_FN token. 'variable_length' => false, @@ -1047,6 +1090,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 45, // Offset from the T_FN token. 'name' => '$g', 'content' => 'iterable $g', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1064,6 +1108,7 @@ public function testArrowFunctionWithAllTypes() 'default' => 'true', 'default_token' => 55, // Offset from the T_FN token. 'default_equal_token' => 53, // Offset from the T_FN token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1081,6 +1126,7 @@ public function testArrowFunctionWithAllTypes() 'default' => "'is_null'", 'default_token' => 65, // Offset from the T_FN token. 'default_equal_token' => 63, // Offset from the T_FN token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1098,6 +1144,7 @@ public function testArrowFunctionWithAllTypes() 'default' => '1.1', 'default_token' => 75, // Offset from the T_FN token. 'default_equal_token' => 73, // Offset from the T_FN token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1112,6 +1159,7 @@ public function testArrowFunctionWithAllTypes() 'token' => 82, // Offset from the T_FN token. 'name' => '$k', 'content' => 'array ...$k', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => true, @@ -1123,9 +1171,7 @@ public function testArrowFunctionWithAllTypes() 'comma_token' => false, ]; - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** @@ -1135,31 +1181,35 @@ public function testArrowFunctionWithAllTypes() */ public function testMessyDeclaration() { + $php8Names = parent::usesPhp8NameTokens(); + $expected = []; $expected[0] = [ - 'token' => 25, // Offset from the T_FUNCTION token. + 'token' => ($php8Names === true) ? 24 : 25, // Offset from the T_FUNCTION token. 'name' => '$a', 'content' => '// comment ?\MyNS /* comment */ \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. \ MyClass $a', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, 'type_hint' => '?\MyNS\SubCat\MyClass', 'type_hint_token' => 9, - 'type_hint_end_token' => 23, + 'type_hint_end_token' => ($php8Names === true) ? 22 : 23, 'nullable_type' => true, - 'comma_token' => 26, // Offset from the T_FUNCTION token. + 'comma_token' => ($php8Names === true) ? 25 : 26, // Offset from the T_FUNCTION token. ]; $expected[1] = [ - 'token' => 29, // Offset from the T_FUNCTION token. + 'token' => ($php8Names === true) ? 28 : 29, // Offset from the T_FUNCTION token. 'name' => '$b', 'content' => "\$b /* test */ = /* test */ 'default' /* test*/", 'default' => "'default' /* test*/", - 'default_token' => 37, // Offset from the T_FUNCTION token. - 'default_equal_token' => 33, // Offset from the T_FUNCTION token. + 'default_token' => ($php8Names === true) ? 36 : 37, // Offset from the T_FUNCTION token. + 'default_equal_token' => ($php8Names === true) ? 32 : 33, // Offset from the T_FUNCTION token. + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, @@ -1168,22 +1218,23 @@ public function testMessyDeclaration() 'type_hint_token' => false, 'type_hint_end_token' => false, 'nullable_type' => false, - 'comma_token' => 40, // Offset from the T_FUNCTION token. + 'comma_token' => ($php8Names === true) ? 39 : 40, // Offset from the T_FUNCTION token. ]; $expected[2] = [ - 'token' => 62, // Offset from the T_FUNCTION token. + 'token' => ($php8Names === true) ? 61 : 62, // Offset from the T_FUNCTION token. 'name' => '$c', 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- For reasons. ? /*comment*/ bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. & /*test*/ ... /* phpcs:ignore */ $c', + 'has_attributes' => false, 'pass_by_reference' => true, - 'reference_token' => 54, // Offset from the T_FUNCTION token. + 'reference_token' => ($php8Names === true) ? 53 : 54, // Offset from the T_FUNCTION token. 'variable_length' => true, - 'variadic_token' => 58, // Offset from the T_FUNCTION token. + 'variadic_token' => ($php8Names === true) ? 57 : 58, // Offset from the T_FUNCTION token. 'type_hint' => '?bool', - 'type_hint_token' => 50, // Offset from the T_FUNCTION token. - 'type_hint_end_token' => 50, // Offset from the T_FUNCTION token. + 'type_hint_token' => ($php8Names === true) ? 49 : 50, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 49 : 50, // Offset from the T_FUNCTION token. 'nullable_type' => true, 'comma_token' => false, ]; @@ -1192,27 +1243,25 @@ public function testMessyDeclaration() } /** - * Verify handling of a closure. + * Verify recognition of PHP8 mixed type declaration. * * @return void */ - public function testClosure() + public function testPHP8MixedTypeHint() { $expected = []; $expected[0] = [ - 'token' => 3, // Offset from the T_FUNCTION token. - 'name' => '$a', - 'content' => '$a = \'test\'', - 'default' => "'test'", - 'default_token' => 7, // Offset from the T_FUNCTION token. - 'default_equal_token' => 5, // Offset from the T_FUNCTION token. - 'pass_by_reference' => false, - 'reference_token' => false, - 'variable_length' => false, - 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$var1', + 'content' => 'mixed &...$var1', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 6, // Offset from the T_FUNCTION token. + 'variable_length' => true, + 'variadic_token' => 7, // Offset from the T_FUNCTION token. + 'type_hint' => 'mixed', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. 'nullable_type' => false, 'comma_token' => false, ]; @@ -1221,64 +1270,1382 @@ public function testClosure() } /** - * Verify handling of a closure T_USE token correctly. + * Verify recognition of PHP8 mixed type declaration with nullability. * * @return void */ - public function testClosureUse() + public function testPHP8MixedTypeHintNullable() { $expected = []; $expected[0] = [ - 'token' => 3, // Offset from the T_USE token. - 'name' => '$foo', - 'content' => '$foo', + 'token' => 7, // Offset from the T_FUNCTION token. + 'name' => '$var1', + 'content' => '?Mixed $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, - 'nullable_type' => false, - 'comma_token' => 4, // Offset from the T_USE token. + 'type_hint' => '?Mixed', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, ]; - $expected[1] = [ - 'token' => 6, // Offset from the T_USE token. - 'name' => '$bar', - 'content' => '$bar', + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of type declarations using the namespace operator. + * + * @return void + */ + public function testNamespaceOperatorTypeHint() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => ($php8Names === true) ? 7 : 9, // Offset from the T_FUNCTION token. + 'name' => '$var1', + 'content' => '?namespace\Name $var1', + 'has_attributes' => false, 'pass_by_reference' => false, 'reference_token' => false, 'variable_length' => false, 'variadic_token' => false, - 'type_hint' => '', - 'type_hint_token' => false, - 'type_hint_end_token' => false, - 'nullable_type' => false, + 'type_hint' => '?namespace\Name', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 5 : 7, // Offset from the T_FUNCTION token. + 'nullable_type' => true, 'comma_token' => false, ]; - $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, [T_USE]); + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** - * Test helper. - * - * @param string $commentString The comment which preceeds the test. - * @param array $expected The expected function output. - * @param array $targetType Optional. The token type to search for after $commentString. - * Defaults to the function/closure tokens. + * Verify recognition of PHP8 union type declaration. * * @return void */ - protected function getMethodParametersTestHelper($commentString, $expected, $targetType = [T_FUNCTION, T_CLOSURE]) + public function testPHP8UnionTypesSimple() { - $target = $this->getTargetToken($commentString, $targetType); - $found = BCFile::getMethodParameters(self::$phpcsFile, $target); - - foreach ($expected as $key => $param) { - $expected[$key]['token'] += $target; - - if ($param['reference_token'] !== false) { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$number', + 'content' => 'int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 17, // Offset from the T_FUNCTION token. + 'name' => '$obj', + 'content' => 'self|parent &...$obj', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 15, // Offset from the T_FUNCTION token. + 'variable_length' => true, + 'variadic_token' => 16, + 'type_hint' => 'self|parent', + 'type_hint_token' => 11, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 13, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration when the variable has either a spread operator or a reference. + * + * @return void + */ + public function testPHP8UnionTypesWithSpreadOperatorAndReference() + { + $expected = []; + $expected[0] = [ + 'token' => 9, // Offset from the T_FUNCTION token. + 'name' => '$paramA', + 'content' => 'float|null &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, // Offset from the T_FUNCTION token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|null', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, // Offset from the T_FUNCTION token. + 'name' => '$paramB', + 'content' => 'string|int ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, // Offset from the T_FUNCTION token. + 'type_hint' => 'string|int', + 'type_hint_token' => 12, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with a bitwise or in the default value. + * + * @return void + */ + public function testPHP8UnionTypesSimpleWithBitwiseOrInDefault() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'int|float $var = CONSTANT_A | CONSTANT_B', + 'default' => 'CONSTANT_A | CONSTANT_B', + 'default_token' => 10, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|float', + 'type_hint_token' => 2, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => ($php8Names === true) ? 8 : 11, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'MyClassA|\Package\MyClassB $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA|\Package\MyClassB', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 6 : 9, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 20, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'array|bool|callable|int|float|null|object|string $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'array|bool|callable|int|float|null|object|string', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 18, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 16, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'false|mixed|self|parent|iterable|Resource $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|mixed|self|parent|iterable|Resource', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$number', + 'content' => '?int|float $number', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int|float', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'null $var = null', + 'default' => 'null', + 'default_token' => 10, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'null', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'false $var = false', + 'default' => 'false', + 'default_token' => 10, // Offset from the T_FUNCTION token. + 'default_equal_token' => 8, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 4, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'bool|false $var = false', + 'default' => 'false', + 'default_token' => 12, // Offset from the T_FUNCTION token. + 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'bool|false', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'object|ClassName $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'object|ClassName', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + $expected = []; + $expected[0] = [ + 'token' => 10, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'iterable|array|Traversable $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'iterable|array|Traversable', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + $expected = []; + $expected[0] = [ + 'token' => 17, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'int | string /*comment*/ | INT $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int|string|INT', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 15, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 constructor property promotion without type declaration, with defaults. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionNoTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$x', + 'content' => 'public $x = 0.0', + 'default' => '0.0', + 'default_token' => 12, // Offset from the T_FUNCTION token. + 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 6, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 18, // Offset from the T_FUNCTION token. + 'name' => '$y', + 'content' => 'protected $y = \'\'', + 'default' => "''", + 'default_token' => 22, // Offset from the T_FUNCTION token. + 'default_equal_token' => 20, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 16, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 23, + ]; + $expected[2] = [ + 'token' => 28, // Offset from the T_FUNCTION token. + 'name' => '$z', + 'content' => 'private $z = null', + 'default' => 'null', + 'default_token' => 32, // Offset from the T_FUNCTION token. + 'default_equal_token' => 30, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 33, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 constructor property promotion with type declarations. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionWithTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 10, // Offset from the T_FUNCTION token. + 'name' => '$x', + 'content' => 'protected float|int $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'float|int', + 'type_hint_token' => 6, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'protected', + 'visibility_token' => 4, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 11, + ]; + $expected[1] = [ + 'token' => 19, // Offset from the T_FUNCTION token. + 'name' => '$y', + 'content' => 'public ?string &$y = \'test\'', + 'default' => "'test'", + 'default_token' => 23, // Offset from the T_FUNCTION token. + 'default_equal_token' => 21, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 18, // Offset from the T_FUNCTION token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 16, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 16, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 13, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 24, + ]; + $expected[2] = [ + 'token' => 30, // Offset from the T_FUNCTION token. + 'name' => '$z', + 'content' => 'private mixed $z', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'mixed', + 'type_hint_token' => 28, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 28, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 26, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 constructor with both property promotion as well as normal parameters. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionAndNormalParam() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$promotedProp', + 'content' => 'public int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 6, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, // Offset from the T_FUNCTION token. + 'name' => '$normalArg', + 'content' => '?int $normalArg', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 12, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 12, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.1 readonly keyword. + * + * @return void + */ + public function testPHP81ConstructorPropertyPromotionWithReadOnly() + { + $expected = []; + $expected[0] = [ + 'token' => 11, // Offset from the T_FUNCTION token. + 'name' => '$promotedProp', + 'content' => 'public readonly ?int $promotedProp', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 9, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 4, // Offset from the T_FUNCTION token. + 'property_readonly' => true, + 'readonly_token' => 6, // Offset from the T_FUNCTION token. + 'comma_token' => 12, + ]; + $expected[1] = [ + 'token' => 23, // Offset from the T_FUNCTION token. + 'name' => '$promotedToo', + 'content' => 'ReadOnly private string|bool &$promotedToo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 22, // Offset from the T_FUNCTION token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string|bool', + 'type_hint_token' => 18, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 20, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 16, // Offset from the T_FUNCTION token. + 'property_readonly' => true, + 'readonly_token' => 14, // Offset from the T_FUNCTION token. + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionGlobalFunction() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FUNCTION token. + 'name' => '$x', + 'content' => 'private $x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 4, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify behaviour when an abstract constructor uses PHP 8 property promotion syntax. + * + * @return void + */ + public function testPHP8ConstructorPropertyPromotionAbstractMethod() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$y', + 'content' => 'public callable $y', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'callable', + 'type_hint_token' => 6, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => 4, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 14, // Offset from the T_FUNCTION token. + 'name' => '$x', + 'content' => 'private ...$x', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 13, // Offset from the T_FUNCTION token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => 11, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify and document behaviour when there are comments within a parameter declaration. + * + * @return void + */ + public function testCommentsInParameter() + { + $expected = []; + $expected[0] = [ + 'token' => 19, // Offset from the T_FUNCTION token. + 'name' => '$param', + 'content' => '// Leading comment. + ?MyClass /*-*/ & /*-*/.../*-*/ $param /*-*/ = /*-*/ \'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default' => '\'default value\' . /*-*/ \'second part\' // Trailing comment.', + 'default_token' => 27, // Offset from the T_FUNCTION token. + 'default_equal_token' => 23, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 13, // Offset from the T_FUNCTION token. + 'variable_length' => true, + 'variadic_token' => 16, // Offset from the T_FUNCTION token. + 'type_hint' => '?MyClass', + 'type_hint_token' => 9, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify behaviour when parameters have attributes attached. + * + * @return void + */ + public function testParameterAttributesInFunctionDeclaration() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => ($php8Names === true) ? 14 : 17, // Offset from the T_FUNCTION token. + 'name' => '$constructorPropPromTypedParamSingleAttribute', + 'content' => '#[\MyExample\MyAttribute] private string' + . ' $constructorPropPromTypedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string', + 'type_hint_token' => ($php8Names === true) ? 12 : 15, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 12 : 15, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'property_visibility' => 'private', + 'visibility_token' => ($php8Names === true) ? 10 : 13, // Offset from the T_FUNCTION token. + 'property_readonly' => false, + 'comma_token' => ($php8Names === true) ? 15 : 18, // Offset from the T_FUNCTION token. + ]; + $expected[1] = [ + 'token' => ($php8Names === true) ? 36 : 39, // Offset from the T_FUNCTION token. + 'name' => '$typedParamSingleAttribute', + 'content' => '#[MyAttr([1, 2])] + Type|false + $typedParamSingleAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Type|false', + 'type_hint_token' => ($php8Names === true) ? 31 : 34, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 33 : 36, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 37 : 40, // Offset from the T_FUNCTION token. + ]; + $expected[2] = [ + 'token' => ($php8Names === true) ? 56 : 59, // Offset from the T_FUNCTION token. + 'name' => '$nullableTypedParamMultiAttribute', + 'content' => '#[MyAttribute(1234), MyAttribute(5678)] ?int $nullableTypedParamMultiAttribute', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => ($php8Names === true) ? 54 : 57, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 54 : 57, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => ($php8Names === true) ? 57 : 60, // Offset from the T_FUNCTION token. + ]; + $expected[3] = [ + 'token' => ($php8Names === true) ? 71 : 74, // Offset from the T_FUNCTION token. + 'name' => '$nonTypedParamTwoAttributes', + 'content' => '#[WithoutArgument] #[SingleArgument(0)] $nonTypedParamTwoAttributes', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 72 : 75, // Offset from the T_FUNCTION token. + ]; + $expected[4] = [ + 'token' => ($php8Names === true) ? 92 : 95, // Offset from the T_FUNCTION token. + 'name' => '$otherParam', + 'content' => '#[MyAttribute(array("key" => "value"))] + &...$otherParam', + 'has_attributes' => true, + 'pass_by_reference' => true, + 'reference_token' => ($php8Names === true) ? 90 : 93, // Offset from the T_FUNCTION token. + 'variable_length' => true, + 'variadic_token' => ($php8Names === true) ? 91 : 94, // Offset from the T_FUNCTION token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 93 : 96, // Offset from the T_FUNCTION token. + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$obj1', + 'content' => 'Foo&Bar $obj1', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 9, + ]; + $expected[1] = [ + 'token' => 15, // Offset from the T_FUNCTION token. + 'name' => '$obj2', + 'content' => 'Boo&Bar $obj2', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 11, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 13, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 intersection type declaration when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP81IntersectionTypesWithSpreadOperatorAndReference() + { + $expected = []; + $expected[0] = [ + 'token' => 9, // Offset from the T_FUNCTION token. + 'name' => '$paramA', + 'content' => 'Boo&Bar &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 8, // Offset from the T_FUNCTION token. + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Boo&Bar', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 10, + ]; + $expected[1] = [ + 'token' => 17, // Offset from the T_FUNCTION token. + 'name' => '$paramB', + 'content' => 'Foo&Bar ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 16, // Offset from the T_FUNCTION token. + 'type_hint' => 'Foo&Bar', + 'type_hint_token' => 12, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => ($php8Names === true) ? 10 : 16, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'MyClassA&\Package\MyClassB&\Package\MyClassC $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 8 : 14, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 7, // Offset from the T_FUNCTION token. + 'name' => '$numeric_string', + 'content' => 'string&int $numeric_string', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string&int', + 'type_hint_token' => 3, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableIntersectionTypes() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$object', + 'content' => '?Foo&Bar $object', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Foo&Bar', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify behaviour when the default value uses the "new" keyword, as is allowed per PHP 8.1. + * + * @return void + */ + public function testPHP81NewInInitializers() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$new', + 'content' => 'TypeA $new = new TypeA(self::CONST_VALUE)', + 'default' => 'new TypeA(self::CONST_VALUE)', + 'default_token' => 12, // Offset from the T_FUNCTION token. + 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'TypeA', + 'type_hint_token' => 6, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => 20, + ]; + $expected[1] = [ + 'token' => ($php8Names === true) ? 25 : 28, // Offset from the T_FUNCTION token. + 'name' => '$newToo', + 'content' => '\Package\TypeB $newToo = new \Package\TypeB(10, \'string\')', + 'default' => "new \Package\TypeB(10, 'string')", + 'default_token' => ($php8Names === true) ? 29 : 32, // Offset from the T_FUNCTION token. + 'default_equal_token' => ($php8Names === true) ? 27 : 30, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '\Package\TypeB', + 'type_hint_token' => 23, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => ($php8Names === true) ? 23 : 26, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => ($php8Names === true) ? 38 : 44, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify handling of a closure. + * + * @return void + */ + public function testClosure() + { + $expected = []; + $expected[0] = [ + 'token' => 3, // Offset from the T_FUNCTION token. + 'name' => '$a', + 'content' => '$a = \'test\'', + 'default' => "'test'", + 'default_token' => 7, // Offset from the T_FUNCTION token. + 'default_equal_token' => 5, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify handling of a closure T_USE token correctly. + * + * @return void + */ + public function testClosureUse() + { + $expected = []; + $expected[0] = [ + 'token' => 3, // Offset from the T_USE token. + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 4, // Offset from the T_USE token. + ]; + $expected[1] = [ + 'token' => 6, // Offset from the T_USE token. + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, [T_USE]); + } + + /** + * Verify function declarations with trailing commas are handled correctly. + * + * @return void + */ + public function testFunctionParamListWithTrailingComma() + { + $expected = []; + $expected[0] = [ + 'token' => 9, // Offset from the T_FUNCTION token. + 'name' => '$foo', + 'content' => '?string $foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?string', + 'type_hint_token' => 7, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => 13, // Offset from the T_FUNCTION token. + ]; + $expected[1] = [ + 'token' => 16, // Offset from the T_FUNCTION token. + 'name' => '$bar', + 'content' => '$bar = 0', + 'default' => '0', + 'default_token' => 20, // Offset from the T_FUNCTION token. + 'default_equal_token' => 18, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 21, // Offset from the T_FUNCTION token. + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify closure declarations with trailing commas are handled correctly. + * + * @return void + */ + public function testClosureParamListWithTrailingComma() + { + $expected = []; + $expected[0] = [ + 'token' => 4, // Offset from the T_FUNCTION token. + 'name' => '$foo', + 'content' => '$foo', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, // Offset from the T_FUNCTION token. + ]; + $expected[1] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 9, // Offset from the T_FUNCTION token. + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify arrow function declarations with trailing commas are handled correctly. + * + * @return void + */ + public function testArrowFunctionParamListWithTrailingComma() + { + $expected = []; + $expected[0] = [ + 'token' => 6, // Offset from the T_FN token. + 'name' => '$a', + 'content' => '?int $a', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?int', + 'type_hint_token' => 4, // Offset from the T_FN token. + 'type_hint_end_token' => 4, // Offset from the T_FN token. + 'nullable_type' => true, + 'comma_token' => 8, // Offset from the T_FN token. + ]; + $expected[1] = [ + 'token' => 11, // Offset from the T_FN token. + 'name' => '$b', + 'content' => '...$b', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 10, // Offset from the T_FN token. + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, // Offset from the T_FN token. + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify closure T_USE statements with trailing commas are handled correctly. + * + * @return void + */ + public function testClosureUseWithTrailingComma() + { + $expected = []; + $expected[0] = [ + 'token' => 4, // Offset from the T_USE token. + 'name' => '$foo', + 'content' => '$foo /*comment*/', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 8, // Offset from the T_USE token. + ]; + $expected[1] = [ + 'token' => 11, // Offset from the T_USE token. + 'name' => '$bar', + 'content' => '$bar', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 12, // Offset from the T_USE token. + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected, [T_USE]); + } + + /** + * Test helper. + * + * @param string $marker The comment which preceeds the test. + * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $marker. + * Defaults to the function/closure/arrow tokens. + * + * @return void + */ + protected function getMethodParametersTestHelper($marker, $expected, $targetType = [T_FUNCTION, T_CLOSURE, T_FN]) + { + $target = $this->getTargetToken($marker, $targetType); + $found = BCFile::getMethodParameters(self::$phpcsFile, $target); + + foreach ($expected as $key => $param) { + $expected[$key]['token'] += $target; + + if ($param['reference_token'] !== false) { $expected[$key]['reference_token'] += $target; } if ($param['variadic_token'] !== false) { @@ -1299,6 +2666,12 @@ protected function getMethodParametersTestHelper($commentString, $expected, $tar if (isset($param['default_equal_token'])) { $expected[$key]['default_equal_token'] += $target; } + if (isset($param['visibility_token'])) { + $expected[$key]['visibility_token'] += $target; + } + if (isset($param['readonly_token'])) { + $expected[$key]['readonly_token'] += $target; + } } $this->assertSame($expected, $found); diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc index 106d65b1..3d149e83 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.inc @@ -41,9 +41,16 @@ class MyClass { function myFunction(): \MyNamespace\MyClass {} /* testReturnMultilineNamespace */ + // Parse error in PHP 8.0. function myFunction(): \MyNamespace /** comment *\/ comment */ \MyClass /* comment */ \Foo {} + + /* testReturnUnqualifiedName */ + private function myFunction(): ?MyClass {} + + /* testReturnPartiallyQualifiedName */ + function myFunction(): Sub\Level\MyClass {} } abstract class MyClass @@ -74,6 +81,83 @@ class ReturnMe { } } +/* testPHP8MixedTypeHint */ +function mixedTypeHint() :mixed {} + +/* testPHP8MixedTypeHintNullable */ +// Intentional fatal error - nullability is not allowed with mixed, but that's not the concern of the method. +function mixedTypeHintNullable(): ?mixed {} + +/* testNamespaceOperatorTypeHint */ +function namespaceOperatorTypeHint() : ?namespace\Name {} + +/* testPHP8UnionTypesSimple */ +function unionTypeSimple($number) : int|float {} + +/* testPHP8UnionTypesTwoClasses */ +$fn = fn($var): MyClassA|\Package\MyClassB => $var; + +/* testPHP8UnionTypesAllBaseTypes */ +function unionTypesAllBaseTypes() : array|bool|callable|int|float|null|Object|string {} + +/* testPHP8UnionTypesAllPseudoTypes */ +// Intentional fatal error - mixing types which cannot be combined, but that's not the concern of the method. +function unionTypesAllPseudoTypes($var) : false|MIXED|self|parent|static|iterable|Resource|void {} + +/* testPHP8UnionTypesNullable */ +// Intentional fatal error - nullability is not allowed with union types, but that's not the concern of the method. +$closure = function () use($a) :?int|float {}; + +/* testPHP8PseudoTypeNull */ +// Intentional fatal error - null pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeNull(): null {} + +/* testPHP8PseudoTypeFalse */ +// Intentional fatal error - false pseudotype is only allowed in union types, but that's not the concern of the method. +function pseudoTypeFalse(): false {} + +/* testPHP8PseudoTypeFalseAndBool */ +// Intentional fatal error - false pseudotype is not allowed in combination with bool, but that's not the concern of the method. +function pseudoTypeFalseAndBool(): bool|false {} + +/* testPHP8ObjectAndClass */ +// Intentional fatal error - object is not allowed in combination with class name, but that's not the concern of the method. +function objectAndClass(): object|ClassName {} + +/* testPHP8PseudoTypeIterableAndArray */ +// Intentional fatal error - iterable pseudotype is not allowed in combination with array or Traversable, but that's not the concern of the method. +interface FooBar { + public function pseudoTypeIterableAndArray(): iterable|array|Traversable; +} + +/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */ +// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method. +function duplicateTypeInUnion(): int | /*comment*/ string | INT {} + +/* testPHP81NeverType */ +function never(): never {} + +/* testPHP81NullableNeverType */ +// Intentional fatal error - nullability is not allowed with never, but that's not the concern of the method. +function nullableNever(): ?never {} + +/* testPHP8IntersectionTypes */ +function intersectionTypes(): Foo&Bar {} + +/* testPHP81MoreIntersectionTypes */ +function moreIntersectionTypes(): MyClassA&\Package\MyClassB&\Package\MyClassC {} + +/* testPHP81IntersectionArrowFunction */ +$fn = fn($var): MyClassA&\Package\MyClassB => $var; + +/* testPHP81IllegalIntersectionTypes */ +// Intentional fatal error - simple types are not allowed with intersection types, but that's not the concern of the method. +$closure = function (): string&int {}; + +/* testPHP81NullableIntersectionTypes */ +// Intentional fatal error - nullability is not allowed with intersection types, but that's not the concern of the method. +$closure = function (): ?Foo&Bar {}; + /* testNotAFunction */ return true; @@ -91,6 +175,9 @@ fn&(?string $a) : ?string => $b; /* testFunctionCallFnPHPCS353-354 */ $value = $obj->fn(true); +/* testFunctionDeclarationNestedInTernaryPHPCS2975 */ +return (!$a ? [ new class { public function b(): c {} } ] : []); + /* testArrowFunctionLiveCoding */ // Intentional parse error. This has to be the last test in the file. $fn = fn diff --git a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php index 8ad64dc4..ee20479d 100644 --- a/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php +++ b/Tests/BackCompat/BCFile/GetMethodPropertiesTest.php @@ -22,7 +22,6 @@ use PHPCSUtils\BackCompat\BCFile; use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Tokens\Collections; /** * Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodProperties method. @@ -70,11 +69,11 @@ public function dataNotAFunctionException() ], 'function-call-fn-phpcs-3.5.3-3.5.4' => [ '/* testFunctionCallFnPHPCS353-354 */', - Collections::arrowFunctionTokensBC(), + [T_FN, T_STRING], ], 'fn-live-coding' => [ '/* testArrowFunctionLiveCoding */', - Collections::arrowFunctionTokensBC(), + [T_FN, T_STRING], ], ]; } @@ -87,15 +86,16 @@ public function dataNotAFunctionException() public function testBasicFunction() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -109,15 +109,16 @@ public function testBasicFunction() public function testReturnFunction() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array', - 'return_type_token' => 11, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 11, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -131,15 +132,16 @@ public function testReturnFunction() public function testNestedClosure() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int', - 'return_type_token' => 8, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -153,15 +155,16 @@ public function testNestedClosure() public function testBasicMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -175,15 +178,16 @@ public function testBasicMethod() public function testPrivateStaticMethod() { $expected = [ - 'scope' => 'private', - 'scope_specified' => true, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => true, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -197,15 +201,16 @@ public function testPrivateStaticMethod() public function testFinalMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => true, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => true, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -219,15 +224,16 @@ public function testFinalMethod() public function testProtectedReturnMethod() { $expected = [ - 'scope' => 'protected', - 'scope_specified' => true, - 'return_type' => 'int', - 'return_type_token' => 8, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'int', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -241,15 +247,16 @@ public function testProtectedReturnMethod() public function testPublicReturnMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => 'array', - 'return_type_token' => 7, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'array', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -263,15 +270,16 @@ public function testPublicReturnMethod() public function testNullableReturnMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '?array', - 'return_type_token' => 8, // Offset from the T_FUNCTION token. - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -285,15 +293,16 @@ public function testNullableReturnMethod() public function testMessyNullableReturnMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => true, - 'return_type' => '?array', - 'return_type_token' => 18, // Offset from the T_FUNCTION token. - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => '?array', + 'return_type_token' => 18, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 18, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -306,16 +315,19 @@ public function testMessyNullableReturnMethod() */ public function testReturnNamespace() { + $php8Names = parent::usesPhp8NameTokens(); + $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '\MyNamespace\MyClass', - 'return_type_token' => 7, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 7 : 10, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -327,17 +339,68 @@ public function testReturnNamespace() * @return void */ public function testReturnMultilineNamespace() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '\MyNamespace\MyClass\Foo', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 20 : 23, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test a method with an unqualified named return type. + * + * @return void + */ + public function testReturnUnqualifiedName() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '\MyNamespace\MyClass\Foo', - 'return_type_token' => 7, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => '?MyClass', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test a method with a partially qualified namespaced return type. + * + * @return void + */ + public function testReturnPartiallyQualifiedName() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Sub\Level\MyClass', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 7 : 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -351,15 +414,16 @@ public function testReturnMultilineNamespace() public function testAbstractMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => true, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -373,15 +437,16 @@ public function testAbstractMethod() public function testAbstractReturnMethod() { $expected = [ - 'scope' => 'protected', - 'scope_specified' => true, - 'return_type' => 'bool', - 'return_type_token' => 7, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => true, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'bool', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -395,15 +460,16 @@ public function testAbstractReturnMethod() public function testInterfaceMethod() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '', - 'return_type_token' => false, - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => false, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -417,20 +483,19 @@ public function testInterfaceMethod() public function testArrowFunction() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'int', - 'return_type_token' => 9, // Offset from the T_FN token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => true, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int', + 'return_type_token' => 9, // Offset from the T_FN token. + 'return_type_end_token' => 9, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => true, + 'has_body' => true, ]; - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** @@ -441,15 +506,509 @@ public function testArrowFunction() public function testReturnTypeStatic() { $expected = [ - 'scope' => 'private', - 'scope_specified' => true, - 'return_type' => 'static', - 'return_type_token' => 7, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'private', + 'scope_specified' => true, + 'return_type' => 'static', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test a function with return type "mixed". + * + * @return void + */ + public function testPHP8MixedTypeHint() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'mixed', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test a function with return type "mixed" and nullability. + * + * @return void + */ + public function testPHP8MixedTypeHintNullable() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?mixed', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test a function with return type using the namespace operator. + * + * @return void + */ + public function testNamespaceOperatorTypeHint() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?namespace\Name', + 'return_type_token' => 9, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 9 : 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration. + * + * @return void + */ + public function testPHP8UnionTypesSimple() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|float', + 'return_type_token' => 9, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with two classes. + * + * @return void + */ + public function testPHP8UnionTypesTwoClasses() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA|\Package\MyClassB', + 'return_type_token' => 6, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 8 : 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all base types. + * + * @return void + */ + public function testPHP8UnionTypesAllBaseTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array|bool|callable|int|float|null|Object|string', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 22, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with all pseudo types. + * + * Note: "Resource" is not a type, but seen as a class name. + * + * @return void + */ + public function testPHP8UnionTypesAllPseudoTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false|MIXED|self|parent|static|iterable|Resource|void', + 'return_type_token' => 9, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 23, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 union type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP8UnionTypesNullable() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?int|float', + 'return_type_token' => 12, // Offset from the T_CLOSURE token. + 'return_type_end_token' => 14, // Offset from the T_CLOSURE token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type null. + * + * @return void + */ + public function testPHP8PseudoTypeNull() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) single type false. + * + * @return void + */ + public function testPHP8PseudoTypeFalse() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'false', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type false combined with type bool. + * + * @return void + */ + public function testPHP8PseudoTypeFalseAndBool() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|false', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type object combined with a class name. + * + * @return void + */ + public function testPHP8ObjectAndClass() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|ClassName', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) type iterable combined with array/Traversable. + * + * @return void + */ + public function testPHP8PseudoTypeIterableAndArray() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'iterable|array|Traversable', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 11, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8 type declaration with (illegal) duplicate types. + * + * @return void + */ + public function testPHP8DuplicateTypeInUnionWhitespaceAndComment() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'int|string|INT', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 17, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 type "never". + * + * @return void + */ + public function testPHP81NeverType() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'never', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 7, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 type "never" with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableNeverType() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?never', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration. + * + * @return void + */ + public function testPHP8IntersectionTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Foo&Bar', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with more types. + * + * @return void + */ + public function testPHP81MoreIntersectionTypes() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB&\Package\MyClassC', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => ($php8Names === true) ? 11 : 17, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration in arrow function. + * + * @return void + */ + public function testPHP81IntersectionArrowFunction() + { + $php8Names = parent::usesPhp8NameTokens(); + + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'MyClassA&\Package\MyClassB', + 'return_type_token' => 6, // Offset from the T_FN token. + 'return_type_end_token' => ($php8Names === true) ? 8 : 11, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with illegal simple types. + * + * @return void + */ + public function testPHP81IllegalIntersectionTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'string&int', + 'return_type_token' => 6, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP8.1 intersection type declaration with (illegal) nullability. + * + * @return void + */ + public function testPHP81NullableIntersectionTypes() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?Foo&Bar', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -465,15 +1024,16 @@ public function testReturnTypeStatic() public function testPhpcsIssue1264() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array', - 'return_type_token' => 8, // Offset from the T_FUNCTION token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 8, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); @@ -490,20 +1050,19 @@ public function testPhpcsIssue1264() public function testArrowFunctionArrayReturnValue() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => 'array', - 'return_type_token' => 5, // Offset from the T_FN token. - 'nullable_return_type' => false, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'array', + 'return_type_token' => 5, // Offset from the T_FN token. + 'return_type_end_token' => 5, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); - - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** @@ -514,20 +1073,43 @@ public function testArrowFunctionArrayReturnValue() public function testArrowFunctionReturnByRef() { $expected = [ - 'scope' => 'public', - 'scope_specified' => false, - 'return_type' => '?string', - 'return_type_token' => 12, - 'nullable_return_type' => true, - 'is_abstract' => false, - 'is_final' => false, - 'is_static' => false, - 'has_body' => true, + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?string', + 'return_type_token' => 12, // Offset from the T_FN token. + 'return_type_end_token' => 12, // Offset from the T_FN token. + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, ]; - $arrowTokenTypes = Collections::arrowFunctionTokensBC(); + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } - $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected, $arrowTokenTypes); + /** + * Test handling of function declaration nested in a ternary, where the colon for the + * return type was incorrectly tokenized as T_INLINE_ELSE prior to PHPCS 3.5.7. + * + * @return void + */ + public function testFunctionDeclarationNestedInTernaryPHPCS2975() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => true, + 'return_type' => 'c', + 'return_type_token' => 7, // Offset from the T_FN token. + 'return_type_end_token' => 7, // Offset from the T_FN token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } /** @@ -540,14 +1122,20 @@ public function testArrowFunctionReturnByRef() * * @return void */ - protected function getMethodPropertiesTestHelper($commentString, $expected, $targetType = [T_FUNCTION, T_CLOSURE]) - { + protected function getMethodPropertiesTestHelper( + $commentString, + $expected, + $targetType = [T_FUNCTION, T_CLOSURE, T_FN] + ) { $function = $this->getTargetToken($commentString, $targetType); $found = BCFile::getMethodProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { $expected['return_type_token'] += $function; } + if ($expected['return_type_end_token'] !== false) { + $expected['return_type_end_token'] += $function; + } $this->assertSame($expected, $found); } diff --git a/Tests/BackCompat/BCFile/GetTokensAsStringTest.inc b/Tests/BackCompat/BCFile/GetTokensAsStringTest.inc index f0293e1b..ace5a9bd 100644 --- a/Tests/BackCompat/BCFile/GetTokensAsStringTest.inc +++ b/Tests/BackCompat/BCFile/GetTokensAsStringTest.inc @@ -8,6 +8,14 @@ use Foo /*comment*/ \ Bar // phpcs:ignore Stnd.Cat.Sniff -- For reasons. \ Bah; +$cl = function() { + /* testCalculation */ + return 1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20; +} + /* testEchoWithTabs */ echo 'foo', 'bar' , diff --git a/Tests/BackCompat/BCFile/GetTokensAsStringTest.php b/Tests/BackCompat/BCFile/GetTokensAsStringTest.php index 42611669..b3df5437 100644 --- a/Tests/BackCompat/BCFile/GetTokensAsStringTest.php +++ b/Tests/BackCompat/BCFile/GetTokensAsStringTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetTokensAsStringTest extends UtilityMethodTestCase +final class GetTokensAsStringTest extends UtilityMethodTestCase { /** @@ -118,68 +118,126 @@ public function testGetTokensAsString($testMarker, $startTokenType, $length, $ex */ public function dataGetTokensAsString() { + $php8Names = parent::usesPhp8NameTokens(); + return [ 'length-0' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 0, '', ], 'length-1' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 1, - 'namespace', + '1', ], 'length-2' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 2, - 'namespace ', + '1 ', ], 'length-3' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 3, - 'namespace Foo', + '1 +', ], 'length-4' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 4, - 'namespace Foo\\', + '1 + ', ], 'length-5' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 5, - 'namespace Foo\Bar', + '1 + 2', ], 'length-6' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 6, - 'namespace Foo\Bar\\', + '1 + 2 ', ], 'length-7' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 7, - 'namespace Foo\Bar\Baz', + '1 + 2 +', ], 'length-8' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 8, - 'namespace Foo\Bar\Baz;', + '1 + 2 + +', ], 'length-9' => [ - '/* testNamespace */', - \T_NAMESPACE, + '/* testCalculation */', + \T_LNUMBER, 9, - 'namespace Foo\Bar\Baz; + '1 + 2 + + ', + ], + 'length-10' => [ + '/* testCalculation */', + \T_LNUMBER, + 10, + '1 + 2 + + // Comment. ', ], + 'length-11' => [ + '/* testCalculation */', + \T_LNUMBER, + 11, + '1 + 2 + + // Comment. + ', + ], + 'length-12' => [ + '/* testCalculation */', + \T_LNUMBER, + 12, + '1 + 2 + + // Comment. + 3', + ], + 'length-13' => [ + '/* testCalculation */', + \T_LNUMBER, + 13, + '1 + 2 + + // Comment. + 3 ', + ], + 'length-14' => [ + '/* testCalculation */', + \T_LNUMBER, + 14, + '1 + 2 + + // Comment. + 3 +', + ], + 'length-34' => [ + '/* testCalculation */', + \T_LNUMBER, + 34, + '1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20;', + ], + 'namespace' => [ + '/* testNamespace */', + \T_NAMESPACE, + ($php8Names === true) ? 4 : 8, + 'namespace Foo\Bar\Baz;', + ], 'use-with-comments' => [ '/* testUseWithComments */', \T_USE, diff --git a/Tests/BackCompat/BCFile/IsReferenceTest.inc b/Tests/BackCompat/BCFile/IsReferenceTest.inc index 6049688e..93c7acc6 100644 --- a/Tests/BackCompat/BCFile/IsReferenceTest.inc +++ b/Tests/BackCompat/BCFile/IsReferenceTest.inc @@ -1,6 +1,8 @@ value){}; + +/* testUseByReferenceWithCommentSecondParam */ +$closure = function() use /*comment*/ ($varA, &$varB){}; + /* testArrowFunctionReturnByReference */ fn&($x) => $x; +$closure = function ( + /* testBitwiseAndExactParameterA */ + $a = MY_CONSTANT & parent::OTHER_CONSTANT, + /* testPassByReferenceExactParameterB */ + &$b, + /* testPassByReferenceExactParameterC */ + &...$c, + /* testBitwiseAndExactParameterD */ + $d = E_NOTICE & E_STRICT, +) {}; + +// Issue PHPCS#3049. +/* testArrowFunctionPassByReferenceA */ +$fn = fn(array &$one) => 1; + +/* testArrowFunctionPassByReferenceB */ +$fn = fn($param, &...$moreParams) => 1; + /* testClosureReturnByReference */ $closure = function &($param) use ($value) {}; + +/* testBitwiseAndArrowFunctionInDefault */ +$fn = fn( $one = E_NOTICE & E_STRICT) => 1; + +/* testTokenizerIssue1284PHPCSlt280A */ +if ($foo) {} +[&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c; + +/* testTokenizerIssue1284PHPCSlt280C */ +if ($foo) {} +[&$a, $b]; diff --git a/Tests/BackCompat/BCFile/IsReferenceTest.php b/Tests/BackCompat/BCFile/IsReferenceTest.php index bf885ad5..2bb169df 100644 --- a/Tests/BackCompat/BCFile/IsReferenceTest.php +++ b/Tests/BackCompat/BCFile/IsReferenceTest.php @@ -88,234 +88,294 @@ public function testIsReference($identifier, $expected) public function dataIsReference() { return [ - [ + 'issue-1971-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271A */', + 'expected' => true, + ], + 'issue-1971-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271B */', + 'expected' => true, + ], + 'bitwise and: param in function call' => [ '/* testBitwiseAndA */', false, ], - [ + 'bitwise and: in unkeyed short array, first value' => [ '/* testBitwiseAndB */', false, ], - [ + 'bitwise and: in unkeyed short array, last value' => [ '/* testBitwiseAndC */', false, ], - [ + 'bitwise and: in unkeyed long array, last value' => [ '/* testBitwiseAndD */', false, ], - [ + 'bitwise and: in keyed short array, last value' => [ '/* testBitwiseAndE */', false, ], - [ + 'bitwise and: in keyed long array, last value' => [ '/* testBitwiseAndF */', false, ], - [ + 'bitwise and: in assignment' => [ '/* testBitwiseAndG */', false, ], - [ + 'bitwise and: in param default value in function declaration' => [ '/* testBitwiseAndH */', false, ], - [ + 'bitwise and: in param default value in closure declaration' => [ '/* testBitwiseAndI */', false, ], - [ + 'reference: function declared to return by reference' => [ '/* testFunctionReturnByReference */', true, ], - [ + 'reference: only param in function declaration, pass by reference' => [ '/* testFunctionPassByReferenceA */', true, ], - [ + 'reference: last param in function declaration, pass by reference' => [ '/* testFunctionPassByReferenceB */', true, ], - [ + 'reference: only param in closure declaration, pass by reference' => [ '/* testFunctionPassByReferenceC */', true, ], - [ + 'reference: last param in closure declaration, pass by reference' => [ '/* testFunctionPassByReferenceD */', true, ], - [ + 'reference: typed param in function declaration, pass by reference' => [ '/* testFunctionPassByReferenceE */', true, ], - [ + 'reference: typed param in closure declaration, pass by reference' => [ '/* testFunctionPassByReferenceF */', true, ], - [ + 'reference: variadic param in function declaration, pass by reference' => [ '/* testFunctionPassByReferenceG */', true, ], - [ + 'reference: foreach value' => [ '/* testForeachValueByReference */', true, ], - [ + 'reference: foreach key' => [ '/* testForeachKeyByReference */', true, ], - [ + 'reference: keyed short array, first value, value by reference' => [ '/* testArrayValueByReferenceA */', true, ], - [ + 'reference: keyed short array, last value, value by reference' => [ '/* testArrayValueByReferenceB */', true, ], - [ + 'reference: unkeyed short array, only value, value by reference' => [ '/* testArrayValueByReferenceC */', true, ], - [ + 'reference: unkeyed short array, last value, value by reference' => [ '/* testArrayValueByReferenceD */', true, ], - [ + 'reference: keyed long array, first value, value by reference' => [ '/* testArrayValueByReferenceE */', true, ], - [ + 'reference: keyed long array, last value, value by reference' => [ '/* testArrayValueByReferenceF */', true, ], - [ + 'reference: unkeyed long array, only value, value by reference' => [ '/* testArrayValueByReferenceG */', true, ], - [ + 'reference: unkeyed long array, last value, value by reference' => [ '/* testArrayValueByReferenceH */', true, ], - [ + 'reference: variable, assign by reference' => [ '/* testAssignByReferenceA */', true, ], - [ + 'reference: variable, assign by reference, spacing variation' => [ '/* testAssignByReferenceB */', true, ], - [ + 'reference: variable, assign by reference, concat assign' => [ '/* testAssignByReferenceC */', true, ], - [ + 'reference: property, assign by reference' => [ '/* testAssignByReferenceD */', true, ], - [ + 'reference: function return value, assign by reference' => [ '/* testAssignByReferenceE */', true, ], - [ + 'reference: function return value, assign by reference, null coalesce assign' => [ '/* testAssignByReferenceF */', true, ], - [ + 'reference: unkeyed short list, first var, assign by reference' => [ '/* testShortListAssignByReferenceNoKeyA */', true, ], - [ + 'reference: unkeyed short list, second var, assign by reference' => [ '/* testShortListAssignByReferenceNoKeyB */', true, ], - [ + 'reference: unkeyed short list, nested var, assign by reference' => [ '/* testNestedShortListAssignByReferenceNoKey */', true, ], - [ + 'reference: unkeyed long list, second var, assign by reference' => [ '/* testLongListAssignByReferenceNoKeyA */', true, ], - [ + 'reference: unkeyed long list, first nested var, assign by reference' => [ '/* testLongListAssignByReferenceNoKeyB */', true, ], - [ + 'reference: unkeyed long list, last nested var, assign by reference' => [ '/* testLongListAssignByReferenceNoKeyC */', true, ], - [ + 'reference: keyed short list, first nested var, assign by reference' => [ '/* testNestedShortListAssignByReferenceWithKeyA */', true, ], - [ + 'reference: keyed short list, last nested var, assign by reference' => [ '/* testNestedShortListAssignByReferenceWithKeyB */', true, ], - [ + 'reference: keyed long list, only var, assign by reference' => [ '/* testLongListAssignByReferenceWithKeyA */', true, ], - [ + 'reference: first param in function call, pass by reference' => [ '/* testPassByReferenceA */', true, ], - [ + 'reference: last param in function call, pass by reference' => [ '/* testPassByReferenceB */', true, ], - [ + 'reference: property in function call, pass by reference' => [ '/* testPassByReferenceC */', true, ], - [ + 'reference: hierarchical self property in function call, pass by reference' => [ '/* testPassByReferenceD */', true, ], - [ + 'reference: hierarchical parent property in function call, pass by reference' => [ '/* testPassByReferenceE */', true, ], - [ + 'reference: hierarchical static property in function call, pass by reference' => [ '/* testPassByReferenceF */', true, ], - [ + 'reference: static property in function call, pass by reference' => [ '/* testPassByReferenceG */', true, ], - [ + 'reference: static property in function call, first with FQN, pass by reference' => [ '/* testPassByReferenceH */', true, ], - [ + 'reference: static property in function call, last with FQN, pass by reference' => [ '/* testPassByReferenceI */', true, ], - [ + 'reference: static property in function call, last with namespace relative name, pass by reference' => [ '/* testPassByReferenceJ */', true, ], - [ + 'reference: static property in function call, last with PQN, pass by reference' => [ + '/* testPassByReferencePartiallyQualifiedName */', + true, + ], + 'reference: new by reference' => [ '/* testNewByReferenceA */', true, ], - [ + 'reference: new by reference as function call param' => [ '/* testNewByReferenceB */', true, ], - [ + 'reference: closure use by reference' => [ '/* testUseByReference */', true, ], - [ + 'reference: closure use by reference, first param, with comment' => [ + '/* testUseByReferenceWithCommentFirstParam */', + true, + ], + 'reference: closure use by reference, last param, with comment' => [ + '/* testUseByReferenceWithCommentSecondParam */', + true, + ], + 'reference: arrow fn declared to return by reference' => [ '/* testArrowFunctionReturnByReference */', true, ], - [ + 'bitwise and: first param default value in closure declaration' => [ + '/* testBitwiseAndExactParameterA */', + false, + ], + 'reference: param in closure declaration, pass by reference' => [ + '/* testPassByReferenceExactParameterB */', + true, + ], + 'reference: variadic param in closure declaration, pass by reference' => [ + '/* testPassByReferenceExactParameterC */', + true, + ], + 'bitwise and: last param default value in closure declaration' => [ + '/* testBitwiseAndExactParameterD */', + false, + ], + 'reference: typed param in arrow fn declaration, pass by reference' => [ + '/* testArrowFunctionPassByReferenceA */', + true, + ], + 'reference: variadic param in arrow fn declaration, pass by reference' => [ + '/* testArrowFunctionPassByReferenceB */', + true, + ], + 'reference: closure declared to return by reference' => [ '/* testClosureReturnByReference */', true, ], + 'bitwise and: param default value in arrow fn declaration' => [ + '/* testBitwiseAndArrowFunctionInDefault */', + false, + ], + 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */', + 'expected' => true, + ], + 'issue-1284-short-list-directly-after-close-curly-control-structure-second-item' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280B */', + 'expected' => true, + ], + 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280C */', + 'expected' => true, + ], ]; } } diff --git a/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php b/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php deleted file mode 100644 index 9bd33a40..00000000 --- a/Tests/BackCompat/BCTokens/ArithmeticTokensTest.php +++ /dev/null @@ -1,46 +0,0 @@ - \T_PLUS, - \T_MINUS => \T_MINUS, - \T_MULTIPLY => \T_MULTIPLY, - \T_DIVIDE => \T_DIVIDE, - \T_MODULUS => \T_MODULUS, - \T_POW => \T_POW, - ]; - - $this->assertSame($expected, BCTokens::arithmeticTokens()); - } -} diff --git a/Tests/BackCompat/BCTokens/AssignmentTokensTest.php b/Tests/BackCompat/BCTokens/AssignmentTokensTest.php deleted file mode 100644 index 1d8f7394..00000000 --- a/Tests/BackCompat/BCTokens/AssignmentTokensTest.php +++ /dev/null @@ -1,66 +0,0 @@ - \T_EQUAL, - \T_AND_EQUAL => \T_AND_EQUAL, - \T_OR_EQUAL => \T_OR_EQUAL, - \T_CONCAT_EQUAL => \T_CONCAT_EQUAL, - \T_DIV_EQUAL => \T_DIV_EQUAL, - \T_MINUS_EQUAL => \T_MINUS_EQUAL, - \T_POW_EQUAL => \T_POW_EQUAL, - \T_MOD_EQUAL => \T_MOD_EQUAL, - \T_MUL_EQUAL => \T_MUL_EQUAL, - \T_PLUS_EQUAL => \T_PLUS_EQUAL, - \T_XOR_EQUAL => \T_XOR_EQUAL, - \T_DOUBLE_ARROW => \T_DOUBLE_ARROW, - \T_SL_EQUAL => \T_SL_EQUAL, - \T_SR_EQUAL => \T_SR_EQUAL, - ]; - - if (\version_compare($version, '2.8.1', '>=') === true - || \version_compare(\PHP_VERSION_ID, '70399', '>=') === true - ) { - $expected[\T_COALESCE_EQUAL] = \T_COALESCE_EQUAL; - } - - if (\version_compare($version, '2.8.0', '>=') === true) { - $expected[\T_ZSR_EQUAL] = \T_ZSR_EQUAL; - } - - $this->assertSame($expected, BCTokens::assignmentTokens()); - } -} diff --git a/Tests/BackCompat/BCTokens/ComparisonTokensTest.php b/Tests/BackCompat/BCTokens/ComparisonTokensTest.php deleted file mode 100644 index a70afb6d..00000000 --- a/Tests/BackCompat/BCTokens/ComparisonTokensTest.php +++ /dev/null @@ -1,57 +0,0 @@ - \T_IS_EQUAL, - \T_IS_IDENTICAL => \T_IS_IDENTICAL, - \T_IS_NOT_EQUAL => \T_IS_NOT_EQUAL, - \T_IS_NOT_IDENTICAL => \T_IS_NOT_IDENTICAL, - \T_LESS_THAN => \T_LESS_THAN, - \T_GREATER_THAN => \T_GREATER_THAN, - \T_IS_SMALLER_OR_EQUAL => \T_IS_SMALLER_OR_EQUAL, - \T_IS_GREATER_OR_EQUAL => \T_IS_GREATER_OR_EQUAL, - \T_SPACESHIP => \T_SPACESHIP, - ]; - - if (\version_compare($version, '2.6.1', '>=') === true - || \version_compare(\PHP_VERSION_ID, '60999', '>=') === true - ) { - $expected[\T_COALESCE] = \T_COALESCE; - } - - $this->assertSame($expected, BCTokens::comparisonTokens()); - } -} diff --git a/Tests/BackCompat/BCTokens/EmptyTokensTest.php b/Tests/BackCompat/BCTokens/EmptyTokensTest.php deleted file mode 100644 index 38dcff9b..00000000 --- a/Tests/BackCompat/BCTokens/EmptyTokensTest.php +++ /dev/null @@ -1,112 +0,0 @@ - => - */ - protected $commentTokens = [ - \T_COMMENT => \T_COMMENT, - \T_DOC_COMMENT => \T_DOC_COMMENT, - \T_DOC_COMMENT_STAR => \T_DOC_COMMENT_STAR, - \T_DOC_COMMENT_WHITESPACE => \T_DOC_COMMENT_WHITESPACE, - \T_DOC_COMMENT_TAG => \T_DOC_COMMENT_TAG, - \T_DOC_COMMENT_OPEN_TAG => \T_DOC_COMMENT_OPEN_TAG, - \T_DOC_COMMENT_CLOSE_TAG => \T_DOC_COMMENT_CLOSE_TAG, - \T_DOC_COMMENT_STRING => \T_DOC_COMMENT_STRING, - ]; - - /** - * Token types that are comments containing PHPCS instructions. - * - * @var array => - */ - protected $phpcsCommentTokens = [ - 'PHPCS_T_PHPCS_ENABLE' => 'PHPCS_T_PHPCS_ENABLE', - 'PHPCS_T_PHPCS_DISABLE' => 'PHPCS_T_PHPCS_DISABLE', - 'PHPCS_T_PHPCS_SET' => 'PHPCS_T_PHPCS_SET', - 'PHPCS_T_PHPCS_IGNORE' => 'PHPCS_T_PHPCS_IGNORE', - 'PHPCS_T_PHPCS_IGNORE_FILE' => 'PHPCS_T_PHPCS_IGNORE_FILE', - ]; - - /** - * Test the Tokens::emptyTokens() method. - * - * @covers \PHPCSUtils\BackCompat\BCTokens::__callStatic - * - * @return void - */ - public function testEmptyTokens() - { - $version = Helper::getVersion(); - $expected = [\T_WHITESPACE => \T_WHITESPACE] + $this->commentTokens; - - if (\version_compare($version, '3.2.0', '>=') === true) { - $expected += $this->phpcsCommentTokens; - } - - $this->assertSame($expected, BCTokens::emptyTokens()); - } - - /** - * Test the Tokens::commentTokens() method. - * - * @covers \PHPCSUtils\BackCompat\BCTokens::__callStatic - * - * @return void - */ - public function testCommentTokens() - { - $version = Helper::getVersion(); - $expected = $this->commentTokens; - - if (\version_compare($version, '3.2.0', '>=') === true) { - $expected += $this->phpcsCommentTokens; - } - - $this->assertSame($expected, BCTokens::commentTokens()); - } - - /** - * Test the Tokens::phpcsCommentTokens() method. - * - * @covers \PHPCSUtils\BackCompat\BCTokens::phpcsCommentTokens - * - * @return void - */ - public function testPhpcsCommentTokens() - { - $version = Helper::getVersion(); - $expected = []; - - if (\version_compare($version, '3.2.0', '>=') === true) { - $expected = $this->phpcsCommentTokens; - } - - $this->assertSame($expected, BCTokens::phpcsCommentTokens()); - } -} diff --git a/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php b/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php index 25f66316..733aa00e 100644 --- a/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php +++ b/Tests/BackCompat/BCTokens/FunctionNameTokensTest.php @@ -10,7 +10,9 @@ namespace PHPCSUtils\Tests\BackCompat\BCTokens; +use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\BackCompat\Helper; use PHPUnit\Framework\TestCase; /** @@ -22,7 +24,7 @@ * * @since 1.0.0 */ -class FunctionNameTokensTest extends TestCase +final class FunctionNameTokensTest extends TestCase { /** @@ -33,20 +35,63 @@ class FunctionNameTokensTest extends TestCase public function testFunctionNameTokens() { $expected = [ - \T_STRING => \T_STRING, - \T_EVAL => \T_EVAL, - \T_EXIT => \T_EXIT, - \T_INCLUDE => \T_INCLUDE, - \T_INCLUDE_ONCE => \T_INCLUDE_ONCE, - \T_REQUIRE => \T_REQUIRE, - \T_REQUIRE_ONCE => \T_REQUIRE_ONCE, - \T_ISSET => \T_ISSET, - \T_UNSET => \T_UNSET, - \T_EMPTY => \T_EMPTY, - \T_SELF => \T_SELF, - \T_STATIC => \T_STATIC, + \T_STRING => \T_STRING, + \T_EVAL => \T_EVAL, + \T_EXIT => \T_EXIT, + \T_INCLUDE => \T_INCLUDE, + \T_INCLUDE_ONCE => \T_INCLUDE_ONCE, + \T_REQUIRE => \T_REQUIRE, + \T_REQUIRE_ONCE => \T_REQUIRE_ONCE, + \T_ISSET => \T_ISSET, + \T_UNSET => \T_UNSET, + \T_EMPTY => \T_EMPTY, + \T_SELF => \T_SELF, + \T_STATIC => \T_STATIC, + \T_PARENT => \T_PARENT, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, ]; - $this->assertSame($expected, BCTokens::functionNameTokens()); + \asort($expected); + + $result = BCTokens::functionNameTokens(); + \asort($result); + + $this->assertSame($expected, $result); + } + + /** + * Test whether the method in BCTokens is still in sync with the latest version of PHPCS. + * + * This group is not run by default and has to be specifically requested to be run. + * + * @group compareWithPHPCS + * + * @return void + */ + public function testPHPCSFunctionNameTokens() + { + $version = Helper::getVersion(); + + if (\version_compare($version, '3.99.99', '>') === true) { + $this->assertSame(Tokens::$functionNameTokens, BCTokens::functionNameTokens()); + } else { + /* + * Don't fail this test on the difference between PHPCS 4.x and 3.x. + * This test is only run against `dev-master` and `dev-master` is still PHPCS 3.x. + */ + $expected = Tokens::$functionNameTokens; + $expected[\T_NAME_QUALIFIED] = \T_NAME_QUALIFIED; + $expected[\T_NAME_FULLY_QUALIFIED] = \T_NAME_FULLY_QUALIFIED; + $expected[\T_NAME_RELATIVE] = \T_NAME_RELATIVE; + + \asort($expected); + + $result = BCTokens::functionNameTokens(); + \asort($result); + + $this->assertSame($expected, $result); + } } } diff --git a/Tests/BackCompat/BCTokens/OoScopeTokensTest.php b/Tests/BackCompat/BCTokens/OoScopeTokensTest.php deleted file mode 100644 index 9a63b8bb..00000000 --- a/Tests/BackCompat/BCTokens/OoScopeTokensTest.php +++ /dev/null @@ -1,44 +0,0 @@ - \T_CLASS, - \T_ANON_CLASS => \T_ANON_CLASS, - \T_INTERFACE => \T_INTERFACE, - \T_TRAIT => \T_TRAIT, - ]; - - $this->assertSame($expected, BCTokens::ooScopeTokens()); - } -} diff --git a/Tests/BackCompat/BCTokens/OperatorsTest.php b/Tests/BackCompat/BCTokens/OperatorsTest.php deleted file mode 100644 index cdabe140..00000000 --- a/Tests/BackCompat/BCTokens/OperatorsTest.php +++ /dev/null @@ -1,65 +0,0 @@ - \T_MINUS, - \T_PLUS => \T_PLUS, - \T_MULTIPLY => \T_MULTIPLY, - \T_DIVIDE => \T_DIVIDE, - \T_MODULUS => \T_MODULUS, - \T_POW => \T_POW, - \T_SPACESHIP => \T_SPACESHIP, - \T_BITWISE_AND => \T_BITWISE_AND, - \T_BITWISE_OR => \T_BITWISE_OR, - \T_BITWISE_XOR => \T_BITWISE_XOR, - \T_SL => \T_SL, - \T_SR => \T_SR, - ]; - - if (\version_compare($version, '2.6.1', '>=') === true - || \version_compare(\PHP_VERSION_ID, '60999', '>=') === true - ) { - $expected[\T_COALESCE] = \T_COALESCE; - } - - \asort($expected); - - $result = BCTokens::operators(); - \asort($result); - - $this->assertSame($expected, $result); - } -} diff --git a/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php b/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php index 94e1ef01..dd409f28 100644 --- a/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php +++ b/Tests/BackCompat/BCTokens/ParenthesisOpenersTest.php @@ -10,19 +10,21 @@ namespace PHPCSUtils\Tests\BackCompat\BCTokens; +use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; +use PHPCSUtils\BackCompat\Helper; use PHPUnit\Framework\TestCase; /** * Test class. * - * @covers \PHPCSUtils\BackCompat\BCTokens::parenthesisOpeners + * @covers \PHPCSUtils\BackCompat\BCTokens::__callStatic * * @group tokens * * @since 1.0.0 */ -class ParenthesisOpenersTest extends TestCase +final class ParenthesisOpenersTest extends TestCase { /** @@ -32,6 +34,7 @@ class ParenthesisOpenersTest extends TestCase */ public function testParenthesisOpeners() { + $version = Helper::getVersion(); $expected = [ \T_ARRAY => \T_ARRAY, \T_LIST => \T_LIST, @@ -46,8 +49,13 @@ public function testParenthesisOpeners() \T_ELSEIF => \T_ELSEIF, \T_CATCH => \T_CATCH, \T_DECLARE => \T_DECLARE, + \T_MATCH => \T_MATCH, ]; + if (\version_compare($version, '3.99.99', '>=') === true) { + $expected[\T_USE] = \T_USE; + } + \asort($expected); $result = BCTokens::parenthesisOpeners(); @@ -55,4 +63,18 @@ public function testParenthesisOpeners() $this->assertSame($expected, $result); } + + /** + * Test whether the method in BCTokens is still in sync with the latest version of PHPCS. + * + * This group is not run by default and has to be specifically requested to be run. + * + * @group compareWithPHPCS + * + * @return void + */ + public function testPHPCSParenthesisOpeners() + { + $this->assertSame(Tokens::$parenthesisOpeners, BCTokens::parenthesisOpeners()); + } } diff --git a/Tests/BackCompat/BCTokens/TextStringTokensTest.php b/Tests/BackCompat/BCTokens/TextStringTokensTest.php deleted file mode 100644 index 5cb44269..00000000 --- a/Tests/BackCompat/BCTokens/TextStringTokensTest.php +++ /dev/null @@ -1,45 +0,0 @@ - \T_CONSTANT_ENCAPSED_STRING, - \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, - \T_INLINE_HTML => \T_INLINE_HTML, - \T_HEREDOC => \T_HEREDOC, - \T_NOWDOC => \T_NOWDOC, - ]; - - $this->assertSame($expected, BCTokens::textStringTokens()); - } -} diff --git a/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php b/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php index c179c949..d7199a74 100644 --- a/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php +++ b/Tests/BackCompat/BCTokens/UnchangedTokenArraysTest.php @@ -10,8 +10,9 @@ namespace PHPCSUtils\Tests\BackCompat\BCTokens; +use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\BackCompat\BCTokens; -use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; /** * Test class. @@ -22,15 +23,39 @@ * * @since 1.0.0 */ -class UnchangedTokenArraysTest extends TestCase +final class UnchangedTokenArraysTest extends TestCase { + /** + * Tokens that represent assignments. + * + * @var array + */ + private $assignmentTokens = [ + \T_EQUAL => \T_EQUAL, + \T_AND_EQUAL => \T_AND_EQUAL, + \T_OR_EQUAL => \T_OR_EQUAL, + \T_CONCAT_EQUAL => \T_CONCAT_EQUAL, + \T_DIV_EQUAL => \T_DIV_EQUAL, + \T_MINUS_EQUAL => \T_MINUS_EQUAL, + \T_POW_EQUAL => \T_POW_EQUAL, + \T_MOD_EQUAL => \T_MOD_EQUAL, + \T_MUL_EQUAL => \T_MUL_EQUAL, + \T_PLUS_EQUAL => \T_PLUS_EQUAL, + \T_XOR_EQUAL => \T_XOR_EQUAL, + \T_DOUBLE_ARROW => \T_DOUBLE_ARROW, + \T_SL_EQUAL => \T_SL_EQUAL, + \T_SR_EQUAL => \T_SR_EQUAL, + \T_COALESCE_EQUAL => \T_COALESCE_EQUAL, + \T_ZSR_EQUAL => \T_ZSR_EQUAL, + ]; + /** * Tokens that represent equality comparisons. * * @var array => */ - protected $equalityTokens = [ + private $equalityTokens = [ \T_IS_EQUAL => \T_IS_EQUAL, \T_IS_NOT_EQUAL => \T_IS_NOT_EQUAL, \T_IS_IDENTICAL => \T_IS_IDENTICAL, @@ -39,12 +64,65 @@ class UnchangedTokenArraysTest extends TestCase \T_IS_GREATER_OR_EQUAL => \T_IS_GREATER_OR_EQUAL, ]; + /** + * Tokens that represent comparison operator. + * + * @var array + */ + private $comparisonTokens = [ + \T_IS_EQUAL => \T_IS_EQUAL, + \T_IS_IDENTICAL => \T_IS_IDENTICAL, + \T_IS_NOT_EQUAL => \T_IS_NOT_EQUAL, + \T_IS_NOT_IDENTICAL => \T_IS_NOT_IDENTICAL, + \T_LESS_THAN => \T_LESS_THAN, + \T_GREATER_THAN => \T_GREATER_THAN, + \T_IS_SMALLER_OR_EQUAL => \T_IS_SMALLER_OR_EQUAL, + \T_IS_GREATER_OR_EQUAL => \T_IS_GREATER_OR_EQUAL, + \T_SPACESHIP => \T_SPACESHIP, + \T_COALESCE => \T_COALESCE, + ]; + + /** + * Tokens that represent arithmetic operators. + * + * @var array + */ + private $arithmeticTokens = [ + \T_PLUS => \T_PLUS, + \T_MINUS => \T_MINUS, + \T_MULTIPLY => \T_MULTIPLY, + \T_DIVIDE => \T_DIVIDE, + \T_MODULUS => \T_MODULUS, + \T_POW => \T_POW, + ]; + + /** + * Tokens that perform operations. + * + * @var array + */ + private $operators = [ + \T_MINUS => \T_MINUS, + \T_PLUS => \T_PLUS, + \T_MULTIPLY => \T_MULTIPLY, + \T_DIVIDE => \T_DIVIDE, + \T_MODULUS => \T_MODULUS, + \T_POW => \T_POW, + \T_SPACESHIP => \T_SPACESHIP, + \T_COALESCE => \T_COALESCE, + \T_BITWISE_AND => \T_BITWISE_AND, + \T_BITWISE_OR => \T_BITWISE_OR, + \T_BITWISE_XOR => \T_BITWISE_XOR, + \T_SL => \T_SL, + \T_SR => \T_SR, + ]; + /** * Tokens that perform boolean operations. * * @var array => */ - protected $booleanOperators = [ + private $booleanOperators = [ \T_BOOLEAN_AND => \T_BOOLEAN_AND, \T_BOOLEAN_OR => \T_BOOLEAN_OR, \T_LOGICAL_AND => \T_LOGICAL_AND, @@ -57,7 +135,7 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $castTokens = [ + private $castTokens = [ \T_INT_CAST => \T_INT_CAST, \T_STRING_CAST => \T_STRING_CAST, \T_DOUBLE_CAST => \T_DOUBLE_CAST, @@ -71,13 +149,14 @@ class UnchangedTokenArraysTest extends TestCase /** * Tokens that are allowed to open scopes. * - * @var array => + * @var array */ - protected $scopeOpeners = [ + private $scopeOpeners = [ \T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, \T_TRAIT => \T_TRAIT, + \T_ENUM => \T_ENUM, \T_NAMESPACE => \T_NAMESPACE, \T_FUNCTION => \T_FUNCTION, \T_CLOSURE => \T_CLOSURE, @@ -98,6 +177,7 @@ class UnchangedTokenArraysTest extends TestCase \T_PROPERTY => \T_PROPERTY, \T_OBJECT => \T_OBJECT, \T_USE => \T_USE, + \T_MATCH => \T_MATCH, ]; /** @@ -105,7 +185,7 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $scopeModifiers = [ + private $scopeModifiers = [ \T_PRIVATE => \T_PRIVATE, \T_PUBLIC => \T_PUBLIC, \T_PROTECTED => \T_PROTECTED, @@ -116,7 +196,7 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $methodPrefixes = [ + private $methodPrefixes = [ \T_PRIVATE => \T_PRIVATE, \T_PUBLIC => \T_PUBLIC, \T_PROTECTED => \T_PROTECTED, @@ -130,21 +210,90 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $blockOpeners = [ + private $blockOpeners = [ \T_OPEN_CURLY_BRACKET => \T_OPEN_CURLY_BRACKET, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_OPEN_PARENTHESIS => \T_OPEN_PARENTHESIS, \T_OBJECT => \T_OBJECT, ]; + /** + * Tokens that don't represent code. + * + * @var array + */ + private $emptyTokens = [ + \T_WHITESPACE => \T_WHITESPACE, + \T_COMMENT => \T_COMMENT, + \T_DOC_COMMENT => \T_DOC_COMMENT, + \T_DOC_COMMENT_STAR => \T_DOC_COMMENT_STAR, + \T_DOC_COMMENT_WHITESPACE => \T_DOC_COMMENT_WHITESPACE, + \T_DOC_COMMENT_TAG => \T_DOC_COMMENT_TAG, + \T_DOC_COMMENT_OPEN_TAG => \T_DOC_COMMENT_OPEN_TAG, + \T_DOC_COMMENT_CLOSE_TAG => \T_DOC_COMMENT_CLOSE_TAG, + \T_DOC_COMMENT_STRING => \T_DOC_COMMENT_STRING, + \T_PHPCS_ENABLE => \T_PHPCS_ENABLE, + \T_PHPCS_DISABLE => \T_PHPCS_DISABLE, + \T_PHPCS_SET => \T_PHPCS_SET, + \T_PHPCS_IGNORE => \T_PHPCS_IGNORE, + \T_PHPCS_IGNORE_FILE => \T_PHPCS_IGNORE_FILE, + ]; + + /** + * Tokens that are comments. + * + * @var array + */ + private $commentTokens = [ + \T_COMMENT => \T_COMMENT, + \T_DOC_COMMENT => \T_DOC_COMMENT, + \T_DOC_COMMENT_STAR => \T_DOC_COMMENT_STAR, + \T_DOC_COMMENT_WHITESPACE => \T_DOC_COMMENT_WHITESPACE, + \T_DOC_COMMENT_TAG => \T_DOC_COMMENT_TAG, + \T_DOC_COMMENT_OPEN_TAG => \T_DOC_COMMENT_OPEN_TAG, + \T_DOC_COMMENT_CLOSE_TAG => \T_DOC_COMMENT_CLOSE_TAG, + \T_DOC_COMMENT_STRING => \T_DOC_COMMENT_STRING, + \T_PHPCS_ENABLE => \T_PHPCS_ENABLE, + \T_PHPCS_DISABLE => \T_PHPCS_DISABLE, + \T_PHPCS_SET => \T_PHPCS_SET, + \T_PHPCS_IGNORE => \T_PHPCS_IGNORE, + \T_PHPCS_IGNORE_FILE => \T_PHPCS_IGNORE_FILE, + ]; + + /** + * Tokens that are comments containing PHPCS instructions. + * + * @var array + */ + private $phpcsCommentTokens = [ + \T_PHPCS_ENABLE => \T_PHPCS_ENABLE, + \T_PHPCS_DISABLE => \T_PHPCS_DISABLE, + \T_PHPCS_SET => \T_PHPCS_SET, + \T_PHPCS_IGNORE => \T_PHPCS_IGNORE, + \T_PHPCS_IGNORE_FILE => \T_PHPCS_IGNORE_FILE, + ]; + /** * Tokens that represent strings. * * @var array => */ - protected $stringTokens = [ + private $stringTokens = [ + \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, + \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, + ]; + + /** + * Tokens that represent text strings. + * + * @var array + */ + private $textStringTokens = [ \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING, + \T_INLINE_HTML => \T_INLINE_HTML, + \T_HEREDOC => \T_HEREDOC, + \T_NOWDOC => \T_NOWDOC, ]; /** @@ -152,7 +301,7 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $bracketTokens = [ + private $bracketTokens = [ \T_OPEN_CURLY_BRACKET => \T_OPEN_CURLY_BRACKET, \T_CLOSE_CURLY_BRACKET => \T_CLOSE_CURLY_BRACKET, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, @@ -166,7 +315,7 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $includeTokens = [ + private $includeTokens = [ \T_REQUIRE_ONCE => \T_REQUIRE_ONCE, \T_REQUIRE => \T_REQUIRE, \T_INCLUDE_ONCE => \T_INCLUDE_ONCE, @@ -178,7 +327,7 @@ class UnchangedTokenArraysTest extends TestCase * * @var array => */ - protected $heredocTokens = [ + private $heredocTokens = [ \T_START_HEREDOC => \T_START_HEREDOC, \T_END_HEREDOC => \T_END_HEREDOC, \T_HEREDOC => \T_HEREDOC, @@ -187,6 +336,117 @@ class UnchangedTokenArraysTest extends TestCase \T_NOWDOC => \T_NOWDOC, ]; + /** + * Tokens that open class and object scopes. + * + * @var array + */ + private $ooScopeTokens = [ + \T_CLASS => \T_CLASS, + \T_ANON_CLASS => \T_ANON_CLASS, + \T_INTERFACE => \T_INTERFACE, + \T_TRAIT => \T_TRAIT, + \T_ENUM => \T_ENUM, + ]; + + /** + * Tokens representing PHP magic constants. + * + * @var array => + * + * @link https://www.php.net/language.constants.predefined PHP Manual on magic constants + */ + private $magicConstants = [ + \T_CLASS_C => \T_CLASS_C, + \T_DIR => \T_DIR, + \T_FILE => \T_FILE, + \T_FUNC_C => \T_FUNC_C, + \T_LINE => \T_LINE, + \T_METHOD_C => \T_METHOD_C, + \T_NS_C => \T_NS_C, + \T_TRAIT_C => \T_TRAIT_C, + ]; + + /** + * Tokens representing context sensitive keywords in PHP. + * + * @link https://wiki.php.net/rfc/context_sensitive_lexer + * + * @var array + */ + private $contextSensitiveKeywords = [ + \T_ABSTRACT => \T_ABSTRACT, + \T_ARRAY => \T_ARRAY, + \T_AS => \T_AS, + \T_BREAK => \T_BREAK, + \T_CALLABLE => \T_CALLABLE, + \T_CASE => \T_CASE, + \T_CATCH => \T_CATCH, + \T_CLASS => \T_CLASS, + \T_CLONE => \T_CLONE, + \T_CONST => \T_CONST, + \T_CONTINUE => \T_CONTINUE, + \T_DECLARE => \T_DECLARE, + \T_DEFAULT => \T_DEFAULT, + \T_DO => \T_DO, + \T_ECHO => \T_ECHO, + \T_ELSE => \T_ELSE, + \T_ELSEIF => \T_ELSEIF, + \T_EMPTY => \T_EMPTY, + \T_ENDDECLARE => \T_ENDDECLARE, + \T_ENDFOR => \T_ENDFOR, + \T_ENDFOREACH => \T_ENDFOREACH, + \T_ENDIF => \T_ENDIF, + \T_ENDSWITCH => \T_ENDSWITCH, + \T_ENDWHILE => \T_ENDWHILE, + \T_ENUM => \T_ENUM, + \T_EVAL => \T_EVAL, + \T_EXIT => \T_EXIT, + \T_EXTENDS => \T_EXTENDS, + \T_FINAL => \T_FINAL, + \T_FINALLY => \T_FINALLY, + \T_FN => \T_FN, + \T_FOR => \T_FOR, + \T_FOREACH => \T_FOREACH, + \T_FUNCTION => \T_FUNCTION, + \T_GLOBAL => \T_GLOBAL, + \T_GOTO => \T_GOTO, + \T_IF => \T_IF, + \T_IMPLEMENTS => \T_IMPLEMENTS, + \T_INCLUDE => \T_INCLUDE, + \T_INCLUDE_ONCE => \T_INCLUDE_ONCE, + \T_INSTANCEOF => \T_INSTANCEOF, + \T_INSTEADOF => \T_INSTEADOF, + \T_INTERFACE => \T_INTERFACE, + \T_ISSET => \T_ISSET, + \T_LIST => \T_LIST, + \T_LOGICAL_AND => \T_LOGICAL_AND, + \T_LOGICAL_OR => \T_LOGICAL_OR, + \T_LOGICAL_XOR => \T_LOGICAL_XOR, + \T_MATCH => \T_MATCH, + \T_NAMESPACE => \T_NAMESPACE, + \T_NEW => \T_NEW, + \T_PRINT => \T_PRINT, + \T_PRIVATE => \T_PRIVATE, + \T_PROTECTED => \T_PROTECTED, + \T_PUBLIC => \T_PUBLIC, + \T_READONLY => \T_READONLY, + \T_REQUIRE => \T_REQUIRE, + \T_REQUIRE_ONCE => \T_REQUIRE_ONCE, + \T_RETURN => \T_RETURN, + \T_STATIC => \T_STATIC, + \T_SWITCH => \T_SWITCH, + \T_THROW => \T_THROW, + \T_TRAIT => \T_TRAIT, + \T_TRY => \T_TRY, + \T_UNSET => \T_UNSET, + \T_USE => \T_USE, + \T_VAR => \T_VAR, + \T_WHILE => \T_WHILE, + \T_YIELD => \T_YIELD, + \T_YIELD_FROM => \T_YIELD_FROM, + ]; + /** * Test the method. * @@ -212,12 +472,15 @@ public function testUnchangedTokenArrays($name, $expected) public function dataUnchangedTokenArrays() { $phpunitProp = [ - 'backupGlobals' => true, - 'backupGlobalsBlacklist' => true, - 'backupStaticAttributes' => true, - 'backupStaticAttributesBlacklist' => true, - 'runTestInSeparateProcess' => true, - 'preserveGlobalState' => true, + 'backupGlobals' => true, + 'backupGlobalsBlacklist' => true, + 'backupGlobalsExcludeList' => true, + 'backupStaticAttributes' => true, + 'backupStaticAttributesBlacklist' => true, + 'backupStaticAttributesExcludeList' => true, + 'runTestInSeparateProcess' => true, + 'preserveGlobalState' => true, + 'providedTests' => true, ]; $data = []; @@ -240,6 +503,27 @@ public function dataUnchangedTokenArrays() */ public function testUndeclaredTokenArray() { - $this->assertSame([], BCTokens::notATokenArray()); + $this->expectException('PHPCSUtils\Exceptions\InvalidTokenArray'); + $this->expectExceptionMessage('Call to undefined method PHPCSUtils\BackCompat\BCTokens::notATokenArray()'); + + BCTokens::notATokenArray(); + } + + /** + * Test whether the method in BCTokens is still in sync with the latest version of PHPCS. + * + * This group is not run by default and has to be specifically requested to be run. + * + * @group compareWithPHPCS + * + * @dataProvider dataUnchangedTokenArrays + * + * @param string $name The token array name. + * + * @return void + */ + public function testPHPCSUnchangedTokenArrays($name) + { + $this->assertSame(Tokens::${$name}, BCTokens::$name()); } } diff --git a/Tests/BackCompat/Helper/ConfigDataTest.php b/Tests/BackCompat/Helper/ConfigDataTest.php index 5677d454..9c3b1fcd 100644 --- a/Tests/BackCompat/Helper/ConfigDataTest.php +++ b/Tests/BackCompat/Helper/ConfigDataTest.php @@ -13,6 +13,7 @@ use PHP_CodeSniffer\Config; use PHPCSUtils\BackCompat\Helper; use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\Polyfills\ExpectException; /** * Test class. @@ -24,8 +25,9 @@ * * @since 1.0.0 */ -class ConfigDataTest extends TestCase +final class ConfigDataTest extends TestCase { + use ExpectException; /** * Test the getConfigData() and setConfigData() method when used in a cross-version compatible manner. @@ -34,10 +36,6 @@ class ConfigDataTest extends TestCase */ public function testConfigData34() { - if (\version_compare(Helper::getVersion(), '2.99.99', '<=') === true) { - $this->markTestSkipped('Test only applicable to PHPCS > 2.x'); - } - $config = new Config(); $original = Helper::getConfigData('arbitrary_name'); $expected = 'expected'; @@ -57,7 +55,7 @@ public function testConfigData34() * * @return void */ - public function testConfigDataPHPCS23() + public function testConfigDataPHPCS3() { if (\version_compare(Helper::getVersion(), '3.99.99', '>') === true) { $this->markTestSkipped('Test only applicable to PHPCS < 4.x'); @@ -87,17 +85,8 @@ public function testConfigDataPHPCS4Exception() $this->markTestSkipped('Test only applicable to PHPCS 4.x'); } - $msg = 'Passing the $config parameter is required in PHPCS 4.x'; - $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - - if (\method_exists($this, 'expectException')) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($msg); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $msg); - } + $this->expectException('PHP_CodeSniffer\Exceptions\RuntimeException'); + $this->expectExceptionMessage('Passing the $config parameter is required in PHPCS 4.x'); Helper::setConfigData('arbitrary_name', 'test', true); } diff --git a/Tests/BackCompat/Helper/GetCommandLineDataTest.inc b/Tests/BackCompat/Helper/GetCommandLineDataTest.inc deleted file mode 100644 index 3e0f3b14..00000000 --- a/Tests/BackCompat/Helper/GetCommandLineDataTest.inc +++ /dev/null @@ -1,3 +0,0 @@ -assertSame($expected, $result); } /** * Test the getCommandLineData() method when requesting an unknown setting. * - * @covers \PHPCSUtils\BackCompat\Helper::getCommandLineData + * @covers ::getCommandLineData * * @return void */ @@ -59,149 +69,106 @@ public function testGetCommandLineDataNull() /** * Test the getTabWidth() method. * - * @covers \PHPCSUtils\BackCompat\Helper::getTabWidth + * @covers ::getTabWidth * * @return void */ public function testGetTabWidth() { + self::$phpcsFile->config->tabWidth = null; + $result = Helper::getTabWidth(self::$phpcsFile); $this->assertSame(4, $result, 'Failed retrieving the default tab width'); - if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - // PHPCS 3.x. - self::$phpcsFile->config->tabWidth = 2; - } else { - // PHPCS 2.x. - self::$phpcsFile->phpcs->cli->setCommandLineValues(['--tab-width=2']); - } + self::$phpcsFile->config->tabWidth = 2; $result = Helper::getTabWidth(self::$phpcsFile); - $this->assertSame(2, $result, 'Failed retrieving the custom set tab width'); - // Restore defaults before moving to the next test. - if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - self::$phpcsFile->config->restoreDefaults(); - } else { - self::$phpcsFile->phpcs->cli->setCommandLineValues(['--tab-width=4']); - } + // Restore default before moving to the next test. + self::$phpcsFile->config->restoreDefaults(); + + $this->assertSame(2, $result, 'Failed retrieving the custom set tab width'); } /** * Test the getEncoding() method. * - * @covers \PHPCSUtils\BackCompat\Helper::getEncoding + * @covers ::getEncoding * * @return void */ public function testGetEncoding() { + self::$phpcsFile->config->encoding = null; + $result = Helper::getEncoding(self::$phpcsFile); - $expected = \version_compare(static::$phpcsVersion, '2.99.99', '>') ? 'utf-8' : 'iso-8859-1'; + $expected = 'utf-8'; $this->assertSame($expected, $result, 'Failed retrieving the default encoding'); - if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - // PHPCS 3.x. - self::$phpcsFile->config->encoding = 'utf-16'; - } else { - // PHPCS 2.x. - self::$phpcsFile->phpcs->cli->setCommandLineValues(['--encoding=utf-16']); - } + self::$phpcsFile->config->encoding = 'utf-16'; $result = Helper::getEncoding(self::$phpcsFile); - $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); - // Restore defaults before moving to the next test. - if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - self::$phpcsFile->config->restoreDefaults(); - } else { - self::$phpcsFile->phpcs->cli->setCommandLineValues(['--encoding=iso-8859-1']); - } + // Restore default before moving to the next test. + self::$phpcsFile->config->restoreDefaults(); + + $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); } /** * Test the getEncoding() method when not passing the PHPCS file parameter. * - * @covers \PHPCSUtils\BackCompat\Helper::getEncoding + * @covers ::getEncoding * * @return void */ public function testGetEncodingWithoutPHPCSFile() { + self::$phpcsFile->config->encoding = null; + $result = Helper::getEncoding(); - $expected = \version_compare(static::$phpcsVersion, '2.99.99', '>') ? 'utf-8' : 'iso-8859-1'; + $expected = 'utf-8'; $this->assertSame($expected, $result, 'Failed retrieving the default encoding'); - $config = null; - if (isset(self::$phpcsFile->config) === true) { - $config = self::$phpcsFile->config; - } - - Helper::setConfigData('encoding', 'utf-16', true, $config); + Helper::setConfigData('encoding', 'utf-16', true, self::$phpcsFile->config); $result = Helper::getEncoding(); - $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); // Restore defaults before moving to the next test. - if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - Helper::setConfigData('encoding', 'utf-8', true, $config); - } else { - Helper::setConfigData('encoding', 'iso-8859-1', true, $config); - } - } - - /** - * Test the ignoreAnnotations() method. - * - * @covers \PHPCSUtils\BackCompat\Helper::ignoreAnnotations - * - * @return void - */ - public function testIgnoreAnnotationsV2() - { - if (\version_compare(static::$phpcsVersion, '2.99.99', '>') === true) { - $this->markTestSkipped('Test only applicable to PHPCS 2.x'); - } + Helper::setConfigData('encoding', 'utf-8', true, self::$phpcsFile->config); - $this->assertFalse(Helper::ignoreAnnotations()); + $this->assertSame('utf-16', $result, 'Failed retrieving the custom set encoding'); } /** * Test the ignoreAnnotations() method. * - * @covers \PHPCSUtils\BackCompat\Helper::ignoreAnnotations + * @covers ::ignoreAnnotations * * @return void */ - public function testIgnoreAnnotationsV3Default() + public function testIgnoreAnnotationsDefault() { - if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { - $this->markTestSkipped('Test only applicable to PHPCS 3.x'); - } - $result = Helper::ignoreAnnotations(); $this->assertFalse($result, 'Failed default ignoreAnnotations test without passing $phpcsFile'); $result = Helper::ignoreAnnotations(self::$phpcsFile); - $this->assertFalse($result, 'Failed default ignoreAnnotations test while passing $phpcsFile'); // Restore defaults before moving to the next test. self::$phpcsFile->config->restoreDefaults(); + + $this->assertFalse($result, 'Failed default ignoreAnnotations test while passing $phpcsFile'); } /** * Test the ignoreAnnotations() method. * - * @covers \PHPCSUtils\BackCompat\Helper::ignoreAnnotations + * @covers ::ignoreAnnotations * * @return void */ - public function testIgnoreAnnotationsV3SetViaMethod() + public function testIgnoreAnnotationsSetViaMethod() { - if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { - $this->markTestSkipped('Test only applicable to PHPCS 3.x'); - } - $config = null; if (isset(self::$phpcsFile->config) === true) { $config = self::$phpcsFile->config; @@ -210,31 +177,29 @@ public function testIgnoreAnnotationsV3SetViaMethod() Helper::setConfigData('annotations', false, true, $config); $result = Helper::ignoreAnnotations(); - $this->assertTrue($result); // Restore defaults before moving to the next test. Helper::setConfigData('annotations', true, true, $config); + + $this->assertTrue($result); } /** * Test the ignoreAnnotations() method. * - * @covers \PHPCSUtils\BackCompat\Helper::ignoreAnnotations + * @covers ::ignoreAnnotations * * @return void */ - public function testIgnoreAnnotationsV3SetViaProperty() + public function testIgnoreAnnotationsSetViaProperty() { - if (\version_compare(static::$phpcsVersion, '2.99.99', '<=') === true) { - $this->markTestSkipped('Test only applicable to PHPCS 3.x'); - } - self::$phpcsFile->config->annotations = false; $result = Helper::ignoreAnnotations(self::$phpcsFile); - $this->assertTrue($result); // Restore defaults before moving to the next test. self::$phpcsFile->config->restoreDefaults(); + + $this->assertTrue($result); } } diff --git a/Tests/BackCompat/Helper/GetVersionTest.php b/Tests/BackCompat/Helper/GetVersionTest.php index da6862aa..da022fc1 100644 --- a/Tests/BackCompat/Helper/GetVersionTest.php +++ b/Tests/BackCompat/Helper/GetVersionTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetVersionTest extends TestCase +final class GetVersionTest extends TestCase { /** @@ -32,7 +32,7 @@ class GetVersionTest extends TestCase * * @var string */ - const DEVMASTER = '3.5.6'; + const DEVMASTER = '3.7.1'; /** * Test the method. @@ -44,7 +44,7 @@ public function testGetVersion() $expected = \getenv('PHPCS_VERSION'); if ($expected === false) { $this->markTestSkipped('The test for the Helper::getVersion() method will only run' - . ' if the PHPCS_VERSION environment variable is set, such as during a Travis CI build' + . ' if the PHPCS_VERSION environment variable is set, such as during a CI build' . ' or when this variable has been set in the PHPUnit configuration file.'); return; diff --git a/Tests/DummyFile.inc b/Tests/DummyFile.inc new file mode 100644 index 00000000..f6de982b --- /dev/null +++ b/Tests/DummyFile.inc @@ -0,0 +1,4 @@ +expectException('PHPCSUtils\Exceptions\InvalidTokenArray'); + $this->expectExceptionMessage(\sprintf('Call to undefined method %s::dummy()', __CLASS__)); + + throw InvalidTokenArray::create('dummy'); + } +} diff --git a/Tests/Exceptions/TestFileNotFound/TestFileNotFoundTest.php b/Tests/Exceptions/TestFileNotFound/TestFileNotFoundTest.php new file mode 100644 index 00000000..a3760eae --- /dev/null +++ b/Tests/Exceptions/TestFileNotFound/TestFileNotFoundTest.php @@ -0,0 +1,54 @@ +expectException('PHPCSUtils\Exceptions\TestFileNotFound'); + $this->expectExceptionMessage( + 'Failed to find a tokenized test case file.' . \PHP_EOL + . 'Make sure the UtilityMethodTestCase::setUpTestFile() method has run' + ); + + throw new TestFileNotFound(); + } + + /** + * Test that a passed message overruled the default message. + * + * @return void + */ + public function testWithCustomMessage() + { + $this->expectException('PHPCSUtils\Exceptions\TestFileNotFound'); + $this->expectExceptionMessage('foobar'); + + throw new TestFileNotFound('foobar'); + } +} diff --git a/Tests/Exceptions/TestMarkerNotFound/TestMarkerNotFoundTest.php b/Tests/Exceptions/TestMarkerNotFound/TestMarkerNotFoundTest.php new file mode 100644 index 00000000..5b2b1a99 --- /dev/null +++ b/Tests/Exceptions/TestMarkerNotFound/TestMarkerNotFoundTest.php @@ -0,0 +1,38 @@ +expectException('PHPCSUtils\Exceptions\TestMarkerNotFound'); + $this->expectExceptionMessage('Failed to find the test marker: /* testDummy */ in test case file filename.inc'); + + throw TestMarkerNotFound::create('/* testDummy */', 'filename.inc'); + } +} diff --git a/Tests/Exceptions/TestTargetNotFound/TestTargetNotFoundTest.php b/Tests/Exceptions/TestTargetNotFound/TestTargetNotFoundTest.php new file mode 100644 index 00000000..ddb77c84 --- /dev/null +++ b/Tests/Exceptions/TestTargetNotFound/TestTargetNotFoundTest.php @@ -0,0 +1,56 @@ +expectException('PHPCSUtils\Exceptions\TestTargetNotFound'); + $this->expectExceptionMessage( + 'Failed to find test target token for comment string: /* testDummy */ in test case file: filename.inc' + ); + + throw TestTargetNotFound::create('/* testDummy */', null, 'filename.inc'); + } + + /** + * Test that the text of the exception is as expected. + * + * @return void + */ + public function testCreateWithContent() + { + $this->expectException('PHPCSUtils\Exceptions\TestTargetNotFound'); + $this->expectExceptionMessage( + 'Failed to find test target token for comment string: /* testDummy */' + . ' with token content: foo in test case file: filename.inc' + ); + + throw TestTargetNotFound::create('/* testDummy */', 'foo', 'filename.inc'); + } +} diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php index 1400c7cc..3ff2ef0e 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerExceptionsTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class SpacesFixerExceptionsTest extends UtilityMethodTestCase +final class SpacesFixerExceptionsTest extends UtilityMethodTestCase { /** diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php index ce508d0d..9e426aad 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerNewlineTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Fixers\SpacesFixer; -use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerNoSpaceTest; +use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerTestCase; /** * Tests for the \PHPCSUtils\Fixers\SpacesFixer::checkAndFix() method. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class SpacesFixerNewlineTest extends SpacesFixerNoSpaceTest +final class SpacesFixerNewlineTest extends SpacesFixerTestCase { /** diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php index 1fd02d75..366706ef 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerNoSpaceTest.php @@ -10,8 +10,7 @@ namespace PHPCSUtils\Tests\Fixers\SpacesFixer; -use PHPCSUtils\Fixers\SpacesFixer; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerTestCase; /** * Tests for the \PHPCSUtils\Fixers\SpacesFixer::checkAndFix() method. @@ -22,7 +21,7 @@ * * @since 1.0.0 */ -class SpacesFixerNoSpaceTest extends UtilityMethodTestCase +final class SpacesFixerNoSpaceTest extends SpacesFixerTestCase { /** @@ -32,13 +31,6 @@ class SpacesFixerNoSpaceTest extends UtilityMethodTestCase */ const SPACES = 0; - /** - * Dummy error message phrase to use for the test. - * - * @var string - */ - const MSG = 'Expected: %s. Found: %s'; - /** * The expected replacement for the first placeholder. * @@ -46,15 +38,6 @@ class SpacesFixerNoSpaceTest extends UtilityMethodTestCase */ const MSG_REPLACEMENT_1 = 'no space'; - /** - * Dummy error code to use for the test. - * - * Using the dummy full error code to force it to record. - * - * @var string - */ - const CODE = 'PHPCSUtils.SpacesFixer.Test.Found'; - /** * Dummy metric name to use for the test. * @@ -69,313 +52,10 @@ class SpacesFixerNoSpaceTest extends UtilityMethodTestCase */ protected $compliantCases = ['no-space']; - /** - * Full path to the test case file associated with this test class. - * - * @var string - */ - protected static $caseFile = ''; - /** * Full path to the fixed version of the test case file associated with this test class. * * @var string */ protected static $fixedFile = '/SpacesFixerNoSpaceTest.inc.fixed'; - - /** - * Set the name of a sniff to pass to PHPCS to limit the run (and force it to record errors). - * - * @var array - */ - protected static $selectedSniff = ['PHPCSUtils.SpacesFixer.Test']; - - /** - * Initialize PHPCS & tokenize the test case file. - * - * @beforeClass - * - * @return void - */ - public static function setUpTestFile() - { - self::$caseFile = __DIR__ . '/SpacesFixerTest.inc'; - parent::setUpTestFile(); - } - - /** - * Test that no violation is reported for a test case complying with the correct number of spaces. - * - * @dataProvider dataCheckAndFixNoError - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param array $expected Expected error details (for the metric input). - * - * @return void - */ - public function testCheckAndFixNoError($testMarker, $expected) - { - $stackPtr = $this->getTargetToken($testMarker, \T_ARRAY); - $secondPtr = $this->getTargetToken($testMarker, \T_OPEN_PARENTHESIS); - - /* - * Note: passing $stackPtr and $secondPtr in reverse order to make sure that case is - * covered by a test as well. - */ - SpacesFixer::checkAndFix( - self::$phpcsFile, - $secondPtr, - $stackPtr, - static::SPACES, - static::MSG, - static::CODE, - 'error', - 0, - static::METRIC - ); - - $result = \array_merge(self::$phpcsFile->getErrors(), self::$phpcsFile->getWarnings()); - - // Expect no errors. - $this->assertCount(0, $result, 'Failed to assert that no violations were found'); - - // Check that the metric is recorded correctly. - $metrics = self::$phpcsFile->getMetrics(); - $this->assertGreaterThanOrEqual( - 1, - $metrics[static::METRIC]['values'][$expected['found']], - 'Failed recorded metric check' - ); - } - - /** - * Data Provider. - * - * @see testCheckAndFixNoError() For the array format. - * - * @return array - */ - public function dataCheckAndFixNoError() - { - $data = []; - $baseData = $this->getAllData(); - - foreach ($this->compliantCases as $caseName) { - if (isset($baseData[$caseName])) { - $data[$caseName] = $baseData[$caseName]; - } - } - - return $data; - } - - /** - * Test that violations are correctly reported. - * - * @dataProvider dataCheckAndFix - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param array $expected Expected error details. - * @param string $type The message type to test: 'error' or 'warning'. - * - * @return void - */ - public function testCheckAndFix($testMarker, $expected, $type) - { - $stackPtr = $this->getTargetToken($testMarker, \T_ARRAY); - $secondPtr = $this->getTargetToken($testMarker, \T_OPEN_PARENTHESIS); - - SpacesFixer::checkAndFix( - self::$phpcsFile, - $stackPtr, - $secondPtr, - static::SPACES, - static::MSG, - static::CODE, - $type, - 0, - static::METRIC - ); - - if ($type === 'error') { - $result = self::$phpcsFile->getErrors(); - } else { - $result = self::$phpcsFile->getWarnings(); - } - - $tokens = self::$phpcsFile->getTokens(); - - if (isset($result[$tokens[$stackPtr]['line']][$tokens[$stackPtr]['column']]) === false) { - $this->fail('Expected 1 violation. None found.'); - } - - $messages = $result[$tokens[$stackPtr]['line']][$tokens[$stackPtr]['column']]; - - // Expect one violation. - $this->assertCount(1, $messages, 'Expected 1 violation, found: ' . \count($messages)); - - /* - * Test the violation details. - */ - - $expectedMessage = \sprintf(static::MSG, static::MSG_REPLACEMENT_1, $expected['found']); - $this->assertSame($expectedMessage, $messages[0]['message'], 'Message comparison failed'); - - // PHPCS 2.x places `unknownSniff.` before the actual error code for utility tests with a dummy error code. - $errorCodeResult = \str_replace('unknownSniff.', '', $messages[0]['source']); - $this->assertSame(static::CODE, $errorCodeResult, 'Error code comparison failed'); - - $this->assertSame($expected['fixable'], $messages[0]['fixable'], 'Fixability comparison failed'); - - // Check that the metric is recorded correctly. - $metrics = self::$phpcsFile->getMetrics(); - $this->assertGreaterThanOrEqual( - 1, - $metrics[static::METRIC]['values'][$expected['found']], - 'Failed recorded metric check' - ); - } - - /** - * Data Provider. - * - * @see testCheckAndFix() For the array format. - * - * @return array - */ - public function dataCheckAndFix() - { - $data = $this->getAllData(); - - foreach ($this->compliantCases as $caseName) { - unset($data[$caseName]); - } - - return $data; - } - - /** - * Test that the fixes are correctly made. - * - * @return void - */ - public function testFixesMade() - { - self::$phpcsFile->fixer->startFile(self::$phpcsFile); - self::$phpcsFile->fixer->enabled = true; - - $data = $this->getAllData(); - foreach ($data as $dataset) { - $stackPtr = $this->getTargetToken($dataset[0], \T_ARRAY); - $secondPtr = $this->getTargetToken($dataset[0], \T_OPEN_PARENTHESIS); - - SpacesFixer::checkAndFix( - self::$phpcsFile, - $stackPtr, - $secondPtr, - static::SPACES, - static::MSG, - static::CODE, - $dataset[1], - 0 - ); - } - - $fixedFile = __DIR__ . static::$fixedFile; - $expected = \file_get_contents($fixedFile); - $result = self::$phpcsFile->fixer->getContents(); - - $this->assertSame( - $expected, - $result, - \sprintf( - 'Fixed version of %s does not match expected version in %s', - \basename(static::$caseFile), - \basename($fixedFile) - ) - ); - } - - /** - * Helper function holding the base data for the data providers. - * - * @return array - */ - protected function getAllData() - { - return [ - 'no-space' => [ - '/* testNoSpace */', - [ - 'found' => 'no spaces', - 'fixable' => true, - ], - 'error', - ], - 'one-space' => [ - '/* testOneSpace */', - [ - 'found' => '1 space', - 'fixable' => true, - ], - 'error', - ], - 'two-spaces' => [ - '/* testTwoSpaces */', - [ - 'found' => '2 spaces', - 'fixable' => true, - ], - 'error', - ], - 'multiple-spaces' => [ - '/* testMultipleSpaces */', - [ - 'found' => '13 spaces', - 'fixable' => true, - ], - 'warning', - ], - 'newline-and-trailing-spaces' => [ - '/* testNewlineAndTrailingSpaces */', - [ - 'found' => 'a new line', - 'fixable' => true, - ], - 'error', - ], - 'multiple-newlines-and-spaces' => [ - '/* testMultipleNewlinesAndSpaces */', - [ - 'found' => 'multiple new lines', - 'fixable' => true, - ], - 'error', - ], - 'comment-no-space' => [ - '/* testCommentNoSpace */', - [ - 'found' => 'non-whitespace tokens', - 'fixable' => false, - ], - 'warning', - ], - 'comment-and-space' => [ - '/* testCommentAndSpaces */', - [ - 'found' => '1 space', - 'fixable' => false, - ], - 'error', - ], - 'comment-and-new line' => [ - '/* testCommentAndNewline */', - [ - 'found' => 'a new line', - 'fixable' => false, - ], - 'error', - ], - ]; - } } diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php index de3cff82..2fe33692 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerOneSpaceTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Fixers\SpacesFixer; -use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerNoSpaceTest; +use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerTestCase; /** * Tests for the \PHPCSUtils\Fixers\SpacesFixer::checkAndFix() method. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class SpacesFixerOneSpaceTest extends SpacesFixerNoSpaceTest +final class SpacesFixerOneSpaceTest extends SpacesFixerTestCase { /** diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerTestCase.php b/Tests/Fixers/SpacesFixer/SpacesFixerTestCase.php new file mode 100644 index 00000000..57988e94 --- /dev/null +++ b/Tests/Fixers/SpacesFixer/SpacesFixerTestCase.php @@ -0,0 +1,383 @@ +getTargetToken($testMarker, \T_ARRAY); + $secondPtr = $this->getTargetToken($testMarker, \T_OPEN_PARENTHESIS); + + /* + * Note: passing $stackPtr and $secondPtr in reverse order to make sure that case is + * covered by a test as well. + */ + SpacesFixer::checkAndFix( + self::$phpcsFile, + $secondPtr, + $stackPtr, + static::SPACES, + static::MSG, + static::CODE, + 'error', + 0, + static::METRIC + ); + + $result = \array_merge(self::$phpcsFile->getErrors(), self::$phpcsFile->getWarnings()); + + // Expect no errors. + $this->assertCount(0, $result, 'Failed to assert that no violations were found'); + + // Check that the metric is recorded correctly. + $metrics = self::$phpcsFile->getMetrics(); + $this->assertGreaterThanOrEqual( + 1, + $metrics[static::METRIC]['values'][$expected['found']], + 'Failed recorded metric check' + ); + } + + /** + * Data Provider. + * + * @see testCheckAndFixNoError() For the array format. + * + * @return array + */ + public function dataCheckAndFixNoError() + { + $data = []; + $baseData = $this->getAllData(); + + foreach ($this->compliantCases as $caseName) { + if (isset($baseData[$caseName])) { + $data[$caseName] = $baseData[$caseName]; + } + } + + return $data; + } + + /** + * Test that violations are correctly reported. + * + * @covers \PHPCSUtils\Fixers\SpacesFixer::checkAndFix + * + * @dataProvider dataCheckAndFix + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected Expected error details. + * @param string $type The message type to test: 'error' or 'warning'. + * + * @return void + */ + public function testCheckAndFix($testMarker, $expected, $type) + { + $stackPtr = $this->getTargetToken($testMarker, \T_ARRAY); + $secondPtr = $this->getTargetToken($testMarker, \T_OPEN_PARENTHESIS); + + SpacesFixer::checkAndFix( + self::$phpcsFile, + $stackPtr, + $secondPtr, + static::SPACES, + static::MSG, + static::CODE, + $type, + 0, + static::METRIC + ); + + if ($type === 'error') { + $result = self::$phpcsFile->getErrors(); + } else { + $result = self::$phpcsFile->getWarnings(); + } + + $tokens = self::$phpcsFile->getTokens(); + + if (isset($result[$tokens[$stackPtr]['line']][$tokens[$stackPtr]['column']]) === false) { + $this->fail('Expected 1 violation. None found.'); + } + + $messages = $result[$tokens[$stackPtr]['line']][$tokens[$stackPtr]['column']]; + + // Expect one violation. + $this->assertCount(1, $messages, 'Expected 1 violation, found: ' . \count($messages)); + + /* + * Test the violation details. + */ + + $expectedMessage = \sprintf(static::MSG, static::MSG_REPLACEMENT_1, $expected['found']); + $this->assertSame($expectedMessage, $messages[0]['message'], 'Message comparison failed'); + + $this->assertSame(static::CODE, $messages[0]['source'], 'Error code comparison failed'); + + $this->assertSame($expected['fixable'], $messages[0]['fixable'], 'Fixability comparison failed'); + + // Check that the metric is recorded correctly. + $metrics = self::$phpcsFile->getMetrics(); + $this->assertGreaterThanOrEqual( + 1, + $metrics[static::METRIC]['values'][$expected['found']], + 'Failed recorded metric check' + ); + } + + /** + * Data Provider. + * + * @see testCheckAndFix() For the array format. + * + * @return array + */ + public function dataCheckAndFix() + { + $data = $this->getAllData(); + + foreach ($this->compliantCases as $caseName) { + unset($data[$caseName]); + } + + return $data; + } + + /** + * Test that the fixes are correctly made. + * + * @covers \PHPCSUtils\Fixers\SpacesFixer::checkAndFix + * + * @return void + */ + public function testFixesMade() + { + self::$phpcsFile->fixer->startFile(self::$phpcsFile); + self::$phpcsFile->fixer->enabled = true; + + $data = $this->getAllData(); + foreach ($data as $dataset) { + $stackPtr = $this->getTargetToken($dataset['testMarker'], \T_ARRAY); + $secondPtr = $this->getTargetToken($dataset['testMarker'], \T_OPEN_PARENTHESIS); + + SpacesFixer::checkAndFix( + self::$phpcsFile, + $stackPtr, + $secondPtr, + static::SPACES, + static::MSG, + static::CODE, + $dataset['type'], + 0 + ); + } + + $fixedFile = __DIR__ . static::$fixedFile; + $result = self::$phpcsFile->fixer->getContents(); + + $this->assertStringEqualsFile( + $fixedFile, + $result, + \sprintf( + 'Fixed version of %s does not match expected version in %s', + \basename(static::$caseFile), + \basename($fixedFile) + ) + ); + } + + /** + * Helper function holding the base data for the data providers. + * + * @return array + */ + protected function getAllData() + { + return [ + 'no-space' => [ + 'testMarker' => '/* testNoSpace */', + 'expected' => [ + 'found' => 'no spaces', + 'fixable' => true, + ], + 'type' => 'error', + ], + 'one-space' => [ + 'testMarker' => '/* testOneSpace */', + 'expected' => [ + 'found' => '1 space', + 'fixable' => true, + ], + 'type' => 'error', + ], + 'two-spaces' => [ + 'testMarker' => '/* testTwoSpaces */', + 'expected' => [ + 'found' => '2 spaces', + 'fixable' => true, + ], + 'type' => 'error', + ], + 'multiple-spaces' => [ + 'testMarker' => '/* testMultipleSpaces */', + 'expected' => [ + 'found' => '13 spaces', + 'fixable' => true, + ], + 'type' => 'warning', + ], + 'newline-and-trailing-spaces' => [ + 'testMarker' => '/* testNewlineAndTrailingSpaces */', + 'expected' => [ + 'found' => 'a new line', + 'fixable' => true, + ], + 'type' => 'error', + ], + 'multiple-newlines-and-spaces' => [ + 'testMarker' => '/* testMultipleNewlinesAndSpaces */', + 'expected' => [ + 'found' => 'multiple new lines', + 'fixable' => true, + ], + 'type' => 'error', + ], + 'comment-no-space' => [ + 'testMarker' => '/* testCommentNoSpace */', + 'expected' => [ + 'found' => 'non-whitespace tokens', + 'fixable' => false, + ], + 'type' => 'warning', + ], + 'comment-and-space' => [ + 'testMarker' => '/* testCommentAndSpaces */', + 'expected' => [ + 'found' => '1 space', + 'fixable' => false, + ], + 'type' => 'error', + ], + 'comment-and-new line' => [ + 'testMarker' => '/* testCommentAndNewline */', + 'expected' => [ + 'found' => 'a new line', + 'fixable' => false, + ], + 'type' => 'error', + ], + ]; + } +} diff --git a/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php b/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php index a76f59cd..9c31d17b 100644 --- a/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php +++ b/Tests/Fixers/SpacesFixer/SpacesFixerTwoSpaceTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Fixers\SpacesFixer; -use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerNoSpaceTest; +use PHPCSUtils\Tests\Fixers\SpacesFixer\SpacesFixerTestCase; /** * Tests for the \PHPCSUtils\Fixers\SpacesFixer::checkAndFix() method. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class SpacesFixerTwoSpaceTest extends SpacesFixerNoSpaceTest +final class SpacesFixerTwoSpaceTest extends SpacesFixerTestCase { /** diff --git a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingNewlineTest.inc b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingNewlineTest.inc new file mode 100644 index 00000000..04245e6b --- /dev/null +++ b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingNewlineTest.inc @@ -0,0 +1,12 @@ +getTargetToken($testMarker, \T_CLOSE_PARENTHESIS); + $secondPtr = self::$phpcsFile->findPrevious(\T_WHITESPACE, ($stackPtr - 1), null, true); + + SpacesFixer::checkAndFix( + self::$phpcsFile, + $stackPtr, + $secondPtr, + self::SPACES, + self::MSG, + self::CODE, + 'error', + 0, + self::METRIC + ); + + $result = \array_merge(self::$phpcsFile->getErrors(), self::$phpcsFile->getWarnings()); + + // Expect no errors. + $this->assertCount(0, $result, 'Failed to assert that no violations were found'); + + // Check that the metric is recorded correctly. + $metrics = self::$phpcsFile->getMetrics(); + $this->assertGreaterThanOrEqual( + 1, + $metrics[self::METRIC]['values'][self::MSG_REPLACEMENT_1], + 'Failed recorded metric check' + ); + } + + /** + * Test that no fixes are made. + * + * @return void + */ + public function testNoFixesMade() + { + self::$phpcsFile->fixer->startFile(self::$phpcsFile); + self::$phpcsFile->fixer->enabled = true; + + $data = $this->dataCheckAndFixNoError(); + foreach ($data as $dataset) { + $stackPtr = $this->getTargetToken($dataset[0], \T_CLOSE_PARENTHESIS); + $secondPtr = self::$phpcsFile->findPrevious(\T_WHITESPACE, ($stackPtr - 1), null, true); + + SpacesFixer::checkAndFix( + self::$phpcsFile, + $stackPtr, + $secondPtr, + self::SPACES, + self::MSG, + self::CODE, + 'error' + ); + } + + $fixedFile = __DIR__ . '/TrailingCommentHandlingNewlineTest.inc'; + $result = self::$phpcsFile->fixer->getContents(); + + $this->assertStringEqualsFile( + $fixedFile, + $result, + \sprintf( + 'Fixed version of %s does not match expected version in %s', + \basename(self::$caseFile), + \basename($fixedFile) + ) + ); + } + + /** + * Data Provider. + * + * @see testCheckAndFixNoError() For the array format. + * + * @return array + */ + public function dataCheckAndFixNoError() + { + return [ + 'correct-newline-before' => [ + '/* testNewlineWithTrailingCommentBefore */', + ], + 'correct-blank-line-before' => [ + '/* testNewlineWithTrailingBlankLineBefore */', + ], + ]; + } +} diff --git a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php index a04858b3..5c771d57 100644 --- a/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php +++ b/Tests/Fixers/SpacesFixer/TrailingCommentHandlingTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class TrailingCommentHandlingTest extends UtilityMethodTestCase +final class TrailingCommentHandlingTest extends UtilityMethodTestCase { /** @@ -120,9 +120,7 @@ public function testCheckAndFix($testMarker, $expected, $type) $expectedMessage = \sprintf(self::MSG, self::MSG_REPLACEMENT_1, $expected['found']); $this->assertSame($expectedMessage, $messages[0]['message'], 'Message comparison failed'); - // PHPCS 2.x places `unknownSniff.` before the actual error code for utility tests with a dummy error code. - $errorCodeResult = \str_replace('unknownSniff.', '', $messages[0]['source']); - $this->assertSame(self::CODE, $errorCodeResult, 'Error code comparison failed'); + $this->assertSame(self::CODE, $messages[0]['source'], 'Error code comparison failed'); $this->assertSame($expected['fixable'], $messages[0]['fixable'], 'Fixability comparison failed'); @@ -132,7 +130,7 @@ public function testCheckAndFix($testMarker, $expected, $type) // Check that no metric is recorded. $metrics = self::$phpcsFile->getMetrics(); $this->assertFalse( - isset($metrics[static::METRIC]['values'][$expected['found']]), + isset($metrics[self::METRIC]['values'][$expected['found']]), 'Failed recorded metric check' ); } @@ -149,8 +147,8 @@ public function testFixesMade() $data = $this->dataCheckAndFix(); foreach ($data as $dataset) { - $stackPtr = $this->getTargetToken($dataset[0], \T_COMMENT); - $secondPtr = $this->getTargetToken($dataset[0], \T_LNUMBER, '3'); + $stackPtr = $this->getTargetToken($dataset['testMarker'], \T_COMMENT); + $secondPtr = $this->getTargetToken($dataset['testMarker'], \T_LNUMBER, '3'); SpacesFixer::checkAndFix( self::$phpcsFile, @@ -159,16 +157,15 @@ public function testFixesMade() self::SPACES, self::MSG, self::CODE, - $dataset[1] + $dataset['type'] ); } $fixedFile = __DIR__ . '/TrailingCommentHandlingTest.inc.fixed'; - $expected = \file_get_contents($fixedFile); $result = self::$phpcsFile->fixer->getContents(); - $this->assertSame( - $expected, + $this->assertStringEqualsFile( + $fixedFile, $result, \sprintf( 'Fixed version of %s does not match expected version in %s', @@ -189,20 +186,20 @@ public function dataCheckAndFix() { return [ 'trailing-comment-not-fixable' => [ - '/* testTrailingOpenCommentAsPtrA */', - [ + 'testMarker' => '/* testTrailingOpenCommentAsPtrA */', + 'expected' => [ 'found' => 'a new line', 'fixable' => false, ], - 'error', + 'type' => 'error', ], 'trailing-comment-fixable' => [ - '/* testTrailingClosedCommentAsPtrA */', - [ + 'testMarker' => '/* testTrailingClosedCommentAsPtrA */', + 'expected' => [ 'found' => 'a new line', 'fixable' => true, ], - 'error', + 'type' => 'error', ], ]; } diff --git a/Tests/Internal/Cache/GetClearTest.php b/Tests/Internal/Cache/GetClearTest.php new file mode 100644 index 00000000..420394a1 --- /dev/null +++ b/Tests/Internal/Cache/GetClearTest.php @@ -0,0 +1,419 @@ + $dataset) { + Cache::set(self::$phpcsFile, 'Utility1', $id, $dataset['input']); + Cache::set(self::$phpcsFile, 'Utility2', $id, $dataset['input']); + } + } + + /** + * Clear the cache between tests and reset the base fixer loop. + * + * @after + * + * @return void + */ + protected function clearCacheAndFixer() + { + Cache::clear(); + self::$phpcsFile->fixer->enabled = false; + self::$phpcsFile->fixer->loops = 0; + } + + /** + * Reset the caching status. + * + * @afterClass + * + * @return void + */ + public static function resetCachingStatus() + { + Cache::$enabled = self::$origCacheEnabled; + } + + /** + * Test that a cache for a loop which has not been set is identified correctly as such. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseForUnavailableLoop() + { + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 3; + $this->assertFalse(Cache::isCached(self::$phpcsFile, 'Utility1', 'numeric string')); + } + + /** + * Test that a cache key which has not been set is identified correctly as such. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseForUnavailableKey() + { + $this->assertFalse(Cache::isCached(self::$phpcsFile, 'Utility3', 'numeric string')); + } + + /** + * Test that a cache id which has not been set is identified correctly as such. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseForUnavailableId() + { + $this->assertFalse(Cache::isCached(self::$phpcsFile, 'Utility1', 'this ID does not exist')); + } + + /** + * Test that disabling the cache will short-circuit cache checking. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseWhenCachingDisabled() + { + $wasEnabled = Cache::$enabled; + Cache::$enabled = false; + + $isCached = Cache::isCached(self::$phpcsFile, 'Utility1', 'numeric string'); + + Cache::$enabled = $wasEnabled; + + $this->assertFalse($isCached); + } + + /** + * Test that retrieving a cache key for a loop which has not been set, yields null. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullForUnavailableLoop() + { + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 2; + $this->assertNull(Cache::get(self::$phpcsFile, 'Utility1', 'numeric string')); + } + + /** + * Test that retrieving a cache key which has not been set, yields null. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullForUnavailableKey() + { + $this->assertNull(Cache::get(self::$phpcsFile, 'Utility3', 'numeric string')); + } + + /** + * Test that retrieving a cache id which has not been set, yields null. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullForUnavailableId() + { + $this->assertNull(Cache::get(self::$phpcsFile, 'Utility1', 'this ID does not exist')); + } + + /** + * Test that disabling the cache will short-circuit cache retrieval. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullWhenCachingDisabled() + { + $wasEnabled = Cache::$enabled; + Cache::$enabled = false; + + $retrieved = Cache::get(self::$phpcsFile, 'Utility1', 'numeric string'); + + Cache::$enabled = $wasEnabled; + + $this->assertNull($retrieved); + } + + /** + * Test that retrieving a cache set for a loop which has not been set, yields an empty array. + * + * @covers ::getForFile + * + * @return void + */ + public function testGetForFileWillReturnEmptyArrayForUnavailableLoop() + { + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 15; + $this->assertSame([], Cache::getForFile(self::$phpcsFile, 'Utility1')); + } + + /** + * Test that retrieving a cache set for a cache key which has not been set, yields an empty array. + * + * @covers ::getForFile + * + * @return void + */ + public function testGetForFileWillReturnEmptyArrayForUnavailableKey() + { + $this->assertSame([], Cache::getForFile(self::$phpcsFile, 'Utility3')); + } + + /** + * Test that disabling the cache will short-circuit cache for file retrieval. + * + * @covers ::getForFile + * + * @return void + */ + public function testGetForFileWillReturnEmptyArrayWhenCachingDisabled() + { + $wasEnabled = Cache::$enabled; + Cache::$enabled = false; + + $retrieved = Cache::getForFile(self::$phpcsFile, 'Utility1'); + + Cache::$enabled = $wasEnabled; + + $this->assertSame([], $retrieved); + } + + /** + * Test that previously cached data can be retrieved correctly. + * + * @dataProvider dataEveryTypeOfInput + * + * @covers ::get + * + * @param int|string $id The ID of the cached value to retrieve. + * @param mixed $expected The expected cached value. + * + * @return void + */ + public function testGetWillRetrievedPreviouslySetValue($id, $expected) + { + if (\is_object($expected)) { + $this->assertEquals($expected, Cache::get(self::$phpcsFile, 'Utility1', $id)); + } else { + $this->assertSame($expected, Cache::get(self::$phpcsFile, 'Utility1', $id)); + } + } + + /** + * Data provider. + * + * @return array + */ + public function dataEveryTypeOfInput() + { + $allTypes = TypeProviderHelper::getAll(); + $data = []; + foreach ($allTypes as $key => $dataset) { + $data[$key] = [ + 'id' => $key, + 'expected' => $dataset['input'], + ]; + } + + return $data; + } + + /** + * Test that the `getForFile()` method correctly retrieves a subset of the cached data. + * + * @covers ::getForFile + * + * @return void + */ + public function testGetForFile() + { + $dataSet1 = Cache::getForFile(self::$phpcsFile, 'Utility1'); + $dataSet2 = Cache::getForFile(self::$phpcsFile, 'Utility2'); + $this->assertSame($dataSet1, $dataSet2); + } + + /** + * Test that data cached during a previous loop will not be recognized once we're in a different loop. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillNotConfuseDataFromDifferentLoops() + { + $id = 50; + + // Set an initial cache value and verify it is available. + Cache::set(self::$phpcsFile, __METHOD__, $id, 'Test value'); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the originally cached value' + ); + + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 2; + + // Verify that the original cache is disregarded. + $this->assertFalse( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() still found the originally cached value' + ); + } + + /** + * Test that data cached during a previous loop will not be returned once we're in a different loop. + * + * @covers ::get + * + * @return void + */ + public function testGetWillNotConfuseDataFromDifferentLoops() + { + $id = 872; + + // Set an initial cache value and verify it is available. + Cache::set(self::$phpcsFile, __METHOD__, $id, 'Test value'); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the originally cached value' + ); + + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 4; + + // Verify that the original cache is disregarded. + $this->assertNull( + Cache::get(self::$phpcsFile, __METHOD__, $id), + 'Cache::get() still returned the originally cached value' + ); + } + + /** + * Test that data cached during a previous loop will not be returned once we're in a different loop. + * + * @covers ::getForFile + * + * @return void + */ + public function testGetForFileWillNotConfuseDataFromDifferentLoops() + { + $id = 233; + + // Set an initial cache value and verify it is available. + Cache::set(self::$phpcsFile, __METHOD__, $id, 'Test value'); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the originally cached value' + ); + + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 1; + + // Verify that the original cache is disregarded. + $this->assertSame( + [], + Cache::getForFile(self::$phpcsFile, __METHOD__), + 'Cache::getForFile() still returned the originally cached value' + ); + } + + /** + * Test that previously cached data is no longer available when the cache has been cleared. + * + * @dataProvider dataEveryTypeOfInput + * + * @covers ::clear + * + * @param int|string $id The ID of the cached value to retrieve. + * + * @return void + */ + public function testClearCache($id) + { + Cache::clear(); + + $this->assertFalse(Cache::isCached(self::$phpcsFile, 'Utility1', $id)); + $this->assertFalse(Cache::isCached(self::$phpcsFile, 'Utility2', $id)); + } +} diff --git a/Tests/Internal/Cache/SetTest.php b/Tests/Internal/Cache/SetTest.php new file mode 100644 index 00000000..b82e67ec --- /dev/null +++ b/Tests/Internal/Cache/SetTest.php @@ -0,0 +1,308 @@ +fixer->enabled = false; + self::$phpcsFile->fixer->loops = 0; + } + + /** + * Reset the caching status. + * + * @afterClass + * + * @return void + */ + public static function resetCachingStatus() + { + Cache::$enabled = self::$origCacheEnabled; + } + + /** + * Test that every data type is accepted as a cachable value, including `null`, that the + * `Cache::isCached()` function recognizes a set value correctly and that all values can be retrieved. + * + * @dataProvider dataEveryTypeOfInput + * + * @param mixed $input Value to cache. + * + * @return void + */ + public function testSetAcceptsEveryTypeOfInput($input) + { + $id = $this->getName(); + Cache::set(self::$phpcsFile, __METHOD__, $id, $input); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the cached value' + ); + + $this->assertSame( + $input, + Cache::get(self::$phpcsFile, __METHOD__, $id), + 'Value retrieved via Cache::get() did not match expectations' + ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataEveryTypeOfInput() + { + return TypeProviderHelper::getAll(); + } + + /** + * Verify that all supported types of IDs are accepted. + * + * Note: this doesn't test the unhappy path of passing an unsupported type of key, but + * non-int/string keys are not accepted by PHP for arrays anyway, so that should result + * in PHP warnings/errors anyway and as this is an internal class, I'm not too concerned + * about that kind of mistake being made. + * + * @dataProvider dataSetAcceptsIntAndStringIdKeys + * + * @param int|string $id ID for the cache. + * + * @return void + */ + public function testSetAcceptsIntAndStringIdKeys($id) + { + $value = 'value' . $id; + + Cache::set(self::$phpcsFile, __METHOD__, $id, $value); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the cached value' + ); + + $this->assertSame( + $value, + Cache::get(self::$phpcsFile, __METHOD__, $id), + 'Value retrieved via Cache::get() did not match expectations' + ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataSetAcceptsIntAndStringIdKeys() + { + return [ + 'ID: int zero' => [ + 'id' => 0, + ], + 'ID: positive int' => [ + 'id' => 12832, + ], + 'ID: negative int' => [ + 'id' => -274, + ], + 'ID: string' => [ + 'id' => 'string ID', + ], + ]; + } + + /** + * Verify that a previously set cached value will be overwritten when set() is called again + * with the same file, ID and key. + * + * @return void + */ + public function testSetWillOverwriteExistingValue() + { + $id = 'my key'; + $origValue = 'original value'; + + Cache::set(self::$phpcsFile, __METHOD__, $id, $origValue); + + // Verify that the original value was set correctly. + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the originally cached value' + ); + $this->assertSame( + $origValue, + Cache::get(self::$phpcsFile, __METHOD__, $id), + 'Original value retrieved via Cache::get() did not match expectations' + ); + + $newValue = 'new value'; + Cache::set(self::$phpcsFile, __METHOD__, $id, $newValue); + + // Verify the overwrite happened. + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() could not find the newly cached value' + ); + $this->assertSame( + $newValue, + Cache::get(self::$phpcsFile, __METHOD__, $id), + 'New value retrieved via Cache::get() did not match expectations' + ); + } + + /** + * Verify that disabling the cache will short-circuit caching (and not eat memory). + * + * @return void + */ + public function testSetWillNotSaveDataWhenCachingIsDisabled() + { + $id = 'id'; + $value = 'value'; + + $wasEnabled = Cache::$enabled; + Cache::$enabled = false; + + Cache::set(self::$phpcsFile, __METHOD__, $id, $value); + + Cache::$enabled = $wasEnabled; + + $this->assertFalse( + Cache::isCached(self::$phpcsFile, __METHOD__, $id), + 'Cache::isCached() found a cache which was set while caching was disabled' + ); + + $this->assertNull( + Cache::get(self::$phpcsFile, __METHOD__, $id), + 'Value retrieved via Cache::get() did not match expectations' + ); + } + + /** + * Test that previously cached data is no longer available if the fixer has moved on to the next loop. + * + * @return void + */ + public function testSetDoesNotClearCacheWhenFixerDisabled() + { + $idA = 50; + $idB = 52; + + // Set an initial cache value and verify it is available. + Cache::set(self::$phpcsFile, __METHOD__, $idA, 'Test value'); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $idA), + 'Cache::isCached() could not find the originally cached value' + ); + + // Changing loops without the fixer being available should have no effect. + self::$phpcsFile->fixer->loops = 5; + Cache::set(self::$phpcsFile, 'Another method', $idB, 'Test value'); + + // Verify the original cache is still available. + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $idA), + 'Cache::isCached() could not find the originally cached value' + ); + // ... as well as the newly cached value + $this->assertTrue( + Cache::isCached(self::$phpcsFile, 'Another method', $idB), + 'Cache::isCached() could not find the newly cached value' + ); + } + + /** + * Test that previously cached data is no longer available if the fixer has moved on to the next loop. + * + * @return void + */ + public function testSetClearsCacheOnDifferentLoop() + { + $idA = 123; + $idB = 276; + + // Set an initial cache value and verify it is available. + Cache::set(self::$phpcsFile, __METHOD__, $idA, 'Test value'); + + $this->assertTrue( + Cache::isCached(self::$phpcsFile, __METHOD__, $idA), + 'Cache::isCached() could not find the originally cached value' + ); + + // Set a different cache on a different loop, which should clear the original cache. + self::$phpcsFile->fixer->enabled = true; + self::$phpcsFile->fixer->loops = 5; + Cache::set(self::$phpcsFile, 'Another method', $idB, 'Test value'); + + // Verify the original cache is no longer available. + $this->assertFalse( + Cache::isCached(self::$phpcsFile, __METHOD__, $idA), + 'Cache::isCached() still found the originally cached value' + ); + } +} diff --git a/Tests/Internal/IsShortArrayOrList/ConstructorTest.inc b/Tests/Internal/IsShortArrayOrList/ConstructorTest.inc new file mode 100644 index 00000000..01bca02d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/ConstructorTest.inc @@ -0,0 +1,20 @@ +expectPhpcsException( + 'The IsShortArrayOrList class expects to be passed a T_OPEN_SHORT_ARRAY or T_OPEN_SQUARE_BRACKET token.' + ); + + new IsShortArrayOrList(self::$phpcsFile, 100000); + } + + /** + * Test receiving an exception when a non-bracket token is passed. + * + * @dataProvider dataNotOpenBracket + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testNotOpenBracket($testMarker, $targetType) + { + $this->expectPhpcsException( + 'The IsShortArrayOrList class expects to be passed a T_OPEN_SHORT_ARRAY or T_OPEN_SQUARE_BRACKET token.' + ); + + $target = $this->getTargetToken($testMarker, $targetType); + new IsShortArrayOrList(self::$phpcsFile, $target); + } + + /** + * Data provider. + * + * @see testNotBracket() For the array format. + * + * @return array + */ + public function dataNotOpenBracket() + { + return [ + 'long-array' => [ + 'testMarker' => '/* testLongArray */', + 'targetType' => \T_ARRAY, + ], + 'long-list' => [ + 'testMarker' => '/* testLongList */', + 'targetType' => \T_LIST, + ], + 'short-array-close-bracket' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => \T_CLOSE_SHORT_ARRAY, + ], + 'short-list-close-bracket' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => \T_CLOSE_SHORT_ARRAY, + ], + 'square-brackets-close-bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => \T_CLOSE_SQUARE_BRACKET, + ], + ]; + } + + /** + * Test the constructor accepts all supported token types which are allowed to be passed to it. + * + * @dataProvider dataSupportedBrackets + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testSupportedBrackets($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $solver = new IsShortArrayOrList(self::$phpcsFile, $target); + + $this->assertInstanceof('\PHPCSUtils\Internal\IsShortArrayOrList', $solver); + } + + /** + * Data provider. + * + * @see testSupportedBrackets() For the array format. + * + * @return array + */ + public function dataSupportedBrackets() + { + return [ + 'short-array-open-bracket' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + ], + 'short-list-open-bracket' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + ], + 'square-brackets-open-bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => \T_OPEN_SQUARE_BRACKET, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsInForeachTest.inc b/Tests/Internal/IsShortArrayOrList/IsInForeachTest.inc new file mode 100644 index 00000000..e8c5a71d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsInForeachTest.inc @@ -0,0 +1,62 @@ + [$id, $name, $info]) {} + +/* testShortListInForeachWithListKeys */ +foreach ($data as ["id" => $id, "name" => $name]) {} + +/* testShortlistInForeachWithReference */ +foreach ($array as [&$a, $b]) {} + + +/* ===== Tests involving brackets within a foreach condition INDIRECTLY handled by isInForeach(). ===== */ +// Handled by the function for the outer set of brackets via walkOutside(). + +foreach ([/* testShortArrayInForeachNestedAtStart */ [$b, $c], $d] as $k => $v) {} +foreach ([$a, /* testShortArrayInForeachNestedInMiddle */ [$b, $c], $d] as $k => $v) {} +foreach ([$a, /* testShortArrayInForeachNestedAtEnd */ [$b, $c]] as $k => $v) {} + +foreach ([$a, /* testShortArrayEmptyInForeachNestedInMiddle */ 'a' => [], $d] as $k => $v) {} + +foreach ($array as [/* testShortListInForeachNestedAtStart */ [$b, $c], $d]) {} +foreach ($array as [$a, /* testShortListInForeachNestedInMiddle */ [$b, $c], $d]) {} +foreach ($array as [$a, /* testShortListInForeachNestedAtEnd */ [$b, $c]]) {} + + +/* ===== Tests involving brackets within a foreach condition NOT handled by isInForeach(). ===== */ + +foreach ($array as $key => $value[$this->get_key(/* testShortArrayInFunctionCallInForeach */ [$b])]) {} + +foreach ($array as [/* testShortArrayAsKeyInShortList1 */[1,2,3][$a] => $b, /* testShortArrayAsKeyInShortList2 */ [$d, $e][$a] => $c]) {} + +foreach([$a, $b, /* testShortListNestedInShortArrayInForeach */ [$d, $g, /* testNestedShortListNestedInShortArrayInForeach */ [$h]] = $array] as $c) {} + +/* testShortArrayAsKeyAfterAs */ +// Fatal error. Cannot use temporary expression in write context. +foreach ($array as [1,2,3][$a] => [$b, $c]) {} + +/* testParseError */ +// Parse error: missing close square bracket. +foreach ($array as [$a => [$b, $c], $d) {} + +/* testForeachWithoutAs */ +// Parse error. +foreach([1,2,3]) {} diff --git a/Tests/Internal/IsShortArrayOrList/IsInForeachTest.php b/Tests/Internal/IsShortArrayOrList/IsInForeachTest.php new file mode 100644 index 00000000..d28e9117 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsInForeachTest.php @@ -0,0 +1,204 @@ +getTargetToken('/* testNotInForeach */', \T_OPEN_SHORT_ARRAY); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame(IsShortArrayOrList::SHORT_ARRAY, $type); + } + + /** + * Test that brackets inside foreach conditions are recognized correctly as short array/short lists. + * + * @dataProvider dataIsInForeachResolved + * @dataProvider dataIsInForeachNestedResolvedViaOuter + * @dataProvider dataIsInForeachUndetermined + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected The expected function output. + * + * @return void + */ + public function testIsInForeach($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY]); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider 1. + * + * These test cases should get resolved DIRECTLY via the `isInForeach()` method. + * + * @see testIsInForeach() For the array format. + * + * @return array + */ + public function dataIsInForeachResolved() + { + return [ + 'resolved: short array in foreach' => [ + 'testMarker' => '/* testShortArrayInForeach */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'resolved: short array in foreach with nested shortlist' => [ + 'testMarker' => '/* testShortArrayInForeachWithNestedShortList */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'resolved: short array in foreach with assignment' => [ + 'testMarker' => '/* testShortArrayInForeachWithAssignment */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'resolved: short list in foreach' => [ + 'testMarker' => '/* testShortListInForeach */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'resolved: short list in foreach with key' => [ + 'testMarker' => '/* testShortListInForeachWithKey */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'resolved: short list in foreach with list keys' => [ + 'testMarker' => '/* testShortListInForeachWithListKeys */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'resolved: short list in foreach with reference' => [ + 'testMarker' => '/* testShortlistInForeachWithReference */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } + + /** + * Data provider 2. + * + * These test cases should get resolved INDIRECTLY once the `isInForeach()` method + * is called for the OUTER set of brackets. + * + * @see testIsInForeach() For the array format. + * + * @return array + */ + public function dataIsInForeachNestedResolvedViaOuter() + { + return [ + 'resolved-on-outer: short array in foreach nested at start' => [ + 'testMarker' => '/* testShortArrayInForeachNestedAtStart */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'resolved-on-outer: short array in foreach nested in middle' => [ + 'testMarker' => '/* testShortArrayInForeachNestedInMiddle */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'resolved-on-outer: short array in foreach nested at end' => [ + 'testMarker' => '/* testShortArrayInForeachNestedAtEnd */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'resolved-on-outer: short array empty in foreach nested in middle' => [ + 'testMarker' => '/* testShortArrayEmptyInForeachNestedInMiddle */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'resolved-on-outer: short list in foreach nested at start' => [ + 'testMarker' => '/* testShortListInForeachNestedAtStart */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'resolved-on-outer: short list in foreach nested in middle' => [ + 'testMarker' => '/* testShortListInForeachNestedInMiddle */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'resolved-on-outer: short list in foreach nested at end' => [ + 'testMarker' => '/* testShortListInForeachNestedAtEnd */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } + + /** + * Data provider 3. + * + * These are test cases, which do involve a `foreach`, but will not get resolved via the `isInForeach()` method. + * + * @see testIsInForeach() For the array format. + * + * @return array + */ + public function dataIsInForeachUndetermined() + { + return [ + 'undetermined: short array in function call in foreach' => [ + 'testMarker' => '/* testShortArrayInFunctionCallInForeach */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'undetermined: short array in foreach as key in shortlist 1' => [ + 'testMarker' => '/* testShortArrayAsKeyInShortList1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'undetermined: short array in foreach as key in shortlist 2' => [ + 'testMarker' => '/* testShortArrayAsKeyInShortList2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'undetermined: short list nested in short array in foreach' => [ + 'testMarker' => '/* testShortListNestedInShortArrayInForeach */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'undetermined: nested short list nested in short array in foreach' => [ + 'testMarker' => '/* testNestedShortListNestedInShortArrayInForeach */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + 'undetermined: short array in foreach as key after as' => [ + 'testMarker' => '/* testShortArrayAsKeyAfterAs */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'undetermined: parse error missing bracket' => [ + 'testMarker' => '/* testParseError */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'undetermined: parse error foreach without as' => [ + 'testMarker' => '/* testForeachWithoutAs */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } +} diff --git a/Tests/Utils/Lists/IsShortListTokenizerBC1Test.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC1Test.inc similarity index 64% rename from Tests/Utils/Lists/IsShortListTokenizerBC1Test.inc rename to Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC1Test.inc index 2f8a7dbe..c8174700 100644 --- a/Tests/Utils/Lists/IsShortListTokenizerBC1Test.inc +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC1Test.inc @@ -29,3 +29,21 @@ $foo = ${$bar}['key']; /* testTokenizerIssue1284PHPCSlt280D */ $c->{$var}[ ] = 2; + +/* testTokenizerIssue3013PHPCSlt356 */ +$var = __FILE__[0]; + +/* testTokenizerIssuePHPCS28xA */ +__NAMESPACE__[] = 'x'; + +/* testTokenizerIssuePHPCS28xB */ +__method__[0]/* testTokenizerIssuePHPCS28xC */[1]/* testTokenizerIssuePHPCS28xD */[2] *= 'x'; + +/* testTokenizerIssue3172PHPCSlt360A */ +$var = "PHP{$rocks}"[1]/* testTokenizerIssue3172PHPCSlt360B */[0]; + +if ( true ) + /* testTokenizerIssue3632PHPCSlt372 */ + [ $a ] = [ 'hi' ]; + +return $a ?? ''; diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC1Test.php b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC1Test.php new file mode 100644 index 00000000..0eec5c4d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC1Test.php @@ -0,0 +1,140 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayBracket() For the array format. + * + * @return array + */ + public function dataIsShortArrayBracket() + { + return [ + 'issue-1971-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271A */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'issue-1971-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271B */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'issue-1381-array-dereferencing-1-array' => [ + 'testMarker' => '/* testTokenizerIssue1381PHPCSlt290A1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'issue-1381-array-dereferencing-1-deref' => [ + 'testMarker' => '/* testTokenizerIssue1381PHPCSlt290A2 */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-1381-array-dereferencing-2' => [ + 'testMarker' => '/* testTokenizerIssue1381PHPCSlt290B */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-1381-array-dereferencing-3' => [ + 'testMarker' => '/* testTokenizerIssue1381PHPCSlt290C */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-1381-array-dereferencing-4' => [ + 'testMarker' => '/* testTokenizerIssue1381PHPCSlt290D1 */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-1381-array-dereferencing-4-deref-deref' => [ + 'testMarker' => '/* testTokenizerIssue1381PHPCSlt290D2 */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280B */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'issue-1284-array-access-variable-variable' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt290C */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-1284-array-access-variable-property' => [ + 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280D */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-3013-magic-constant-dereferencing' => [ + 'testMarker' => '/* testTokenizerIssue3013PHPCSlt356 */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-more-magic-constant-dereferencing-1' => [ + 'testMarker' => '/* testTokenizerIssuePHPCS28xA */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-nested-magic-constant-dereferencing-2' => [ + 'testMarker' => '/* testTokenizerIssuePHPCS28xB */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-nested-magic-constant-dereferencing-3' => [ + 'testMarker' => '/* testTokenizerIssuePHPCS28xC */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-nested-magic-constant-dereferencing-4' => [ + 'testMarker' => '/* testTokenizerIssuePHPCS28xD */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-interpolated-string-dereferencing' => [ + 'testMarker' => '/* testTokenizerIssue3172PHPCSlt360A */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-interpolated-string-dereferencing-nested' => [ + 'testMarker' => '/* testTokenizerIssue3172PHPCSlt360B */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'issue-3632-short-list-in-non-braced-control-structure' => [ + 'testMarker' => '/* testTokenizerIssue3632PHPCSlt372 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } +} diff --git a/Tests/Utils/Lists/IsShortListTokenizerBC2Test.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC2Test.inc similarity index 67% rename from Tests/Utils/Lists/IsShortListTokenizerBC2Test.inc rename to Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC2Test.inc index 56db4b44..059f736e 100644 --- a/Tests/Utils/Lists/IsShortListTokenizerBC2Test.inc +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC2Test.inc @@ -2,4 +2,4 @@ /* testTokenizerIssue1971PHPCSlt330gt271C */ // Valid PHP, though not useful. Declaring an array without assigning it to anything. -[1, 2, /* testTokenizerIssue1971PHPCSlt330gt271D */ [3]]; +[$a, $b, /* testTokenizerIssue1971PHPCSlt330gt271D */ [$c], $d]; diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC2Test.php b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC2Test.php new file mode 100644 index 00000000..39c0348d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC2Test.php @@ -0,0 +1,69 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayBracket() For the array format. + * + * @return array + */ + public function dataIsShortArrayBracket() + { + return [ + // Make sure the utility method does not throw false positives for a short array at the start of a file. + 'issue-1971-short-array-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271C */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'issue-1971-short-array-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271D */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC3Test.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC3Test.inc new file mode 100644 index 00000000..a95f3a43 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC3Test.inc @@ -0,0 +1,5 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayBracket() For the array format. + * + * @return array + */ + public function dataIsShortArrayBracket() + { + return [ + 'issue-1971-short-array-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271E */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'issue-1971-short-array-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271F */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC4Test.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC4Test.inc new file mode 100644 index 00000000..8a0c82c6 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC4Test.inc @@ -0,0 +1,5 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayBracket() For the array format. + * + * @return array + */ + public function dataIsShortArrayBracket() + { + return [ + 'issue-1971-short-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271G */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'issue-1971-short-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271H */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC5Test.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC5Test.inc new file mode 100644 index 00000000..40b15dea --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC5Test.inc @@ -0,0 +1,4 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayBracket() For the array format. + * + * @return array + */ + public function dataIsShortArrayBracket() + { + return [ + 'issue-1971-short-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271I */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'issue-1971-short-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271J */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC6Test.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC6Test.inc new file mode 100644 index 00000000..afc27cd2 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayBracketBC6Test.inc @@ -0,0 +1,4 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayBracket() For the array format. + * + * @return array + */ + public function dataIsShortArrayBracket() + { + return [ + 'issue-1971-short-list-first-in-file' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271K */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'issue-1971-short-list-first-in-file-nested' => [ + 'testMarker' => '/* testTokenizerIssue1971PHPCSlt330gt271L */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayOrListTest.inc b/Tests/Internal/IsShortArrayOrList/IsShortArrayOrListTest.inc new file mode 100644 index 00000000..d6198ac9 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayOrListTest.inc @@ -0,0 +1,211 @@ + /* testShortArrayNotEqualBracketsSecond */ [3, 4]) {} + +/* testShortArrayNonIdenticalFirst */ +if([1, 2] !== /* testShortArrayNonIdenticalSecond */ [3, 4]) {} + +/* testShortListMultiItem */ +[$a, $b] = $c; + +/* testShortListWithKeys */ +["id" => $id1, "name" => $name1] = $data[0]; + +/* testShortListWithNesting */ +[$a, /* testShortListNested */ [$b]] = array(new stdclass, array(new stdclass)); + +/* testShortlistMultiAssign */ +$foo = [$baz, $bat] = /* testShortArrayMultiAssign */ [$a, $b] + [$c, $d]; + +/* testShortArrayWithNestingAndKeys */ +$array = [ + /* testNestedShortArrayWithKeys_1 */ + ["x" => $x1, "y" => $y1], + /* testNestedShortArrayWithKeys_2 */ + 1 => ["x" => $x2, "y" => $y2], + /* testNestedShortArrayWithKeys_3 */ + 'key' => ["x" => $x3, "y" => $y3], + /* testNestedShortArrayPHP74UnpackingWithoutKeys */ + ...[$x3, $y3], + /* testNestedShortArrayPHP81UnpackingWithKeys */ + ...["x" => $x3, "y" => $y3], +]; + +/* testShortListWithNestingAndKeys */ +[ + /* testNestedShortListWithKeys_1 */ + ["x" => $x1, "y" => $y1], + /* testNestedShortListWithKeys_2 */ + ["x" => $x2, "y" => $y2], + /* testNestedShortListWithKeys_3 */ + ["x" => $x3, "y" => $y3], +] = $points; + +[$x, [ $y, /* testDeeplyNestedShortList */ [$z]], $q] = $a; + +if ( true ) { + /* testShortListInBracedControlStructure */ + [ $a ] = [ 'hi' ]; +} + +if ( true ) : + /* testShortListInAlternativeControlStructure */ + [ $a ] = [ 'hi' ]; +endif; + +return $a ?? ''; + +/* testShortListWithShortArrayAsKey */ +[/* testShortArrayAsKeyForShortList */[1,2,3][$a] => /* testShortListWithShortArrayAsKeyNested */ [$a, $b]] = $array; + +/* testShortListWithShortArrayInKey */ +// Please sack anyone who writes code like this. +[ + /* testShortArrayInKeyForShortListA */ + (function($a = [1,2,3]) { + return $a[$b]; + })(/* testShortArrayInKeyForShortListB */[1,2,3]) => /* testShortListWithShortArrayInKeyNested */ [$a, $b] +] = $array; + +[/* testNestedShortListWithEmpties */[,,$a]] = $array; + +$array = [ + 'key1' => function($a, $b) { + /* testShortListInClosureInShortArrayValue */ + ['a' => $a, $key['b'] => /* testNestedShortListInClosureInShortArrayValue */ [$b]] = + /* testShortArrayInClosureInShortArrayValue */ + [$a, /* testNestedShortArrayInClosureInShortArrayValue */ [$b]]; + return $a; + }, + /* testShortArrayInFunctionCallInShortArrayValue */ + 'key2' => function_call([$a, $b]), + /* testPlainShortListInShortArrayValue */ + 'key3' => [$a, $b] = $foo, + /* testPlainShortListInShortArrayValueNoKey */ + [$a, $b] = $foo, + /* testKeyedShortListInShortArrayValue1 */ + 'key4' => [ /* testShortArrayInShortListAsKey */['a', 'b'] [0] => $a] = $foo, + /* testKeyedShortListInShortArrayValue2 */ + 'key5' => [ get_key( /* testShortArrayInFunctionCallInShortListKey */ ['a', 'b']) => $a] = $foo, + 'key6' => [ $a, /* testEmptyShortListInShortListInShortArrayValue */ [], $b ] = $foo, +]; + +$keys[ /* testOuterShortArrayStopAtBrackets */ [$a, $b, $c]['index'] ] = 'value'; + +$array = [ + $keys[ /* testShortArrayInShortArrayKeyStopAtBrackets */ [$a, $b, $c]['index'] ] => 'value', +]; + +[ + $keys[ /* testShortArrayInShortListKeyStopAtBrackets */ [$a, $b, $c]['index'] ] => $a, +] = $array; + +/* testRiskySyntaxCombiButNonNested-FunctionCall */ +$var = function_call($arg, [$arg], $arg); + +/* testRiskySyntaxCombiButNonNested-ClosureCall */ +$var = $closure($arg, [$arg], $arg); + +/* testRiskySyntaxCombiButNonNested-FnCall */ +$var = $fn($arg, [$arg], $arg); + +/* testRiskySyntaxCombiButNonNested-Echo */ +echo $arg, [$arg], $arg; + +$array = [ + /* testShortArrayInShortArrowFunction */ + 'key' => fn($p) : array => [$p], + + // Prevent going straight to outer brackets for last item. + 'skip' => [$b], +]; + +$match = match($foo) { + /* testShortArrayConditionInMatchExpression */ + [$bar] => 10, + default => 20, +}; + +$match = match($foo) { + [$bar, /* testNestedShortArrayConditionInMatchExpression */ [$baz], $bal] => 10, + default => 20, +}; + +$match = match($foo) { + /* testShortArrayReturnedFromMatchExpression */ + 10 => [$bar], + default => 20, +}; + +$match = match($foo) { + 10 => [$bar, /* testNestedShortArrayReturnedFromMatchExpression */ [$baz], $bal], + default => 20, +}; + +$match = match($foo) { + /* testShortListConditionInMatchExpression */ + [$bar] = $array => 10, + default => 20, +}; + +$match = match($foo) { + [$bar, /* testNestedShortListConditionInMatchExpression */ [$baz], $bal] = $array => 10, + default => 20, +}; + +$match = match($foo) { + /* testShortListReturnedFromMatchExpression */ + 10 => [$bar] = $array, + default => 20, +}; + +$match = match($foo) { + 10 => [$bar, /* testNestedShortListReturnedFromMatchExpression */ [$baz], $bal] = $array, + default => 20, +}; + + +/* ===== Tests involving various illegal syntaxes/parse errors. ===== */ + +// Invalid as empty lists are not allowed, but it is short list syntax. +[$x, /* testNestedShortListEmpty */ [], $y] = $a; + +/* testShortListWithoutVars */ +// Invalid list as it doesn't contain variables, but it is short list syntax. +[42] = [1]; + +/* testShortListNestedLongList */ +// Invalid list as mixing short list syntax with list() is not allowed, but it is short list syntax. +[list($a, $b), list($c, $d)] = [[1, 2], [3, 4]]; + +/* testNestedAnonClassWithTraitUseAs */ +// Parse error, but not our concern, it is short array syntax. +array_map(function($a) { + return new class() { + use MyTrait { + MyTrait::functionName as []; + } + }; +}, $array); + +/* testParseError */ +// Parse error, but not our concern, it is short array syntax. +use Something as [$a]; diff --git a/Tests/Internal/IsShortArrayOrList/IsShortArrayOrListTest.php b/Tests/Internal/IsShortArrayOrList/IsShortArrayOrListTest.php new file mode 100644 index 00000000..e12cc60d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsShortArrayOrListTest.php @@ -0,0 +1,365 @@ +getTargetToken($testMarker, \T_OPEN_SHORT_ARRAY); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testIsShortArrayOrList() For the array format. + * + * @return array + */ + public function dataIsShortArrayOrList() + { + return [ + 'short-array-comparison-no-assignment' => [ + 'testMarker' => '/* testShortArrayInComparison */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-comparison-no-assignment-nested' => [ + 'testMarker' => '/* testShortArrayNestedInComparison */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-union-before' => [ + 'testMarker' => '/* testShortArrayUnionFirst */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-union-after' => [ + 'testMarker' => '/* testShortArrayUnionSecond */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-equal-before' => [ + 'testMarker' => '/* testShortArrayEqualFirst */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-equal-after' => [ + 'testMarker' => '/* testShortArrayEqualSecond */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-identical-before' => [ + 'testMarker' => '/* testShortArrayIdenticalFirst */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-identical-after' => [ + 'testMarker' => '/* testShortArrayIdenticalSecond */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-not-equal-before' => [ + 'testMarker' => '/* testShortArrayNotEqualFirst */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-not-equal-after' => [ + 'testMarker' => '/* testShortArrayNotEqualSecond */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-not-equal-brackets-before' => [ + 'testMarker' => '/* testShortArrayNotEqualBracketsFirst */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-not-equal-brackets-after' => [ + 'testMarker' => '/* testShortArrayNotEqualBracketsSecond */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-not-identical-before' => [ + 'testMarker' => '/* testShortArrayNonIdenticalFirst */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-not-identical-after' => [ + 'testMarker' => '/* testShortArrayNonIdenticalSecond */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-multi-item' => [ + 'testMarker' => '/* testShortListMultiItem */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-with-keys' => [ + 'testMarker' => '/* testShortListWithKeys */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-with-nesting' => [ + 'testMarker' => '/* testShortListWithNesting */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested' => [ + 'testMarker' => '/* testShortListNested */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-in-chained-assignment' => [ + 'testMarker' => '/* testShortlistMultiAssign */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-array-in-chained-assignment' => [ + 'testMarker' => '/* testShortArrayMultiAssign */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-with-nesting-and-keys' => [ + 'testMarker' => '/* testShortArrayWithNestingAndKeys */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-with-keys-1' => [ + 'testMarker' => '/* testNestedShortArrayWithKeys_1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-with-keys-2' => [ + 'testMarker' => '/* testNestedShortArrayWithKeys_2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-with-keys-3' => [ + 'testMarker' => '/* testNestedShortArrayWithKeys_3 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-unpacking-without-keys-php74' => [ + 'testMarker' => '/* testNestedShortArrayPHP74UnpackingWithoutKeys */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-unpacking-with-keys-php81' => [ + 'testMarker' => '/* testNestedShortArrayPHP81UnpackingWithKeys */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-with-nesting-and-keys' => [ + 'testMarker' => '/* testShortListWithNestingAndKeys */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-with-keys-1' => [ + 'testMarker' => '/* testNestedShortListWithKeys_1 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-with-keys-2' => [ + 'testMarker' => '/* testNestedShortListWithKeys_2 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-with-keys-3' => [ + 'testMarker' => '/* testNestedShortListWithKeys_3 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-deeply-nested' => [ + 'testMarker' => '/* testDeeplyNestedShortList */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-in-braced-control-structure' => [ + 'testMarker' => '/* testShortListInBracedControlStructure */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-in-alternative-control-structure' => [ + 'testMarker' => '/* testShortListInAlternativeControlStructure */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-containing-short-array-as-key' => [ + 'testMarker' => '/* testShortListWithShortArrayAsKey */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-array-as-key-for-nested-short-list' => [ + 'testMarker' => '/* testShortArrayAsKeyForShortList */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-nested-with-array-key' => [ + 'testMarker' => '/* testShortListWithShortArrayAsKeyNested */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-containing-short-array-in-key' => [ + 'testMarker' => '/* testShortListWithShortArrayInKey */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-array-in-key-for-short-list-closure-default' => [ + 'testMarker' => '/* testShortArrayInKeyForShortListA */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-in-key-for-short-list-closure-call-param' => [ + 'testMarker' => '/* testShortArrayInKeyForShortListB */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-nested-with-array-in-key' => [ + 'testMarker' => '/* testShortListWithShortArrayInKeyNested */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-with-empties' => [ + 'testMarker' => '/* testNestedShortListWithEmpties */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + 'short-list-in-closure-in-short-array-value' => [ + 'testMarker' => '/* testShortListInClosureInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-in-closure-in-short-array-value' => [ + 'testMarker' => '/* testNestedShortListInClosureInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-array-in-closure-in-short-array-value' => [ + 'testMarker' => '/* testShortArrayInClosureInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-in-closure-in-short-array-value' => [ + 'testMarker' => '/* testNestedShortArrayInClosureInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-in-function-call-in-short-array-value' => [ + 'testMarker' => '/* testShortArrayInFunctionCallInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-in-short-array-value' => [ + 'testMarker' => '/* testPlainShortListInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-in-short-array-value-no-key' => [ + 'testMarker' => '/* testPlainShortListInShortArrayValueNoKey */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-keyed-in-short-array-value-1' => [ + 'testMarker' => '/* testKeyedShortListInShortArrayValue1 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-array-as-key-for-short-list-in-array-value' => [ + 'testMarker' => '/* testShortArrayInShortListAsKey */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-keyed-in-short-array-value-2' => [ + 'testMarker' => '/* testKeyedShortListInShortArrayValue2 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-array-in-function-call-as-key-for-short-list-in-array-value' => [ + 'testMarker' => '/* testShortArrayInFunctionCallInShortListKey */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-nested-and-empty-in-short-array-value' => [ + 'testMarker' => '/* testEmptyShortListInShortListInShortArrayValue */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + 'outer-short-array-stop-test-square-open' => [ + 'testMarker' => '/* testOuterShortArrayStopAtBrackets */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-square-open-1' => [ + 'testMarker' => '/* testShortArrayInShortArrayKeyStopAtBrackets */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-square-open-2' => [ + 'testMarker' => '/* testShortArrayInShortListKeyStopAtBrackets */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'short-array-comma-before-after-in-function-call' => [ + 'testMarker' => '/* testRiskySyntaxCombiButNonNested-FunctionCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-comma-before-after-in-closure-call' => [ + 'testMarker' => '/* testRiskySyntaxCombiButNonNested-ClosureCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-comma-before-after-in-fn-call' => [ + 'testMarker' => '/* testRiskySyntaxCombiButNonNested-FnCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-comma-before-after-in-echo-statement' => [ + 'testMarker' => '/* testRiskySyntaxCombiButNonNested-Echo */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'short-array-in-arrow-fn-return-expression' => [ + 'testMarker' => '/* testShortArrayInShortArrowFunction */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'short-array-in-match-condition' => [ + 'testMarker' => '/* testShortArrayConditionInMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-in-match-condition' => [ + 'testMarker' => '/* testNestedShortArrayConditionInMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-in-match-return-expression' => [ + 'testMarker' => '/* testShortArrayReturnedFromMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-array-nested-in-match-return-expression' => [ + 'testMarker' => '/* testNestedShortArrayReturnedFromMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short-list-in-match-condition' => [ + 'testMarker' => '/* testShortListConditionInMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-in-match-condition' => [ + 'testMarker' => '/* testNestedShortListConditionInMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-in-match-return-expression' => [ + 'testMarker' => '/* testShortListReturnedFromMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-in-match-return-expression' => [ + 'testMarker' => '/* testNestedShortListReturnedFromMatchExpression */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + // Invalid syntaxes. + 'short-list-nested-empty' => [ + 'testMarker' => '/* testNestedShortListEmpty */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-without-vars' => [ + 'testMarker' => '/* testShortListWithoutVars */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short-list-nested-long-list' => [ + 'testMarker' => '/* testShortListNestedLongList */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'parse-error-anon-class-trait-use-as' => [ + 'testMarker' => '/* testNestedAnonClassWithTraitUseAs */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'parse-error-use-as' => [ + 'testMarker' => '/* testParseError */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/IsSquareBracketTest.inc b/Tests/Internal/IsShortArrayOrList/IsSquareBracketTest.inc new file mode 100644 index 00000000..59a6208b --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsSquareBracketTest.inc @@ -0,0 +1,53 @@ +function_call()[$x]; + +$array = [ + 'key1' => function($a, $b) { + ['a' => $a, /* testArrayAccessForShortListKey */ $key['b'] => [$b]] = [$a, [$b]]; + return $a; + }, + 'key2' => [/* testListAssignmentToArrayStringKey */ $a['key'], /* testListAssignmentToArrayEmptyKey */ $a[], $c] = [$a, [$b]]; + return $a; + }, + 'key3' => [ ['a', 'b'] /* testArrayDerefOfShortArrayInShortListAsKey */[0] => $a] = $foo, +]; + +/* testLiveCoding */ +// Intentional parse error. This has to be the last test in the file. +[$a, diff --git a/Tests/Internal/IsShortArrayOrList/IsSquareBracketTest.php b/Tests/Internal/IsShortArrayOrList/IsSquareBracketTest.php new file mode 100644 index 00000000..cd10578d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/IsSquareBracketTest.php @@ -0,0 +1,120 @@ +getTargetToken('/* testShortArray */', \T_OPEN_SHORT_ARRAY); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertNotSame(IsShortArrayOrList::SQUARE_BRACKETS, $type); + } + + /** + * Test that real square brackets are recognized as such. + * + * @dataProvider dataSquareBrackets + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @return void + */ + public function testSquareBrackets($testMarker) + { + $stackPtr = $this->getTargetToken($testMarker, \T_OPEN_SQUARE_BRACKET); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr); + $type = $solver->solve(); + + $this->assertSame(IsShortArrayOrList::SQUARE_BRACKETS, $type); + } + + /** + * Data provider. + * + * @see testSquareBrackets() For the array format. + * + * @return array + */ + public function dataSquareBrackets() + { + return [ + 'array-assignment-no-key' => [ + 'testMarker' => '/* testArrayAssignmentEmpty */', + ], + 'array-assignment-string-key' => [ + 'testMarker' => '/* testArrayAssignmentStringKey */', + ], + 'array-assignment-int-key' => [ + 'testMarker' => '/* testArrayAssignmentIntKey */', + ], + 'array-assignment-var-key' => [ + 'testMarker' => '/* testArrayAssignmentVarKey */', + ], + 'array-access-string-key' => [ + 'testMarker' => '/* testArrayAccessStringKey */', + ], + 'array-access-int-key-1' => [ + 'testMarker' => '/* testArrayAccessIntKey1 */', + ], + 'array-access-int-key-2' => [ + 'testMarker' => '/* testArrayAccessIntKey2 */', + ], + 'array-access-function-call' => [ + 'testMarker' => '/* testArrayAccessFunctionCall */', + ], + 'array-access-constant' => [ + 'testMarker' => '/* testArrayAccessConstant */', + ], + 'array-access-magic-constant' => [ + 'testMarker' => '/* testArrayAccessMagicConstant */', + ], + 'array-access-nullsafe-method-call' => [ + 'testMarker' => '/* testNullsafeMethodCallDereferencing */', + ], + 'array-access-for-short-list-key' => [ + 'testMarker' => '/* testArrayAccessForShortListKey */', + ], + 'list-assignment-to-array-with-string-key' => [ + 'testMarker' => '/* testListAssignmentToArrayStringKey */', + ], + 'list-assignment-to-array-without-key' => [ + 'testMarker' => '/* testListAssignmentToArrayEmptyKey */', + ], + 'array-access-for-short-list-key-with-hardcoded-array' => [ + 'testMarker' => '/* testArrayDerefOfShortArrayInShortListAsKey */', + ], + + 'live-coding' => [ + 'testMarker' => '/* testLiveCoding */', + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/SolveTest.inc b/Tests/Internal/IsShortArrayOrList/SolveTest.inc new file mode 100644 index 00000000..29157588 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/SolveTest.inc @@ -0,0 +1,57 @@ + $something; + +/* testShortArrayInForeach */ +foreach ([1, 2, 3] as /* testShortListInForeach */ [$id, $name, $info]) {} + +/* testShortArray */ +$array = [$a]; + +$array = [/* testNestedShortArrayParentBracketBefore */[$b], [$a]]; +[$a, /* testNestedShortListParentBracketAfter */ [$a, $b]] = $array; +[$a, /* testNestedShortListParentBracketAfterWithTrailingComma */ [$a, $b],] = $array; + +$array = [ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortArrayContentNonAmbiguous */ + [ 1, 2, ], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +]; + +[ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortListContentNonAmbiguous */ + [$a,, $b], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +] = $array; + +/* testOuterShortArray */ +echo 'previous-semicolon'; +echo $arg, [$arg], $arg; + + +/* ===== Tests involving various illegal syntaxes/parse errors. ===== */ + +// Intentional parse error. This has to be the last test in the file. +[$a, /* testLiveCodingNested */ [$b] diff --git a/Tests/Internal/IsShortArrayOrList/SolveTest.php b/Tests/Internal/IsShortArrayOrList/SolveTest.php new file mode 100644 index 00000000..ec188307 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/SolveTest.php @@ -0,0 +1,110 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr, []); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testSolve() For the array format. + * + * @return array + */ + public function dataSolve() + { + return [ + 'real square brackets' => [ + 'testMarker' => '/* testSquareBrackets */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'unambiguous short list' => [ + 'testMarker' => '/* testShortList */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short array in attribute' => [ + 'testMarker' => '/* testShortArrayInAttribute */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short array in foreach' => [ + 'testMarker' => '/* testShortArrayInForeach */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short list in foreach' => [ + 'testMarker' => '/* testShortListInForeach */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'unambiguous short array' => [ + 'testMarker' => '/* testShortArray */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested short array, first item in parent' => [ + 'testMarker' => '/* testNestedShortArrayParentBracketBefore */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested short list, last item in parent' => [ + 'testMarker' => '/* testNestedShortListParentBracketAfter */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested short list, last item in parent, trailing comma' => [ + 'testMarker' => '/* testNestedShortListParentBracketAfterWithTrailingComma */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested short array, content unambiguous' => [ + 'testMarker' => '/* testNestedShortArrayContentNonAmbiguous */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested short list, content unambiguous' => [ + 'testMarker' => '/* testNestedShortListContentNonAmbiguous */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested short array via outer brackets' => [ + 'testMarker' => '/* testOuterShortArray */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short array, parse error' => [ + 'testMarker' => '/* testLiveCodingNested */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/WalkInsideTest.inc b/Tests/Internal/IsShortArrayOrList/WalkInsideTest.inc new file mode 100644 index 00000000..c33c7857 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/WalkInsideTest.inc @@ -0,0 +1,239 @@ + $a, 'b' => $b->prop, 'c' => self::$staticProp, 'd' => static::$staticProp, 'e' => parent::$staticProp], + /* testNestedShortArrayWithReferenceUndetermined */ + [&Foo::$a, &$b[++$i], $c[$i . '1'], $d['key']->prop,], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +]; + +[ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortListEmpty */ + [], + + /* testNestedShortListUndetermined */ + [$a, $b->prop, Sub\ClassName::$staticProp, namespace\ClassName::$staticProp, $c[$i . '1'],], + /* testNestedShortListWithKeysUndetermined */ + ['a' => $a['key'], 'b' => $b[1]['text'],], + /* testNestedShortListWithReferenceUndetermined */ + [&$a, &Bar::$b, $d['key']->prop], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +] = $array; + + +// Complex variables at start of item. Undetermined for now. +$array = [ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortArrayValueHasContentAfterVar1 */ + ['arithmetic' => $c[1]['text'] + $d,], + /* testNestedShortArrayValueHasContentAfterVar2 */ + ['concat' => $c->prop . 'text'], + /* testNestedShortArrayValueHasContentAfterVar3 */ + ['compare' => $c->prop?->deeperProp === true,], + /* testNestedShortArrayValueHasContentAfterVar4 */ + ['ternary' => $c[$key]::CONST_NAME ? 10 : 20], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +]; + + +/* ===== Tests where the nature of a set of (nested) brackets CAN be determined by their content. ===== */ + +$array = [ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortArrayNoVarsOrNestedNull */ + [null], + /* testNestedShortArrayNoVarsOrNestedInts */ + [1, 2, 3,], + /* testNestedShortArrayWithKeysNoVarsOrNestedTextStrings */ + [1 => 'text', 2 => 'more text'], + /* testNestedShortArrayWithKeysNoVarsOrNestedBools */ + [1 => true, 2 => false,], + /* testNestedShortArrayNoVarsOrNestedFloats */ + [1.5, 3.7], + /* testNestedShortArrayNoVarsOrNestedLongArray */ + [array(1, 2, 3),], + /* testNestedShortArrayNoVarsOrNestedObject */ + [new stdClass()], + + /* testNestedShortArrayFuncCall */ + [$b->prop, functionCall(),], + /* testNestedShortArrayNamespacedConstant */ + [$a, namespace\CONSTANT_NAME], + /* testNestedShortArrayClassConstant1 */ + [$b, PartiallyQ\ClassName::CONSTANT_NAME,], + /* testNestedShortArrayClassConstant2 */ + [$b, static::CONSTANT_NAME,], + /* testNestedShortArrayMethodCall */ + [$b, \FullyQ\ClassName::functionCall(),], + /* testNestedShortArrayMixedContent */ + [$a, $b, [$c], 1,], + + /* testNestedShortArrayValueHasContentAfterShortArray1 */ + ['union' => [$c] + [$d]], + /* testNestedShortArrayValueHasContentAfterShortArray2 */ + ['compare' => [$c] === [1],], + /* testNestedShortArrayValueHasContentAfterShortArray3 */ + ['list' => [$c] = $array,], + + /* testNestedShortArrayRecursion1 */ + [$a, $b, ['text'], $c], + + /* testNestedShortArrayRecursion2 */ + [ + $a, + [ + $b, + [ + 10, + ], + ], + ], + + /* testNestedShortArrayRecursion3 */ + [ + $a, + [ + $b, + [ + $c, + [ + 10, + ], + ], + ], + ], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +]; + +[ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortListEmptyEntryAtStart */ + [, $a, $b], + /* testNestedShortListEmptyEntryInMiddle */ + [$a,, $b], + /* testNestedShortListEmptyEntryAtEnd */ + [$a, $b, , ], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +] = $array; + + +/* ===== Test where the nature of a set of (nested) brackets COULD be determined by their content, + but the amount of parameters retrieved is too small. ===== */ + +$array = [ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortArraySampleTooSmall */ + [$a, $b, $c, [$d], $e, 10], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +]; + + +/* ===== Tests where the nature of a set of (nested) brackets CAN be determined by their content, but the recursion limit prevent this. ===== */ + +$array = [ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortArrayRecursion4 */ + [ + $a, + [ + $b, + [ + $c, + [ + $d, + [ + 20.5, + ], + ], + ], + ], + ], + + /* testNestedShortArrayRecursion6 */ + [ + $a, + [ + $b, + [ + $c, + [ + $d, + [ + $e, + [ + $f, + [ + 10 + ], + ], + ], + ], + ], + ], + ], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +]; + +[ + // Prevent going straight to outer brackets for first item. + [$a, $b], + + /* testNestedShortListRecursion4 */ + [ + $a, + [ + $b, + [ + $c, + [ + $d, + [ + $e, + $f, + ], + ], + ], + ], + ], + + // Prevent going straight to outer brackets for last item. + [$a, $b], +] = $array; diff --git a/Tests/Internal/IsShortArrayOrList/WalkInsideTest.php b/Tests/Internal/IsShortArrayOrList/WalkInsideTest.php new file mode 100644 index 00000000..a4388675 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/WalkInsideTest.php @@ -0,0 +1,293 @@ +getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY]); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr, []); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testWalkInsideUndetermined() For the array format. + * + * @return array + */ + public function dataWalkInsideUndetermined() + { + return [ + 'nested-short-array-empty' => [ + 'testMarker' => '/* testNestedShortArrayEmpty */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-array' => [ + 'testMarker' => '/* testNestedShortArrayUndetermined */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-keys' => [ + 'testMarker' => '/* testNestedShortArrayWithKeysUndetermined */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-reference' => [ + 'testMarker' => '/* testNestedShortArrayWithReferenceUndetermined */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-list-empty' => [ + 'testMarker' => '/* testNestedShortListEmpty */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + 'nested-short-list' => [ + 'testMarker' => '/* testNestedShortListUndetermined */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested-short-list-with-keys' => [ + 'testMarker' => '/* testNestedShortListWithKeysUndetermined */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested-short-list-with-reference' => [ + 'testMarker' => '/* testNestedShortListWithReferenceUndetermined */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + 'nested-short-array-operator-after-var-1' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterVar1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-operator-after-var-2' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterVar2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-operator-after-var-3' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterVar3 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-operator-after-var-4' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterVar4 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } + + /** + * Test that nested brackets are recognized as a short array when based on the contents + * it can't be a short list. + * + * @dataProvider dataWalkInsideResolved + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected The expected function output. + * + * @return void + */ + public function testWalkInsideResolved($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY]); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr, []); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testWalkInsideResolved() For the array format. + * + * @return array + */ + public function dataWalkInsideResolved() + { + return [ + 'nested-short-array-no-vars-or-nested-null' => [ + 'testMarker' => '/* testNestedShortArrayNoVarsOrNestedNull */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-no-vars-or-nested-ints' => [ + 'testMarker' => '/* testNestedShortArrayNoVarsOrNestedInts */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-keys-no-vars-or-nested-text-strings' => [ + 'testMarker' => '/* testNestedShortArrayWithKeysNoVarsOrNestedTextStrings */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-keys-no-vars-or-nested-bools' => [ + 'testMarker' => '/* testNestedShortArrayWithKeysNoVarsOrNestedBools */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-no-vars-or-nested-floats' => [ + 'testMarker' => '/* testNestedShortArrayNoVarsOrNestedFloats */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-no-vars-or-nested-long-array' => [ + 'testMarker' => '/* testNestedShortArrayNoVarsOrNestedLongArray */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-no-vars-or-nested-object' => [ + 'testMarker' => '/* testNestedShortArrayNoVarsOrNestedObject */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-array-function-call' => [ + 'testMarker' => '/* testNestedShortArrayFuncCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-namespaced-constant' => [ + 'testMarker' => '/* testNestedShortArrayNamespacedConstant */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-class-constant' => [ + 'testMarker' => '/* testNestedShortArrayClassConstant1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-class-constant-with-hierarchy-keyword' => [ + 'testMarker' => '/* testNestedShortArrayClassConstant2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-fqn-method-call' => [ + 'testMarker' => '/* testNestedShortArrayMethodCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-mixed-content' => [ + 'testMarker' => '/* testNestedShortArrayMixedContent */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-array-content-after-short-array-1' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterShortArray1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-content-after-short-array-2' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterShortArray2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-content-after-short-array-3' => [ + 'testMarker' => '/* testNestedShortArrayValueHasContentAfterShortArray3 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-array-with-nested-short-array-recursion-1' => [ + 'testMarker' => '/* testNestedShortArrayRecursion1 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-nested-short-array-recursion-2' => [ + 'testMarker' => '/* testNestedShortArrayRecursion2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-nested-short-array-recursion-3' => [ + 'testMarker' => '/* testNestedShortArrayRecursion3 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-list-empty-entry-at-start' => [ + 'testMarker' => '/* testNestedShortListEmptyEntryAtStart */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested-short-list-empty-entry-in-middle' => [ + 'testMarker' => '/* testNestedShortListEmptyEntryInMiddle */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'nested-short-list-empty-entry-at-end' => [ + 'testMarker' => '/* testNestedShortListEmptyEntryAtEnd */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } + + /** + * Ensure the "cannot be determined based on the array entry sample size" condition gets hit. + * + * @return void + */ + public function testSampleTooSmall() + { + $stackPtr = $this->getTargetToken('/* testNestedShortArraySampleTooSmall */', \T_OPEN_SHORT_ARRAY); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr, []); + $type = $solver->solve(); + + $this->assertSame(IsShortArrayOrList::SHORT_ARRAY, $type); + } + + /** + * Ensure the "cannot be determined due to the recursion limit" condition gets hit. + * + * @dataProvider dataRecursionLimit + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected The expected function output. + * + * @return void + */ + public function testRecursionLimit($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY]); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr, []); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testRecursionLimit() For the array format. + * + * @return array + */ + public function dataRecursionLimit() + { + return [ + 'nested-short-array-with-nested-short-array-recursion-4' => [ + 'testMarker' => '/* testNestedShortArrayRecursion4 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-array-with-nested-short-array-recursion-6' => [ + 'testMarker' => '/* testNestedShortArrayRecursion6 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-list-with-nested-short-list-recursion-4' => [ + 'testMarker' => '/* testNestedShortListRecursion4 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrList/WalkOutsideTest.inc b/Tests/Internal/IsShortArrayOrList/WalkOutsideTest.inc new file mode 100644 index 00000000..9a7aee9b --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/WalkOutsideTest.inc @@ -0,0 +1,182 @@ + 'text', + 'jump over non-cached short array' => [$a], + 'jump over short list' => [$a] = $array, + 'jump over parenthesis' => function_call($param, $param, $param), + 'jump over parenthesis to owner' => array($var, $var, $var), + 'jump over scope curlies 1' => match($a) { + 1 => true, + 2 => false, + }, + 'jump over scope curlies 2' => function($a) { + return $something, + }, + 'jump over non-scope curlies' => ${'var_name'}, + 'jump over heredoc' => << <<<'EOD' +text +EOD + , + 'jump over square brackets' => $a['key'], + + 'jump over attributes' => #[MyAttribute([1, 2, 3])] fn($a) => $something, + + /* testShortArrayJumpingOver */ + 'array under investigation' => [$a], + + // Prevent going straight to outer brackets for last item. + [$b], +]; + +[ + /** + * Docblock. + */ + 'key' => $a['jump over docblock'], + [1,2,3]['index'] => $a['jump over short array'], + function_call($param, $param, $param) => $a['jump over parenthesis'], + ${'var_name'} => $a['jump over non-scope curlies'], + << $a['jump over heredoc'], + <<<'EOD' +key +EOD + => $a['jump over nowdoc'], + $a['key'] => $a['jump over square brackets'], + + /* testShortListJumpingOver */ + 'list under investigation' => [$a], + + // Prevent going straight to outer brackets for last item. + 'skip' => [$b], + +] = $array; + + +/* ===== Tests verifying that the loop stops as quickly as possible for OUTER brackets. ===== */ + +/* testOuterShortArrayStopAtSemicolon */ +echo 'previous-semicolon'; +echo $arg, [$arg], $arg; + +?> + + function() { + /* testShortArrayInShortArrayStopAtCurly */ + echo $arg, [$arg], $arg; + }, +]; + +[ + 'key' => $a, + (function() { + ob_start(); + /* testShortArrayInShortListStopAtSemicolon */ + echo $arg, [$arg], $arg; + return ob_get_flush(); + })() => $b, + 'key' => $c, +] = $array; + + +$array = [ + /* testShortArrayInShortArrayStopAtParensFuncCall */ + 'func'. 'Call' => function_call($arg, [$arg], $arg), + + /* testShortArrayInShortArrayStopAtParensClosureCall */ + 'closureCall' => $closure($arg, [$arg], $arg), + + /* testShortArrayInShortArrayStopAtParensFnCall */ + 'fnCall' => $fn($arg, [$arg], $arg), +]; + +[ + /* testShortArrayInShortListStopAtParensFuncCall */ + function_call($arg, [$arg], $arg) => $a, + + /* testShortArrayInShortListStopAtParensClosureCall */ + $closure($arg, [$arg], $arg) => $b, + + /* testShortArrayInShortListStopAtParensFnCall */ + $fn($arg, [$arg], $arg) => $c, +] = $array; + + +/* ===== Tests verifying that the loop stops as quickly as possible when an adjacent bracket set is found for which the type is known. ===== */ + +$array = [ + /* testShortArrayAdjacent1 */ + 'adjacent with same code pattern' => [$a], + + /* testShortArrayAdjacent2 */ + [$a], // Adjacent not same code pattern. + + /* testShortArrayReuseTypeOfAdjacent */ + 'array under investigation' => [$a], + + // Prevent going straight to outer brackets for last item. + [$b], +]; + +[ + /* testShortListAdjacent1 */ + 'adjacent with same code pattern' => [$a], + + /* testShortListAdjacent2 */ + [$a], // Adjacent not same code pattern. + + /* testShortListReuseTypeOfAdjacent */ + 'list under investigation' => [$a], + + // Prevent going straight to outer brackets for last item. + 'skip' => [$b], + +] = $array; + + +/* ===== Tests handling unclosed open brackets. ===== */ + +// Intentional parse error. This has to be the last test in the file. +[$a, /* testLiveCodingNested */ [$b], diff --git a/Tests/Internal/IsShortArrayOrList/WalkOutsideTest.php b/Tests/Internal/IsShortArrayOrList/WalkOutsideTest.php new file mode 100644 index 00000000..c95c098a --- /dev/null +++ b/Tests/Internal/IsShortArrayOrList/WalkOutsideTest.php @@ -0,0 +1,205 @@ +getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY]); + $solver = new IsShortArrayOrList(self::$phpcsFile, $stackPtr, []); + $type = $solver->solve(); + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testWalkOutside() For the array format. + * + * @return array + */ + public function dataWalkOutside() + { + return [ + 'nested-short-array-start-of-file' => [ + 'testMarker' => '/* testShortArrayStopAtStartOfFile */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-array-jump-test' => [ + 'testMarker' => '/* testShortArrayJumpingOver */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'nested-short-list-jump-test' => [ + 'testMarker' => '/* testShortListJumpingOver */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + + 'outer-short-array-stop-test-semicolon' => [ + 'testMarker' => '/* testOuterShortArrayStopAtSemicolon */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'outer-short-array-stop-test-open-tag' => [ + 'testMarker' => '/* testOuterShortArrayStopAtOpenTag */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'outer-short-array-stop-test-short-open-echo' => [ + 'testMarker' => '/* testOuterShortArrayStopAtOpenEchoTag */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'outer-short-array-stop-test-curly-open' => [ + 'testMarker' => '/* testOuterShortArrayStopAtCurly */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'outer-short-array-stop-test-parens-open-1' => [ + 'testMarker' => '/* testOuterShortArrayStopAtParensFuncCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'outer-short-array-stop-test-parens-open-2' => [ + 'testMarker' => '/* testOuterShortArrayStopAtParensClosureCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'outer-short-array-stop-test-parens-open-3' => [ + 'testMarker' => '/* testOuterShortArrayStopAtParensFnCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'inner-short-array-stop-test-curly-open' => [ + 'testMarker' => '/* testShortArrayInShortArrayStopAtCurly */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-list-stop-test-semicolon' => [ + 'testMarker' => '/* testShortArrayInShortListStopAtSemicolon */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'inner-short-array-stop-test-parens-open-1' => [ + 'testMarker' => '/* testShortArrayInShortArrayStopAtParensFuncCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-parens-open-2' => [ + 'testMarker' => '/* testShortArrayInShortArrayStopAtParensClosureCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-parens-open-3' => [ + 'testMarker' => '/* testShortArrayInShortArrayStopAtParensFnCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-parens-open-4' => [ + 'testMarker' => '/* testShortArrayInShortListStopAtParensFuncCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-parens-open-5' => [ + 'testMarker' => '/* testShortArrayInShortListStopAtParensClosureCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'inner-short-array-stop-test-parens-open-6' => [ + 'testMarker' => '/* testShortArrayInShortListStopAtParensFnCall */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'parse-error-live-coding' => [ + 'testMarker' => '/* testLiveCodingNested */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + ]; + } + + /** + * Test that the method correctly re-uses cached information for adjacent sets of brackets. + * + * @dataProvider dataReuseCacheFromAdjacent + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $adjacent1 The comment which prefaces the matching adjacent bracket set in the test file. + * @param string $adjacent2 The comment which prefaces the non-matching adjacent bracket set in the test file. + * @param string $expected The expected function output. + * + * @return void + */ + public function testReuseCacheFromAdjacent($testMarker, $adjacent1, $adjacent2, $expected) + { + $adjacentPtr1 = $this->getTargetToken($adjacent1, \T_OPEN_SHORT_ARRAY); + $adjacentPtr2 = $this->getTargetToken($adjacent2, \T_OPEN_SHORT_ARRAY); + $target = $this->getTargetToken($testMarker, \T_OPEN_SHORT_ARRAY); + + // Verify the cache of the adjacent bracket set is re-used. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + // Make sure the type of the adjacent bracket sets is cached. + IsShortArrayOrListWithCache::getType(self::$phpcsFile, $adjacentPtr1); // Same code pattern. + IsShortArrayOrListWithCache::getType(self::$phpcsFile, $adjacentPtr2); // Not the same code pattern. + + // Check the type of the current target set of brackets. + $solver = new IsShortArrayOrList(self::$phpcsFile, $target); + $type = $solver->solve(); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $type); + } + + /** + * Data provider. + * + * @see testReuseCacheFromAdjacent() For the array format. + * + * @return array + */ + public function dataReuseCacheFromAdjacent() + { + return [ + 'nested-short-array' => [ + 'testMarker' => '/* testShortArrayReuseTypeOfAdjacent */', + 'adjacent1' => '/* testShortArrayAdjacent1 */', + 'adjacent2' => '/* testShortArrayAdjacent2 */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + + 'nested-short-list' => [ + 'testMarker' => '/* testShortListReuseTypeOfAdjacent */', + 'adjacent1' => '/* testShortListAdjacent1 */', + 'adjacent2' => '/* testShortListAdjacent2 */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrListWithCache/CachingTest.php b/Tests/Internal/IsShortArrayOrListWithCache/CachingTest.php new file mode 100644 index 00000000..2005af44 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrListWithCache/CachingTest.php @@ -0,0 +1,116 @@ +getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); + $closer = $this->getTargetToken($testMarker, [\T_CLOSE_SHORT_ARRAY, \T_CLOSE_SQUARE_BRACKET]); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = IsShortArrayOrListWithCache::getType(self::$phpcsFile, $closer); + $isCachedOpener = Cache::isCached(self::$phpcsFile, IsShortArrayOrListWithCache::CACHE_KEY, $opener); + $isCachedCloser = Cache::isCached(self::$phpcsFile, IsShortArrayOrListWithCache::CACHE_KEY, $closer); + $resultSecondRun = IsShortArrayOrListWithCache::getType(self::$phpcsFile, $opener); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCachedOpener, 'Cache::isCached() could not find the cached value'); + $this->assertFalse($isCachedCloser, 'Cache::isCached() erroneously found a cached value for the closer'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } + + /** + * Data provider. + * + * @return array + */ + public function dataResultIsCached() + { + return [ + 'short array' => [ + 'testMarker' => '/* testShortArray */', + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short list' => [ + 'testMarker' => '/* testShortList */', + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'square bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + ]; + } + + /** + * Verify that the result is not cached when an invalid token is passed. + * + * @return void + */ + public function testInvalidTokenResultIsNotCached() + { + $stackPtr = $this->getTargetToken('/* testLongArray */', \T_ARRAY); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = IsShortArrayOrListWithCache::getType(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, IsShortArrayOrListWithCache::CACHE_KEY, $stackPtr); + $resultSecondRun = IsShortArrayOrListWithCache::getType(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertFalse($resultFirstRun, 'First result did not match expectation'); + $this->assertFalse($isCached, 'Cache::isCached() erroneously found a cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } +} diff --git a/Tests/Internal/IsShortArrayOrListWithCache/EntryPointsTest.php b/Tests/Internal/IsShortArrayOrListWithCache/EntryPointsTest.php new file mode 100644 index 00000000..b70cb39d --- /dev/null +++ b/Tests/Internal/IsShortArrayOrListWithCache/EntryPointsTest.php @@ -0,0 +1,162 @@ +getTargetToken($testMarker, $targetType); + $this->assertIsBool(Arrays::isShortArray(self::$phpcsFile, $target)); + } + + /** + * Validate that the `Lists::isShortList()` method is accessible and always returns a boolean value. + * + * @dataProvider dataEntryPoints + * + * @covers \PHPCSUtils\Utils\Lists::isShortList + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testIsShortListApi($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertIsBool(Lists::isShortList(self::$phpcsFile, $target)); + } + + /** + * Validate that the `IsShortArrayOrListWithCache::isShortArray()` method is accessible + * and always returns a boolean value. + * + * @dataProvider dataEntryPoints + * + * @covers \PHPCSUtils\Internal\IsShortArrayOrListWithCache::isShortArray + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testIsShortArrayInternal($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertIsBool(IsShortArrayOrListWithCache::isShortArray(self::$phpcsFile, $target)); + } + + /** + * Validate that the `IsShortArrayOrListWithCache::isShortList()` method is accessible + * and always returns a boolean value. + * + * @dataProvider dataEntryPoints + * + * @covers \PHPCSUtils\Internal\IsShortArrayOrListWithCache::isShortList + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testIsShortListInternal($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertIsBool(IsShortArrayOrListWithCache::isShortList(self::$phpcsFile, $target)); + } + + /** + * Validate that the `IsShortArrayOrListWithCache::getType()` method is accessible + * and always returns a boolean value. + * + * @dataProvider dataEntryPoints + * + * @covers \PHPCSUtils\Internal\IsShortArrayOrListWithCache::getType + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testGetTypeInternal($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertContains(IsShortArrayOrListWithCache::getType(self::$phpcsFile, $target), $this->validValues); + } + + /** + * Data provider. + * + * @return array + */ + public function dataEntryPoints() + { + $defaultTargets = Collections::shortArrayListOpenTokensBC(); + + return [ + 'not a square bracket' => [ + 'testMarker' => '/* testLongArray */', + 'targetType' => \T_ARRAY, + ], + 'short array' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => $defaultTargets, + ], + 'short list' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => $defaultTargets, + ], + 'square bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => $defaultTargets, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrListWithCache/IsShortArrayOrListWithCacheTest.inc b/Tests/Internal/IsShortArrayOrListWithCache/IsShortArrayOrListWithCacheTest.inc new file mode 100644 index 00000000..b422081f --- /dev/null +++ b/Tests/Internal/IsShortArrayOrListWithCache/IsShortArrayOrListWithCacheTest.inc @@ -0,0 +1,23 @@ +assertFalse(IsShortArrayOrListWithCache::getType(self::$phpcsFile, 100000)); + } + + /** + * Test that false is returned when a non-bracket token is passed. + * + * @dataProvider dataNotBracket + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testNotBracket($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertFalse(IsShortArrayOrListWithCache::getType(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testNotBracket() For the array format. + * + * @return array + */ + public function dataNotBracket() + { + return [ + 'long-array' => [ + 'testMarker' => '/* testLongArray */', + 'targetType' => \T_ARRAY, + ], + 'long-list' => [ + 'testMarker' => '/* testLongList */', + 'targetType' => \T_LIST, + ], + ]; + } + + /** + * Test that the returned type is one of the valid values when a valid bracket token is passed. + * + * This test also safeguards that the class supports both open, as well as close brackets. + * + * @dataProvider dataValidBracket + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testValidBracket($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $result = IsShortArrayOrListWithCache::getType(self::$phpcsFile, $target); + + $this->assertContains($result, $this->validValues); + } + + /** + * Data provider. + * + * @see testNotBracket() For the array format. + * + * @return array + */ + public function dataValidBracket() + { + return [ + 'open square bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => \T_OPEN_SQUARE_BRACKET, + ], + 'close square bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => \T_CLOSE_SQUARE_BRACKET, + ], + 'open short array token' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + ], + 'close short list token' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => \T_CLOSE_SHORT_ARRAY, + ], + ]; + } +} diff --git a/Tests/Internal/IsShortArrayOrListWithCache/ProcessTest.php b/Tests/Internal/IsShortArrayOrListWithCache/ProcessTest.php new file mode 100644 index 00000000..7a651867 --- /dev/null +++ b/Tests/Internal/IsShortArrayOrListWithCache/ProcessTest.php @@ -0,0 +1,104 @@ +getTargetToken('/* testLongArray */', \T_ARRAY); + $this->assertFalse(IsShortArrayOrListWithCache::getType(self::$phpcsFile, $target)); + } + + /** + * Test the process method works for all supported token types which are allowed to be passed to it. + * + * @dataProvider dataSupportedBrackets + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * @param string|false $expected The expected function return value. + * + * @return void + */ + public function testSupportedBrackets($testMarker, $targetType, $expected) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertSame($expected, IsShortArrayOrListWithCache::getType(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testSupportedBrackets() For the array format. + * + * @return array + */ + public function dataSupportedBrackets() + { + return [ + 'short array open bracket' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short array close bracket' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => \T_CLOSE_SHORT_ARRAY, + 'expected' => IsShortArrayOrList::SHORT_ARRAY, + ], + 'short list openbracket' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'short list close bracket' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => \T_CLOSE_SHORT_ARRAY, + 'expected' => IsShortArrayOrList::SHORT_LIST, + ], + 'square brackets open bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => \T_OPEN_SQUARE_BRACKET, + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'square brackets close-bracket' => [ + 'testMarker' => '/* testSquareBrackets */', + 'targetType' => \T_CLOSE_SQUARE_BRACKET, + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + 'parse error close bracket' => [ + 'testMarker' => '/* testParseError */', + 'targetType' => \T_CLOSE_SQUARE_BRACKET, + 'expected' => IsShortArrayOrList::SQUARE_BRACKETS, + ], + ]; + } +} diff --git a/Tests/Internal/NoFileCache/GetClearTest.php b/Tests/Internal/NoFileCache/GetClearTest.php new file mode 100644 index 00000000..e00ca447 --- /dev/null +++ b/Tests/Internal/NoFileCache/GetClearTest.php @@ -0,0 +1,283 @@ + $dataset) { + NoFileCache::set('Utility1', $id, $dataset['input']); + NoFileCache::set('Utility2', $id, $dataset['input']); + } + } + + /** + * Clear the cache between tests. + * + * @after + * + * @return void + */ + protected function clearCache() + { + NoFileCache::clear(); + } + + /** + * Reset the caching status. + * + * @afterClass + * + * @return void + */ + public static function resetCachingStatus() + { + NoFileCache::$enabled = self::$origCacheEnabled; + } + + /** + * Test that a cache key which has not been set is identified correctly as such. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseForUnavailableKey() + { + $this->assertFalse(NoFileCache::isCached('Utility3', 'numeric string')); + } + + /** + * Test that a cache id which has not been set is identified correctly as such. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseForUnavailableId() + { + $this->assertFalse(NoFileCache::isCached('Utility1', 'this ID does not exist')); + } + + /** + * Test that disabling the cache will short-circuit cache checking. + * + * @covers ::isCached + * + * @return void + */ + public function testIsCachedWillReturnFalseWhenCachingDisabled() + { + $wasEnabled = NoFileCache::$enabled; + NoFileCache::$enabled = false; + + $isCached = NoFileCache::isCached('Utility1', 'numeric string'); + + NoFileCache::$enabled = $wasEnabled; + + $this->assertFalse($isCached); + } + + /** + * Test that retrieving a cache key which has not been set, yields null. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullForUnavailableKey() + { + $this->assertNull(NoFileCache::get('Utility3', 'numeric string')); + } + + /** + * Test that retrieving a cache id which has not been set, yields null. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullForUnavailableId() + { + $this->assertNull(NoFileCache::get('Utility1', 'this ID does not exist')); + } + + /** + * Test that disabling the cache will short-circuit cache retrieval. + * + * @covers ::get + * + * @return void + */ + public function testGetWillReturnNullWhenCachingDisabled() + { + $wasEnabled = NoFileCache::$enabled; + NoFileCache::$enabled = false; + + $retrieved = NoFileCache::get('Utility1', 'numeric string'); + + NoFileCache::$enabled = $wasEnabled; + + $this->assertNull($retrieved); + } + + /** + * Test that retrieving a cache set for a cache key which has not been set, yields an empty array. + * + * @covers ::getForKey + * + * @return void + */ + public function testGetForKeyWillReturnEmptyArrayForUnavailableData() + { + $this->assertSame([], NoFileCache::getForKey('Utility3')); + } + + /** + * Test that disabling the cache will short-circuit cache for key retrieval. + * + * @covers ::getForKey + * + * @return void + */ + public function testGetForKeyWillReturnEmptyArrayWhenCachingDisabled() + { + $wasEnabled = NoFileCache::$enabled; + NoFileCache::$enabled = false; + + $retrieved = NoFileCache::getForKey('Utility1'); + + NoFileCache::$enabled = $wasEnabled; + + $this->assertSame([], $retrieved); + } + + /** + * Test that previously cached data can be retrieved correctly. + * + * @dataProvider dataEveryTypeOfInput + * + * @covers ::get + * + * @param int|string $id The ID of the cached value to retrieve. + * @param mixed $expected The expected cached value. + * + * @return void + */ + public function testGetWillRetrievedPreviouslySetValue($id, $expected) + { + if (\is_object($expected)) { + $this->assertEquals($expected, NoFileCache::get('Utility1', $id)); + } else { + $this->assertSame($expected, NoFileCache::get('Utility1', $id)); + } + } + + /** + * Data provider. + * + * @return array + */ + public function dataEveryTypeOfInput() + { + $allTypes = TypeProviderHelper::getAll(); + $data = []; + foreach ($allTypes as $key => $dataset) { + $data[$key] = [ + 'id' => $key, + 'expected' => $dataset['input'], + ]; + } + + return $data; + } + + /** + * Test that the `getForKey()` method correctly retrieves a subset of the cached data. + * + * @covers ::getForKey + * + * @return void + */ + public function testGetForKey() + { + $dataSet1 = NoFileCache::getForKey('Utility1'); + $dataSet2 = NoFileCache::getForKey('Utility2'); + $this->assertSame($dataSet1, $dataSet2); + } + + /** + * Test that previously cached data is no longer available when the cache has been cleared. + * + * @dataProvider dataEveryTypeOfInput + * + * @covers ::clear + * + * @param int|string $id The ID of the cached value to retrieve. + * + * @return void + */ + public function testClearCache($id) + { + NoFileCache::clear(); + + $this->assertFalse(NoFileCache::isCached('Utility1', $id)); + $this->assertFalse(NoFileCache::isCached('Utility2', $id)); + } +} diff --git a/Tests/Internal/NoFileCache/SetTest.php b/Tests/Internal/NoFileCache/SetTest.php new file mode 100644 index 00000000..916f53f0 --- /dev/null +++ b/Tests/Internal/NoFileCache/SetTest.php @@ -0,0 +1,238 @@ +getName(); + NoFileCache::set(__METHOD__, $id, $input); + + $this->assertTrue( + NoFileCache::isCached(__METHOD__, $id), + 'NoFileCache::isCached() could not find the cached value' + ); + + $this->assertSame( + $input, + NoFileCache::get(__METHOD__, $id), + 'Value retrieved via NoFileCache::get() did not match expectations' + ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataEveryTypeOfInput() + { + return TypeProviderHelper::getAll(); + } + + /** + * Verify that all supported types of IDs are accepted. + * + * Note: this doesn't test the unhappy path of passing an unsupported type of key, but + * non-int/string keys are not accepted by PHP for arrays anyway, so that should result + * in PHP warnings/errors anyway and as this is an internal class, I'm not too concerned + * about that kind of mistake being made. + * + * @dataProvider dataSetAcceptsIntAndStringIdKeys + * + * @param int|string $id ID for the cache. + * + * @return void + */ + public function testSetAcceptsIntAndStringIdKeys($id) + { + $value = 'value' . $id; + + NoFileCache::set(__METHOD__, $id, $value); + + $this->assertTrue( + NoFileCache::isCached(__METHOD__, $id), + 'NoFileCache::isCached() could not find the cached value' + ); + + $this->assertSame( + $value, + NoFileCache::get(__METHOD__, $id), + 'Value retrieved via NoFileCache::get() did not match expectations' + ); + } + + /** + * Data provider. + * + * @return array + */ + public function dataSetAcceptsIntAndStringIdKeys() + { + return [ + 'ID: int zero' => [ + 'id' => 0, + ], + 'ID: positive int' => [ + 'id' => 12832, + ], + 'ID: negative int' => [ + 'id' => -274, + ], + 'ID: string' => [ + 'id' => 'string ID', + ], + ]; + } + + /** + * Verify that a previously set cached value will be overwritten when set() is called again + * with the same file, ID and key. + * + * @return void + */ + public function testSetWillOverwriteExistingValue() + { + $id = 'my key'; + $origValue = 'original value'; + + NoFileCache::set(__METHOD__, $id, $origValue); + + // Verify that the original value was set correctly. + $this->assertTrue( + NoFileCache::isCached(__METHOD__, $id), + 'NoFileCache::isCached() could not find the originally cached value' + ); + $this->assertSame( + $origValue, + NoFileCache::get(__METHOD__, $id), + 'Original value retrieved via NoFileCache::get() did not match expectations' + ); + + $newValue = 'new value'; + NoFileCache::set(__METHOD__, $id, $newValue); + + // Verify the overwrite happened. + $this->assertTrue( + NoFileCache::isCached(__METHOD__, $id), + 'NoFileCache::isCached() could not find the newly cached value' + ); + $this->assertSame( + $newValue, + NoFileCache::get(__METHOD__, $id), + 'New value retrieved via NoFileCache::get() did not match expectations' + ); + } + + /** + * Verify that disabling the cache will short-circuit caching (and not eat memory). + * + * @return void + */ + public function testSetWillNotSaveDataWhenCachingIsDisabled() + { + $id = 'id'; + $value = 'value'; + + $wasEnabled = NoFileCache::$enabled; + NoFileCache::$enabled = false; + + NoFileCache::set(__METHOD__, $id, $value); + + NoFileCache::$enabled = $wasEnabled; + + $this->assertFalse( + NoFileCache::isCached(__METHOD__, $id), + 'NoFileCache::isCached() found a cache which was set while caching was disabled' + ); + + $this->assertNull( + NoFileCache::get(__METHOD__, $id), + 'Value retrieved via NoFileCache::get() did not match expectations' + ); + } +} diff --git a/Tests/PolyfilledTestCase.php b/Tests/PolyfilledTestCase.php new file mode 100644 index 00000000..58af5e3d --- /dev/null +++ b/Tests/PolyfilledTestCase.php @@ -0,0 +1,65 @@ +expectPhpcsException('testing-1-2-3'); + throw new RuntimeException('testing-1-2-3'); + } + + /** + * Test that the helper method to handle cross-version testing of exceptions in PHPUnit + * works correctly. + * + * @return void + */ + public function testExpectPhpcsTokenizerException() + { + $this->expectPhpcsException('testing-1-2-3', 'tokenizer'); + throw new TokenizerException('testing-1-2-3'); + } +} diff --git a/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php b/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php index 39a2af03..988d89b3 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/FailedToTokenizeTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; /** * Tests for the \PHPCSUtils\TestUtils\UtilityMethodTestCase class. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class FailedToTokenizeTest extends UtilityMethodTestCase +final class FailedToTokenizeTest extends PolyfilledTestCase { /** @@ -50,14 +50,8 @@ public function testMissingCaseFile() $exception = 'PHPUnit_Framework_AssertionFailedError'; } - if (\method_exists($this, 'expectException')) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($msg); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $msg); - } + $this->expectException($exception); + $this->expectExceptionMessage($msg); parent::setUpTestFile(); } diff --git a/Tests/TestUtils/UtilityMethodTestCase/GetTargetTokenFileNotFoundTest.php b/Tests/TestUtils/UtilityMethodTestCase/GetTargetTokenFileNotFoundTest.php new file mode 100644 index 00000000..1990b7b6 --- /dev/null +++ b/Tests/TestUtils/UtilityMethodTestCase/GetTargetTokenFileNotFoundTest.php @@ -0,0 +1,54 @@ +expectException('PHPCSUtils\Exceptions\TestFileNotFound'); + $this->expectExceptionMessage( + 'Failed to find a tokenized test case file.' . \PHP_EOL + . 'Make sure the UtilityMethodTestCase::setUpTestFile() method has run' + ); + + $this->getTargetToken('/* testSomething */', [\T_VARIABLE], '$a'); + } +} diff --git a/Tests/TestUtils/UtilityMethodTestCase/GetTargetTokenTest.php b/Tests/TestUtils/UtilityMethodTestCase/GetTargetTokenTest.php new file mode 100644 index 00000000..162da8f5 --- /dev/null +++ b/Tests/TestUtils/UtilityMethodTestCase/GetTargetTokenTest.php @@ -0,0 +1,152 @@ +getTargetToken($commentString, $tokenType, $tokenContent); + } else { + $result = self::getTargetToken($commentString, $tokenType); + } + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetTargetToken() For the array format. + * + * @return array + */ + public function dataGetTargetToken() + { + return [ + 'single-token-type' => [ + 'expected' => 6, + 'commentString' => '/* testFindingTarget */', + 'tokenType' => \T_VARIABLE, + ], + 'multi-token-type-1' => [ + 'expected' => 6, + 'commentString' => '/* testFindingTarget */', + 'tokenType' => [\T_VARIABLE, \T_FALSE], + ], + 'multi-token-type-2' => [ + 'expected' => 11, + 'commentString' => '/* testFindingTarget */', + 'tokenType' => [\T_FALSE, \T_LNUMBER], + ], + 'content-method' => [ + 'expected' => 23, + 'commentString' => '/* testFindingTargetWithContent */', + 'tokenType' => \T_STRING, + 'tokenContent' => 'method', + ], + 'content-otherMethod' => [ + 'expected' => 33, + 'commentString' => '/* testFindingTargetWithContent */', + 'tokenType' => \T_STRING, + 'tokenContent' => 'otherMethod', + ], + 'content-$a' => [ + 'expected' => 21, + 'commentString' => '/* testFindingTargetWithContent */', + 'tokenType' => \T_VARIABLE, + 'tokenContent' => '$a', + ], + 'content-$b' => [ + 'expected' => 31, + 'commentString' => '/* testFindingTargetWithContent */', + 'tokenType' => \T_VARIABLE, + 'tokenContent' => '$b', + ], + 'content-foo' => [ + 'expected' => 26, + 'commentString' => '/* testFindingTargetWithContent */', + 'tokenType' => [\T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING], + 'tokenContent' => "'foo'", + ], + 'content-bar' => [ + 'expected' => 36, + 'commentString' => '/* testFindingTargetWithContent */', + 'tokenType' => [\T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING], + 'tokenContent' => "'bar'", + ], + ]; + } + + /** + * Test the behaviour of the getTargetToken() method when the test marker comment is not found. + * + * @return void + */ + public function testGetTargetTokenCommentNotFound() + { + $this->expectException('PHPCSUtils\Exceptions\TestMarkerNotFound'); + $this->expectExceptionMessage('Failed to find the test marker: '); + + $this->getTargetToken('/* testCommentDoesNotExist */', [\T_VARIABLE], '$a'); + } + + /** + * Test the behaviour of the getTargetToken() method when the target is not found. + * + * @return void + */ + public function testGetTargetTokenNotFoundException() + { + $this->expectException('PHPCSUtils\Exceptions\TestTargetNotFound'); + $this->expectExceptionMessage('Failed to find test target token for comment string: '); + + self::getTargetToken('/* testNotFindingTarget */', [\T_VARIABLE], '$a'); + } +} diff --git a/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php b/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php index f53d4c87..ead82dfa 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/MissingCaseFileTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; /** * Tests for the \PHPCSUtils\TestUtils\UtilityMethodTestCase class. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class MissingCaseFileTest extends UtilityMethodTestCase +final class MissingCaseFileTest extends PolyfilledTestCase { /** @@ -50,14 +50,8 @@ public function testMissingCaseFile() $exception = 'PHPUnit_Framework_AssertionFailedError'; } - if (\method_exists($this, 'expectException')) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($msg); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $msg); - } + $this->expectException($exception); + $this->expectExceptionMessage($msg); parent::setUpTestFile(); } diff --git a/Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.js b/Tests/TestUtils/UtilityMethodTestCase/SkipJSCSSTestsOnPHPCS4Test.js similarity index 100% rename from Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.js rename to Tests/TestUtils/UtilityMethodTestCase/SkipJSCSSTestsOnPHPCS4Test.js diff --git a/Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.php b/Tests/TestUtils/UtilityMethodTestCase/SkipJSCSSTestsOnPHPCS4Test.php similarity index 73% rename from Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.php rename to Tests/TestUtils/UtilityMethodTestCase/SkipJSCSSTestsOnPHPCS4Test.php index 0831bc34..76064d2c 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/SkipCSJSTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/SkipJSCSSTestsOnPHPCS4Test.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; /** * Tests for the \PHPCSUtils\TestUtils\UtilityMethodTestCase class. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class SkipJSCSSTest extends UtilityMethodTestCase +final class SkipJSCSSTestsOnPHPCS4Test extends PolyfilledTestCase { /** @@ -46,13 +46,11 @@ public function skipJSCSSTestsOnPHPCS4() /** * Test that the skipJSCSSTestsOnPHPCS4() skips JS/CSS file tests on PHPCS 4.x. * - * @doesNotPerformAssertions - * * @return void */ public function testSkipJsCss() { - if (\version_compare(static::$phpcsVersion, '3.99.99', '>') === true) { + if (\version_compare(parent::$phpcsVersion, '3.99.99', '>') === true) { $msg = 'JS and CSS support has been removed in PHPCS 4.'; $exception = 'PHPUnit\Framework\SkippedTestError'; if (\class_exists('PHPUnit_Framework_SkippedTestError')) { @@ -60,14 +58,11 @@ public function testSkipJsCss() $exception = 'PHPUnit_Framework_SkippedTestError'; } - if (\method_exists($this, 'expectException')) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($msg); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $msg); - } + $this->expectException($exception); + $this->expectExceptionMessage($msg); + } else { + // Get rid of the "does not perform assertions" warning when run with PHPCS 3.x. + $this->assertTrue(true); } parent::skipJSCSSTestsOnPHPCS4(); diff --git a/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php b/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php index 9a0ba793..6247c17f 100644 --- a/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php +++ b/Tests/TestUtils/UtilityMethodTestCase/UtilityMethodTestCaseTest.php @@ -10,9 +10,7 @@ namespace PHPCSUtils\Tests\TestUtils\UtilityMethodTestCase; -use PHP_CodeSniffer\Exceptions\RuntimeException; -use PHP_CodeSniffer\Exceptions\TokenizerException; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; /** * Tests for the \PHPCSUtils\TestUtils\UtilityMethodTestCase class. @@ -23,7 +21,7 @@ * * @since 1.0.0 */ -class UtilityMethodTestCaseTest extends UtilityMethodTestCase +final class UtilityMethodTestCaseTest extends PolyfilledTestCase { /** @@ -51,160 +49,24 @@ public function testSetUp() $this->assertSame(57, self::$phpcsFile->numTokens); $tokens = self::$phpcsFile->getTokens(); - if (\method_exists($this, 'assertIsArray')) { - // PHPUnit 7+. - $this->assertIsArray($tokens); - } else { - // PHPUnit 4/5/6. - $this->assertInternalType('array', $tokens); - } - } - - /** - * Test the getTargetToken() method. - * - * @dataProvider dataGetTargetToken - * - * @param int|false $expected Expected function output. - * @param string $commentString The delimiter comment to look for. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. - * - * @return void - */ - public function testGetTargetToken($expected, $commentString, $tokenType, $tokenContent = null) - { - if (isset($tokenContent)) { - $result = $this->getTargetToken($commentString, $tokenType, $tokenContent); - } else { - $result = $this->getTargetToken($commentString, $tokenType); - } - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testGetTargetToken() For the array format. - * - * @return array - */ - public function dataGetTargetToken() - { - return [ - 'single-token-type' => [ - 6, - '/* testFindingTarget */', - \T_VARIABLE, - ], - 'multi-token-type-1' => [ - 6, - '/* testFindingTarget */', - [\T_VARIABLE, \T_FALSE], - ], - 'multi-token-type-2' => [ - 11, - '/* testFindingTarget */', - [\T_FALSE, \T_LNUMBER], - ], - 'content-method' => [ - 23, - '/* testFindingTargetWithContent */', - \T_STRING, - 'method', - ], - 'content-otherMethod' => [ - 33, - '/* testFindingTargetWithContent */', - \T_STRING, - 'otherMethod', - ], - 'content-$a' => [ - 21, - '/* testFindingTargetWithContent */', - \T_VARIABLE, - '$a', - ], - 'content-$b' => [ - 31, - '/* testFindingTargetWithContent */', - \T_VARIABLE, - '$b', - ], - 'content-foo' => [ - 26, - '/* testFindingTargetWithContent */', - [\T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING], - "'foo'", - ], - 'content-bar' => [ - 36, - '/* testFindingTargetWithContent */', - [\T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING], - "'bar'", - ], - ]; - } - - /** - * Test the behaviour of the getTargetToken() method when the target is not found. - * - * @return void - */ - public function testGetTargetTokenNotFound() - { - $msg = 'Failed to find test target token for comment string: '; - $exception = 'PHPUnit\Framework\AssertionFailedError'; - if (\class_exists('PHPUnit_Framework_AssertionFailedError')) { - // PHPUnit < 6. - $exception = 'PHPUnit_Framework_AssertionFailedError'; - } - - if (\method_exists($this, 'expectException')) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($msg); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $msg); - } - - $this->getTargetToken('/* testNotFindingTarget */', [\T_VARIABLE], '$a'); - } - - /** - * Test that the helper method to handle cross-version testing of exceptions in PHPUnit - * works correctly. - * - * @return void - */ - public function testExpectPhpcsRuntimeException() - { - $this->expectPhpcsException('testing-1-2-3'); - throw new RuntimeException('testing-1-2-3'); - } - - /** - * Test that the helper method to handle cross-version testing of exceptions in PHPUnit - * works correctly. - * - * @return void - */ - public function testExpectPhpcsTokenizerException() - { - $this->expectPhpcsException('testing-1-2-3', 'tokenizer'); - throw new TokenizerException('testing-1-2-3'); + $this->assertIsArray($tokens); } /** * Test that the class is correct reset. * + * @depends testSetUp + * * @return void */ public function testTearDown() { parent::resetTestFile(); - $this->assertNull(self::$phpcsFile); + $this->assertSame('0', self::$phpcsVersion, 'phpcsVersion was not reset'); + $this->assertSame('inc', self::$fileExtension, 'fileExtension was not reset'); + $this->assertSame('', self::$caseFile, 'caseFile was not reset'); + $this->assertSame(4, self::$tabWidth, 'tabWidth was not reset'); + $this->assertNull(self::$phpcsFile, 'phpcsFile was not reset'); + $this->assertSame(['Dummy.Dummy.Dummy'], self::$selectedSniff, 'selectedSniff was not reset'); } } diff --git a/Tests/Tokens/Collections/AlternativeControlStructureSyntaxClosersTest.php b/Tests/Tokens/Collections/AlternativeControlStructureSyntaxClosersTest.php new file mode 100644 index 00000000..6b6fec78 --- /dev/null +++ b/Tests/Tokens/Collections/AlternativeControlStructureSyntaxClosersTest.php @@ -0,0 +1,40 @@ +assertSame( + Collections::$alternativeControlStructureSyntaxCloserTokens, + Collections::alternativeControlStructureSyntaxClosers() + ); + } +} diff --git a/Tests/Tokens/Collections/AlternativeControlStructureSyntaxesTest.php b/Tests/Tokens/Collections/AlternativeControlStructureSyntaxesTest.php new file mode 100644 index 00000000..af3b3707 --- /dev/null +++ b/Tests/Tokens/Collections/AlternativeControlStructureSyntaxesTest.php @@ -0,0 +1,40 @@ +assertSame( + Collections::$alternativeControlStructureSyntaxTokens, + Collections::alternativeControlStructureSyntaxes() + ); + } +} diff --git a/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php b/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php index 2d45f09c..f7b205ad 100644 --- a/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php +++ b/Tests/Tokens/Collections/ArrowFunctionTokensBCTest.php @@ -10,20 +10,20 @@ namespace PHPCSUtils\Tests\Tokens\Collections; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; -use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; /** * Test class. * * @covers \PHPCSUtils\Tokens\Collections::arrowFunctionTokensBC + * @covers \PHPCSUtils\Tokens\Collections::triggerDeprecation * * @group collections * * @since 1.0.0 */ -class ArrowFunctionTokensBCTest extends TestCase +final class ArrowFunctionTokensBCTest extends TestCase { /** @@ -33,17 +33,16 @@ class ArrowFunctionTokensBCTest extends TestCase */ public function testArrowFunctionTokensBC() { - $version = Helper::getVersion(); + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'Collections::arrowFunctionTokensBC() method is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + $expected = [ - \T_STRING => \T_STRING, + \T_FN => \T_FN, ]; - if (\version_compare($version, '3.5.3', '>=') === true - || \version_compare(\PHP_VERSION_ID, '70399', '>=') === true - ) { - $expected[\T_FN] = \T_FN; - } - $this->assertSame($expected, Collections::arrowFunctionTokensBC()); } } diff --git a/Tests/Tokens/Collections/FunctionCallTokensTest.php b/Tests/Tokens/Collections/FunctionCallTokensTest.php new file mode 100644 index 00000000..2c7b0fb3 --- /dev/null +++ b/Tests/Tokens/Collections/FunctionCallTokensTest.php @@ -0,0 +1,49 @@ + \T_STRING, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + \T_VARIABLE => \T_VARIABLE, + \T_ANON_CLASS => \T_ANON_CLASS, + \T_PARENT => \T_PARENT, + \T_SELF => \T_SELF, + \T_STATIC => \T_STATIC, + ]; + + $this->assertSame($expected, Collections::functionCallTokens()); + } +} diff --git a/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php b/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php index 4a40ecfc..067a2ac4 100644 --- a/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php +++ b/Tests/Tokens/Collections/FunctionDeclarationTokensBCTest.php @@ -10,20 +10,20 @@ namespace PHPCSUtils\Tests\Tokens\Collections; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; -use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; /** * Test class. * * @covers \PHPCSUtils\Tokens\Collections::functionDeclarationTokensBC + * @covers \PHPCSUtils\Tokens\Collections::triggerDeprecation * * @group collections * * @since 1.0.0 */ -class FunctionDeclarationTokensBCTest extends TestCase +final class FunctionDeclarationTokensBCTest extends TestCase { /** @@ -33,19 +33,18 @@ class FunctionDeclarationTokensBCTest extends TestCase */ public function testFunctionDeclarationTokensBC() { - $version = Helper::getVersion(); + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'Collections::functionDeclarationTokensBC() method is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the PHPCSUtils\Tokens\Collections::functionDeclarationTokens() method instead.' + ); + $expected = [ \T_FUNCTION => \T_FUNCTION, \T_CLOSURE => \T_CLOSURE, - \T_STRING => \T_STRING, + \T_FN => \T_FN, ]; - if (\version_compare($version, '3.5.3', '>=') === true - || \version_compare(\PHP_VERSION_ID, '70399', '>=') === true - ) { - $expected[\T_FN] = \T_FN; - } - $this->assertSame($expected, Collections::functionDeclarationTokensBC()); } } diff --git a/Tests/Tokens/Collections/FunctionDeclarationTokensTest.php b/Tests/Tokens/Collections/FunctionDeclarationTokensTest.php deleted file mode 100644 index e5e2c3cd..00000000 --- a/Tests/Tokens/Collections/FunctionDeclarationTokensTest.php +++ /dev/null @@ -1,50 +0,0 @@ - \T_FUNCTION, - \T_CLOSURE => \T_CLOSURE, - ]; - - if (\version_compare($version, '3.5.3', '>=') === true - || \version_compare(\PHP_VERSION_ID, '70399', '>=') === true - ) { - $expected[\T_FN] = \T_FN; - } - - $this->assertSame($expected, Collections::functionDeclarationTokens()); - } -} diff --git a/Tests/Tokens/Collections/NamespacedNameTokensTest.php b/Tests/Tokens/Collections/NamespacedNameTokensTest.php new file mode 100644 index 00000000..9fb3d4c1 --- /dev/null +++ b/Tests/Tokens/Collections/NamespacedNameTokensTest.php @@ -0,0 +1,46 @@ + \T_NS_SEPARATOR, + \T_NAMESPACE => \T_NAMESPACE, + \T_STRING => \T_STRING, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + ]; + + $this->assertSame($expected, Collections::namespacedNameTokens()); + } +} diff --git a/Tests/Tokens/Collections/OoCanExtendTest.php b/Tests/Tokens/Collections/OoCanExtendTest.php new file mode 100644 index 00000000..17d8e842 --- /dev/null +++ b/Tests/Tokens/Collections/OoCanExtendTest.php @@ -0,0 +1,37 @@ +assertSame(Collections::$OOCanExtend, Collections::ooCanExtend()); + } +} diff --git a/Tests/Tokens/Collections/OoCanImplementTest.php b/Tests/Tokens/Collections/OoCanImplementTest.php new file mode 100644 index 00000000..cdbd7178 --- /dev/null +++ b/Tests/Tokens/Collections/OoCanImplementTest.php @@ -0,0 +1,37 @@ +assertSame(Collections::$OOCanImplement, Collections::ooCanImplement()); + } +} diff --git a/Tests/Tokens/Collections/OoConstantScopesTest.php b/Tests/Tokens/Collections/OoConstantScopesTest.php new file mode 100644 index 00000000..e0f7a605 --- /dev/null +++ b/Tests/Tokens/Collections/OoConstantScopesTest.php @@ -0,0 +1,37 @@ +assertSame(Collections::$OOConstantScopes, Collections::ooConstantScopes()); + } +} diff --git a/Tests/Tokens/Collections/OoHierarchyKeywordsTest.php b/Tests/Tokens/Collections/OoHierarchyKeywordsTest.php new file mode 100644 index 00000000..52e3a689 --- /dev/null +++ b/Tests/Tokens/Collections/OoHierarchyKeywordsTest.php @@ -0,0 +1,37 @@ +assertSame(Collections::$OOHierarchyKeywords, Collections::ooHierarchyKeywords()); + } +} diff --git a/Tests/Tokens/Collections/OoPropertyScopesTest.php b/Tests/Tokens/Collections/OoPropertyScopesTest.php new file mode 100644 index 00000000..957479fd --- /dev/null +++ b/Tests/Tokens/Collections/OoPropertyScopesTest.php @@ -0,0 +1,37 @@ +assertSame(Collections::$OOPropertyScopes, Collections::ooPropertyScopes()); + } +} diff --git a/Tests/Tokens/Collections/ParameterPassingTokensTest.php b/Tests/Tokens/Collections/ParameterPassingTokensTest.php new file mode 100644 index 00000000..db07e640 --- /dev/null +++ b/Tests/Tokens/Collections/ParameterPassingTokensTest.php @@ -0,0 +1,54 @@ + \T_STRING, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + \T_VARIABLE => \T_VARIABLE, + \T_ANON_CLASS => \T_ANON_CLASS, + \T_PARENT => \T_PARENT, + \T_SELF => \T_SELF, + \T_STATIC => \T_STATIC, + \T_ISSET => \T_ISSET, + \T_UNSET => \T_UNSET, + \T_ARRAY => \T_ARRAY, + \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, + \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, + ]; + + $this->assertSame($expected, Collections::parameterPassingTokens()); + } +} diff --git a/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php b/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php index 0fcb7cf1..abab2b11 100644 --- a/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/ParameterTypeTokensBCTest.php @@ -10,20 +10,20 @@ namespace PHPCSUtils\Tests\Tokens\Collections; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; -use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; /** * Test class. * * @covers \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC + * @covers \PHPCSUtils\Tokens\Collections::triggerDeprecation * * @group collections * * @since 1.0.0 */ -class ParameterTypeTokensBCTest extends TestCase +final class ParameterTypeTokensBCTest extends TestCase { /** @@ -33,13 +33,12 @@ class ParameterTypeTokensBCTest extends TestCase */ public function testParameterTypeTokensBC() { - $version = Helper::getVersion(); - $expected = Collections::$parameterTypeTokens; + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'Collections::parameterTypeTokensBC() method is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the PHPCSUtils\Tokens\Collections::parameterTypeTokens() method instead.' + ); - if (\version_compare($version, '3.99.99', '<=') === true) { - $expected[\T_ARRAY_HINT] = \T_ARRAY_HINT; - } - - $this->assertSame($expected, Collections::parameterTypeTokensBC()); + $this->assertSame(Collections::parameterTypeTokens(), Collections::parameterTypeTokensBC()); } } diff --git a/Tests/Tokens/Collections/ParameterTypeTokensTest.php b/Tests/Tokens/Collections/ParameterTypeTokensTest.php new file mode 100644 index 00000000..bf62dbfe --- /dev/null +++ b/Tests/Tokens/Collections/ParameterTypeTokensTest.php @@ -0,0 +1,54 @@ + \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, + \T_TRUE => \T_TRUE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, + \T_NAMESPACE => \T_NAMESPACE, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + ]; + + $this->assertSame($expected, Collections::parameterTypeTokens()); + } +} diff --git a/Tests/Tokens/Collections/PropertyBasedTokenArraysTest.php b/Tests/Tokens/Collections/PropertyBasedTokenArraysTest.php new file mode 100644 index 00000000..d71354ce --- /dev/null +++ b/Tests/Tokens/Collections/PropertyBasedTokenArraysTest.php @@ -0,0 +1,105 @@ +setAccessible(true); + $expected = $reflProp->getValue(); + $reflProp->setAccessible(false); + + $this->assertSame($expected, Collections::$name()); + } + + /** + * Data provider. + * + * @see testPropertyBasedTokenArrays() For the array format. + * + * @return array + */ + public function dataPropertyBasedTokenArrays() + { + $names = [ + 'arrayOpenTokensBC', + 'arrayTokens', + 'arrayTokensBC', + 'classModifierKeywords', + 'closedScopes', + 'controlStructureTokens', + 'functionDeclarationTokens', + 'incrementDecrementOperators', + 'listTokens', + 'listTokensBC', + 'namespaceDeclarationClosers', + 'nameTokens', + 'objectOperators', + 'phpOpenTags', + 'propertyModifierKeywords', + 'shortArrayListOpenTokensBC', + 'shortArrayTokens', + 'shortArrayTokensBC', + 'shortListTokens', + 'shortListTokensBC', + ]; + + $data = []; + foreach ($names as $name) { + $data[$name] = [$name]; + } + + return $data; + } + + /** + * Test calling a token property method for a token array which doesn't exist. + * + * @return void + */ + public function testUndeclaredTokenArray() + { + $this->expectException('PHPCSUtils\Exceptions\InvalidTokenArray'); + $this->expectExceptionMessage('Call to undefined method PHPCSUtils\Tokens\Collections::notATokenArray()'); + + Collections::notATokenArray(); + } +} diff --git a/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php b/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php index b743eaad..ff492c35 100644 --- a/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/PropertyTypeTokensBCTest.php @@ -10,20 +10,20 @@ namespace PHPCSUtils\Tests\Tokens\Collections; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; -use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; /** * Test class. * * @covers \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC + * @covers \PHPCSUtils\Tokens\Collections::triggerDeprecation * * @group collections * * @since 1.0.0 */ -class PropertyTypeTokensBCTest extends TestCase +final class PropertyTypeTokensBCTest extends TestCase { /** @@ -33,13 +33,12 @@ class PropertyTypeTokensBCTest extends TestCase */ public function testPropertyTypeTokensBC() { - $version = Helper::getVersion(); - $expected = Collections::$propertyTypeTokens; + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'Collections::propertyTypeTokensBC() method is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the PHPCSUtils\Tokens\Collections::propertyTypeTokens() method instead.' + ); - if (\version_compare($version, '3.99.99', '<=') === true) { - $expected[\T_ARRAY_HINT] = \T_ARRAY_HINT; - } - - $this->assertSame($expected, Collections::propertyTypeTokensBC()); + $this->assertSame(Collections::propertyTypeTokens(), Collections::propertyTypeTokensBC()); } } diff --git a/Tests/Tokens/Collections/PropertyTypeTokensTest.php b/Tests/Tokens/Collections/PropertyTypeTokensTest.php new file mode 100644 index 00000000..0f8e2b17 --- /dev/null +++ b/Tests/Tokens/Collections/PropertyTypeTokensTest.php @@ -0,0 +1,54 @@ + \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_FALSE => \T_FALSE, + \T_TRUE => \T_TRUE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, + \T_NAMESPACE => \T_NAMESPACE, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + ]; + + $this->assertSame($expected, Collections::propertyTypeTokens()); + } +} diff --git a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php index 347ca673..a3b6b9d9 100644 --- a/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php +++ b/Tests/Tokens/Collections/ReturnTypeTokensBCTest.php @@ -10,20 +10,20 @@ namespace PHPCSUtils\Tests\Tokens\Collections; -use PHPCSUtils\BackCompat\Helper; use PHPCSUtils\Tokens\Collections; -use PHPUnit\Framework\TestCase; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; /** * Test class. * * @covers \PHPCSUtils\Tokens\Collections::returnTypeTokensBC + * @covers \PHPCSUtils\Tokens\Collections::triggerDeprecation * * @group collections * * @since 1.0.0 */ -class ReturnTypeTokensBCTest extends TestCase +final class ReturnTypeTokensBCTest extends TestCase { /** @@ -33,18 +33,12 @@ class ReturnTypeTokensBCTest extends TestCase */ public function testReturnTypeTokensBC() { - $version = Helper::getVersion(); - $expected = Collections::$returnTypeTokens; + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'Collections::returnTypeTokensBC() method is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the PHPCSUtils\Tokens\Collections::returnTypeTokens() method instead.' + ); - if (\version_compare($version, '3.99.99', '<=') === true) { - $expected[\T_RETURN_TYPE] = \T_RETURN_TYPE; - $expected[\T_ARRAY_HINT] = \T_ARRAY_HINT; - } - - if (\version_compare($version, '3.5.3', '<=') === true) { - $expected[\T_ARRAY] = \T_ARRAY; - } - - $this->assertSame($expected, Collections::returnTypeTokensBC()); + $this->assertSame(Collections::returnTypeTokens(), Collections::returnTypeTokensBC()); } } diff --git a/Tests/Tokens/Collections/ReturnTypeTokensTest.php b/Tests/Tokens/Collections/ReturnTypeTokensTest.php new file mode 100644 index 00000000..513a8f1d --- /dev/null +++ b/Tests/Tokens/Collections/ReturnTypeTokensTest.php @@ -0,0 +1,55 @@ + \T_CALLABLE, + \T_SELF => \T_SELF, + \T_PARENT => \T_PARENT, + \T_STATIC => \T_STATIC, + \T_FALSE => \T_FALSE, + \T_TRUE => \T_TRUE, + \T_NULL => \T_NULL, + \T_STRING => \T_STRING, + \T_NS_SEPARATOR => \T_NS_SEPARATOR, + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, + \T_NAMESPACE => \T_NAMESPACE, + \T_NAME_QUALIFIED => \T_NAME_QUALIFIED, + \T_NAME_FULLY_QUALIFIED => \T_NAME_FULLY_QUALIFIED, + \T_NAME_RELATIVE => \T_NAME_RELATIVE, + ]; + + $this->assertSame($expected, Collections::returnTypeTokens()); + } +} diff --git a/Tests/Tokens/Collections/TextStringStartTokensTest.php b/Tests/Tokens/Collections/TextStringStartTokensTest.php new file mode 100644 index 00000000..89b89b9b --- /dev/null +++ b/Tests/Tokens/Collections/TextStringStartTokensTest.php @@ -0,0 +1,37 @@ +assertSame(Collections::$textStingStartTokens, Collections::textStringStartTokens()); + } +} diff --git a/Tests/Tokens/TokenHelper/TokenExistsTest.php b/Tests/Tokens/TokenHelper/TokenExistsTest.php new file mode 100644 index 00000000..96f23266 --- /dev/null +++ b/Tests/Tokens/TokenHelper/TokenExistsTest.php @@ -0,0 +1,86 @@ +assertSame($expected, TokenHelper::tokenExists($name)); + } + + /** + * Data provider. + * + * {@internal This dataprovider does not currently contain any tests for + * PHP native tokens which may not exist (depending on the PHPCS version). + * These tests are not relevant at this time with the current minimum + * PHPCS version of 3.7.1, but this may change again in the future.} + * + * @return array + */ + public function dataTokenExists() + { + return [ + 'Token which doesn\'t exist either way' => [ + 'name' => 'T_DOESNOTEXIST', + 'expected' => false, + ], + 'PHP native token which always exists' => [ + 'name' => 'T_FUNCTION', + 'expected' => true, + ], + 'PHPCS native token which always exists (in the PHPCS versions supported)' => [ + 'name' => 'T_CLOSURE', + 'expected' => true, + ], + 'Mocked polyfilled token' => [ + 'name' => 'T_FAKETOKEN', + 'expected' => false, + ], + ]; + } +} diff --git a/Tests/TypeProviderHelper.php b/Tests/TypeProviderHelper.php new file mode 100644 index 00000000..ca2ae22e --- /dev/null +++ b/Tests/TypeProviderHelper.php @@ -0,0 +1,92 @@ +> + */ + public static function getAll() + { + return [ + 'null' => [ + 'input' => null, + ], + 'boolean false' => [ + 'input' => false, + ], + 'boolean true' => [ + 'input' => true, + ], + 'integer 0' => [ + 'input' => 0, + ], + 'negative integer' => [ + 'input' => -123, + ], + 'positive integer' => [ + 'input' => 786687, + ], + 'float 0.0' => [ + 'input' => 0.0, + ], + 'negative float' => [ + 'input' => 5.600e-3, + ], + 'positive float' => [ + 'input' => 124.7, + ], + 'empty string' => [ + 'input' => '', + ], + 'numeric string' => [ + 'input' => '123', + ], + 'textual string' => [ + 'input' => 'foobar', + ], + 'textual string starting with numbers' => [ + 'input' => '123 My Street', + ], + 'empty array' => [ + 'input' => [], + ], + 'array with values, no keys' => [ + 'input' => [1, 2, 3], + ], + 'array with values, string keys' => [ + 'input' => ['a' => 1, 'b' => 2], + ], + 'plain object' => [ + 'input' => new stdClass(), + ], + 'ArrayIterator object' => [ + 'input' => new ArrayIterator([1, 2, 3]), + ], + 'Iterator object, no array access' => [ + 'input' => new EmptyIterator(), + ], + ]; + } +} diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc index 0d1b31d4..c0e6a866 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc @@ -67,10 +67,10 @@ $array = [ }, /* testNoArrowValueClosureYieldWithKey */ - function() { yield 'k' => $x }, + function() { yield 'k' => $x; }, /* testArrowKeyClosureYieldWithKey */ - function() { yield 'k' => $x }() => 'value', + function() { yield 'k' => $x; }() => 'value', /* testFnFunctionWithKey */ 'fn' => fn ($x) => yield 'k' => $x, @@ -87,6 +87,30 @@ $array = [ /* testDoubleArrowTokenizedAsTstring-PHPCS2865 */ $obj->fn => 'value', + /* testNoArrowValueMatchExpr */ + match($a) { + FOO => BAR, + default => [0 => BAZ], + }, + + /* testArrowValueMatchExpr */ + 'key' => match($a) { + [0 => 10] => BAR, + default => BAZ, + }, + + /* testArrowKeyMatchExpr */ + match($a) { + FOO => BAR, + default => [0 => 10], + } => 'value', + + /* testNoArrowValueClosureWithAttribute */ + #[MyAttribute([0 => 'value'])] function() { /* do something */ }(), + + /* testArrowKeyClosureWithAttribute */ + #[MyAttribute([0 => 'value'])] function() { /* do something */ }() => 'value', + /* testEmptyArrayItem */ // Intentional parse error. , diff --git a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php index c1f44113..8ff7fa75 100644 --- a/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php +++ b/Tests/Utils/Arrays/GetDoubleArrowPtrTest.php @@ -10,6 +10,7 @@ namespace PHPCSUtils\Tests\Utils\Arrays; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Utils\Arrays; use PHPCSUtils\Utils\PassedParameters; @@ -23,7 +24,7 @@ * * @since 1.0.0 */ -class GetDoubleArrowPtrTest extends UtilityMethodTestCase +final class GetDoubleArrowPtrTest extends UtilityMethodTestCase { /** @@ -49,7 +50,7 @@ protected function setUpCache() $target = $this->getTargetToken('/* testGetDoubleArrowPtr */', [\T_OPEN_SHORT_ARRAY]); $parameters = PassedParameters::getParameters(self::$phpcsFile, $target); - foreach ($parameters as $index => $values) { + foreach ($parameters as $values) { \preg_match('`^(/\* test[^*]+ \*/)`', $values['raw'], $matches); if (empty($matches[1]) === false) { self::$parameters[$matches[1]] = $values; @@ -141,86 +142,154 @@ public function dataGetDoubleArrowPtr() { return [ 'test-no-arrow' => [ - '/* testValueNoArrow */', - false, + 'testMarker' => '/* testValueNoArrow */', + 'expected' => false, ], 'test-arrow-numeric-index' => [ - '/* testArrowNumericIndex */', - 8, + 'testMarker' => '/* testArrowNumericIndex */', + 'expected' => 8, ], 'test-arrow-string-index' => [ - '/* testArrowStringIndex */', - 8, + 'testMarker' => '/* testArrowStringIndex */', + 'expected' => 8, ], 'test-arrow-multi-token-index' => [ - '/* testArrowMultiTokenIndex */', - 12, + 'testMarker' => '/* testArrowMultiTokenIndex */', + 'expected' => 12, ], 'test-no-arrow-value-short-array' => [ - '/* testNoArrowValueShortArray */', - false, + 'testMarker' => '/* testNoArrowValueShortArray */', + 'expected' => false, ], 'test-no-arrow-value-long-array' => [ - '/* testNoArrowValueLongArray */', - false, + 'testMarker' => '/* testNoArrowValueLongArray */', + 'expected' => false, ], 'test-no-arrow-value-nested-arrays' => [ - '/* testNoArrowValueNestedArrays */', - false, + 'testMarker' => '/* testNoArrowValueNestedArrays */', + 'expected' => false, ], 'test-no-arrow-value-closure' => [ - '/* testNoArrowValueClosure */', - false, + 'testMarker' => '/* testNoArrowValueClosure */', + 'expected' => false, ], 'test-arrow-value-short-array' => [ - '/* testArrowValueShortArray */', - 8, + 'testMarker' => '/* testArrowValueShortArray */', + 'expected' => 8, ], 'test-arrow-value-long-array' => [ - '/* testArrowValueLongArray */', - 8, + 'testMarker' => '/* testArrowValueLongArray */', + 'expected' => 8, ], 'test-arrow-value-closure' => [ - '/* testArrowValueClosure */', - 8, + 'testMarker' => '/* testArrowValueClosure */', + 'expected' => 8, ], 'test-no-arrow-value-anon-class-with-foreach' => [ - '/* testNoArrowValueAnonClassForeach */', - false, + 'testMarker' => '/* testNoArrowValueAnonClassForeach */', + 'expected' => false, ], 'test-no-arrow-value-closure-with-keyed-yield' => [ - '/* testNoArrowValueClosureYieldWithKey */', - false, + 'testMarker' => '/* testNoArrowValueClosureYieldWithKey */', + 'expected' => false, ], 'test-arrow-key-closure-with-keyed-yield' => [ - '/* testArrowKeyClosureYieldWithKey */', - 24, + 'testMarker' => '/* testArrowKeyClosureYieldWithKey */', + 'expected' => 25, ], 'test-arrow-value-fn-function' => [ - '/* testFnFunctionWithKey */', - 8, + 'testMarker' => '/* testFnFunctionWithKey */', + 'expected' => 8, ], 'test-no-arrow-value-fn-function' => [ - '/* testNoArrowValueFnFunction */', - false, + 'testMarker' => '/* testNoArrowValueFnFunction */', + 'expected' => false, ], 'test-arrow-tstring-key-not-fn-function' => [ - '/* testTstringKeyNotFnFunction */', - 8, + 'testMarker' => '/* testTstringKeyNotFnFunction */', + 'expected' => 8, ], // Test specifically for PHPCS 3.5.3 and 3.5.4 in which all "fn" tokens were tokenized as T_FN. + // While PHPCS < 3.7.1 is no longer supported, the test remains to safeguard against tokenizer regressions. 'test-arrow-access-to-property-named-fn-as-key-phpcs-3.5.3-3.5.4' => [ - '/* testKeyPropertyAccessFnPHPCS353-354 */', - 12, + 'testMarker' => '/* testKeyPropertyAccessFnPHPCS353-354 */', + 'expected' => 12, ], 'test-double-arrow-incorrectly-tokenized-phpcs-issue-2865' => [ - '/* testDoubleArrowTokenizedAsTstring-PHPCS2865 */', - 10, + 'testMarker' => '/* testDoubleArrowTokenizedAsTstring-PHPCS2865 */', + 'expected' => 10, ], + + // Safeguard that PHP 8.0 match expressions are handled correctly. + 'test-no-arrow-value-match-expression' => [ + 'testMarker' => '/* testNoArrowValueMatchExpr */', + 'expected' => false, + ], + 'test-double-arrow-value-match-expression' => [ + 'testMarker' => '/* testArrowValueMatchExpr */', + 'expected' => 8, + ], + 'test-double-arrow-key-match-expression' => [ + 'testMarker' => '/* testArrowKeyMatchExpr */', + 'expected' => 38, + ], + + // Safeguard that double arrows in PHP 8.0 attributes are disregarded. + 'test-no-arrow-value-closure-with-attached-attribute-containing-arrow' => [ + 'testMarker' => '/* testNoArrowValueClosureWithAttribute */', + 'expected' => false, + ], + 'test-double-arrow-key-closure-with-attached-attribute-containing-arrow' => [ + 'testMarker' => '/* testArrowKeyClosureWithAttribute */', + 'expected' => 31, + ], + 'test-empty-array-item' => [ - '/* testEmptyArrayItem */', - false, + 'testMarker' => '/* testEmptyArrayItem */', + 'expected' => false, ], ]; } + + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testResultIsCached() + { + $methodName = 'PHPCSUtils\\Utils\\Arrays::getDoubleArrowPtr'; + $cases = $this->dataGetDoubleArrowPtr(); + $testMarker = $cases['test-arrow-value-short-array']['testMarker']; + $expected = $cases['test-arrow-value-short-array']['expected']; + + if (isset(self::$parameters[$testMarker]) === false) { + $this->fail('Test case not found for ' . $testMarker); + } + + $start = self::$parameters[$testMarker]['start']; + $end = self::$parameters[$testMarker]['end']; + + // Change double arrow position from offset to exact position. + if ($expected !== false) { + $expected += $start; + } + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = Arrays::getDoubleArrowPtr(self::$phpcsFile, $start, $end); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, "$start-$end"); + $resultSecondRun = Arrays::getDoubleArrowPtr(self::$phpcsFile, $start, $end); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } } diff --git a/Tests/Utils/Arrays/GetOpenCloseTest.php b/Tests/Utils/Arrays/GetOpenCloseTest.php index 99445bb2..456bbb55 100644 --- a/Tests/Utils/Arrays/GetOpenCloseTest.php +++ b/Tests/Utils/Arrays/GetOpenCloseTest.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\Arrays; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Arrays; /** @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class GetOpenCloseTest extends UtilityMethodTestCase +final class GetOpenCloseTest extends UtilityMethodTestCase { /** @@ -46,7 +47,7 @@ public function testNonExistentToken() */ public function testNotArrayToken($testMarker) { - $target = $this->getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET]); + $target = $this->getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); $this->assertFalse(Arrays::getOpenClose(self::$phpcsFile, $target)); } @@ -103,49 +104,49 @@ public function dataGetOpenClose() { return [ 'long-array' => [ - '/* testLongArray */', - \T_ARRAY, - [ + 'testMarker' => '/* testLongArray */', + 'targetToken' => \T_ARRAY, + 'expected' => [ 'opener' => 1, 'closer' => 14, ], ], 'long-array-nested' => [ - '/* testNestedLongArray */', - \T_ARRAY, - [ + 'testMarker' => '/* testNestedLongArray */', + 'targetToken' => \T_ARRAY, + 'expected' => [ 'opener' => 2, 'closer' => 6, ], ], 'short-array' => [ - '/* testShortArray */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortArray */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 'opener' => 0, 'closer' => 9, ], ], 'short-array-nested' => [ - '/* testNestedShortArray */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testNestedShortArray */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 'opener' => 0, 'closer' => 2, ], ], 'long-array-with-comments-and-annotations' => [ - '/* testArrayWithCommentsAndAnnotations */', - \T_ARRAY, - [ + 'testMarker' => '/* testArrayWithCommentsAndAnnotations */', + 'targetToken' => \T_ARRAY, + 'expected' => [ 'opener' => 4, 'closer' => 26, ], ], 'parse-error' => [ - '/* testParseError */', - \T_ARRAY, - false, + 'testMarker' => '/* testParseError */', + 'targetToken' => \T_ARRAY, + 'expected' => false, ], ]; } diff --git a/Tests/Utils/Arrays/IsShortArrayTest.inc b/Tests/Utils/Arrays/IsShortArrayTest.inc deleted file mode 100644 index f900264c..00000000 --- a/Tests/Utils/Arrays/IsShortArrayTest.inc +++ /dev/null @@ -1,68 +0,0 @@ - $x1, "y" => $y1], - /* testNestedShortArrayWithKeys_2 */ - 1 => ["x" => $x2, "y" => $y2], - /* testNestedShortArrayWithKeys_3 */ - 'key' => ["x" => $x3, "y" => $y3], -]; - -/* testNestedAnonClassWithTraitUseAs */ -// Parse error, but not our concern, it is short array syntax. -array_map(function($a) { - return new class() { - use MyTrait { - MyTrait::functionName as []; - } - }; -}, $array); - -/* testParseError */ -// Parse error, but not our concern, it is short array syntax. -use Something as [$a]; - -/* testLiveCoding */ -// This has to be the last test in the file. -[$a, /* testLiveCodingNested */ [$b] diff --git a/Tests/Utils/Arrays/IsShortArrayTest.php b/Tests/Utils/Arrays/IsShortArrayTest.php deleted file mode 100644 index fb9b3041..00000000 --- a/Tests/Utils/Arrays/IsShortArrayTest.php +++ /dev/null @@ -1,199 +0,0 @@ -assertFalse(Arrays::isShortArray(self::$phpcsFile, 100000)); - } - - /** - * Test that false is returned when a non-short array token is passed. - * - * @dataProvider dataNotShortArrayToken - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int|string|array $targetToken The token type(s) to look for. - * - * @return void - */ - public function testNotShortArrayToken($testMarker, $targetToken) - { - $target = $this->getTargetToken($testMarker, $targetToken); - $this->assertFalse(Arrays::isShortArray(self::$phpcsFile, $target)); - } - - /** - * Data provider. - * - * @see testNotShortArrayToken() For the array format. - * - * @return array - */ - public function dataNotShortArrayToken() - { - return [ - 'long-array' => [ - '/* testLongArray */', - \T_ARRAY, - ], - 'array-assignment-no-key' => [ - '/* testArrayAssignmentEmpty */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-assignment-string-key' => [ - '/* testArrayAssignmentStringKey */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-assignment-int-key' => [ - '/* testArrayAssignmentIntKey */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-assignment-var-key' => [ - '/* testArrayAssignmentVarKey */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-access-string-key' => [ - '/* testArrayAccessStringKey */', - \T_CLOSE_SQUARE_BRACKET, - ], - 'array-access-int-key-1' => [ - '/* testArrayAccessIntKey1 */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-access-int-key-2' => [ - '/* testArrayAccessIntKey2 */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-access-function-call' => [ - '/* testArrayAccessFunctionCall */', - \T_OPEN_SQUARE_BRACKET, - ], - 'array-access-constant' => [ - '/* testArrayAccessConstant */', - \T_OPEN_SQUARE_BRACKET, - ], - 'live-coding' => [ - '/* testLiveCoding */', - \T_OPEN_SQUARE_BRACKET, - ], - ]; - } - - /** - * Test whether a T_OPEN_SHORT_ARRAY token is a short array. - * - * @dataProvider dataIsShortArray - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param bool $expected The expected boolean return value. - * @param int|string|array $targetToken The token type(s) to test. Defaults to T_OPEN_SHORT_ARRAY. - * - * @return void - */ - public function testIsShortArray($testMarker, $expected, $targetToken = \T_OPEN_SHORT_ARRAY) - { - $stackPtr = $this->getTargetToken($testMarker, $targetToken); - $result = Arrays::isShortArray(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testIsShortArray() For the array format. - * - * @return array - */ - public function dataIsShortArray() - { - return [ - 'short-array-not-nested' => [ - '/* testNonNestedShortArray */', - true, - ], - 'comparison-no-assignment' => [ - '/* testInComparison */', - true, - ], - 'comparison-no-assignment-nested' => [ - '/* testNestedInComparison */', - true, - ], - 'short-array-in-foreach' => [ - '/* testShortArrayInForeach */', - true, - ], - 'short-list-in-foreach' => [ - '/* testShortListInForeach */', - false, - ], - 'chained-assignment-short-list' => [ - '/* testMultiAssignShortlist */', - false, - ], - 'chained-assignment-short-array' => [ - '/* testMultiAssignShortArray */', - true, - \T_CLOSE_SHORT_ARRAY, - ], - 'short-array-with-nesting-and-keys' => [ - '/* testShortArrayWithNestingAndKeys */', - true, - ], - 'short-array-nested-with-keys-1' => [ - '/* testNestedShortArrayWithKeys_1 */', - true, - ], - 'short-array-nested-with-keys-2' => [ - '/* testNestedShortArrayWithKeys_2 */', - true, - ], - 'short-array-nested-with-keys-3' => [ - '/* testNestedShortArrayWithKeys_3 */', - true, - ], - 'parse-error-anon-class-trait-use-as' => [ - '/* testNestedAnonClassWithTraitUseAs */', - true, - ], - 'parse-error-use-as' => [ - '/* testParseError */', - true, - ], - 'parse-error-live-coding' => [ - '/* testLiveCodingNested */', - true, - ], - ]; - } -} diff --git a/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php b/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php deleted file mode 100644 index 4a649b94..00000000 --- a/Tests/Utils/Arrays/IsShortArrayTokenizerBC1Test.php +++ /dev/null @@ -1,129 +0,0 @@ -getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET]); - $result = Arrays::isShortArray(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testIsShortArray() For the array format. - * - * @return array - */ - public function dataIsShortArray() - { - return [ - 'issue-1971-list-first-in-file' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271A */', - false, - ], - 'issue-1971-list-first-in-file-nested' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271B */', - false, - ], - 'issue-1381-array-dereferencing-1-array' => [ - '/* testTokenizerIssue1381PHPCSlt290A1 */', - true, - ], - 'issue-1381-array-dereferencing-1-deref' => [ - '/* testTokenizerIssue1381PHPCSlt290A2 */', - false, - ], - 'issue-1381-array-dereferencing-2' => [ - '/* testTokenizerIssue1381PHPCSlt290B */', - false, - ], - 'issue-1381-array-dereferencing-3' => [ - '/* testTokenizerIssue1381PHPCSlt290C */', - false, - ], - 'issue-1381-array-dereferencing-4' => [ - '/* testTokenizerIssue1381PHPCSlt290D1 */', - false, - ], - 'issue-1381-array-dereferencing-4-deref-deref' => [ - '/* testTokenizerIssue1381PHPCSlt290D2 */', - false, - ], - 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ - '/* testTokenizerIssue1284PHPCSlt280A */', - false, - ], - 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ - '/* testTokenizerIssue1284PHPCSlt280B */', - true, - ], - 'issue-1284-array-access-variable-variable' => [ - '/* testTokenizerIssue1284PHPCSlt290C */', - false, - ], - 'issue-1284-array-access-variable-property' => [ - '/* testTokenizerIssue1284PHPCSlt280D */', - false, - ], - ]; - } -} diff --git a/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php b/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php deleted file mode 100644 index 4b975324..00000000 --- a/Tests/Utils/Arrays/IsShortArrayTokenizerBC2Test.php +++ /dev/null @@ -1,90 +0,0 @@ -getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET]); - $result = Arrays::isShortArray(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testIsShortArray() For the array format. - * - * @return array - */ - public function dataIsShortArray() - { - return [ - // Make sure the utility method does not throw false positives for short array at start of file. - 'issue-1971-short-array-first-in-file' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271C */', - true, - ], - 'issue-1971-short-array-first-in-file-nested' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271D */', - true, - ], - ]; - } -} diff --git a/Tests/Utils/Arrays/README-IsShortArrayTests.md b/Tests/Utils/Arrays/README-IsShortArrayTests.md new file mode 100644 index 00000000..a76e8c56 --- /dev/null +++ b/Tests/Utils/Arrays/README-IsShortArrayTests.md @@ -0,0 +1,4 @@ +# Regarding tests for `Arrays::isShortArray()` + +The `Arrays::isShortArray()` method is tested together with the `Lists::isShortList()` method. +The tests for this can be found in the `Tests/Internal/IsShortArrayOrList` folder. diff --git a/Tests/Utils/Conditions/GetConditionTest.php b/Tests/Utils/Conditions/GetConditionTest.php index a3e6cb6b..e2dcc63c 100644 --- a/Tests/Utils/Conditions/GetConditionTest.php +++ b/Tests/Utils/Conditions/GetConditionTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetConditionTest extends BCFile_GetConditionTest +final class GetConditionTest extends BCFile_GetConditionTest { /** @@ -103,7 +103,12 @@ public function testGetConditionMultipleTypes() */ public function testNonConditionalTokenGetFirstLast() { - $stackPtr = $this->getTargetToken('/* testStartPoint */', \T_STRING); + $targetType = \T_STRING; + if (parent::usesPhp8NameTokens() === true) { + $targetType = \T_NAME_QUALIFIED; + } + + $stackPtr = $this->getTargetToken('/* testStartPoint */', $targetType); $result = Conditions::getFirstCondition(self::$phpcsFile, $stackPtr); $this->assertFalse($result, 'Failed asserting that getFirstCondition() on non conditional token returns false'); @@ -194,32 +199,32 @@ public function dataGetLastCondition() { return [ 'testSeriouslyNestedMethod' => [ - '/* testSeriouslyNestedMethod */', - [ + 'testMarker' => '/* testSeriouslyNestedMethod */', + 'expected' => [ 'no type' => '/* condition 5: nested class */', 'T_IF' => '/* condition 4: if */', 'OO tokens' => '/* condition 5: nested class */', ], ], 'testDeepestNested' => [ - '/* testDeepestNested */', - [ + 'testMarker' => '/* testDeepestNested */', + 'expected' => [ 'no type' => '/* condition 13: closure */', 'T_IF' => '/* condition 10-1: if */', 'OO tokens' => '/* condition 11-1: nested anonymous class */', ], ], 'testInException' => [ - '/* testInException */', - [ + 'testMarker' => '/* testInException */', + 'expected' => [ 'no type' => '/* condition 11-3: catch */', 'T_IF' => '/* condition 4: if */', 'OO tokens' => '/* condition 5: nested class */', ], ], 'testInDefault' => [ - '/* testInDefault */', - [ + 'testMarker' => '/* testInDefault */', + 'expected' => [ 'no type' => '/* condition 8b: default */', 'T_IF' => '/* condition 4: if */', 'OO tokens' => '/* condition 5: nested class */', diff --git a/Tests/Utils/Context/InAttributeTest.inc b/Tests/Utils/Context/InAttributeTest.inc new file mode 100644 index 00000000..75298e9e --- /dev/null +++ b/Tests/Utils/Context/InAttributeTest.inc @@ -0,0 +1,18 @@ + $something; + +/* testMultiLineAttributeWithVars */ +// Illegal syntax, vars not allowed in attribute, but not our concern. +#[ + MyAttribute([$a, $b]) +] +function foo() {} + +/* testParseError */ +#[ + UnClosedAttribute() diff --git a/Tests/Utils/Context/InAttributeTest.php b/Tests/Utils/Context/InAttributeTest.php new file mode 100644 index 00000000..95333014 --- /dev/null +++ b/Tests/Utils/Context/InAttributeTest.php @@ -0,0 +1,167 @@ +assertFalse(Context::inAttribute(self::$phpcsFile, 10000)); + } + + /** + * Test correctly identifying that an arbitrary token is NOT within an attribute. + * + * @dataProvider dataNotInAttribute + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testNotInAttribute($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertFalse(Context::inAttribute(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testInAttribute() + * + * @return array + */ + public function dataNotInAttribute() + { + return [ + 'code nowhere near an attribute [1]' => [ + 'testMarker' => '/* testNotAttribute */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + ], + 'code nowhere near an attribute [2]' => [ + 'testMarker' => '/* testNotAttribute */', + 'targetType' => \T_SELF, + ], + + 'code directly before an attribute (same line)' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_VARIABLE, + ], + 'attribute opener' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_ATTRIBUTE, + ], + 'attribute closer' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_ATTRIBUTE_END, + ], + 'code directly after an attribute (same line)' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_FN, + ], + + 'code directly after an attribute (different line)' => [ + 'testMarker' => '/* testMultiLineAttributeWithVars */', + 'targetType' => \T_FUNCTION, + ], + + 'code in an unclosed attribute (parse error)' => [ + 'testMarker' => '/* testParseError */', + 'targetType' => \T_STRING, + ], + ]; + } + + /** + * Test correctly identifying that an arbitrary token IS within an attribute. + * + * @dataProvider dataInAttribute + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string|array $targetType The token type(s) to look for. + * + * @return void + */ + public function testInAttribute($testMarker, $targetType) + { + $target = $this->getTargetToken($testMarker, $targetType); + $this->assertTrue(Context::inAttribute(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testInAttribute() + * + * @return array + */ + public function dataInAttribute() + { + return [ + 'single line attribute - attribute name' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_STRING, + ], + 'single line attribute - attribute param [1]' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_LNUMBER, + ], + 'single line attribute - comma in attribute param sequence' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_COMMA, + ], + 'single line attribute - attribute param [2]' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_SELF, + ], + 'single line attribute - close parenthesis' => [ + 'testMarker' => '/* testAttribute */', + 'targetType' => \T_CLOSE_PARENTHESIS, + ], + + 'multi line attribute - attribute name' => [ + 'testMarker' => '/* testMultiLineAttributeWithVars */', + 'targetType' => \T_STRING, + ], + 'multi line attribute - attribute param [1]' => [ + 'testMarker' => '/* testMultiLineAttributeWithVars */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + ], + 'multi line attribute - attribute param [2]' => [ + 'testMarker' => '/* testMultiLineAttributeWithVars */', + 'targetType' => \T_VARIABLE, + ], + 'multi line attribute - close parenthesis' => [ + 'testMarker' => '/* testMultiLineAttributeWithVars */', + 'targetType' => \T_CLOSE_PARENTHESIS, + ], + ]; + } +} diff --git a/Tests/Utils/Context/InEmptyTest.inc b/Tests/Utils/Context/InEmptyTest.inc new file mode 100644 index 00000000..bc93b6e6 --- /dev/null +++ b/Tests/Utils/Context/InEmptyTest.inc @@ -0,0 +1,17 @@ +empty($target); + +/* testOwnerNotEmpty */ +if ($target + 1 > 10) {} + +/* testInEmpty */ +$a = empty($target); + +/* testInEmptynested */ +if ((Empty($obj->methodCall($target->prop)) || $somethingElse)) {} + +/* testParseError */ +// This has to be the last test in the file. +empty($target diff --git a/Tests/Utils/Context/InEmptyTest.php b/Tests/Utils/Context/InEmptyTest.php new file mode 100644 index 00000000..0a49654a --- /dev/null +++ b/Tests/Utils/Context/InEmptyTest.php @@ -0,0 +1,86 @@ +assertFalse(Context::inEmpty(self::$phpcsFile, 10000)); + } + + /** + * Test correctly identifying that an arbitrary token is within an empty(). + * + * @dataProvider dataInEmpty + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $expected The expected function return value. + * + * @return void + */ + public function testInEmpty($testMarker, $expected) + { + $target = $this->getTargetToken($testMarker, \T_VARIABLE, '$target'); + $this->assertSame($expected, Context::inEmpty(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testInEmpty() + * + * @return array + */ + public function dataInEmpty() + { + return [ + 'method-called-empty' => [ + 'testMarker' => '/* testNotEmptyMethodCall */', + 'expected' => false, + ], + 'owner-not-empty' => [ + 'testMarker' => '/* testOwnerNotEmpty */', + 'expected' => false, + ], + 'in-empty' => [ + 'testMarker' => '/* testInEmpty */', + 'expected' => true, + ], + 'in-empty-nested' => [ + 'testMarker' => '/* testInEmptynested */', + 'expected' => true, + ], + 'parse-error' => [ + 'testMarker' => '/* testParseError */', + 'expected' => false, + ], + ]; + } +} diff --git a/Tests/Utils/Context/InForConditionTest.inc b/Tests/Utils/Context/InForConditionTest.inc new file mode 100644 index 00000000..9352d86e --- /dev/null +++ b/Tests/Utils/Context/InForConditionTest.inc @@ -0,0 +1,64 @@ + 10) {} + +/* testOwnerNotForNestedParentheses */ +foreach (function_call(array($target)) as $value) {} + +/* testNotForMethodCall */ +$obj->for ($target) {} + +/* testForParseErrorTwoExpressions */ +for ($i = $target; $i < 10) {} // Intentional parse error. + +/* testForParseErrorFourExpressions */ +for ($i = $target; $i < 10; $i++; $nonsense) {} // Intentional parse error. + +/* testFor */ +for ($i = 0; $i < 10; $target++) : + // Do something. +endfor; + +/* testForMultipleStatementsInExpr */ +for ($i = 0, $c = namespace\sizeof($target); $i < $c /* testForSecondSemicolon */ ; $j += $i, print $i, ++$i) {} + +/* testForEmptyExpr1 */ +For (; $i < 10; $target + $i) {} + +/* testForEmptyExpr2 */ +for ($target = 0; ; ++$i) {} + +/* testForEmptyExpr3 */ +for ($i = 0; $target > $i;) {} + +/* testForEmptyExpr12 */ +for (;; $next = find($target)) {} + +/* testForEmptyExpr13 */ +for (; $target->valid();) {} + +/* testForEmptyExpr23 */ +for ($i = $target; ; /* Deliberately empty */) {} + +/* testForEmptyExpr123 */ +for (;;) {} + +/* testForWithNestedSemiColon */ +for ($closure = function($a, $b) { return $a * $b; }, $i = 10; $closure($a, $b) < 10; $i++) {} + +/* testNestedFor */ +add_action('something', function($array) { + for($a = call(); $obj->valid($a); $obj->next($a)) {} + return; +}); + +// Intentional parse error. This has to be the last test in the file. +/* testParseError */ +for ($i = $target; $i < 10 diff --git a/Tests/Utils/Context/InForConditionTest.php b/Tests/Utils/Context/InForConditionTest.php new file mode 100644 index 00000000..57531278 --- /dev/null +++ b/Tests/Utils/Context/InForConditionTest.php @@ -0,0 +1,222 @@ +assertFalse(Context::inForCondition(self::$phpcsFile, 10000)); + } + + /** + * Test receiving `false` when the token passed is not in a for condition. + * + * @dataProvider dataNotInFor + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @return void + */ + public function testNotInFor($testMarker) + { + $target = $this->getTargetToken($testMarker, \T_VARIABLE, '$target'); + $this->assertFalse(Context::inForCondition(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testNotInFor() + * + * @return array + */ + public function dataNotInFor() + { + return [ + 'no-parenthesis' => ['/* testNoParentheses */'], + 'no-parenthesis-owner' => ['/* testNoParenthesisOwner */'], + 'owner-not-for' => ['/* testOwnerNotFor */'], + 'owner-not-for-nested-parentheses' => ['/* testOwnerNotForNestedParentheses */'], + 'method-called-for' => ['/* testNotForMethodCall */'], + 'for-two-expressions' => ['/* testForParseErrorTwoExpressions */'], + 'for-four-expressions' => ['/* testForParseErrorFourExpressions */'], + 'parse-error' => ['/* testParseError */'], + ]; + } + + /** + * Test correctly identifying the position of a token in a for condition. + * + * @dataProvider dataInForCondition + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected The expected function return value. + * @param int|string|array $targetType Optional. The token type of the target token. + * Defaults to T_VARIABLE. + * @param string $targetContent Optional. The token content of the target token. + * Defaults to `$target` for `T_VARIABLE`. + * + * @return void + */ + public function testInForCondition($testMarker, $expected, $targetType = \T_VARIABLE, $targetContent = null) + { + if ($targetType === \T_VARIABLE && $targetContent === null) { + $targetContent = '$target'; + } + + $stackPtr = $this->getTargetToken($testMarker, $targetType, $targetContent); + $result = Context::inForCondition(self::$phpcsFile, $stackPtr); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testInForCondition() + * + * @return array + */ + public function dataInForCondition() + { + return [ + 'expr1' => [ + 'testMarker' => '/* testFor */', + 'expected' => 'expr1', + 'targetType' => \T_EQUAL, + ], + 'expr1-semicolon' => [ + 'testMarker' => '/* testFor */', + 'expected' => 'expr1', + 'targetType' => \T_SEMICOLON, + ], + 'expr2' => [ + 'testMarker' => '/* testFor */', + 'expected' => 'expr2', + 'targetType' => \T_LNUMBER, + 'targetContent' => '10', + ], + 'expr3' => [ + 'testMarker' => '/* testFor */', + 'expected' => 'expr3', + ], + 'multi-expression-expr1' => [ + 'testMarker' => '/* testForMultipleStatementsInExpr */', + 'expected' => 'expr1', + ], + 'multi-expression-expr2' => [ + 'testMarker' => '/* testForMultipleStatementsInExpr */', + 'expected' => 'expr2', + 'targetType' => \T_LESS_THAN, + ], + 'multi-expression-expr2-semicolon' => [ + 'testMarker' => '/* testForSecondSemicolon */', + 'expected' => 'expr2', + 'targetType' => \T_SEMICOLON, + ], + 'multi-expression-expr3' => [ + 'testMarker' => '/* testForSecondSemicolon */', + 'expected' => 'expr3', + 'targetType' => \T_PRINT, + ], + 'empty-1-expr2' => [ + 'testMarker' => '/* testForEmptyExpr1 */', + 'expected' => 'expr2', + 'targetType' => \T_LNUMBER, + 'targetContent' => '10', + ], + 'empty-1-expr3' => [ + 'testMarker' => '/* testForEmptyExpr1 */', + 'expected' => 'expr3', + ], + 'empty-2-expr1' => [ + 'testMarker' => '/* testForEmptyExpr2 */', + 'expected' => 'expr1', + ], + 'empty-2-expr3' => [ + 'testMarker' => '/* testForEmptyExpr2 */', + 'expected' => 'expr3', + 'targetType' => \T_INC, + ], + 'empty-3-expr1' => [ + 'testMarker' => '/* testForEmptyExpr3 */', + 'expected' => 'expr1', + 'targetType' => \T_VARIABLE, + 'targetContent' => '$i', + ], + 'empty-3-expr2' => [ + 'testMarker' => '/* testForEmptyExpr3 */', + 'expected' => 'expr2', + ], + 'empty-12-expr3' => [ + 'testMarker' => '/* testForEmptyExpr12 */', + 'expected' => 'expr3', + ], + 'empty-13-expr2' => [ + 'testMarker' => '/* testForEmptyExpr13 */', + 'expected' => 'expr2', + ], + 'empty-23-expr1' => [ + 'testMarker' => '/* testForEmptyExpr23 */', + 'expected' => 'expr1', + ], + 'empty-23-expr3' => [ + 'testMarker' => '/* testForEmptyExpr23 */', + 'expected' => 'expr3', + 'targetType' => \T_COMMENT, + ], + 'empty-123-expr1' => [ + 'testMarker' => '/* testForEmptyExpr123 */', + 'expected' => 'expr1', + 'targetType' => \T_SEMICOLON, + ], + 'nested-semicolon-expr1' => [ + 'testMarker' => '/* testForWithNestedSemiColon */', + 'expected' => 'expr1', + 'targetType' => \T_RETURN, + ], + 'nested-semicolon-expr2' => [ + 'testMarker' => '/* testForWithNestedSemiColon */', + 'expected' => 'expr2', + 'targetType' => \T_LESS_THAN, + ], + 'nested-semicolon-expr3' => [ + 'testMarker' => '/* testForWithNestedSemiColon */', + 'expected' => 'expr3', + 'targetType' => \T_INC, + ], + 'nested-for-expr2' => [ + 'testMarker' => '/* testNestedFor */', + 'expected' => 'expr2', + 'targetType' => \T_STRING, + 'targetContent' => 'valid', + ], + ]; + } +} diff --git a/Tests/Utils/Context/InForeachConditionTest.inc b/Tests/Utils/Context/InForeachConditionTest.inc new file mode 100644 index 00000000..f5ba6946 --- /dev/null +++ b/Tests/Utils/Context/InForeachConditionTest.inc @@ -0,0 +1,52 @@ + 10) {} + +/* testOwnerNotForeachNestedParentheses */ +for ($i = 1; function_call(array($target)) < 10; $i++) {} + +/* testNotForeachMethodCall */ +$obj->foreach ($target) {} + +/* testForeachWithoutAs */ +foreach ($target) {} // Intentional parse error. + +/* testForeachValue */ +foreach ($array as $value) {} + +/* testForeachKeyValue */ +foreach ($iterator AS $key => $value) {} + +/* testForeachBeforeLongArrayMinimalWhiteSpace */ +foreach (array('a' => 1, 'b' => 2, 3)as$key => $value) {} + +/* testForeachBeforeFunctionCall */ +Foreach (callMe(array($target)) As $key => $value) {} + +/* testForeachVarAfterAsList */ +foreach($array as list($target, $else)) {} + +/* testForeachVarAfterAsShortList */ +foreach($array as [$something, $target]) {} + +/* testForeachVarAfterAsKeyedList */ +foreach ($array as list('id' => $id, 'name' => $target)): + // Do something. +endforeach; + +/* testNestedForeach */ +add_action('something', function($array) { + foreach($array as $target) {} + return; +}); + +// Intentional parse error. This has to be the last test in the file. +/* testParseError */ +foreach ($array as $target {} diff --git a/Tests/Utils/Context/InForeachConditionTest.php b/Tests/Utils/Context/InForeachConditionTest.php new file mode 100644 index 00000000..4ce9f86c --- /dev/null +++ b/Tests/Utils/Context/InForeachConditionTest.php @@ -0,0 +1,185 @@ +assertFalse(Context::inForeachCondition(self::$phpcsFile, 10000)); + } + + /** + * Test receiving `false` when the token passed is not in a foreach condition. + * + * @dataProvider dataNotInForeach + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @return void + */ + public function testNotInForeach($testMarker) + { + $target = $this->getTargetToken($testMarker, \T_VARIABLE, '$target'); + $this->assertFalse(Context::inForeachCondition(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testNotInForeach() + * + * @return array + */ + public function dataNotInForeach() + { + return [ + 'no-parenthesis' => ['/* testNoParentheses */'], + 'no-parenthesis-owner' => ['/* testNoParenthesisOwner */'], + 'owner-not-foreach' => ['/* testOwnerNotForeach */'], + 'owner-not-foreach-nested-parentheses' => ['/* testOwnerNotForeachNestedParentheses */'], + 'method-called-foreach' => ['/* testNotForeachMethodCall */'], + 'foreach-without-as' => ['/* testForeachWithoutAs */'], + 'parse-error' => ['/* testParseError */'], + ]; + } + + /** + * Test correctly identifying the position of a token in a foreach condition. + * + * @dataProvider dataInForeachCondition + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expected The expected function return value. + * @param int|string|array $targetType Optional. The token type of the target token. + * Defaults to T_VARIABLE. + * @param string $targetContent Optional. The token content of the target token. + * Defaults to `$target` for `T_VARIABLE`. + * + * @return void + */ + public function testInForeachCondition($testMarker, $expected, $targetType = \T_VARIABLE, $targetContent = null) + { + if ($targetType === \T_VARIABLE && $targetContent === null) { + $targetContent = '$target'; + } + + $stackPtr = $this->getTargetToken($testMarker, $targetType, $targetContent); + $result = Context::inForeachCondition(self::$phpcsFile, $stackPtr); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testInForeachCondition() + * + * @return array + */ + public function dataInForeachCondition() + { + return [ + 'before' => [ + 'testMarker' => '/* testForeachValue */', + 'expected' => 'beforeAs', + 'targetType' => \T_VARIABLE, + 'targetContent' => '$array', + ], + 'as' => [ + 'testMarker' => '/* testForeachValue */', + 'expected' => 'as', + 'targetType' => \T_AS, + ], + 'after' => [ + 'testMarker' => '/* testForeachValue */', + 'expected' => 'afterAs', + 'targetType' => \T_VARIABLE, + 'targetContent' => '$value', + ], + 'as-caps' => [ + 'testMarker' => '/* testForeachKeyValue */', + 'expected' => 'as', + 'targetType' => \T_AS, + ], + 'after-key' => [ + 'testMarker' => '/* testForeachKeyValue */', + 'expected' => 'afterAs', + 'targetType' => \T_VARIABLE, + 'targetContent' => '$key', + ], + 'before-in-long-array' => [ + 'testMarker' => '/* testForeachBeforeLongArrayMinimalWhiteSpace */', + 'expected' => 'beforeAs', + 'targetType' => \T_LNUMBER, + 'targetContent' => '2', + ], + 'before-function-call' => [ + 'testMarker' => '/* testForeachBeforeFunctionCall */', + 'expected' => 'beforeAs', + 'targetType' => \T_STRING, + ], + 'before-array-nested-in-function-call' => [ + 'testMarker' => '/* testForeachBeforeFunctionCall */', + 'expected' => 'beforeAs', + 'targetType' => \T_ARRAY, + ], + 'before-var-nested-in-array-nested-in-function-call' => [ + 'testMarker' => '/* testForeachBeforeFunctionCall */', + 'expected' => 'beforeAs', + ], + 'after-list' => [ + 'testMarker' => '/* testForeachVarAfterAsList */', + 'expected' => 'afterAs', + 'targetType' => \T_LIST, + ], + 'after-variable-in-list' => [ + 'testMarker' => '/* testForeachVarAfterAsList */', + 'expected' => 'afterAs', + ], + 'after-variable-in-short-list' => [ + 'testMarker' => '/* testForeachVarAfterAsList */', + 'expected' => 'afterAs', + ], + 'after-variable-in-list-value' => [ + 'testMarker' => '/* testForeachVarAfterAsKeyedList */', + 'expected' => 'afterAs', + ], + 'after-variable-in-list-key' => [ + 'testMarker' => '/* testForeachVarAfterAsKeyedList */', + 'expected' => 'afterAs', + 'targetType' => \T_CONSTANT_ENCAPSED_STRING, + 'targetContent' => "'name'", + ], + 'after-foreach-nested-in-closure' => [ + 'testMarker' => '/* testNestedForeach */', + 'expected' => 'afterAs', + ], + ]; + } +} diff --git a/Tests/Utils/Context/InIssetTest.inc b/Tests/Utils/Context/InIssetTest.inc new file mode 100644 index 00000000..a3a87d2f --- /dev/null +++ b/Tests/Utils/Context/InIssetTest.inc @@ -0,0 +1,17 @@ +isset($target); + +/* testOwnerNotIsset */ +if ($target + 1 > 10) {} + +/* testInIsset */ +$a = isset($target); + +/* testInIssetnested */ +if ((Isset($something, $target, $else) || $somethingElse)) {} + +/* testParseError */ +// This has to be the last test in the file. +isset($target diff --git a/Tests/Utils/Context/InIssetTest.php b/Tests/Utils/Context/InIssetTest.php new file mode 100644 index 00000000..e332e75b --- /dev/null +++ b/Tests/Utils/Context/InIssetTest.php @@ -0,0 +1,86 @@ +assertFalse(Context::inIsset(self::$phpcsFile, 10000)); + } + + /** + * Test correctly identifying that an arbitrary token is within an isset(). + * + * @dataProvider dataInIsset + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $expected The expected function return value. + * + * @return void + */ + public function testInIsset($testMarker, $expected) + { + $target = $this->getTargetToken($testMarker, \T_VARIABLE, '$target'); + $this->assertSame($expected, Context::inIsset(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testInIsset() + * + * @return array + */ + public function dataInIsset() + { + return [ + 'method-called-isset' => [ + 'testMarker' => '/* testNotIssetMethodCall */', + 'expected' => false, + ], + 'owner-not-isset' => [ + 'testMarker' => '/* testOwnerNotIsset */', + 'expected' => false, + ], + 'in-isset' => [ + 'testMarker' => '/* testInIsset */', + 'expected' => true, + ], + 'in-isset-nested' => [ + 'testMarker' => '/* testInIssetnested */', + 'expected' => true, + ], + 'parse-error' => [ + 'testMarker' => '/* testParseError */', + 'expected' => false, + ], + ]; + } +} diff --git a/Tests/Utils/Context/InUnsetTest.inc b/Tests/Utils/Context/InUnsetTest.inc new file mode 100644 index 00000000..46d9d5ea --- /dev/null +++ b/Tests/Utils/Context/InUnsetTest.inc @@ -0,0 +1,16 @@ +unset($target); + +function foo() { + /* testOwnerNotUnset */ + if (isset($target) && $target + 1 > 10) { + /* testInUnset */ + Unset($something['a'], $target->prop, $else); + } +} + +/* testParseError */ +// This has to be the last test in the file. +unset($target diff --git a/Tests/Utils/Context/InUnsetTest.php b/Tests/Utils/Context/InUnsetTest.php new file mode 100644 index 00000000..b0b65cae --- /dev/null +++ b/Tests/Utils/Context/InUnsetTest.php @@ -0,0 +1,82 @@ +assertFalse(Context::inUnset(self::$phpcsFile, 10000)); + } + + /** + * Test correctly identifying that an arbitrary token is within an unset(). + * + * @dataProvider dataInUnset + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $expected The expected function return value. + * + * @return void + */ + public function testInUnset($testMarker, $expected) + { + $target = $this->getTargetToken($testMarker, \T_VARIABLE, '$target'); + $this->assertSame($expected, Context::inUnset(self::$phpcsFile, $target)); + } + + /** + * Data provider. + * + * @see testInUnset() + * + * @return array + */ + public function dataInUnset() + { + return [ + 'method-called-unset' => [ + 'testMarker' => '/* testNotUnsetMethodCall */', + 'expected' => false, + ], + 'owner-not-unset' => [ + 'testMarker' => '/* testOwnerNotUnset */', + 'expected' => false, + ], + 'in-unset' => [ + 'testMarker' => '/* testInUnset */', + 'expected' => true, + ], + 'parse-error' => [ + 'testMarker' => '/* testParseError */', + 'expected' => false, + ], + ]; + } +} diff --git a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php index 0c7811a5..0b0b3702 100644 --- a/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php +++ b/Tests/Utils/ControlStructures/GetCaughtExceptionsTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetCaughtExceptionsTest extends UtilityMethodTestCase +final class GetCaughtExceptionsTest extends UtilityMethodTestCase { /** @@ -95,9 +95,11 @@ public function testGetCaughtExceptions($testMarker, $expected) */ public function dataGetCaughtExceptions() { + $php8Names = parent::usesPhp8NameTokens(); + return [ 'single-name-only' => [ - 'target' => '/* testSingleCatchNameOnly */', + 'testMarker' => '/* testSingleCatchNameOnly */', 'expected' => [ [ 'type' => 'RuntimeException', @@ -107,57 +109,57 @@ public function dataGetCaughtExceptions() ], ], 'single-name-leading-backslash' => [ - 'target' => '/* testSingleCatchNameLeadingBackslash */', + 'testMarker' => '/* testSingleCatchNameLeadingBackslash */', 'expected' => [ [ 'type' => '\RuntimeException', 'type_token' => 3, - 'type_end_token' => 4, + 'type_end_token' => ($php8Names === true) ? 3 : 4, ], ], ], 'single-partially-qualified' => [ - 'target' => '/* testSingleCatchPartiallyQualified */', + 'testMarker' => '/* testSingleCatchPartiallyQualified */', 'expected' => [ [ 'type' => 'MyNS\RuntimeException', 'type_token' => 4, - 'type_end_token' => 6, + 'type_end_token' => ($php8Names === true) ? 4 : 6, ], ], ], 'single-fully-qualified' => [ - 'target' => '/* testSingleCatchFullyQualified */', + 'testMarker' => '/* testSingleCatchFullyQualified */', 'expected' => [ [ 'type' => '\MyNS\RuntimeException', 'type_token' => 4, - 'type_end_token' => 7, + 'type_end_token' => ($php8Names === true) ? 4 : 7, ], ], ], 'single-name-with-comments-whitespace' => [ - 'target' => '/* testSingleCatchPartiallyQualifiedWithCommentAndWhitespace */', + 'testMarker' => '/* testSingleCatchPartiallyQualifiedWithCommentAndWhitespace */', 'expected' => [ [ 'type' => 'My\NS\Sub\RuntimeException', 'type_token' => 4, - 'type_end_token' => 15, + 'type_end_token' => ($php8Names === true) ? 13 : 15, ], ], ], 'single-namespace-operator' => [ - 'target' => '/* testSingleCatchNamespaceOperator */', + 'testMarker' => '/* testSingleCatchNamespaceOperator */', 'expected' => [ [ 'type' => 'namespace\RuntimeException', 'type_token' => 4, - 'type_end_token' => 6, + 'type_end_token' => ($php8Names === true) ? 4 : 6, ], ], ], 'multi-unqualified-names' => [ - 'target' => '/* testMultiCatchSingleNames */', + 'testMarker' => '/* testMultiCatchSingleNames */', 'expected' => [ [ 'type' => 'RuntimeException', @@ -178,27 +180,27 @@ public function dataGetCaughtExceptions() ], 'multi-qualified-names' => [ - 'target' => '/* testMultiCatchCompoundNames */', + 'testMarker' => '/* testMultiCatchCompoundNames */', 'expected' => [ [ 'type' => '\NS\RuntimeException', 'type_token' => 3, - 'type_end_token' => 6, + 'type_end_token' => ($php8Names === true) ? 3 : 6, ], [ 'type' => 'My\ParseErrorException', - 'type_token' => 10, - 'type_end_token' => 12, + 'type_token' => ($php8Names === true) ? 7 : 10, + 'type_end_token' => ($php8Names === true) ? 7 : 12, ], [ 'type' => 'namespace\AnotherException', - 'type_token' => 16, - 'type_end_token' => 20, + 'type_token' => ($php8Names === true) ? 11 : 16, + 'type_end_token' => ($php8Names === true) ? 15 : 20, ], ], ], 'non-capturing-catch' => [ - 'target' => '/* testPHP8NonCapturingCatch */', + 'testMarker' => '/* testPHP8NonCapturingCatch */', 'expected' => [ [ 'type' => 'RuntimeException', diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php index fb299040..7b86f993 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError1Test.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Utils\ControlStructures; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; use PHPCSUtils\Utils\ControlStructures; /** @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetDeclareScopeOpenCloseParseError1Test extends UtilityMethodTestCase +final class GetDeclareScopeOpenCloseParseError1Test extends PolyfilledTestCase { /** @@ -32,6 +32,12 @@ class GetDeclareScopeOpenCloseParseError1Test extends UtilityMethodTestCase */ public function testGetDeclareScopeOpenCloseParseError() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $stackPtr = $this->getTargetToken('/* testNoCloseParenthesis */', \T_DECLARE); $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); $this->assertFalse($result); diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php index 791654c1..85adcda2 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError2Test.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Utils\ControlStructures; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; use PHPCSUtils\Utils\ControlStructures; /** @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetDeclareScopeOpenCloseParseError2Test extends UtilityMethodTestCase +final class GetDeclareScopeOpenCloseParseError2Test extends PolyfilledTestCase { /** @@ -32,6 +32,12 @@ class GetDeclareScopeOpenCloseParseError2Test extends UtilityMethodTestCase */ public function testGetDeclareScopeOpenCloseParseError() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $stackPtr = $this->getTargetToken('/* testNoScopeOpener */', \T_DECLARE); $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); $this->assertFalse($result); diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php index 9c87aee0..e4207e43 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError3Test.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Utils\ControlStructures; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; use PHPCSUtils\Utils\ControlStructures; /** @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetDeclareScopeOpenCloseParseError3Test extends UtilityMethodTestCase +final class GetDeclareScopeOpenCloseParseError3Test extends PolyfilledTestCase { /** @@ -32,6 +32,12 @@ class GetDeclareScopeOpenCloseParseError3Test extends UtilityMethodTestCase */ public function testGetDeclareScopeOpenCloseParseError() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $stackPtr = $this->getTargetToken('/* testNoScopeCloser */', \T_DECLARE); $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); $this->assertFalse($result); diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php index e72c1b3b..7e1aa7c5 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseParseError4Test.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Utils\ControlStructures; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tests\PolyfilledTestCase; use PHPCSUtils\Utils\ControlStructures; /** @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetDeclareScopeOpenCloseParseError4Test extends UtilityMethodTestCase +final class GetDeclareScopeOpenCloseParseError4Test extends PolyfilledTestCase { /** @@ -32,6 +32,12 @@ class GetDeclareScopeOpenCloseParseError4Test extends UtilityMethodTestCase */ public function testGetDeclareScopeOpenCloseParseError() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $stackPtr = $this->getTargetToken('/* testUnexpectedToken */', \T_DECLARE); $result = ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $stackPtr); $this->assertFalse($result); diff --git a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc index 964e9b21..057e07ba 100644 --- a/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc +++ b/Tests/Utils/ControlStructures/GetDeclareScopeOpenCloseTest.inc @@ -48,6 +48,24 @@ declare(ticks=1) : } enddeclare; +/* testMultiDirectiveFileScope */ +declare(strict_types=1, encoding='UTF-8'); + +/* testMultiDirectiveBraces */ +declare(strict_types=1, encoding='UTF-8') { + // entire script here +} + +/* testMultiDirectiveAltSyntax */ +declare(strict_types=1, encoding='UTF-8'): + // entire script here +enddeclare; + +/* testPHPCloseTag */ +?> + +expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $this->assertFalse(ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, 10000)); } @@ -42,6 +48,12 @@ public function testNonExistentToken() */ public function testNotDeclare() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $target = $this->getTargetToken('/* testNotDeclare */', \T_ECHO); $this->assertFalse(ControlStructures::getDeclareScopeOpenClose(self::$phpcsFile, $target)); } @@ -58,6 +70,12 @@ public function testNotDeclare() */ public function testGetDeclareScopeOpenClose($testMarker, $expected) { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'ControlStructures::getDeclareScopeOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Check for the "scope_opener"/"scope_closer" keys instead.' + ); + $stackPtr = $this->getTargetToken($testMarker, \T_DECLARE); // Translate offsets to absolute token positions. @@ -81,90 +99,114 @@ public function dataGetDeclareScopeOpenClose() { return [ 'file-scope' => [ - '/* testFileScope */', - false, + 'testMarker' => '/* testFileScope */', + 'expected' => false, ], 'curlies' => [ - '/* testCurlies */', - [ + 'testMarker' => '/* testCurlies */', + 'expected' => [ 'opener' => 7, 'closer' => 11, ], ], 'nested-curlies-outside' => [ - '/* testNestedCurliesOutside */', - [ + 'testMarker' => '/* testNestedCurliesOutside */', + 'expected' => [ 'opener' => 7, 'closer' => 32, ], ], 'nested-curlies-inside' => [ - '/* testNestedCurliesInside */', - [ + 'testMarker' => '/* testNestedCurliesInside */', + 'expected' => [ 'opener' => 12, 'closer' => 17, ], ], 'alternative-syntax' => [ - '/* testAlternativeSyntax */', - [ + 'testMarker' => '/* testAlternativeSyntax */', + 'expected' => [ 'opener' => 7, 'closer' => 11, ], ], 'alternative-syntax-nested-level-1' => [ - '/* testAlternativeSyntaxNestedLevel1 */', - [ + 'testMarker' => '/* testAlternativeSyntaxNestedLevel1 */', + 'expected' => [ 'opener' => 7, 'closer' => 50, ], ], 'alternative-syntax-nested-level-2' => [ - '/* testAlternativeSyntaxNestedLevel2 */', - [ + 'testMarker' => '/* testAlternativeSyntaxNestedLevel2 */', + 'expected' => [ 'opener' => 12, 'closer' => 34, ], ], 'alternative-syntax-nested-level-3' => [ - '/* testAlternativeSyntaxNestedLevel3 */', - [ + 'testMarker' => '/* testAlternativeSyntaxNestedLevel3 */', + 'expected' => [ 'opener' => 7, 'closer' => 12, ], ], 'mixed-nested-level-1' => [ - '/* testMixedNestedLevel1 */', - [ + 'testMarker' => '/* testMixedNestedLevel1 */', + 'expected' => [ 'opener' => 7, 'closer' => 61, ], ], 'mixed-nested-level-2' => [ - '/* testMixedNestedLevel2 */', - [ + 'testMarker' => '/* testMixedNestedLevel2 */', + 'expected' => [ 'opener' => 12, 'closer' => 46, ], ], 'mixed-nested-level-3' => [ - '/* testMixedNestedLevel3 */', - [ + 'testMarker' => '/* testMixedNestedLevel3 */', + 'expected' => [ 'opener' => 7, 'closer' => 24, ], ], 'mixed-nested-level-4' => [ - '/* testMixedNestedLevel4 */', - false, + 'testMarker' => '/* testMixedNestedLevel4 */', + 'expected' => false, + ], + + 'multi-directive-file-scoped' => [ + 'testMarker' => '/* testMultiDirectiveFileScope */', + 'expected' => false, + ], + 'multi-directive-brace-scoped' => [ + 'testMarker' => '/* testMultiDirectiveBraces */', + 'expected' => [ + 'opener' => 12, + 'closer' => 16, + ], + ], + 'multi-directive-alt-syntax' => [ + 'testMarker' => '/* testMultiDirectiveAltSyntax */', + 'expected' => [ + 'opener' => 11, + 'closer' => 15, + ], + ], + + 'php-close-tag' => [ + 'testMarker' => '/* testPHPCloseTag */', + 'expected' => false, ], 'live-coding' => [ - '/* testLiveCoding */', - false, + 'testMarker' => '/* testLiveCoding */', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/ControlStructures/HasBodyParseError1Test.php b/Tests/Utils/ControlStructures/HasBodyParseError1Test.php index 225343d0..3869f40a 100644 --- a/Tests/Utils/ControlStructures/HasBodyParseError1Test.php +++ b/Tests/Utils/ControlStructures/HasBodyParseError1Test.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class HasBodyParseError1Test extends UtilityMethodTestCase +final class HasBodyParseError1Test extends UtilityMethodTestCase { /** diff --git a/Tests/Utils/ControlStructures/HasBodyParseError2Test.php b/Tests/Utils/ControlStructures/HasBodyParseError2Test.php index 1f8f4953..83072b75 100644 --- a/Tests/Utils/ControlStructures/HasBodyParseError2Test.php +++ b/Tests/Utils/ControlStructures/HasBodyParseError2Test.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class HasBodyParseError2Test extends UtilityMethodTestCase +final class HasBodyParseError2Test extends UtilityMethodTestCase { /** diff --git a/Tests/Utils/ControlStructures/HasBodyTest.inc b/Tests/Utils/ControlStructures/HasBodyTest.inc index e0363bb0..d68d3b7d 100644 --- a/Tests/Utils/ControlStructures/HasBodyTest.inc +++ b/Tests/Utils/ControlStructures/HasBodyTest.inc @@ -217,6 +217,28 @@ do echo $i; while (++$i <= 10); + +/* + * PHP 8.0 match expressions. + */ + +/* testMatchEmptyBody */ +// Intentional fatal error, "unhandled match case", but not the concern of this method. +$match = match($a) {}; + +/* testMatchEmptyBodyWithComment */ +// Intentional fatal error, "unhandled match case", but not the concern of this method. +$match = match($a) { + // Deliberately empty. +}; + +/* testMatchWithCode */ +$match = match ($a) { + 0 => 'Foo', + 1 => 'Bar', + 2 => 'Baz', +}; + // Live coding. // Intentional parse error. This test has to be the last in the file. if ($a) { diff --git a/Tests/Utils/ControlStructures/HasBodyTest.php b/Tests/Utils/ControlStructures/HasBodyTest.php index 7182cc47..896ca8e3 100644 --- a/Tests/Utils/ControlStructures/HasBodyTest.php +++ b/Tests/Utils/ControlStructures/HasBodyTest.php @@ -23,7 +23,7 @@ * * @since 1.0.0 */ -class HasBodyTest extends UtilityMethodTestCase +final class HasBodyTest extends UtilityMethodTestCase { /** @@ -62,7 +62,7 @@ public function testNotControlStructure() */ public function testHasBody($testMarker, $hasBody, $hasNonEmptyBody) { - $stackPtr = $this->getTargetToken($testMarker, Collections::$controlStructureTokens); + $stackPtr = $this->getTargetToken($testMarker, Collections::controlStructureTokens()); $result = ControlStructures::hasBody(self::$phpcsFile, $stackPtr); $this->assertSame($hasBody, $result, 'Failed hasBody check with $allowEmpty = true'); @@ -82,239 +82,262 @@ public function dataHasBody() { return [ 'if-without-body' => [ - '/* testIfWithoutBody */', - false, - false, + 'testMarker' => '/* testIfWithoutBody */', + 'hasBody' => false, + 'hasNonEmptyBody' => false, ], 'if-empty-body' => [ - '/* testIfEmptyBody */', - true, - false, + 'testMarker' => '/* testIfEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'elseif-empty-body' => [ - '/* testElseIfEmptyBody */', - true, - false, + 'testMarker' => '/* testElseIfEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'else-if-empty-body' => [ - '/* testElseSpaceIfEmptyBody */', - true, - false, + 'testMarker' => '/* testElseSpaceIfEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'else-empty-body' => [ - '/* testElseEmptyBody */', - true, - false, + 'testMarker' => '/* testElseEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'if-with-code' => [ - '/* testIfWithCode */', - true, - true, + 'testMarker' => '/* testIfWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'elseif-with-code' => [ - '/* testElseIfWithCode */', - true, - true, + 'testMarker' => '/* testElseIfWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'else-if-with-code' => [ - '/* testElseSpaceIfWithCode */', - true, - true, + 'testMarker' => '/* testElseSpaceIfWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'else-with-code' => [ - '/* testElseWithCode */', - true, - true, + 'testMarker' => '/* testElseWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'for-without-body' => [ - '/* testForWithoutBody */', - false, - false, + 'testMarker' => '/* testForWithoutBody */', + 'hasBody' => false, + 'hasNonEmptyBody' => false, ], 'for-empty-body' => [ - '/* testForEmptyBody */', - true, - false, + 'testMarker' => '/* testForEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'for-with-code' => [ - '/* testForWithCode */', - true, - true, + 'testMarker' => '/* testForWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'foreach-without-body' => [ - '/* testForEachWithoutBody */', - false, - false, + 'testMarker' => '/* testForEachWithoutBody */', + 'hasBody' => false, + 'hasNonEmptyBody' => false, ], 'foreach-empty-body' => [ - '/* testForEachEmptyBody */', - true, - false, + 'testMarker' => '/* testForEachEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'foreach-with-code' => [ - '/* testForEachWithCode */', - true, - true, + 'testMarker' => '/* testForEachWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'while-without-body' => [ - '/* testWhileWithoutBody */', - false, - false, + 'testMarker' => '/* testWhileWithoutBody */', + 'hasBody' => false, + 'hasNonEmptyBody' => false, ], 'while-empty-body' => [ - '/* testWhileEmptyBody */', - true, - false, + 'testMarker' => '/* testWhileEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'while-with-code' => [ - '/* testWhileWithCode */', - true, - true, + 'testMarker' => '/* testWhileWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'do-while-empty-body' => [ - '/* testDoWhileEmptyBody */', - true, - false, + 'testMarker' => '/* testDoWhileEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'do-while-with-code' => [ - '/* testDoWhileWithCode */', - true, - true, + 'testMarker' => '/* testDoWhileWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'switch-without-body' => [ - '/* testSwitchWithoutBody */', - false, - false, + 'testMarker' => '/* testSwitchWithoutBody */', + 'hasBody' => false, + 'hasNonEmptyBody' => false, ], 'switch-empty-body' => [ - '/* testSwitchEmptyBody */', - true, - false, + 'testMarker' => '/* testSwitchEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'switch-with-code' => [ - '/* testSwitchWithCode */', - true, - true, + 'testMarker' => '/* testSwitchWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'declare-without-body' => [ - '/* testDeclareWithoutBody */', - false, - false, + 'testMarker' => '/* testDeclareWithoutBody */', + 'hasBody' => false, + 'hasNonEmptyBody' => false, ], 'declare-empty-body' => [ - '/* testDeclareEmptyBody */', - true, - false, + 'testMarker' => '/* testDeclareEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'declare-with-code' => [ - '/* testDeclareWithCode */', - true, - true, + 'testMarker' => '/* testDeclareWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-if-empty-body' => [ - '/* testAlternativeIfEmptyBody */', - true, - false, + 'testMarker' => '/* testAlternativeIfEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'alternative-syntax-elseif-with-code' => [ - '/* testAlternativeElseIfWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeElseIfWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-else-with-code' => [ - '/* testAlternativeElseWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeElseWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-for-empty-body' => [ - '/* testAlternativeForEmptyBody */', - true, - false, + 'testMarker' => '/* testAlternativeForEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'alternative-syntax-for-with-code' => [ - '/* testAlternativeForWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeForWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-foreach-empty-body' => [ - '/* testAlternativeForeachEmptyBody */', - true, - false, + 'testMarker' => '/* testAlternativeForeachEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'alternative-syntax-foreach-with-code' => [ - '/* testAlternativeForeachWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeForeachWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-while-empty-body' => [ - '/* testAlternativeWhileEmptyBody */', - true, - false, + 'testMarker' => '/* testAlternativeWhileEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'alternative-syntax-while-with-code' => [ - '/* testAlternativeWhileWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeWhileWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-switch-empty-body' => [ - '/* testAlternativeSwitchEmptyBody */', - true, - false, + 'testMarker' => '/* testAlternativeSwitchEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'alternative-syntax-switch-with-code' => [ - '/* testAlternativeSwitchWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeSwitchWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'alternative-syntax-declare-empty-body' => [ - '/* testAlternativeDeclareEmptyBody */', - true, - false, + 'testMarker' => '/* testAlternativeDeclareEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], 'alternative-syntax-declare-with-code' => [ - '/* testAlternativeDeclareWithCode */', - true, - true, + 'testMarker' => '/* testAlternativeDeclareWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-if-with-code' => [ - '/* testInlineIfWithCode */', - true, - true, + 'testMarker' => '/* testInlineIfWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-elseif-with-code' => [ - '/* testInlineElseIfWithCode */', - true, - true, + 'testMarker' => '/* testInlineElseIfWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-else-with-code' => [ - '/* testInlineElseWithCode */', - true, - true, + 'testMarker' => '/* testInlineElseWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-for-with-code' => [ - '/* testInlineForWithCode */', - true, - true, + 'testMarker' => '/* testInlineForWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-foreach-with-code' => [ - '/* testInlineForEachWithCode */', - true, - true, + 'testMarker' => '/* testInlineForEachWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-while-with-code' => [ - '/* testInlineWhileWithCode */', - true, - true, + 'testMarker' => '/* testInlineWhileWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], 'inline-do-while-with-code' => [ - '/* testInlineDoWhileWithCode */', - true, - true, + 'testMarker' => '/* testInlineDoWhileWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, ], + + /* + * Match without body cannot be tested as, in that case, `match` will tokenize as `T_STRING`. + * Without body (`match();`), match will either yield a parse error + * or be interpreted as a function call (`\match();` or `self::match()` etc). + */ + + 'match-empty-body' => [ + 'testMarker' => '/* testMatchEmptyBody */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, + ], + 'match-empty-body-comment-only' => [ + 'testMarker' => '/* testMatchEmptyBodyWithComment */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, + ], + 'match-with-code' => [ + 'testMarker' => '/* testMatchWithCode */', + 'hasBody' => true, + 'hasNonEmptyBody' => true, + ], + 'else-live-coding' => [ - '/* testElseLiveCoding */', - true, - false, + 'testMarker' => '/* testElseLiveCoding */', + 'hasBody' => true, + 'hasNonEmptyBody' => false, ], ]; } diff --git a/Tests/Utils/ControlStructures/IsElseIfTest.php b/Tests/Utils/ControlStructures/IsElseIfTest.php index d25dfb2a..cc63b327 100644 --- a/Tests/Utils/ControlStructures/IsElseIfTest.php +++ b/Tests/Utils/ControlStructures/IsElseIfTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsElseIfTest extends UtilityMethodTestCase +final class IsElseIfTest extends UtilityMethodTestCase { /** @@ -74,59 +74,59 @@ public function dataIsElseIf() { return [ 'if' => [ - '/* testIf */', - false, + 'testMarker' => '/* testIf */', + 'expected' => false, ], 'elseif' => [ - '/* testElseIf */', - true, + 'testMarker' => '/* testElseIf */', + 'expected' => true, ], 'else-if' => [ - '/* testElseSpaceIf */', - true, + 'testMarker' => '/* testElseSpaceIf */', + 'expected' => true, ], 'else-if-with-comment-else' => [ - '/* testElseCommentIfElse */', - true, + 'testMarker' => '/* testElseCommentIfElse */', + 'expected' => true, ], 'else-if-with-comment-if' => [ - '/* testElseCommentIfIf */', - true, + 'testMarker' => '/* testElseCommentIfIf */', + 'expected' => true, ], 'else' => [ - '/* testElse */', - false, + 'testMarker' => '/* testElse */', + 'expected' => false, ], 'alternative-syntax-if' => [ - '/* testAlternativeIf */', - false, + 'testMarker' => '/* testAlternativeIf */', + 'expected' => false, ], 'alternative-syntax-elseif' => [ - '/* testAlternativeElseIf */', - true, + 'testMarker' => '/* testAlternativeElseIf */', + 'expected' => true, ], 'alternative-syntax-else' => [ - '/* testAlternativeElse */', - false, + 'testMarker' => '/* testAlternativeElse */', + 'expected' => false, ], 'inline-if' => [ - '/* testInlineIf */', - false, + 'testMarker' => '/* testInlineIf */', + 'expected' => false, ], 'inline-elseif' => [ - '/* testInlineElseIf */', - true, + 'testMarker' => '/* testInlineElseIf */', + 'expected' => true, ], 'inline-else' => [ - '/* testInlineElse */', - false, + 'testMarker' => '/* testInlineElse */', + 'expected' => false, ], 'live-coding' => [ - '/* testLiveCoding */', - false, + 'testMarker' => '/* testLiveCoding */', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc index 0b8c0af4..d9f8c995 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc +++ b/Tests/Utils/FunctionDeclarations/GetParametersDiffTest.inc @@ -1,3 +1,8 @@ 7, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => '?true $var = true', + 'default' => 'true', + 'default_token' => 11, // Offset from the T_FUNCTION token. + 'default_equal_token' => 9, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?true', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + $expected = []; + $expected[0] = [ + 'token' => 8, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => 'true|false $var = true', + 'default' => 'true', + 'default_token' => 12, // Offset from the T_FUNCTION token. + 'default_equal_token' => 10, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'true|false', + 'type_hint_token' => 4, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 6, // Offset from the T_FUNCTION token. + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + + /** + * Test helper. + * + * @param string $marker The comment which preceeds the test. + * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $marker. + * Defaults to the function/closure/arrow tokens. + * + * @return void + */ + protected function getMethodParametersTestHelper($marker, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE, \T_FN]) + { + $target = $this->getTargetToken($marker, $targetType); + $found = FunctionDeclarations::getParameters(self::$phpcsFile, $target); + $expected = $this->updateExpectedTokenPositions($target, $expected); + + $this->assertSame($expected, $found); + } + + /** + * Test helper to translate token offsets to absolute positions in an "expected" array. + * + * @param string $targetPtr The token pointer to the target token from which the offset is calculated. + * @param array $expected The expected function output containing offsets. + * + * @return array + */ + private function updateExpectedTokenPositions($targetPtr, $expected) + { + foreach ($expected as $key => $param) { + $expected[$key]['token'] += $targetPtr; + + if ($param['reference_token'] !== false) { + $expected[$key]['reference_token'] += $targetPtr; + } + if ($param['variadic_token'] !== false) { + $expected[$key]['variadic_token'] += $targetPtr; + } + if ($param['type_hint_token'] !== false) { + $expected[$key]['type_hint_token'] += $targetPtr; + } + if ($param['type_hint_end_token'] !== false) { + $expected[$key]['type_hint_end_token'] += $targetPtr; + } + if ($param['comma_token'] !== false) { + $expected[$key]['comma_token'] += $targetPtr; + } + if (isset($param['default_token'])) { + $expected[$key]['default_token'] += $targetPtr; + } + if (isset($param['default_equal_token'])) { + $expected[$key]['default_equal_token'] += $targetPtr; + } + if (isset($param['visibility_token'])) { + $expected[$key]['visibility_token'] += $targetPtr; + } + if (isset($param['readonly_token'])) { + $expected[$key]['readonly_token'] += $targetPtr; + } + } + + return $expected; + } + + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testResultIsCached() + { + // The test case used is specifically selected to be one which will always reach the cache check. + $methodName = 'PHPCSUtils\\Utils\\FunctionDeclarations::getParameters'; + $testMarker = '/* testPHP82PseudoTypeTrue */'; + $expected = [ + 0 => [ + 'token' => 7, // Offset from the T_FUNCTION token. + 'name' => '$var', + 'content' => '?true $var = true', + 'default' => 'true', + 'default_token' => 11, // Offset from the T_FUNCTION token. + 'default_equal_token' => 9, // Offset from the T_FUNCTION token. + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?true', + 'type_hint_token' => 5, // Offset from the T_FUNCTION token. + 'type_hint_end_token' => 5, // Offset from the T_FUNCTION token. + 'nullable_type' => true, + 'comma_token' => false, + ], + ]; + + $stackPtr = $this->getTargetToken($testMarker, Collections::functionDeclarationTokens()); + $expected = $this->updateExpectedTokenPositions($stackPtr, $expected); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = FunctionDeclarations::getParameters(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, $stackPtr); + $resultSecondRun = FunctionDeclarations::getParameters(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } } diff --git a/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php b/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php index 2efd50cc..e914a62b 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersParseError1Test.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class GetParametersParseError1Test extends UtilityMethodTestCase +final class GetParametersParseError1Test extends UtilityMethodTestCase { /** @@ -54,7 +55,7 @@ public static function setUpTestFile() */ public function testParseError() { - $target = $this->getTargetToken('/* testParseError */', [\T_FUNCTION, \T_CLOSURE]); + $target = $this->getTargetToken('/* testParseError */', Collections::functionDeclarationTokens()); $result = FunctionDeclarations::getParameters(self::$phpcsFile, $target); $this->assertSame([], $result); diff --git a/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php b/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php index ebefed1d..edc7335b 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersParseError2Test.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class GetParametersParseError2Test extends UtilityMethodTestCase +final class GetParametersParseError2Test extends UtilityMethodTestCase { /** @@ -54,7 +55,7 @@ public static function setUpTestFile() */ public function testParseError() { - $target = $this->getTargetToken('/* testParseError */', [\T_FUNCTION, \T_CLOSURE]); + $target = $this->getTargetToken('/* testParseError */', Collections::functionDeclarationTokens()); $result = FunctionDeclarations::getParameters(self::$phpcsFile, $target); $this->assertSame([], $result); diff --git a/Tests/Utils/FunctionDeclarations/GetParametersTest.php b/Tests/Utils/FunctionDeclarations/GetParametersTest.php index ff5e7b8d..43e779f1 100644 --- a/Tests/Utils/FunctionDeclarations/GetParametersTest.php +++ b/Tests/Utils/FunctionDeclarations/GetParametersTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetParametersTest extends BCFile_GetMethodParametersTest +final class GetParametersTest extends BCFile_GetMethodParametersTest { /** @@ -89,11 +89,11 @@ public function testInvalidUse($identifier) * * @param string $commentString The comment which preceeds the test. * @param array $targetTokenType Optional. The token type to search for after $commentString. - * Defaults to the function/closure tokens. + * Defaults to the function/closure/arrow tokens. * * @return void */ - public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T_CLOSURE]) + public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T_CLOSURE, \T_FN]) { $target = $this->getTargetToken($commentString, $targetTokenType); $result = FunctionDeclarations::getParameters(self::$phpcsFile, $target); @@ -104,16 +104,16 @@ public function testNoParams($commentString, $targetTokenType = [\T_FUNCTION, \T /** * Test helper. * - * @param string $commentString The comment which preceeds the test. - * @param array $expected The expected function output. - * @param array $targetType Optional. The token type to search for after $commentString. - * Defaults to the function/closure tokens. + * @param string $marker The comment which preceeds the test. + * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $marker. + * Defaults to the function/closure/arrow tokens. * * @return void */ - protected function getMethodParametersTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) + protected function getMethodParametersTestHelper($marker, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE, \T_FN]) { - $target = $this->getTargetToken($commentString, $targetType); + $target = $this->getTargetToken($marker, $targetType); $found = FunctionDeclarations::getParameters(self::$phpcsFile, $target); foreach ($expected as $key => $param) { @@ -140,6 +140,12 @@ protected function getMethodParametersTestHelper($commentString, $expected, $tar if (isset($param['default_equal_token'])) { $expected[$key]['default_equal_token'] += $target; } + if (isset($param['visibility_token'])) { + $expected[$key]['visibility_token'] += $target; + } + if (isset($param['readonly_token'])) { + $expected[$key]['readonly_token'] += $target; + } } $this->assertSame($expected, $found); diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc index 34138d72..e78b70e9 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.inc @@ -18,7 +18,9 @@ trait FooTrait { } } -/* testReturnTypeEndTokenIndex */ -function myFunction(): ?\MyNamespace /* comment */ - \MyClass // comment - \Foo {} +/* testPHP82PseudoTypeTrue */ +function pseudoTypeTrue(): ?true {} + +/* testPHP82PseudoTypeFalseAndTrue */ +// Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. +function pseudoTypeFalseAndTrue(): true|false {} diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php index 8fee9566..1a0755a6 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesDiffTest.php @@ -25,7 +25,7 @@ * * @since 1.0.0 */ -class GetPropertiesDiffTest extends UtilityMethodTestCase +final class GetPropertiesDiffTest extends UtilityMethodTestCase { /** @@ -87,18 +87,18 @@ public function testMessyPhpcsAnnotationsStaticClosure() } /** - * Test that the new "return_type_end_token" index is set correctly. + * Verify recognition of PHP 8.2 stand-alone `true` type. * * @return void */ - public function testReturnTypeEndTokenIndex() + public function testPHP82PseudoTypeTrue() { $expected = [ 'scope' => 'public', 'scope_specified' => false, - 'return_type' => '?\MyNamespace\MyClass\Foo', + 'return_type' => '?true', 'return_type_token' => 8, // Offset from the T_FUNCTION token. - 'return_type_end_token' => 20, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 8, // Offset from the T_FUNCTION token. 'nullable_return_type' => true, 'is_abstract' => false, 'is_final' => false, @@ -109,17 +109,45 @@ public function testReturnTypeEndTokenIndex() $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); } + /** + * Verify recognition of PHP 8.2 type declaration with (illegal) type false combined with type true. + * + * @return void + */ + public function testPHP82PseudoTypeFalseAndTrue() + { + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'true|false', + 'return_type_token' => 7, // Offset from the T_FUNCTION token. + 'return_type_end_token' => 9, // Offset from the T_FUNCTION token. + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getPropertiesTestHelper('/* ' . __FUNCTION__ . ' */', $expected); + } + /** * Test helper. * * @param string $commentString The comment which preceeds the test. * @param array $expected The expected function output. + * @param array $targetType Optional. The token type to search for after $commentString. + * Defaults to the function/closure tokens. * * @return void */ - protected function getPropertiesTestHelper($commentString, $expected) - { - $function = $this->getTargetToken($commentString, [\T_FUNCTION, \T_CLOSURE]); + protected function getPropertiesTestHelper( + $commentString, + $expected, + $targetType = [\T_FUNCTION, \T_CLOSURE, \T_FN] + ) { + $function = $this->getTargetToken($commentString, $targetType); $found = FunctionDeclarations::getProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { diff --git a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php index 83bafbad..aa0f172e 100644 --- a/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php +++ b/Tests/Utils/FunctionDeclarations/GetPropertiesTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetPropertiesTest extends BCFile_GetMethodPropertiesTest +final class GetPropertiesTest extends BCFile_GetMethodPropertiesTest { /** @@ -75,23 +75,20 @@ public function testNotAFunctionException($commentString, $targetTokenType) * * @return void */ - protected function getMethodPropertiesTestHelper($commentString, $expected, $targetType = [\T_FUNCTION, \T_CLOSURE]) - { + protected function getMethodPropertiesTestHelper( + $commentString, + $expected, + $targetType = [\T_FUNCTION, \T_CLOSURE, \T_FN] + ) { $function = $this->getTargetToken($commentString, $targetType); $found = FunctionDeclarations::getProperties(self::$phpcsFile, $function); if ($expected['return_type_token'] !== false) { $expected['return_type_token'] += $function; } - - /* - * Test the new `return_type_end_token` key which is not in the original datasets. - */ - $this->assertArrayHasKey('return_type_end_token', $found); - $this->assertTrue($found['return_type_end_token'] === false || \is_int($found['return_type_end_token'])); - - // Remove the array key before doing the compare against the original dataset. - unset($found['return_type_end_token']); + if ($expected['return_type_end_token'] !== false) { + $expected['return_type_end_token'] += $function; + } $this->assertSame($expected, $found); } diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php index ca2431fd..17ced8a2 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunction2926Test.php @@ -11,8 +11,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; use PHPCSUtils\BackCompat\Helper; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Tests\PolyfilledTestCase; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -22,7 +21,7 @@ * * These tests are based on the `Tokenizer/BackfillFnTokenTest` file in PHPCS itself. * - * @link https://github.com/squizlabs/php_codesniffer/issues/2926 + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/2926 * * @covers \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction * @covers \PHPCSUtils\Utils\FunctionDeclarations::getArrowFunctionOpenClose @@ -31,7 +30,7 @@ * * @since 1.0.0 */ -class IsArrowFunction2926Test extends UtilityMethodTestCase +final class IsArrowFunction2926Test extends PolyfilledTestCase { /** @@ -94,6 +93,18 @@ public function setUpTestFileForReal() } } + /** + * Reset static properties to their default value after the tests have finished. + * + * @afterClass + * + * @return void + */ + public static function resetProperties() + { + self::$tokenized = false; + } + /** * Test correctly detecting arrow functions. * @@ -108,7 +119,13 @@ public function setUpTestFileForReal() */ public function testIsArrowFunction($testMarker, $expected, $targetContent = null) { - $targets = Collections::arrowFunctionTokensBC(); + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::isArrowFunction() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + + $targets = [\T_FN, \T_STRING]; $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); $this->assertSame($expected['is'], $result); @@ -128,11 +145,17 @@ public function testIsArrowFunction($testMarker, $expected, $targetContent = nul */ public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = 'fn') { - $targets = Collections::arrowFunctionTokensBC(); + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::getArrowFunctionOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + + $targets = [\T_FN, \T_STRING]; $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); // Change from offsets to absolute token positions. - if ($expected['get'] != false) { + if ($expected['get'] !== false) { foreach ($expected['get'] as $key => $value) { $expected['get'][$key] += $stackPtr; } @@ -154,8 +177,8 @@ public function dataArrowFunction() { return [ 'arrow-function-returning-heredoc' => [ - '/* testHeredoc */', - [ + 'testMarker' => '/* testHeredoc */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -166,8 +189,8 @@ public function dataArrowFunction() ], ], 'arrow-function-returning-nowdoc' => [ - '/* testNowdoc */', - [ + 'testMarker' => '/* testNowdoc */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc index 37b96680..733cb236 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.inc @@ -61,9 +61,15 @@ $a = fn($x) => yield 'k' => $x; /* testReturnTypeNamespacedClass */ $fn = fn($x) : ?\My\NS\ClassName => $x; +/* testReturnTypePartiallyQualifiedClass */ +$fn = fn($x) : ?NS\ClassName => $x; + /* testReturnTypeNullableFQNClass */ $a = fn(?\DateTime $x) : ?\DateTime => $x; +/* testNamespaceOperatorInTypes */ +$fn = fn(namespace\Foo $a) : ?namespace\Foo => $a; + /* testReturnTypeSelf */ $fn = fn(self $a) : ?self => $a; @@ -76,6 +82,15 @@ $fn = fn(callable $a) : callable => $a; /* testReturnTypeArray */ $fn = fn(array $a) : array => $a; +/* testReturnTypeStatic */ +$fn = fn(array $a) : static => $a; + +/* testUnionParamType */ +$arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param); + +/* testUnionReturnType */ +$arrowWithUnionReturn = fn($param) : int|float => $param | 10; + /* testReturnTypeArrayBug2773 */ $fn = fn(): array => [a($a, $b)]; @@ -144,6 +159,9 @@ $a = MyNS\Sub\Fn($param); /* testNonArrowNamespaceOperatorFunctionCall */ $a = namespace\fn($param); +/* testNonArrowFunctionNameWithUnionTypes */ +function &fn(int|float $param) : string|null {} + /* testLiveCoding */ // Intentional parse error. This has to be the last test in the file. $fn = fn diff --git a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php index 06ee6265..6c4cb85a 100644 --- a/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php +++ b/Tests/Utils/FunctionDeclarations/IsArrowFunctionTest.php @@ -10,8 +10,7 @@ namespace PHPCSUtils\Tests\Utils\FunctionDeclarations; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Tokens\Collections; +use PHPCSUtils\Tests\PolyfilledTestCase; use PHPCSUtils\Utils\FunctionDeclarations; /** @@ -27,7 +26,7 @@ * * @since 1.0.0 */ -class IsArrowFunctionTest extends UtilityMethodTestCase +final class IsArrowFunctionTest extends PolyfilledTestCase { /** @@ -37,6 +36,12 @@ class IsArrowFunctionTest extends UtilityMethodTestCase */ public function testNonExistentToken() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::isArrowFunction() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, 10000); $this->assertFalse($result, 'Failed isArrowFunction() test'); @@ -51,6 +56,12 @@ public function testNonExistentToken() */ public function testUnsupportedToken() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::isArrowFunction() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + $stackPtr = $this->getTargetToken('/* testConstantDeclaration */', \T_CONST); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); @@ -67,6 +78,12 @@ public function testUnsupportedToken() */ public function testTStringNotFn() { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::isArrowFunction() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + $stackPtr = $this->getTargetToken('/* testNotTheRightContent */', \T_STRING); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); @@ -85,12 +102,25 @@ public function testTStringNotFn() * @param array $expected The expected return value for the respective functions. * @param array $targetContent The content for the target token to look for in case there could * be confusion. + * @param bool $skipOnPHP8 Optional. Whether the test should be skipped when the PHP 8 identifier + * name tokenization is used (as the target token won't exist). + * Defaults to `false`. * * @return void */ - public function testIsArrowFunction($testMarker, $expected, $targetContent = null) + public function testIsArrowFunction($testMarker, $expected, $targetContent = null, $skipOnPHP8 = false) { - $targets = Collections::arrowFunctionTokensBC(); + if ($skipOnPHP8 === true && parent::usesPhp8NameTokens() === true) { + $this->markTestSkipped("PHP 8.0 identifier name tokenization used. Target token won't exist."); + } + + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::isArrowFunction() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + + $targets = [\T_FN, \T_STRING]; $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); $result = FunctionDeclarations::isArrowFunction(self::$phpcsFile, $stackPtr); $this->assertSame($expected['is'], $result); @@ -105,16 +135,29 @@ public function testIsArrowFunction($testMarker, $expected, $targetContent = nul * @param array $expected The expected return value for the respective functions. * @param string $targetContent The content for the target token to look for in case there could * be confusion. + * @param bool $skipOnPHP8 Optional. Whether the test should be skipped when the PHP 8 identifier + * name tokenization is used (as the target token won't exist). + * Defaults to `false`. * * @return void */ - public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = 'fn') + public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetContent = 'fn', $skipOnPHP8 = false) { - $targets = Collections::arrowFunctionTokensBC(); + if ($skipOnPHP8 === true && parent::usesPhp8NameTokens() === true) { + $this->markTestSkipped("PHP 8.0 identifier name tokenization used. Target token won't exist."); + } + + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'FunctionDeclarations::getArrowFunctionOpenClose() function is deprecated since PHPCSUtils 1.0.0-alpha4.' + . ' Use the `T_FN` token instead.' + ); + + $targets = [\T_FN, \T_STRING]; $stackPtr = $this->getTargetToken($testMarker, $targets, $targetContent); // Change from offsets to absolute token positions. - if ($expected['get'] != false) { + if ($expected['get'] !== false) { foreach ($expected['get'] as $key => $value) { $expected['get'][$key] += $stackPtr; } @@ -134,10 +177,12 @@ public function testGetArrowFunctionOpenClose($testMarker, $expected, $targetCon */ public function dataArrowFunction() { + $php8Names = parent::usesPhp8NameTokens(); + return [ 'arrow-function-standard' => [ - '/* testStandard */', - [ + 'testMarker' => '/* testStandard */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -148,8 +193,8 @@ public function dataArrowFunction() ], ], 'arrow-function-mixed-case' => [ - '/* testMixedCase */', - [ + 'testMarker' => '/* testMixedCase */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -158,11 +203,11 @@ public function dataArrowFunction() 'scope_closer' => 12, ], ], - 'Fn', + 'targetContent' => 'Fn', ], 'arrow-function-with-whitespace' => [ - '/* testWhitespace */', - [ + 'testMarker' => '/* testWhitespace */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 2, @@ -173,8 +218,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-comment' => [ - '/* testComment */', - [ + 'testMarker' => '/* testComment */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 4, @@ -185,15 +230,15 @@ public function dataArrowFunction() ], ], 'non-arrow-function-global-function-declaration' => [ - '/* testFunctionName */', - [ + 'testMarker' => '/* testFunctionName */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'arrow-function-nested-outer' => [ - '/* testNestedOuter */', - [ + 'testMarker' => '/* testNestedOuter */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -204,8 +249,8 @@ public function dataArrowFunction() ], ], 'arrow-function-nested-inner' => [ - '/* testNestedInner */', - [ + 'testMarker' => '/* testNestedInner */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -216,8 +261,8 @@ public function dataArrowFunction() ], ], 'arrow-function-function-call' => [ - '/* testFunctionCall */', - [ + 'testMarker' => '/* testFunctionCall */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -228,8 +273,8 @@ public function dataArrowFunction() ], ], 'arrow-function-chained-function-call' => [ - '/* testChainedFunctionCall */', - [ + 'testMarker' => '/* testChainedFunctionCall */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -238,11 +283,11 @@ public function dataArrowFunction() 'scope_closer' => 12, ], ], - 'fn', + 'targetContent' => 'fn', ], 'arrow-function-as-function-argument' => [ - '/* testFunctionArgument */', - [ + 'testMarker' => '/* testFunctionArgument */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -253,8 +298,8 @@ public function dataArrowFunction() ], ], 'arrow-function-nested-closure' => [ - '/* testClosure */', - [ + 'testMarker' => '/* testClosure */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -265,8 +310,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-return-type-nullable-int' => [ - '/* testReturnTypeNullableInt */', - [ + 'testMarker' => '/* testReturnTypeNullableInt */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -277,8 +322,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-reference' => [ - '/* testReference */', - [ + 'testMarker' => '/* testReference */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 2, @@ -289,8 +334,8 @@ public function dataArrowFunction() ], ], 'arrow-function-grouped-within-parenthesis' => [ - '/* testGrouped */', - [ + 'testMarker' => '/* testGrouped */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -301,8 +346,8 @@ public function dataArrowFunction() ], ], 'arrow-function-as-array-value' => [ - '/* testArrayValue */', - [ + 'testMarker' => '/* testArrayValue */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -313,8 +358,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-yield-in-value' => [ - '/* testYield */', - [ + 'testMarker' => '/* testYield */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -325,32 +370,56 @@ public function dataArrowFunction() ], ], 'arrow-function-with-return-type-nullable-namespaced-class' => [ - '/* testReturnTypeNamespacedClass */', - [ + 'testMarker' => '/* testReturnTypeNamespacedClass */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, 'parenthesis_closer' => 3, - 'scope_opener' => 15, - 'scope_closer' => 18, + 'scope_opener' => ($php8Names === true) ? 10 : 15, + 'scope_closer' => ($php8Names === true) ? 13 : 18, + ], + ], + ], + 'arrow-function-with-return-type-nullable-partially-qualified-class' => [ + 'testMarker' => '/* testReturnTypePartiallyQualifiedClass */', + 'expected' => [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => ($php8Names === true) ? 10 : 12, + 'scope_closer' => ($php8Names === true) ? 13 : 15, ], ], ], 'arrow-function-with-fqn-class' => [ - '/* testReturnTypeNullableFQNClass */', - [ + 'testMarker' => '/* testReturnTypeNullableFQNClass */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, - 'parenthesis_closer' => 7, - 'scope_opener' => 15, - 'scope_closer' => 18, + 'parenthesis_closer' => ($php8Names === true) ? 6 : 7, + 'scope_opener' => ($php8Names === true) ? 13 : 15, + 'scope_closer' => ($php8Names === true) ? 16 : 18, + ], + ], + ], + 'arrow-function-with-namespace-operator-in-types' => [ + 'testMarker' => '/* testNamespaceOperatorInTypes */', + 'expected' => [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => ($php8Names === true) ? 5 : 7, + 'scope_opener' => ($php8Names === true) ? 12 : 16, + 'scope_closer' => ($php8Names === true) ? 15 : 19, ], ], ], 'arrow-function-with-return-type-nullable-self' => [ - '/* testReturnTypeSelf */', - [ + 'testMarker' => '/* testReturnTypeSelf */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -361,8 +430,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-return-type-parent' => [ - '/* testReturnTypeParent */', - [ + 'testMarker' => '/* testReturnTypeParent */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -373,8 +442,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-return-type-callable' => [ - '/* testReturnTypeCallable */', - [ + 'testMarker' => '/* testReturnTypeCallable */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -385,8 +454,20 @@ public function dataArrowFunction() ], ], 'arrow-function-with-return-type-array' => [ - '/* testReturnTypeArray */', - [ + 'testMarker' => '/* testReturnTypeArray */', + 'expected' => [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 5, + 'scope_opener' => 11, + 'scope_closer' => 14, + ], + ], + ], + 'arrow-function-with-return-type-static' => [ + 'testMarker' => '/* testReturnTypeStatic */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -396,9 +477,34 @@ public function dataArrowFunction() ], ], ], + + 'arrow-function-with-union-param-type' => [ + 'testMarker' => '/* testUnionParamType */', + 'expected' => [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 7, + 'scope_opener' => 13, + 'scope_closer' => 21, + ], + ], + ], + 'arrow-function-with-union-return-type' => [ + 'testMarker' => '/* testUnionReturnType */', + 'expected' => [ + 'is' => true, + 'get' => [ + 'parenthesis_opener' => 1, + 'parenthesis_closer' => 3, + 'scope_opener' => 11, + 'scope_closer' => 18, + ], + ], + ], 'arrow-function-with-return-type-array-bug-2773' => [ - '/* testReturnTypeArrayBug2773 */', - [ + 'testMarker' => '/* testReturnTypeArrayBug2773 */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -409,8 +515,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-array-param-and-return-type' => [ - '/* testMoreArrayTypeDeclarations */', - [ + 'testMarker' => '/* testMoreArrayTypeDeclarations */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 2, @@ -421,8 +527,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-ternary-content' => [ - '/* testTernary */', - [ + 'testMarker' => '/* testTernary */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -433,8 +539,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-ternary-content-after-then' => [ - '/* testTernaryThen */', - [ + 'testMarker' => '/* testTernaryThen */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -445,8 +551,8 @@ public function dataArrowFunction() ], ], 'arrow-function-with-ternary-content-after-else' => [ - '/* testTernaryElse */', - [ + 'testMarker' => '/* testTernaryElse */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -457,8 +563,8 @@ public function dataArrowFunction() ], ], 'arrow-function-as-function-call-argument' => [ - '/* testArrowFunctionAsArgument */', - [ + 'testMarker' => '/* testArrowFunctionAsArgument */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -469,8 +575,8 @@ public function dataArrowFunction() ], ], 'arrow-function-as-function-call-argument-with-array-return' => [ - '/* testArrowFunctionWithArrayAsArgument */', - [ + 'testMarker' => '/* testArrowFunctionWithArrayAsArgument */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -481,8 +587,8 @@ public function dataArrowFunction() ], ], 'arrow-function-nested-in-method' => [ - '/* testNestedInMethod */', - [ + 'testMarker' => '/* testNestedInMethod */', + 'expected' => [ 'is' => true, 'get' => [ 'parenthesis_opener' => 1, @@ -497,99 +603,109 @@ public function dataArrowFunction() * Use of the "fn" keyword when not an arrow function. */ 'non-arrow-function-const-declaration' => [ - '/* testConstantDeclaration */', - [ + 'testMarker' => '/* testConstantDeclaration */', + 'expected' => [ 'is' => false, 'get' => false, ], - 'FN', + 'targetContent' => 'FN', ], 'non-arrow-function-const-declaration-lowercase' => [ - '/* testConstantDeclarationLower */', - [ + 'testMarker' => '/* testConstantDeclarationLower */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'non-arrow-function-static-method-declaration' => [ - '/* testStaticMethodName */', - [ + 'testMarker' => '/* testStaticMethodName */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'non-arrow-function-assignment-to-property' => [ - '/* testPropertyAssignment */', - [ + 'testMarker' => '/* testPropertyAssignment */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'non-arrow-function-anon-class-method-declaration' => [ - '/* testAnonClassMethodName */', - [ + 'testMarker' => '/* testAnonClassMethodName */', + 'expected' => [ 'is' => false, 'get' => false, ], - 'fN', + 'targetContent' => 'fN', ], 'non-arrow-function-call-to-static-method' => [ - '/* testNonArrowStaticMethodCall */', - [ + 'testMarker' => '/* testNonArrowStaticMethodCall */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'non-arrow-function-class-constant-access' => [ - '/* testNonArrowConstantAccess */', - [ + 'testMarker' => '/* testNonArrowConstantAccess */', + 'expected' => [ 'is' => false, 'get' => false, ], - 'FN', + 'targetContent' => 'FN', ], 'non-arrow-function-class-constant-access-with-deref' => [ - '/* testNonArrowConstantAccessDeref */', - [ + 'testMarker' => '/* testNonArrowConstantAccessDeref */', + 'expected' => [ 'is' => false, 'get' => false, ], - 'Fn', + 'targetContent' => 'Fn', ], 'non-arrow-function-call-to-object-method' => [ - '/* testNonArrowObjectMethodCall */', - [ + 'testMarker' => '/* testNonArrowObjectMethodCall */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'non-arrow-function-call-to-object-method-uppercase' => [ - '/* testNonArrowObjectMethodCallUpper */', - [ + 'testMarker' => '/* testNonArrowObjectMethodCallUpper */', + 'expected' => [ 'is' => false, 'get' => false, ], - 'FN', + 'targetContent' => 'FN', ], 'non-arrow-function-call-to-namespaced-function' => [ - '/* testNonArrowNamespacedFunctionCall */', - [ + 'testMarker' => '/* testNonArrowNamespacedFunctionCall */', + 'expected' => [ 'is' => false, 'get' => false, ], - 'Fn', + 'targetContent' => 'Fn', + 'skipOnPHP8' => true, ], 'non-arrow-function-call-to-namespaced-function-using-namespace-operator' => [ - '/* testNonArrowNamespaceOperatorFunctionCall */', - [ + 'testMarker' => '/* testNonArrowNamespaceOperatorFunctionCall */', + 'expected' => [ + 'is' => false, + 'get' => false, + ], + 'targetContent' => 'fn', + 'skipOnPHP8' => true, + ], + 'non-arrow-function-declaration-with-union-types' => [ + 'testMarker' => '/* testNonArrowFunctionNameWithUnionTypes */', + 'expected' => [ 'is' => false, 'get' => false, ], ], 'live-coding' => [ - '/* testLiveCoding */', - [ + 'testMarker' => '/* testLiveCoding */', + 'expected' => [ 'is' => false, 'get' => false, ], diff --git a/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php b/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php index 03c267d0..0b81a56f 100644 --- a/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php +++ b/Tests/Utils/FunctionDeclarations/IsMagicFunctionNameTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsMagicFunctionNameTest extends TestCase +final class IsMagicFunctionNameTest extends TestCase { /** diff --git a/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php b/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php index 82a48a4b..1ad5f01c 100644 --- a/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php +++ b/Tests/Utils/FunctionDeclarations/IsMagicMethodNameTest.php @@ -16,18 +16,20 @@ /** * Tests for the \PHPCSUtils\Utils\FunctionDeclarations::isMagicMethodName() method. * + * @coversDefaultClass \PHPCSUtils\Utils\FunctionDeclarations + * * @group functiondeclarations * * @since 1.0.0 */ -class IsMagicMethodNameTest extends TestCase +final class IsMagicMethodNameTest extends TestCase { /** * Test valid PHP magic method names. * * @dataProvider dataIsMagicMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicMethodName + * @covers ::isMagicMethodName * * @param string $name The function name to test. * @@ -42,7 +44,7 @@ public function testIsMagicMethodName($name) * Test valid PHP magic method names. * * @dataProvider dataIsMagicMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethodName + * @covers ::isSpecialMethodName * * @param string $name The function name to test. * @@ -108,7 +110,7 @@ public function dataIsMagicMethodName() * Test non-magic method names. * * @dataProvider dataIsNotMagicMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicMethodName + * @covers ::isMagicMethodName * * @param string $name The function name to test. * @@ -123,7 +125,7 @@ public function testIsNotMagicMethodName($name) * Test non-magic method names. * * @dataProvider dataIsNotMagicMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethodName + * @covers ::isSpecialMethodName * * @param string $name The function name to test. * diff --git a/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php b/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php index 2feb771a..f5735666 100644 --- a/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php +++ b/Tests/Utils/FunctionDeclarations/IsPHPDoubleUnderscoreMethodNameTest.php @@ -14,20 +14,23 @@ use PHPUnit\Framework\TestCase; /** - * Tests for the \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethodName() method. + * Tests for the \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethodName() + * and the \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethodName() method. + * + * @coversDefaultClass \PHPCSUtils\Utils\FunctionDeclarations * * @group functiondeclarations * * @since 1.0.0 */ -class IsPHPDoubleUnderscoreMethodNameTest extends TestCase +final class IsPHPDoubleUnderscoreMethodNameTest extends TestCase { /** * Test valid PHP native double underscore method names. * * @dataProvider dataIsPHPDoubleUnderscoreMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethodName + * @covers ::isPHPDoubleUnderscoreMethodName * * @param string $name The function name to test. * @@ -42,7 +45,7 @@ public function testIsPHPDoubleUnderscoreMethodName($name) * Test valid PHP native double underscore method names. * * @dataProvider dataIsPHPDoubleUnderscoreMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethodName + * @covers ::isSpecialMethodName * * @param string $name The function name to test. * @@ -98,7 +101,7 @@ public function dataIsPHPDoubleUnderscoreMethodName() * Test function names which are not valid PHP native double underscore methods. * * @dataProvider dataIsNotPHPDoubleUnderscoreMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethodName + * @covers ::isPHPDoubleUnderscoreMethodName * * @param string $name The function name to test. * @@ -113,7 +116,7 @@ public function testIsNotPHPDoubleUnderscoreMethodName($name) * Test function names which are not valid PHP native double underscore methods. * * @dataProvider dataIsNotPHPDoubleUnderscoreMethodName - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethodName + * @covers ::isSpecialMethodName * * @param string $name The function name to test. * diff --git a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc index ffc59a77..6ff48133 100644 --- a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc +++ b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.inc @@ -49,9 +49,9 @@ $a = new class { function __myFunction() {} }; -class MySoapImplementation extends \SoapClient { +abstract class MySoapImplementation extends \SoapClient { /* testDoubleUnderscoreMethodInClass */ - public function __getCookies() {} + abstract public function __getCookies(); /* testDoubleUnderscoreMethodInClassMixedcase */ public function __getLASTRequestHeaders() {} @@ -86,7 +86,7 @@ interface MagicInterface function __set_state($name, $args); /* testDoubleUnderscoreMethodInInterface */ - public function __setLocation() {} + public function __setLocation(); /* testMagicFunctionInInterfaceNotGlobal */ function __autoload(); diff --git a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php index ae747601..499c64c3 100644 --- a/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php +++ b/Tests/Utils/FunctionDeclarations/SpecialFunctionsTest.php @@ -19,20 +19,22 @@ * \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethod() and the * \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethod() methods. * + * @coversDefaultClass \PHPCSUtils\Utils\FunctionDeclarations + * * @group functiondeclarations * * @since 1.0.0 */ -class SpecialFunctionsTest extends UtilityMethodTestCase +final class SpecialFunctionsTest extends UtilityMethodTestCase { /** * Test that the special function methods return false when passed a non-existent token. * - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicFunction - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicMethod - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethod - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethod + * @covers ::isMagicFunction + * @covers ::isMagicMethod + * @covers ::isPHPDoubleUnderscoreMethod + * @covers ::isSpecialMethod * * @return void */ @@ -54,10 +56,10 @@ public function testNonExistentToken() /** * Test that the special function methods return false when passed a non-function token. * - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicFunction - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicMethod - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethod - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethod + * @covers ::isMagicFunction + * @covers ::isMagicMethod + * @covers ::isPHPDoubleUnderscoreMethod + * @covers ::isSpecialMethod * * @return void */ @@ -82,7 +84,7 @@ public function testNotAFunctionToken() * Test correctly detecting magic functions. * * @dataProvider dataItsAKindOfMagic - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicFunction + * @covers ::isMagicFunction * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected return values for the various functions. @@ -100,7 +102,7 @@ public function testIsMagicFunction($testMarker, $expected) * Test correctly detecting magic methods. * * @dataProvider dataItsAKindOfMagic - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isMagicMethod + * @covers ::isMagicMethod * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected return values for the various functions. @@ -118,7 +120,7 @@ public function testIsMagicMethod($testMarker, $expected) * Test correctly detecting PHP native double underscore methods. * * @dataProvider dataItsAKindOfMagic - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isPHPDoubleUnderscoreMethod + * @covers ::isPHPDoubleUnderscoreMethod * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected return values for the various functions. @@ -136,7 +138,7 @@ public function testIsPHPDoubleUnderscoreMethod($testMarker, $expected) * Test correctly detecting magic methods and double underscore methods. * * @dataProvider dataItsAKindOfMagic - * @covers \PHPCSUtils\Utils\FunctionDeclarations::isSpecialMethod + * @covers ::isSpecialMethod * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected return values for the various functions. @@ -164,8 +166,8 @@ public function dataItsAKindOfMagic() { return [ 'MagicMethodInClass' => [ - '/* testMagicMethodInClass */', - [ + 'testMarker' => '/* testMagicMethodInClass */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -173,8 +175,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodInClassUppercase' => [ - '/* testMagicMethodInClassUppercase */', - [ + 'testMarker' => '/* testMagicMethodInClassUppercase */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -182,8 +184,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodInClassMixedCase' => [ - '/* testMagicMethodInClassMixedCase */', - [ + 'testMarker' => '/* testMagicMethodInClassMixedCase */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -191,8 +193,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicFunctionInClassNotGlobal' => [ - '/* testMagicFunctionInClassNotGlobal */', - [ + 'testMarker' => '/* testMagicFunctionInClassNotGlobal */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -200,8 +202,8 @@ public function dataItsAKindOfMagic() ], ], 'MethodInClassNotMagicName' => [ - '/* testMethodInClassNotMagicName */', - [ + 'testMarker' => '/* testMethodInClassNotMagicName */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -209,8 +211,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodNotInClass' => [ - '/* testMagicMethodNotInClass */', - [ + 'testMarker' => '/* testMagicMethodNotInClass */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -218,8 +220,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicFunction' => [ - '/* testMagicFunction */', - [ + 'testMarker' => '/* testMagicFunction */', + 'expected' => [ 'function' => true, 'method' => false, 'double' => false, @@ -227,8 +229,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicFunctionInConditionMixedCase' => [ - '/* testMagicFunctionInConditionMixedCase */', - [ + 'testMarker' => '/* testMagicFunctionInConditionMixedCase */', + 'expected' => [ 'function' => true, 'method' => false, 'double' => false, @@ -236,8 +238,8 @@ public function dataItsAKindOfMagic() ], ], 'FunctionNotMagicName' => [ - '/* testFunctionNotMagicName */', - [ + 'testMarker' => '/* testFunctionNotMagicName */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -245,8 +247,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodInAnonClass' => [ - '/* testMagicMethodInAnonClass */', - [ + 'testMarker' => '/* testMagicMethodInAnonClass */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -254,8 +256,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodInAnonClassUppercase' => [ - '/* testMagicMethodInAnonClassUppercase */', - [ + 'testMarker' => '/* testMagicMethodInAnonClassUppercase */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -263,8 +265,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicFunctionInAnonClassNotGlobal' => [ - '/* testMagicFunctionInAnonClassNotGlobal */', - [ + 'testMarker' => '/* testMagicFunctionInAnonClassNotGlobal */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -272,8 +274,8 @@ public function dataItsAKindOfMagic() ], ], 'MethodInAnonClassNotMagicName' => [ - '/* testMethodInAnonClassNotMagicName */', - [ + 'testMarker' => '/* testMethodInAnonClassNotMagicName */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -281,8 +283,8 @@ public function dataItsAKindOfMagic() ], ], 'DoubleUnderscoreMethodInClass' => [ - '/* testDoubleUnderscoreMethodInClass */', - [ + 'testMarker' => '/* testDoubleUnderscoreMethodInClass */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => true, @@ -290,8 +292,8 @@ public function dataItsAKindOfMagic() ], ], 'DoubleUnderscoreMethodInClassMixedcase' => [ - '/* testDoubleUnderscoreMethodInClassMixedcase */', - [ + 'testMarker' => '/* testDoubleUnderscoreMethodInClassMixedcase */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => true, @@ -300,8 +302,8 @@ public function dataItsAKindOfMagic() ], 'DoubleUnderscoreMethodInClassNotExtended' => [ - '/* testDoubleUnderscoreMethodInClassNotExtended */', - [ + 'testMarker' => '/* testDoubleUnderscoreMethodInClassNotExtended */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -309,8 +311,8 @@ public function dataItsAKindOfMagic() ], ], 'DoubleUnderscoreMethodNotInClass' => [ - '/* testDoubleUnderscoreMethodNotInClass */', - [ + 'testMarker' => '/* testDoubleUnderscoreMethodNotInClass */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -318,8 +320,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodInTrait' => [ - '/* testMagicMethodInTrait */', - [ + 'testMarker' => '/* testMagicMethodInTrait */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -328,8 +330,8 @@ public function dataItsAKindOfMagic() ], 'DoubleUnderscoreMethodInTrait' => [ - '/* testDoubleUnderscoreMethodInTrait */', - [ + 'testMarker' => '/* testDoubleUnderscoreMethodInTrait */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => true, @@ -337,8 +339,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicFunctionInTraitNotGloba' => [ - '/* testMagicFunctionInTraitNotGlobal */', - [ + 'testMarker' => '/* testMagicFunctionInTraitNotGlobal */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -346,8 +348,8 @@ public function dataItsAKindOfMagic() ], ], 'MethodInTraitNotMagicName' => [ - '/* testMethodInTraitNotMagicName */', - [ + 'testMarker' => '/* testMethodInTraitNotMagicName */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -355,8 +357,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicMethodInInterface' => [ - '/* testMagicMethodInInterface */', - [ + 'testMarker' => '/* testMagicMethodInInterface */', + 'expected' => [ 'function' => false, 'method' => true, 'double' => false, @@ -365,8 +367,8 @@ public function dataItsAKindOfMagic() ], 'DoubleUnderscoreMethodInInterface' => [ - '/* testDoubleUnderscoreMethodInInterface */', - [ + 'testMarker' => '/* testDoubleUnderscoreMethodInInterface */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => true, @@ -374,8 +376,8 @@ public function dataItsAKindOfMagic() ], ], 'MagicFunctionInInterfaceNotGlobal' => [ - '/* testMagicFunctionInInterfaceNotGlobal */', - [ + 'testMarker' => '/* testMagicFunctionInInterfaceNotGlobal */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -383,8 +385,8 @@ public function dataItsAKindOfMagic() ], ], 'MethodInInterfaceNotMagicName' => [ - '/* testMethodInInterfaceNotMagicName */', - [ + 'testMarker' => '/* testMethodInInterfaceNotMagicName */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -393,8 +395,8 @@ public function dataItsAKindOfMagic() ], 'NonMagicMethod' => [ - '/* testNonMagicMethod */', - [ + 'testMarker' => '/* testNonMagicMethod */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -402,8 +404,8 @@ public function dataItsAKindOfMagic() ], ], 'NestedFunctionDeclarationMagicFunction' => [ - '/* testNestedFunctionDeclarationMagicFunction */', - [ + 'testMarker' => '/* testNestedFunctionDeclarationMagicFunction */', + 'expected' => [ 'function' => true, 'method' => false, 'double' => false, @@ -411,8 +413,8 @@ public function dataItsAKindOfMagic() ], ], 'NestedFunctionDeclarationNonMagicFunction' => [ - '/* testNestedFunctionDeclarationNonMagicFunction */', - [ + 'testMarker' => '/* testNestedFunctionDeclarationNonMagicFunction */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, @@ -420,8 +422,8 @@ public function dataItsAKindOfMagic() ], ], 'NestedFunctionDeclarationNonSpecialFunction' => [ - '/* testNestedFunctionDeclarationNonSpecialFunction */', - [ + 'testMarker' => '/* testNestedFunctionDeclarationNonSpecialFunction */', + 'expected' => [ 'function' => false, 'method' => false, 'double' => false, diff --git a/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php b/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php index d08560d4..30f6b6fb 100644 --- a/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php +++ b/Tests/Utils/GetTokensAsString/GetTokensAsStringTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetTokensAsStringTest extends UtilityMethodTestCase +final class GetTokensAsStringTest extends UtilityMethodTestCase { /** @@ -125,8 +125,8 @@ public function testNormal($testMarker, $startTokenType, $expected) $start = $this->getTargetToken($testMarker, $startTokenType); $end = $this->getTargetToken($testMarker, \T_SEMICOLON); - $result = GetTokensAsString::normal(self::$phpcsFile, $start, $end); - $this->assertSame($expected['normal'], $result); + $result = GetTokensAsString::tabReplaced(self::$phpcsFile, $start, $end); + $this->assertSame($expected['tab_replaced'], $result); } /** @@ -248,60 +248,81 @@ public function dataGetTokensAsString() 'marker' => '/* testNamespace */', 'type' => \T_NAMESPACE, 'expected' => [ - 'normal' => 'namespace Foo\Bar\Baz;', - 'orig' => 'namespace Foo\Bar\Baz;', - 'no_comments' => 'namespace Foo\Bar\Baz;', - 'no_empties' => 'namespaceFoo\Bar\Baz;', - 'compact' => 'namespace Foo\Bar\Baz;', - 'compact_nc' => 'namespace Foo\Bar\Baz;', + 'tab_replaced' => 'namespace Foo\Bar\Baz;', + 'orig' => 'namespace Foo\Bar\Baz;', + 'no_comments' => 'namespace Foo\Bar\Baz;', + 'no_empties' => 'namespaceFoo\Bar\Baz;', + 'compact' => 'namespace Foo\Bar\Baz;', + 'compact_nc' => 'namespace Foo\Bar\Baz;', ], ], 'use-with-comments' => [ 'marker' => '/* testUseWithComments */', 'type' => \T_STRING, 'expected' => [ - 'normal' => 'Foo /*comment*/ \ Bar + 'tab_replaced' => 'Foo /*comment*/ \ Bar // phpcs:ignore Stnd.Cat.Sniff -- For reasons. \ Bah;', - 'orig' => 'Foo /*comment*/ \ Bar + 'orig' => 'Foo /*comment*/ \ Bar // phpcs:ignore Stnd.Cat.Sniff -- For reasons. \ Bah;', - 'no_comments' => 'Foo \ Bar + 'no_comments' => 'Foo \ Bar \ Bah;', - 'no_empties' => 'Foo\Bar\Bah;', - 'compact' => 'Foo /*comment*/ \ Bar // phpcs:ignore Stnd.Cat.Sniff -- For reasons. + 'no_empties' => 'Foo\Bar\Bah;', + 'compact' => 'Foo /*comment*/ \ Bar // phpcs:ignore Stnd.Cat.Sniff -- For reasons. \ Bah;', - 'compact_nc' => 'Foo \ Bar \ Bah;', + 'compact_nc' => 'Foo \ Bar \ Bah;', + ], + ], + 'calculation' => [ + 'marker' => '/* testCalculation */', + 'type' => \T_LNUMBER, + 'expected' => [ + 'tab_replaced' => '1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20;', + 'orig' => '1 + 2 + + // Comment. + 3 + 4 + + 5 + 6 + 7 > 20;', + 'no_comments' => '1 + 2 + + 3 + 4 + + 5 + 6 + 7 > 20;', + 'no_empties' => '1+2+3+4+5+6+7>20;', + 'compact' => '1 + 2 + // Comment. + 3 + 4 + 5 + 6 + 7 > 20;', + 'compact_nc' => '1 + 2 + 3 + 4 + 5 + 6 + 7 > 20;', ], ], 'echo-with-tabs' => [ 'marker' => '/* testEchoWithTabs */', 'type' => \T_ECHO, 'expected' => [ - 'normal' => 'echo \'foo\', + 'tab_replaced' => 'echo \'foo\', \'bar\' , \'baz\';', - 'orig' => 'echo \'foo\', + 'orig' => 'echo \'foo\', \'bar\' , \'baz\';', - 'no_comments' => 'echo \'foo\', + 'no_comments' => 'echo \'foo\', \'bar\' , \'baz\';', - 'no_empties' => 'echo\'foo\',\'bar\',\'baz\';', - 'compact' => 'echo \'foo\', \'bar\' , \'baz\';', - 'compact_nc' => 'echo \'foo\', \'bar\' , \'baz\';', + 'no_empties' => 'echo\'foo\',\'bar\',\'baz\';', + 'compact' => 'echo \'foo\', \'bar\' , \'baz\';', + 'compact_nc' => 'echo \'foo\', \'bar\' , \'baz\';', ], ], 'end-of-file' => [ 'marker' => '/* testEndOfFile */', 'type' => \T_ECHO, 'expected' => [ - 'normal' => 'echo $foo;', - 'orig' => 'echo $foo;', - 'no_comments' => 'echo $foo;', - 'no_empties' => 'echo$foo;', - 'compact' => 'echo $foo;', - 'compact_nc' => 'echo $foo;', + 'tab_replaced' => 'echo $foo;', + 'orig' => 'echo $foo;', + 'no_comments' => 'echo $foo;', + 'no_empties' => 'echo$foo;', + 'compact' => 'echo $foo;', + 'compact_nc' => 'echo $foo;', ], ], ]; diff --git a/Tests/Utils/Lists/GetAssignmentsTest.php b/Tests/Utils/Lists/GetAssignmentsTest.php index 7876d464..7ab9cbaa 100644 --- a/Tests/Utils/Lists/GetAssignmentsTest.php +++ b/Tests/Utils/Lists/GetAssignmentsTest.php @@ -10,7 +10,9 @@ namespace PHPCSUtils\Tests\Utils\Lists; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Lists; /** @@ -22,7 +24,7 @@ * * @since 1.0.0 */ -class GetAssignmentsTest extends UtilityMethodTestCase +final class GetAssignmentsTest extends UtilityMethodTestCase { /** @@ -66,12 +68,12 @@ public function dataNotListToken() { return [ 'not-a-list' => [ - '/* testNotAList */', - \T_OPEN_SHORT_ARRAY, + 'testMarker' => '/* testNotAList */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, ], 'live-coding' => [ - '/* testLiveCoding */', - \T_LIST, + 'testMarker' => '/* testLiveCoding */', + 'targetToken' => \T_LIST, ], ]; } @@ -130,19 +132,19 @@ public function dataGetAssignments() { return [ 'long-list-empty' => [ - '/* testEmptyLongList */', - \T_LIST, - [], + 'testMarker' => '/* testEmptyLongList */', + 'targetToken' => \T_LIST, + 'expected' => [], ], 'short-list-empty' => [ - '/* testEmptyShortList */', - \T_OPEN_SHORT_ARRAY, - [], + 'testMarker' => '/* testEmptyShortList */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [], ], 'long-list-all-empty' => [ - '/* testLongListOnlyEmpties */', - \T_LIST, - [ + 'testMarker' => '/* testLongListOnlyEmpties */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '', 'assignment' => '', @@ -190,14 +192,14 @@ public function dataGetAssignments() ], ], 'short-list-all-empty-with-comment' => [ - '/* testShortListOnlyEmpties */', - \T_OPEN_SHORT_ARRAY, - [], + 'testMarker' => '/* testShortListOnlyEmpties */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [], ], 'long-list-basic' => [ - '/* testSimpleLongList */', - \T_LIST, - [ + 'testMarker' => '/* testSimpleLongList */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '$id', 'assignment' => '$id', @@ -223,9 +225,9 @@ public function dataGetAssignments() ], ], 'short-list-basic' => [ - '/* testSimpleShortList */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testSimpleShortList */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 0 => [ 'raw' => '$this->propA', 'assignment' => '$this->propA', @@ -251,9 +253,9 @@ public function dataGetAssignments() ], ], 'short-list-in-foreach-keyed-with-ref' => [ - '/* testShortListInForeachKeyedWithRef */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortListInForeachKeyedWithRef */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 0 => [ 'raw' => '\'id\' => & $id', 'assignment' => '$id', @@ -287,9 +289,9 @@ public function dataGetAssignments() ], ], 'long-list-nested' => [ - '/* testNestedLongList */', - \T_LIST, - [ + 'testMarker' => '/* testNestedLongList */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '$a', 'assignment' => '$a', @@ -315,9 +317,9 @@ public function dataGetAssignments() ], ], 'long-list-with-keys' => [ - '/* testLongListWithKeys */', - \T_LIST, - [ + 'testMarker' => '/* testLongListWithKeys */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '\'name\' => $a', 'assignment' => '$a', @@ -366,9 +368,9 @@ public function dataGetAssignments() ], ], 'long-list-with-empties' => [ - '/* testLongListWithEmptyEntries */', - \T_LIST, - [ + 'testMarker' => '/* testLongListWithEmptyEntries */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '', 'assignment' => '', @@ -460,9 +462,9 @@ public function dataGetAssignments() ], ], 'long-list-multi-line-keyed' => [ - '/* testLongListMultiLineKeyedWithTrailingComma */', - \T_LIST, - [ + 'testMarker' => '/* testLongListMultiLineKeyedWithTrailingComma */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '"name" => $this->name', 'assignment' => '$this->name', @@ -537,9 +539,9 @@ public function dataGetAssignments() ], ], 'short-list-with-keys-nested-lists' => [ - '/* testShortListWithKeysNestedLists */', - [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET], - [ + 'testMarker' => '/* testShortListWithKeysNestedLists */', + 'targetToken' => Collections::shortArrayListOpenTokensBC(), + 'expected' => [ 0 => [ 'raw' => '\'a\' => [&$a, $b]', 'assignment' => '[&$a, $b]', @@ -573,9 +575,9 @@ public function dataGetAssignments() ], ], 'long-list-with-array-vars' => [ - '/* testLongListWithArrayVars */', - \T_LIST, - [ + 'testMarker' => '/* testLongListWithArrayVars */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '$a[]', 'assignment' => '$a[]', @@ -612,9 +614,9 @@ public function dataGetAssignments() ], ], 'short-list-multi-line-with-variable-keys' => [ - '/* testShortListMultiLineWithVariableKeys */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortListMultiLineWithVariableKeys */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 0 => [ 'raw' => '\'a\' . \'b\' => $a', 'assignment' => '$a', @@ -750,9 +752,9 @@ public function dataGetAssignments() ], ], 'long-list-with-close-parens-in-key' => [ - '/* testLongListWithCloseParensInKey */', - \T_LIST, - [ + 'testMarker' => '/* testLongListWithCloseParensInKey */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => 'get_key()[1] => &$e', 'assignment' => '$e', @@ -771,9 +773,9 @@ public function dataGetAssignments() ], ], 'long-list-variable-vars' => [ - '/* testLongListVariableVar */', - \T_LIST, - [ + 'testMarker' => '/* testLongListVariableVar */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '${$drink}', 'assignment' => '${$drink}', @@ -799,9 +801,9 @@ public function dataGetAssignments() ], ], 'long-list-keyed-with-nested-lists' => [ - '/* testLongListKeyedNestedLists */', - \T_LIST, - [ + 'testMarker' => '/* testLongListKeyedNestedLists */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '\'a\' => list("x" => $x1, "y" => $y1)', @@ -837,9 +839,9 @@ public function dataGetAssignments() ], ], 'parse-error-long-list-mixed-keyed-unkeyed' => [ - '/* testLongListMixedKeyedUnkeyed */', - \T_LIST, - [ + 'testMarker' => '/* testLongListMixedKeyedUnkeyed */', + 'targetToken' => \T_LIST, + 'expected' => [ 0 => [ 'raw' => '$unkeyed', 'assignment' => '$unkeyed', @@ -869,9 +871,9 @@ public function dataGetAssignments() ], ], 'parse-error-short-list-empties-and-key' => [ - '/* testShortListWithEmptiesAndKey */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortListWithEmptiesAndKey */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 0 => [ 'raw' => '', 'assignment' => '', @@ -935,4 +937,59 @@ public function dataGetAssignments() ], ]; } + + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testResultIsCached() + { + $methodName = 'PHPCSUtils\\Utils\\Lists::getAssignments'; + $cases = $this->dataGetAssignments(); + $testMarker = $cases['short-list-with-keys-nested-lists']['testMarker']; + $targetToken = $cases['short-list-with-keys-nested-lists']['targetToken']; + $expected = $cases['short-list-with-keys-nested-lists']['expected']; + + $stackPtr = $this->getTargetToken($testMarker, $targetToken); + + // Convert offsets to absolute positions. + foreach ($expected as $index => $subset) { + if (isset($subset['key_token'])) { + $expected[$index]['key_token'] += $stackPtr; + } + if (isset($subset['key_end_token'])) { + $expected[$index]['key_end_token'] += $stackPtr; + } + if (isset($subset['double_arrow_token'])) { + $expected[$index]['double_arrow_token'] += $stackPtr; + } + if (isset($subset['reference_token']) && $subset['reference_token'] !== false) { + $expected[$index]['reference_token'] += $stackPtr; + } + if (isset($subset['assignment_token']) && $subset['assignment_token'] !== false) { + $expected[$index]['assignment_token'] += $stackPtr; + } + if (isset($subset['assignment_end_token']) && $subset['assignment_end_token'] !== false) { + $expected[$index]['assignment_end_token'] += $stackPtr; + } + } + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = Lists::getAssignments(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, $stackPtr); + $resultSecondRun = Lists::getAssignments(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } } diff --git a/Tests/Utils/Lists/GetOpenCloseTest.php b/Tests/Utils/Lists/GetOpenCloseTest.php index e085dc0c..0d1f8476 100644 --- a/Tests/Utils/Lists/GetOpenCloseTest.php +++ b/Tests/Utils/Lists/GetOpenCloseTest.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\Lists; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Lists; /** @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class GetOpenCloseTest extends UtilityMethodTestCase +final class GetOpenCloseTest extends UtilityMethodTestCase { /** @@ -46,7 +47,7 @@ public function testNonExistentToken() */ public function testNotListToken($testMarker) { - $target = $this->getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET]); + $target = $this->getTargetToken($testMarker, Collections::shortArrayListOpenTokensBC()); $this->assertFalse(Lists::getOpenClose(self::$phpcsFile, $target)); } @@ -103,49 +104,49 @@ public function dataGetOpenClose() { return [ 'long-list' => [ - '/* testLongList */', - \T_LIST, - [ + 'testMarker' => '/* testLongList */', + 'targetToken' => \T_LIST, + 'expected' => [ 'opener' => 1, 'closer' => 14, ], ], 'long-list-nested' => [ - '/* testNestedLongList */', - \T_LIST, - [ + 'testMarker' => '/* testNestedLongList */', + 'targetToken' => \T_LIST, + 'expected' => [ 'opener' => 2, 'closer' => 6, ], ], 'short-list' => [ - '/* testShortList */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortList */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 'opener' => 0, 'closer' => 9, ], ], 'short-list-nested' => [ - '/* testNestedShortList */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testNestedShortList */', + 'targetToken' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 'opener' => 0, 'closer' => 2, ], ], 'long-list-with-comments-and-annotations' => [ - '/* testListWithCommentsAndAnnotations */', - \T_LIST, - [ + 'testMarker' => '/* testListWithCommentsAndAnnotations */', + 'targetToken' => \T_LIST, + 'expected' => [ 'opener' => 7, 'closer' => 18, ], ], 'parse-error' => [ - '/* testParseError */', - \T_LIST, - false, + 'testMarker' => '/* testParseError */', + 'targetToken' => \T_LIST, + 'expected' => false, ], ]; } diff --git a/Tests/Utils/Lists/IsShortListTest.inc b/Tests/Utils/Lists/IsShortListTest.inc deleted file mode 100644 index 9c41956e..00000000 --- a/Tests/Utils/Lists/IsShortListTest.inc +++ /dev/null @@ -1,87 +0,0 @@ - [$id, $name, $info]) {} - -foreach ($array as [$a, /* testShortListInForeachNested */ [$b, $c]]) {} - -/* testMultiAssignShortlist */ -$foo = [$baz, $bat] = [$a, $b]; - -/* testShortListWithKeys */ -["id" => $id1, "name" => $name1] = $data[0]; - -/* testShortListInForeachWithKeysDetectOnCloseBracket */ -foreach ($data as ["id" => $id, "name" => $name]) {} - -echo 'just here to prevent the below test running into a tokenizer issue tested separately'; - -// Invalid as empty lists are not allowed, but it is short list syntax. -[$x, /* testNestedShortListEmpty */ [], $y] = $a; - -[$x, [ $y, /* testDeeplyNestedShortList */ [$z]], $q] = $a; - -/* testShortListWithNestingAndKeys */ -[ - /* testNestedShortListWithKeys_1 */ - ["x" => $x1, "y" => $y1], - /* testNestedShortListWithKeys_2 */ - ["x" => $x2, "y" => $y2], - /* testNestedShortListWithKeys_3 */ - ["x" => $x3, "y" => $y3], -] = $points; - -/* testShortListWithoutVars */ -// Invalid list as it doesn't contain variables, but it is short list syntax. -[42] = [1]; - -/* testShortListNestedLongList */ -// Invalid list as mixing short list syntax with list() is not allowed, but it is short list syntax. -[list($a, $b), list($c, $d)] = [[1, 2], [3, 4]]; - -/* testNestedAnonClassWithTraitUseAs */ -// Parse error, but not short list syntax. -array_map(function($a) { - return new class() { - use MyTrait { - MyTrait::functionName as []; - } - }; -}, $array); - -/* testParseError */ -// Parse error, but not short list syntax. -use Something as [$a]; - -/* testLiveCoding */ -// Intentional parse error. This has to be the last test in the file. -[$a, [$b] diff --git a/Tests/Utils/Lists/IsShortListTest.php b/Tests/Utils/Lists/IsShortListTest.php deleted file mode 100644 index 4b74cecb..00000000 --- a/Tests/Utils/Lists/IsShortListTest.php +++ /dev/null @@ -1,208 +0,0 @@ -assertFalse(Lists::isShortList(self::$phpcsFile, 100000)); - } - - /** - * Test that false is returned when a non-short array token is passed. - * - * @dataProvider dataNotShortArrayToken - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int|string|array $targetToken The token type(s) to look for. - * - * @return void - */ - public function testNotShortArrayToken($testMarker, $targetToken) - { - $target = $this->getTargetToken($testMarker, $targetToken); - $this->assertFalse(Lists::isShortList(self::$phpcsFile, $target)); - } - - /** - * Data provider. - * - * @see testNotShortArrayToken() For the array format. - * - * @return array - */ - public function dataNotShortArrayToken() - { - return [ - 'long-list' => [ - '/* testLongList */', - \T_LIST, - ], - 'array-assignment' => [ - '/* testArrayAssignment */', - \T_CLOSE_SQUARE_BRACKET, - ], - 'live-coding' => [ - '/* testLiveCoding */', - \T_OPEN_SQUARE_BRACKET, - ], - ]; - } - - /** - * Test whether a T_OPEN_SHORT_ARRAY token is a short list. - * - * @dataProvider dataIsShortList - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param bool $expected The expected boolean return value. - * @param int|string|array $targetToken The token type(s) to test. Defaults to T_OPEN_SHORT_ARRAY. - * - * @return void - */ - public function testIsShortList($testMarker, $expected, $targetToken = \T_OPEN_SHORT_ARRAY) - { - $stackPtr = $this->getTargetToken($testMarker, $targetToken); - $result = Lists::isShortList(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testIsShortList() For the array format. - * - * @return array - */ - public function dataIsShortList() - { - return [ - 'short-array-not-nested' => [ - '/* testNonNestedShortArray */', - false, - ], - 'comparison-no-assignment' => [ - '/* testNoAssignment */', - false, - ], - 'comparison-no-assignment-nested' => [ - '/* testNestedNoAssignment */', - false, - ], - 'short-array-in-foreach' => [ - '/* testShortArrayInForeach */', - false, - ], - 'short-list' => [ - '/* testShortList */', - true, - ], - 'short-list-detect-on-close-bracket' => [ - '/* testShortListDetectOnCloseBracket */', - true, - \T_CLOSE_SHORT_ARRAY, - ], - 'short-list-with-nesting' => [ - '/* testShortListWithNesting */', - true, - ], - 'short-list-nested' => [ - '/* testNestedShortList */', - true, - ], - 'short-list-in-foreach' => [ - '/* testShortListInForeach */', - true, - ], - 'short-list-in-foreach-with-key' => [ - '/* testShortListInForeachWithKey */', - true, - ], - 'short-list-in-foreach-nested' => [ - '/* testShortListInForeachNested */', - true, - ], - 'short-list-chained-assignment' => [ - '/* testMultiAssignShortlist */', - true, - ], - 'short-list-with-keys' => [ - '/* testShortListWithKeys */', - true, - ], - 'short-list-in-foreach-with-keys-detect-on-close-bracket' => [ - '/* testShortListInForeachWithKeysDetectOnCloseBracket */', - true, - \T_CLOSE_SHORT_ARRAY, - ], - 'short-list-nested-empty' => [ - '/* testNestedShortListEmpty */', - true, - ], - 'short-list-deeply-nested' => [ - '/* testDeeplyNestedShortList */', - true, - ], - 'short-list-with-nesting-and-keys' => [ - '/* testShortListWithNestingAndKeys */', - true, - ], - 'short-list-nested-with-keys-1' => [ - '/* testNestedShortListWithKeys_1 */', - true, - ], - 'short-list-nested-with-keys-2' => [ - '/* testNestedShortListWithKeys_2 */', - true, - ], - 'short-list-nested-with-keys-3' => [ - '/* testNestedShortListWithKeys_3 */', - true, - ], - 'short-list-without-vars' => [ - '/* testShortListWithoutVars */', - true, - ], - 'short-list-nested-long-list' => [ - '/* testShortListNestedLongList */', - true, - ], - 'parse-error-anon-class-trait-use-as' => [ - '/* testNestedAnonClassWithTraitUseAs */', - false, - ], - 'parse-error-use-as' => [ - '/* testParseError */', - false, - ], - ]; - } -} diff --git a/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php b/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php deleted file mode 100644 index 2df3b7b8..00000000 --- a/Tests/Utils/Lists/IsShortListTokenizerBC1Test.php +++ /dev/null @@ -1,107 +0,0 @@ -getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET]); - $result = Lists::isShortList(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testIsShortList() For the array format. - * - * @return array - */ - public function dataIsShortList() - { - return [ - 'issue-1971-list-first-in-file' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271A */', - true, - ], - 'issue-1971-list-first-in-file-nested' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271B */', - true, - ], - 'issue-1381-array-dereferencing-1' => [ - '/* testTokenizerIssue1381PHPCSlt290A1 */', - false, - ], - 'issue-1381-array-dereferencing-1-deref' => [ - '/* testTokenizerIssue1381PHPCSlt290A2 */', - false, - ], - 'issue-1381-array-dereferencing-2' => [ - '/* testTokenizerIssue1381PHPCSlt290B */', - false, - ], - 'issue-1381-array-dereferencing-3' => [ - '/* testTokenizerIssue1381PHPCSlt290C */', - false, - ], - 'issue-1381-array-dereferencing-4' => [ - '/* testTokenizerIssue1381PHPCSlt290D1 */', - false, - ], - 'issue-1381-array-dereferencing-4-deref-deref' => [ - '/* testTokenizerIssue1381PHPCSlt290D2 */', - false, - ], - 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ - '/* testTokenizerIssue1284PHPCSlt280A */', - true, - ], - 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ - '/* testTokenizerIssue1284PHPCSlt280B */', - false, - ], - 'issue-1284-array-access-variable-variable' => [ - '/* testTokenizerIssue1284PHPCSlt290C */', - false, - ], - 'issue-1284-array-access-variable-property' => [ - '/* testTokenizerIssue1284PHPCSlt280D */', - false, - ], - ]; - } -} diff --git a/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php b/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php deleted file mode 100644 index 47b6840b..00000000 --- a/Tests/Utils/Lists/IsShortListTokenizerBC2Test.php +++ /dev/null @@ -1,68 +0,0 @@ -getTargetToken($testMarker, [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET]); - $result = Lists::isShortList(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - - /** - * Data provider. - * - * @see testIsShortList() For the array format. - * - * @return array - */ - public function dataIsShortList() - { - return [ - // Make sure the utility method does not throw false positives for a short array at the start of a file. - 'issue-1971-short-array-first-in-file' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271C */', - false, - ], - 'issue-1971-short-array-first-in-file-nested' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271D */', - false, - ], - ]; - } -} diff --git a/Tests/Utils/Lists/README-IsShortListTests.md b/Tests/Utils/Lists/README-IsShortListTests.md new file mode 100644 index 00000000..4f30ed64 --- /dev/null +++ b/Tests/Utils/Lists/README-IsShortListTests.md @@ -0,0 +1,4 @@ +# Regarding tests for `Lists::isShortList()` + +The `Lists::isShortList()` method is tested together with the `Arrays::isShortArray()` method. +The tests for this can be found in the `Tests/Internal/IsShortArrayOrList` folder. diff --git a/Tests/Utils/MessageHelper/AddMessageTest.inc b/Tests/Utils/MessageHelper/AddMessageTest.inc new file mode 100644 index 00000000..ce27ac26 --- /dev/null +++ b/Tests/Utils/MessageHelper/AddMessageTest.inc @@ -0,0 +1,13 @@ +getTokens(); + $stackPtr = $this->getTargetToken($testMarker, \T_CONSTANT_ENCAPSED_STRING); + $severity = \mt_rand(5, 10); + $expected['severity'] = $severity; + + $return = MessageHelper::addMessage( + self::$phpcsFile, + 'Message added. Text: %s', + $stackPtr, + $isError, + self::CODE, + [$tokens[$stackPtr]['content']], + $severity + ); + + $this->assertTrue($return); + + $this->verifyRecordedMessages($stackPtr, $isError, $expected); + } + + /** + * Data Provider. + * + * @see testAddMessage() For the array format. + * + * @return array + */ + public function dataAddMessage() + { + return [ + 'add-error' => [ + 'testMarker' => '/* testAddErrorMessage */', + 'isError' => true, + 'expected' => [ + 'message' => "Message added. Text: 'test 1'", + 'source' => self::CODE, + 'fixable' => false, + ], + ], + 'add-warning' => [ + 'testMarker' => '/* testAddWarningMessage */', + 'isError' => false, + 'expected' => [ + 'message' => "Message added. Text: 'test 2'", + 'source' => self::CODE, + 'fixable' => false, + ], + ], + ]; + } + + /** + * Test the addFixableMessage wrapper. + * + * @dataProvider dataAddFixableMessage + * @covers ::addFixableMessage + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $isError Whether to test adding an error or a warning. + * @param array $expected Expected error details. + * + * @return void + */ + public function testAddFixableMessage($testMarker, $isError, $expected) + { + $tokens = self::$phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken($testMarker, \T_CONSTANT_ENCAPSED_STRING); + $severity = \mt_rand(5, 10); + $expected['severity'] = $severity; + + $return = MessageHelper::addFixableMessage( + self::$phpcsFile, + 'Message added. Text: %s', + $stackPtr, + $isError, + self::CODE, + [$tokens[$stackPtr]['content']], + $severity + ); + + // Fixable message recording only returns true when the fixer is enabled (=phpcbf). + $this->assertFalse($return); + + $this->verifyRecordedMessages($stackPtr, $isError, $expected); + } + + /** + * Data Provider. + * + * @see testAddFixableMessage() For the array format. + * + * @return array + */ + public function dataAddFixableMessage() + { + return [ + 'add-fixable-error' => [ + 'testMarker' => '/* testAddFixableErrorMessage */', + 'isError' => true, + 'expected' => [ + 'message' => "Message added. Text: 'test 3'", + 'source' => self::CODE, + 'fixable' => true, + ], + ], + 'add-fixable-warning' => [ + 'testMarker' => '/* testAddFixableWarningMessage */', + 'isError' => false, + 'expected' => [ + 'message' => "Message added. Text: 'test 4'", + 'source' => self::CODE, + 'fixable' => true, + ], + ], + ]; + } + + /** + * Helper method to verify the expected message details. + * + * @param int $stackPtr The stack pointer on which the error/warning is expected. + * @param bool $isError Whether to test adding an error or a warning. + * @param array $expected Expected error details. + * + * @return void + */ + protected function verifyRecordedMessages($stackPtr, $isError, $expected) + { + $tokens = self::$phpcsFile->getTokens(); + $errors = self::$phpcsFile->getErrors(); + $warnings = self::$phpcsFile->getWarnings(); + $result = ($isError === true) ? $errors : $warnings; + + /* + * Make sure that no errors/warnings were recorded when the other type is set to be expected. + */ + if ($isError === true) { + $this->assertArrayNotHasKey( + $tokens[$stackPtr]['line'], + $warnings, + 'Expected no warnings on line ' . $tokens[$stackPtr]['line'] . '. At least one found.' + ); + } else { + $this->assertArrayNotHasKey( + $tokens[$stackPtr]['line'], + $errors, + 'Expected no errors on line ' . $tokens[$stackPtr]['line'] . '. At least one found.' + ); + } + + /* + * Make sure the expected array keys for the errors/warnings are available. + */ + $this->assertArrayHasKey( + $tokens[$stackPtr]['line'], + $result, + 'Expected a violation on line ' . $tokens[$stackPtr]['line'] . '. None found.' + ); + + $this->assertArrayHasKey( + $tokens[$stackPtr]['column'], + $result[$tokens[$stackPtr]['line']], + 'Expected a violation on line ' . $tokens[$stackPtr]['line'] . ', column ' + . $tokens[$stackPtr]['column'] . '. None found.' + ); + + $messages = $result[$tokens[$stackPtr]['line']][$tokens[$stackPtr]['column']]; + + // Expect one violation. + $this->assertCount(1, $messages, 'Expected 1 violation, found: ' . \count($messages)); + + $violation = $messages[0]; + + // PHPCS 2.x places `unknownSniff.` before the actual error code for utility tests with a dummy error code. + $violation['source'] = \str_replace('unknownSniff.', '', $violation['source']); + + /* + * Test the violation details. + */ + foreach ($expected as $key => $value) { + $this->assertSame($value, $violation[$key], \ucfirst($key) . ' comparison failed'); + } + } +} diff --git a/Tests/Utils/MessageHelper/ShowEscapeCharsTest.php b/Tests/Utils/MessageHelper/ShowEscapeCharsTest.php new file mode 100644 index 00000000..a2240cb6 --- /dev/null +++ b/Tests/Utils/MessageHelper/ShowEscapeCharsTest.php @@ -0,0 +1,90 @@ +assertSame($expected, MessageHelper::showEscapeChars($input)); + } + + /** + * Data provider. + * + * @see testShowEscapeChars() For the array format. + * + * @return array + */ + public function dataShowEscapeChars() + { + return [ + 'no-escape-chars' => [ + 'input' => 'if ($var === true) {', + 'expected' => 'if ($var === true) {', + ], + 'has-escape-chars-in-single-quoted-string' => [ + 'input' => 'if ($var === true) {\r\n\t// Do something.\r\n}', + 'expected' => 'if ($var === true) {\r\n\t// Do something.\r\n}', + ], + 'has-real-tabs' => [ + 'input' => '$var = 123;', + 'expected' => '$var\t\t= 123;', + ], + 'has-tab-escape-chars-in-double-quoted-string' => [ + 'input' => "\$var\t\t= 123;", + 'expected' => '$var\t\t= 123;', + ], + 'has-real-new-line' => [ + 'input' => '$foo = 123; +$bar = 456;', + 'expected' => '$foo = 123;\n$bar = 456;', + ], + 'has-new-line-escape-char-in-double-quoted-string' => [ + 'input' => "\$foo = 123;\n\$bar = 456;", + 'expected' => '$foo = 123;\n$bar = 456;', + ], + 'has-real-tab-and-new-lines' => [ + 'input' => 'if ($var === true) { + // Do something. +}', + 'expected' => 'if ($var === true) {\n\t// Do something.\n}', + ], + 'has-tab-and-new-lines-escape-chars-in-double-quoted-string' => [ + 'input' => "if (\$var === true) {\r\n\t// Do something.\r\n}", + 'expected' => 'if ($var === true) {\r\n\t// Do something.\r\n}', + ], + ]; + } +} diff --git a/Tests/Utils/MessageHelper/StringToErrorcodeTest.php b/Tests/Utils/MessageHelper/StringToErrorcodeTest.php new file mode 100644 index 00000000..f45f46b1 --- /dev/null +++ b/Tests/Utils/MessageHelper/StringToErrorcodeTest.php @@ -0,0 +1,127 @@ +assertSame($expected, MessageHelper::stringToErrorCode($input)); + } + + /** + * Data provider. + * + * @see testStringToErrorCode() For the array format. + * + * @return array + */ + public function dataStringToErrorCode() + { + return [ + 'no-special-chars' => [ + 'input' => 'dir_name', + 'expected' => 'dir_name', + ], + 'full-stop' => [ + 'input' => 'soap.wsdl_cache', + 'expected' => 'soap_wsdl_cache', + ], + 'dash-and-space' => [ + 'input' => 'arbitrary-string with space', + 'expected' => 'arbitrary_string_with_space', + ], + 'no-alphanum-chars' => [ + 'input' => '^%*&%*€à?', + 'expected' => '____________', + ], + 'mixed-case-chars' => [ + 'input' => 'MyArbitraryName', + 'expected' => 'MyArbitraryName', + ], + 'mixed-case-chars-with-special-chars' => [ + 'input' => 'My-Arb#tr$ryN@me', + 'expected' => 'My_Arb_tr_ryN_me', + ], + ]; + } + + /** + * Test the stringToErrorcode() method. + * + * @dataProvider dataStringToErrorCodeWithCaseChange + * + * @param string $input The input string. + * @param string $expected The expected function output. + * + * @return void + */ + public function testStringToErrorCodeWithCaseChange($input, $expected) + { + $this->assertSame($expected, MessageHelper::stringToErrorCode($input, true)); + } + + /** + * Data provider. + * + * @see testStringToErrorCode() For the array format. + * + * @return array + */ + public function dataStringToErrorCodeWithCaseChange() + { + return [ + 'no-special-chars' => [ + 'input' => 'dir_name', + 'expected' => 'dir_name', + ], + 'no-alphanum-chars' => [ + 'input' => '^%*&%*€à?', + 'expected' => '____________', + ], + 'mixed-case-chars' => [ + 'input' => 'MyArbitraryName', + 'expected' => 'myarbitraryname', + ], + 'mixed-case-chars-with-special-chars' => [ + 'input' => 'My-Arb#tr$ryN@me', + 'expected' => 'my_arb_tr_ryn_me', + ], + 'mixed-case-chars-non-alpha' => [ + 'input' => 'MyÄrbÌtraryNãme', + 'expected' => 'my__rb__traryn__me', + ], + ]; + } +} diff --git a/Tests/Utils/Namespaces/DetermineNamespaceTest.inc b/Tests/Utils/Namespaces/DetermineNamespaceTest.inc index 911813af..e99c5561 100644 --- a/Tests/Utils/Namespaces/DetermineNamespaceTest.inc +++ b/Tests/Utils/Namespaces/DetermineNamespaceTest.inc @@ -114,7 +114,12 @@ echo 0; /** * Docblock to skip over. */ +#[ + AttributeToSkipOver, + AnotherAttribute, +] class Foo { + #[AttributeToSkipOver()] #[AnotherAttribute] function test() { /* testNonScopedNamedNamespace2Nested */ echo 0; diff --git a/Tests/Utils/Namespaces/DetermineNamespaceTest.php b/Tests/Utils/Namespaces/DetermineNamespaceTest.php index 774b9e16..3256217a 100644 --- a/Tests/Utils/Namespaces/DetermineNamespaceTest.php +++ b/Tests/Utils/Namespaces/DetermineNamespaceTest.php @@ -10,6 +10,7 @@ namespace PHPCSUtils\Tests\Utils\Namespaces; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Utils\Namespaces; @@ -24,7 +25,7 @@ * * @since 1.0.0 */ -class DetermineNamespaceTest extends UtilityMethodTestCase +final class DetermineNamespaceTest extends UtilityMethodTestCase { /** @@ -89,99 +90,99 @@ public function dataDetermineNamespace() { return [ 'no-namespace' => [ - '/* testNoNamespace */', - [ + 'testMarker' => '/* testNoNamespace */', + 'expected' => [ 'ptr' => false, 'name' => '', ], ], 'no-namespace-nested' => [ - '/* testNoNamespaceNested */', - [ + 'testMarker' => '/* testNoNamespaceNested */', + 'expected' => [ 'ptr' => false, 'name' => '', ], ], 'non-scoped-namespace-1' => [ - '/* testNonScopedNamedNamespace1 */', - [ + 'testMarker' => '/* testNonScopedNamedNamespace1 */', + 'expected' => [ 'ptr' => '/* Non-scoped named namespace 1 */', 'name' => 'Vendor\Package\Baz', ], ], 'non-scoped-namespace-1-nested' => [ - '/* testNonScopedNamedNamespace1Nested */', - [ + 'testMarker' => '/* testNonScopedNamedNamespace1Nested */', + 'expected' => [ 'ptr' => '/* Non-scoped named namespace 1 */', 'name' => 'Vendor\Package\Baz', ], ], 'global-namespace-scoped' => [ - '/* testGlobalNamespaceScoped */', - [ + 'testMarker' => '/* testGlobalNamespaceScoped */', + 'expected' => [ 'ptr' => '/* Scoped global namespace */', 'name' => '', ], ], 'global-namespace-scoped-nested' => [ - '/* testGlobalNamespaceScopedNested */', - [ + 'testMarker' => '/* testGlobalNamespaceScopedNested */', + 'expected' => [ 'ptr' => '/* Scoped global namespace */', 'name' => '', ], ], 'no-namespace-after-unnamed-scoped' => [ - '/* testNoNamespaceAfterUnnamedScoped */', - [ + 'testMarker' => '/* testNoNamespaceAfterUnnamedScoped */', + 'expected' => [ 'ptr' => false, 'name' => '', ], ], 'no-namespace-nested-after-unnamed-scoped' => [ - '/* testNoNamespaceNestedAfterUnnamedScoped */', - [ + 'testMarker' => '/* testNoNamespaceNestedAfterUnnamedScoped */', + 'expected' => [ 'ptr' => false, 'name' => '', ], ], 'named-namespace-scoped' => [ - '/* testNamedNamespaceScoped */', - [ + 'testMarker' => '/* testNamedNamespaceScoped */', + 'expected' => [ 'ptr' => '/* Scoped named namespace */', 'name' => 'Vendor\Package\Foo', ], ], 'named-namespace-scoped-nested' => [ - '/* testNamedNamespaceScopedNested */', - [ + 'testMarker' => '/* testNamedNamespaceScopedNested */', + 'expected' => [ 'ptr' => '/* Scoped named namespace */', 'name' => 'Vendor\Package\Foo', ], ], 'no-namespace-after-named-scoped' => [ - '/* testNoNamespaceAfterNamedScoped */', - [ + 'testMarker' => '/* testNoNamespaceAfterNamedScoped */', + 'expected' => [ 'ptr' => false, 'name' => '', ], ], 'no-namespace-nested-after-named-scoped' => [ - '/* testNoNamespaceNestedAfterNamedScoped */', - [ + 'testMarker' => '/* testNoNamespaceNestedAfterNamedScoped */', + 'expected' => [ 'ptr' => false, 'name' => '', ], ], 'non-scoped-namespace-2' => [ - '/* testNonScopedNamedNamespace2 */', - [ + 'testMarker' => '/* testNonScopedNamedNamespace2 */', + 'expected' => [ 'ptr' => '/* Non-scoped named namespace 2 */', 'name' => 'Vendor\Package\Foz', ], ], 'non-scoped-namespace-2-nested' => [ - '/* testNonScopedNamedNamespace2Nested */', - [ + 'testMarker' => '/* testNonScopedNamedNamespace2Nested */', + 'expected' => [ 'ptr' => '/* Non-scoped named namespace 2 */', 'name' => 'Vendor\Package\Foz', ], @@ -189,6 +190,40 @@ public function dataDetermineNamespace() ]; } + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testFindNamespacePtrResultIsCached() + { + // The test case used is specifically selected to be one which will always reach the cache check. + $methodName = 'PHPCSUtils\\Utils\\Namespaces::findNamespacePtr'; + $cases = $this->dataDetermineNamespace(); + $testMarker = $cases['non-scoped-namespace-2']['testMarker']; + $expected = $cases['non-scoped-namespace-2']['expected']['ptr']; + + $stackPtr = $this->getTargetToken($testMarker, \T_ECHO); + $expected = $this->getTargetToken($expected, \T_NAMESPACE); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = Namespaces::findNamespacePtr(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, $stackPtr); + $resultSecondRun = Namespaces::findNamespacePtr(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } + /** * Test that the namespace declaration itself is not regarded as being namespaced. * @@ -200,7 +235,14 @@ public function testNamespaceDeclarationIsNotNamespaced() $result = Namespaces::findNamespacePtr(self::$phpcsFile, $stackPtr); $this->assertFalse($result, 'Failed checking that namespace declaration token is not regarded as namespaced'); - $stackPtr = $this->getTargetToken('/* Non-scoped named namespace 2 */', \T_STRING, 'Package'); + $targetType = \T_STRING; + $targetContent = 'Package'; + if (parent::usesPhp8NameTokens() === true) { + $targetType = \T_NAME_QUALIFIED; + $targetContent = 'Vendor\Package\Foz'; + } + + $stackPtr = $this->getTargetToken('/* Non-scoped named namespace 2 */', $targetType, $targetContent); $result = Namespaces::findNamespacePtr(self::$phpcsFile, $stackPtr); $this->assertFalse($result, 'Failed checking that a token in the namespace name is not regarded as namespaced'); } diff --git a/Tests/Utils/Namespaces/GetDeclaredNameTest.php b/Tests/Utils/Namespaces/GetDeclaredNameTest.php index fe8c3c40..bfbfc518 100644 --- a/Tests/Utils/Namespaces/GetDeclaredNameTest.php +++ b/Tests/Utils/Namespaces/GetDeclaredNameTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetDeclaredNameTest extends UtilityMethodTestCase +final class GetDeclaredNameTest extends UtilityMethodTestCase { /** @@ -46,11 +46,18 @@ public function testInvalidTokenPassed() * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected output for the function. + * @param bool $skipOnPHP8 Optional. Whether the test should be skipped when the PHP 8 identifier + * name tokenization is used (as the target token won't exist). + * Defaults to `false`. * * @return void */ - public function testGetDeclaredNameClean($testMarker, $expected) + public function testGetDeclaredNameClean($testMarker, $expected, $skipOnPHP8 = false) { + if ($skipOnPHP8 === true && parent::usesPhp8NameTokens() === true) { + $this->markTestSkipped("PHP 8.0 identifier name tokenization used. Target token won't exist."); + } + $stackPtr = $this->getTargetToken($testMarker, \T_NAMESPACE); $result = Namespaces::getDeclaredName(self::$phpcsFile, $stackPtr, true); @@ -64,11 +71,18 @@ public function testGetDeclaredNameClean($testMarker, $expected) * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected output for the function. + * @param bool $skipOnPHP8 Optional. Whether the test should be skipped when the PHP 8 identifier + * name tokenization is used (as the target token won't exist). + * Defaults to `false`. * * @return void */ - public function testGetDeclaredNameDirty($testMarker, $expected) + public function testGetDeclaredNameDirty($testMarker, $expected, $skipOnPHP8 = false) { + if ($skipOnPHP8 === true && parent::usesPhp8NameTokens() === true) { + $this->markTestSkipped("PHP 8.0 identifier name tokenization used. Target token won't exist."); + } + $stackPtr = $this->getTargetToken($testMarker, \T_NAMESPACE); $result = Namespaces::getDeclaredName(self::$phpcsFile, $stackPtr, false); @@ -86,50 +100,50 @@ public function dataGetDeclaredName() { return [ 'global-namespace-curlies' => [ - '/* testGlobalNamespaceCurlies */', - [ + 'testMarker' => '/* testGlobalNamespaceCurlies */', + 'expected' => [ 'clean' => '', 'dirty' => '', ], ], 'namespace-semicolon' => [ - '/* testNamespaceSemiColon */', - [ + 'testMarker' => '/* testNamespaceSemiColon */', + 'expected' => [ 'clean' => 'Vendor', 'dirty' => 'Vendor', ], ], 'namespace-curlies' => [ - '/* testNamespaceCurlies */', - [ + 'testMarker' => '/* testNamespaceCurlies */', + 'expected' => [ 'clean' => 'Vendor\Package\Sublevel\End', 'dirty' => 'Vendor\Package\Sublevel\End', ], ], 'namespace-curlies-no-space-at-end' => [ - '/* testNamespaceCurliesNoSpaceAtEnd */', - [ + 'testMarker' => '/* testNamespaceCurliesNoSpaceAtEnd */', + 'expected' => [ 'clean' => 'Vendor\Package\Sublevel\Deeperlevel\End', 'dirty' => 'Vendor\Package\Sublevel\Deeperlevel\End', ], ], 'namespace-close-tag' => [ - '/* testNamespaceCloseTag */', - [ + 'testMarker' => '/* testNamespaceCloseTag */', + 'expected' => [ 'clean' => 'My\Name', 'dirty' => 'My\Name', ], ], 'namespace-close-tag-no-space-at-end' => [ - '/* testNamespaceCloseTagNoSpaceAtEnd */', - [ + 'testMarker' => '/* testNamespaceCloseTagNoSpaceAtEnd */', + 'expected' => [ 'clean' => 'My\Other\Name', 'dirty' => 'My\Other\Name', ], ], 'namespace-whitespace-tolerance' => [ - '/* testNamespaceLotsOfWhitespace */', - [ + 'testMarker' => '/* testNamespaceLotsOfWhitespace */', + 'expected' => [ 'clean' => 'Vendor\Package\Sub\Deeperlevel\End', 'dirty' => 'Vendor \ Package\ @@ -139,8 +153,8 @@ public function dataGetDeclaredName() ], ], 'namespace-with-comments-and-annotations' => [ - '/* testNamespaceWithCommentsWhitespaceAndAnnotations */', - [ + 'testMarker' => '/* testNamespaceWithCommentsWhitespaceAndAnnotations */', + 'expected' => [ 'clean' => 'Vendor\Package\Sublevel\Deeper\End', 'dirty' => 'Vendor\/*comment*/ Package\Sublevel \ //phpcs:ignore Standard.Category.Sniff -- for reasons. @@ -149,29 +163,30 @@ public function dataGetDeclaredName() ], ], 'namespace-operator' => [ - '/* testNamespaceOperator */', - [ + 'testMarker' => '/* testNamespaceOperator */', + 'expected' => [ 'clean' => false, 'dirty' => false, ], + 'skipOnPHP8' => true, ], 'parse-error-reserved-keywords' => [ - '/* testParseErrorReservedKeywords */', - [ + 'testMarker' => '/* testParseErrorReservedKeywords */', + 'expected' => [ 'clean' => 'Vendor\while\Package\protected\name\try\this', 'dirty' => 'Vendor\while\Package\protected\name\try\this', ], ], 'parse-error-semicolon' => [ - '/* testParseErrorSemiColon */', - [ + 'testMarker' => '/* testParseErrorSemiColon */', + 'expected' => [ 'clean' => false, 'dirty' => false, ], ], 'live-coding' => [ - '/* testLiveCoding */', - [ + 'testMarker' => '/* testLiveCoding */', + 'expected' => [ 'clean' => false, 'dirty' => false, ], diff --git a/Tests/Utils/Namespaces/NamespaceTypeTest.inc b/Tests/Utils/Namespaces/NamespaceTypeTest.inc index 99e13c1a..7b9c31ab 100644 --- a/Tests/Utils/Namespaces/NamespaceTypeTest.inc +++ b/Tests/Utils/Namespaces/NamespaceTypeTest.inc @@ -45,6 +45,9 @@ namespace\ClassName::$property++; /* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken3 */ namespace\CONSTANT['key']; +/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken4 */ +namespace\functionReturningObj()?->chained(); + /* testParseErrorScopedNamespaceDeclaration */ function testScope() { diff --git a/Tests/Utils/Namespaces/NamespaceTypeTest.php b/Tests/Utils/Namespaces/NamespaceTypeTest.php index 5eb39394..320eae61 100644 --- a/Tests/Utils/Namespaces/NamespaceTypeTest.php +++ b/Tests/Utils/Namespaces/NamespaceTypeTest.php @@ -26,7 +26,7 @@ * * @since 1.0.0 */ -class NamespaceTypeTest extends UtilityMethodTestCase +final class NamespaceTypeTest extends UtilityMethodTestCase { /** @@ -60,11 +60,18 @@ public function testNonNamespaceToken() * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected output for the functions. + * @param bool $skipOnPHP8 Optional. Whether the test should be skipped when the PHP 8 identifier + * name tokenization is used (as the target token won't exist). + * Defaults to `false`. * * @return void */ - public function testIsDeclaration($testMarker, $expected) + public function testIsDeclaration($testMarker, $expected, $skipOnPHP8 = false) { + if ($skipOnPHP8 === true && parent::usesPhp8NameTokens() === true) { + $this->markTestSkipped("PHP 8.0 identifier name tokenization used. Target token won't exist."); + } + $stackPtr = $this->getTargetToken($testMarker, \T_NAMESPACE); $result = Namespaces::isDeclaration(self::$phpcsFile, $stackPtr); @@ -78,11 +85,18 @@ public function testIsDeclaration($testMarker, $expected) * * @param string $testMarker The comment which prefaces the target token in the test file. * @param array $expected The expected output for the functions. + * @param bool $skipOnPHP8 Optional. Whether the test should be skipped when the PHP 8 identifier + * name tokenization is used (as the target token won't exist). + * Defaults to `false`. * * @return void */ - public function testIsOperator($testMarker, $expected) + public function testIsOperator($testMarker, $expected, $skipOnPHP8 = false) { + if ($skipOnPHP8 === true && parent::usesPhp8NameTokens() === true) { + $this->markTestSkipped("PHP 8.0 identifier name tokenization used. Target token won't exist."); + } + $stackPtr = $this->getTargetToken($testMarker, \T_NAMESPACE); $result = Namespaces::isOperator(self::$phpcsFile, $stackPtr); @@ -101,128 +115,144 @@ public function dataNamespaceType() { return [ 'namespace-declaration' => [ - '/* testNamespaceDeclaration */', - [ + 'testMarker' => '/* testNamespaceDeclaration */', + 'expected' => [ 'declaration' => true, 'operator' => false, ], ], 'namespace-declaration-with-comment' => [ - '/* testNamespaceDeclarationWithComment */', - [ + 'testMarker' => '/* testNamespaceDeclarationWithComment */', + 'expected' => [ 'declaration' => true, 'operator' => false, ], ], 'namespace-declaration-scoped' => [ - '/* testNamespaceDeclarationScoped */', - [ + 'testMarker' => '/* testNamespaceDeclarationScoped */', + 'expected' => [ 'declaration' => true, 'operator' => false, ], ], 'namespace-operator' => [ - '/* testNamespaceOperator */', - [ + 'testMarker' => '/* testNamespaceOperator */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-with-annotation' => [ - '/* testNamespaceOperatorWithAnnotation */', - [ + 'testMarker' => '/* testNamespaceOperatorWithAnnotation */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], ], 'namespace-operator-in-conditional' => [ - '/* testNamespaceOperatorInConditional */', - [ + 'testMarker' => '/* testNamespaceOperatorInConditional */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-in-closed-scope' => [ - '/* testNamespaceOperatorInClosedScope */', - [ + 'testMarker' => '/* testNamespaceOperatorInClosedScope */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-in-parentheses' => [ - '/* testNamespaceOperatorInParentheses */', - [ + 'testMarker' => '/* testNamespaceOperatorInParentheses */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-global-namespace-start-of-statement-function-call' => [ - '/* testNamespaceOperatorGlobalNamespaceStartOfStatementFunctionCall */', - [ + 'testMarker' => '/* testNamespaceOperatorGlobalNamespaceStartOfStatementFunctionCall */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-1' => [ - '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken1 */', - [ + 'testMarker' => '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken1 */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-2' => [ - '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken2 */', - [ + 'testMarker' => '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken2 */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-3' => [ - '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken3 */', - [ + 'testMarker' => '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken3 */', + 'expected' => [ + 'declaration' => false, + 'operator' => true, + ], + 'skipOnPHP8' => true, + ], + 'namespace-operator-global-namespace-start-of-statement-with-non-confusing-token-4' => [ + 'testMarker' => '/* testNamespaceOperatorGlobalNamespaceStartOfStatementCombiWithNonConfusingToken4 */', + 'expected' => [ 'declaration' => false, 'operator' => true, ], + 'skipOnPHP8' => true, ], 'parse-error-scoped-namespace-declaration' => [ - '/* testParseErrorScopedNamespaceDeclaration */', - [ + 'testMarker' => '/* testParseErrorScopedNamespaceDeclaration */', + 'expected' => [ 'declaration' => false, 'operator' => false, ], ], 'parse-error-conditional-namespace' => [ - '/* testParseErrorConditionalNamespace */', - [ + 'testMarker' => '/* testParseErrorConditionalNamespace */', + 'expected' => [ 'declaration' => false, 'operator' => false, ], ], 'fatal-error-declaration-leading-slash' => [ - '/* testFatalErrorDeclarationLeadingSlash */', - [ + 'testMarker' => '/* testFatalErrorDeclarationLeadingSlash */', + 'expected' => [ 'declaration' => false, 'operator' => false, ], ], 'parse-error-double-colon' => [ - '/* testParseErrorDoubleColon */', - [ + 'testMarker' => '/* testParseErrorDoubleColon */', + 'expected' => [ 'declaration' => false, 'operator' => false, ], ], 'parse-error-semicolon' => [ - '/* testParseErrorSemiColon */', - [ + 'testMarker' => '/* testParseErrorSemiColon */', + 'expected' => [ 'declaration' => false, 'operator' => false, ], ], 'live-coding' => [ - '/* testLiveCoding */', - [ + 'testMarker' => '/* testLiveCoding */', + 'expected' => [ 'declaration' => false, 'operator' => false, ], diff --git a/Tests/Utils/NamingConventions/IsEqualTest.php b/Tests/Utils/NamingConventions/IsEqualTest.php index 2f084b4a..85104ce9 100644 --- a/Tests/Utils/NamingConventions/IsEqualTest.php +++ b/Tests/Utils/NamingConventions/IsEqualTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsEqualTest extends TestCase +final class IsEqualTest extends TestCase { /** @@ -52,49 +52,49 @@ public function dataIsEqual() { return [ 'a-z-0-9-only-same-case' => [ - 'abcdefghijklmnopqrstuvwxyz_0123456789', - 'abcdefghijklmnopqrstuvwxyz_0123456789', - true, + 'inputA' => 'abcdefghijklmnopqrstuvwxyz_0123456789', + 'inputB' => 'abcdefghijklmnopqrstuvwxyz_0123456789', + 'expected' => true, ], 'a-z-0-9-only-different-case' => [ - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789', - 'abcdefghijklmnopqrstuvwxyz_0123456789', - true, + 'inputA' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789', + 'inputB' => 'abcdefghijklmnopqrstuvwxyz_0123456789', + 'expected' => true, ], 'extended-ascii-same-case' => [ - 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', - 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', - true, + 'inputA' => 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', + 'inputB' => 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', + 'expected' => true, ], 'extended-ascii-different-case' => [ - 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', - 'çÜÉÂÄÀÅÇÊËÈÏÎÌäåéÆæÔÖÒÛÙŸöü¢ÁÍÓÚÑñ', - false, + 'inputA' => 'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢áíóúñÑ', + 'inputB' => 'çÜÉÂÄÀÅÇÊËÈÏÎÌäåéÆæÔÖÒÛÙŸöü¢ÁÍÓÚÑñ', + 'expected' => false, ], 'mixed-ascii-extended-ascii-same-case' => [ - 'Déjàvü', - 'Déjàvü', - true, + 'inputA' => 'Déjàvü', + 'inputB' => 'Déjàvü', + 'expected' => true, ], 'mixed-ascii-extended-ascii-different-case-only-for-ascii' => [ - 'Déjàvü', - 'déJàVü', - true, + 'inputA' => 'Déjàvü', + 'inputB' => 'déJàVü', + 'expected' => true, ], 'mixed-ascii-extended-ascii-different-case' => [ - 'Déjàvü', - 'DÉJÀVÜ', - false, + 'inputA' => 'Déjàvü', + 'inputB' => 'DÉJÀVÜ', + 'expected' => false, ], 'emoji-name' => [ - '💩💩💩', - '💩💩💩', - true, + 'inputA' => '💩💩💩', + 'inputB' => '💩💩💩', + 'expected' => true, ], 'invalid-input-but-not-relevant' => [ - true, - true, - true, + 'inputA' => true, + 'inputB' => true, + 'expected' => true, ], ]; } diff --git a/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php b/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php index 316a0283..d3b6b195 100644 --- a/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php +++ b/Tests/Utils/NamingConventions/IsValidIdentifierNameTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsValidIdentifierNameTest extends TestCase +final class IsValidIdentifierNameTest extends TestCase { /** @@ -52,78 +52,78 @@ public function dataIsValidIdentifierName() return [ // Valid names. 'a-z-only' => [ - 'valid_name', - true, + 'input' => 'valid_name', + 'expected' => true, ], 'a-z-uppercase' => [ - 'VALID_NAME', - true, + 'input' => 'VALID_NAME', + 'expected' => true, ], 'a-z-camel-caps' => [ - 'Valid_Name', - true, + 'input' => 'Valid_Name', + 'expected' => true, ], 'alphanum-mixed-case' => [ - 'VaLiD128NaMe', - true, + 'input' => 'VaLiD128NaMe', + 'expected' => true, ], 'underscore-prefix' => [ - '_valid_name', - true, + 'input' => '_valid_name', + 'expected' => true, ], 'double-underscore-prefix' => [ - '__valid_name', - true, + 'input' => '__valid_name', + 'expected' => true, ], 'extended-ascii-lowercase' => [ - 'пасха', - true, + 'input' => 'пасха', + 'expected' => true, ], 'extended-ascii-mixed-case' => [ - 'Пасха', - true, + 'input' => 'Пасха', + 'expected' => true, ], 'extended-ascii-non-letter' => [ - '¢£¥ƒ¿½¼«»±÷˜°²', - true, + 'input' => '¢£¥ƒ¿½¼«»±÷˜°²', + 'expected' => true, ], 'emoji-name-1' => [ - '💩💩💩', - true, + 'input' => '💩💩💩', + 'expected' => true, ], 'emoji-name-2' => [ - '😎', - true, + 'input' => '😎', + 'expected' => true, ], // Invalid names. 'not-a-string' => [ - 12345, - false, + 'input' => 12345, + 'expected' => false, ], 'empty-string' => [ - '', - false, + 'input' => '', + 'expected' => false, ], 'name-with-whitespace' => [ - 'aa bb', - false, + 'input' => 'aa bb', + 'expected' => false, ], 'starts-with-number' => [ - '2beornot2be', - false, + 'input' => '2beornot2be', + 'expected' => false, ], 'name-with-quotes-in-it' => [ - "aa'1'", - false, + 'input' => "aa'1'", + 'expected' => false, ], 'name-with-dash' => [ - 'some-thing', - false, + 'input' => 'some-thing', + 'expected' => false, ], 'name-with-punctuation-chars' => [ - '!@#$%&*(){}[]', - false, + 'input' => '!@#$%&*(){}[]', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/Numbers/GetCompleteNumberTest.inc b/Tests/Utils/Numbers/GetCompleteNumberTest.inc index 475b68ac..bf808e58 100644 --- a/Tests/Utils/Numbers/GetCompleteNumberTest.inc +++ b/Tests/Utils/Numbers/GetCompleteNumberTest.inc @@ -1,7 +1,7 @@ '); - self::$usableBackfill = \version_compare(self::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '>'); - } - /** * Test receiving an exception when a non-numeric token is passed to the method. * @@ -76,25 +38,6 @@ public function testNotANumberException() Numbers::getCompleteNumber(self::$phpcsFile, $stackPtr); } - /** - * Test receiving an exception when PHPCS is run on PHP < 7.4 in combination with PHPCS 3.5.3. - * - * @return void - */ - public function testUnsupportedPhpcsException() - { - if (\version_compare(static::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '!=') === true) { - $this->markTestSkipped('Test specific to a limited set of PHPCS versions'); - } - - $this->expectPhpcsException( - 'The PHPCSUtils\Utils\Numbers::getCompleteNumber() method does not support PHPCS ' - ); - - $stackPtr = $this->getTargetToken('/* testPHP74IntDecimalMultiUnderscore */', \T_LNUMBER); - Numbers::getCompleteNumber(self::$phpcsFile, $stackPtr); - } - /** * Test correctly identifying all tokens belonging to a numeric literal. * @@ -107,13 +50,6 @@ public function testUnsupportedPhpcsException() */ public function testGetCompleteNumber($testMarker, $expected) { - // Skip the test(s) on unsupported PHPCS versions. - if (\version_compare(static::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '==') === true) { - $this->markTestSkipped( - 'PHPCS ' . static::$phpcsVersion . ' is not supported due to buggy numeric string literal backfill.' - ); - } - $stackPtr = $this->getTargetToken($testMarker, [\T_LNUMBER, \T_DNUMBER]); $expected['last_token'] += $stackPtr; @@ -136,12 +72,6 @@ public function testGetCompleteNumber($testMarker, $expected) */ public function dataGetCompleteNumber() { - self::setUpStaticProperties(); - $multiToken = true; - if (self::$php74OrHigher === true || self::$usableBackfill === true) { - $multiToken = false; - } - /* * Disabling the hexnumeric string detection for the rest of the file. * These are only strings within the context of PHPCS and need to be tested as such. @@ -152,8 +82,8 @@ public function dataGetCompleteNumber() return [ // Ordinary numbers. 'normal-integer-decimal' => [ - '/* testIntDecimal */', - [ + 'testMarker' => '/* testIntDecimal */', + 'expected' => [ 'orig_content' => '1000000000', 'content' => '1000000000', 'code' => \T_LNUMBER, @@ -162,9 +92,20 @@ public function dataGetCompleteNumber() 'last_token' => 0, // Offset from $stackPtr. ], ], + 'normal-integer-larger-than-intmax-is-float' => [ + 'testMarker' => '/* testIntLargerThanIntMaxIsFloat */', + 'expected' => [ + 'orig_content' => '10223372036854775810', + 'content' => '10223372036854775810', + 'code' => \T_DNUMBER, + 'type' => 'T_DNUMBER', + 'decimal' => '10223372036854775810', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], 'normal-float' => [ - '/* testFloat */', - [ + 'testMarker' => '/* testFloat */', + 'expected' => [ 'orig_content' => '107925284.88', 'content' => '107925284.88', 'code' => \T_DNUMBER, @@ -174,8 +115,8 @@ public function dataGetCompleteNumber() ], ], 'normal-float-negative' => [ - '/* testFloatNegative */', - [ + 'testMarker' => '/* testFloatNegative */', + 'expected' => [ 'orig_content' => '58987.789', 'content' => '58987.789', 'code' => \T_DNUMBER, @@ -185,8 +126,8 @@ public function dataGetCompleteNumber() ], ], 'normal-integer-binary' => [ - '/* testIntBinary */', - [ + 'testMarker' => '/* testIntBinary */', + 'expected' => [ 'orig_content' => '0b1', 'content' => '0b1', 'code' => \T_LNUMBER, @@ -196,8 +137,8 @@ public function dataGetCompleteNumber() ], ], 'normal-integer-hex' => [ - '/* testIntHex */', - [ + 'testMarker' => '/* testIntHex */', + 'expected' => [ 'orig_content' => '0xA', 'content' => '0xA', 'code' => \T_LNUMBER, @@ -207,8 +148,8 @@ public function dataGetCompleteNumber() ], ], 'normal-integer-octal' => [ - '/* testIntOctal */', - [ + 'testMarker' => '/* testIntOctal */', + 'expected' => [ 'orig_content' => '052', 'content' => '052', 'code' => \T_LNUMBER, @@ -220,8 +161,8 @@ public function dataGetCompleteNumber() // Parse error. 'parse-error' => [ - '/* testParseError */', - [ + 'testMarker' => '/* testParseError */', + 'expected' => [ 'orig_content' => '100', 'content' => '100', 'code' => \T_LNUMBER, @@ -233,188 +174,199 @@ public function dataGetCompleteNumber() // Numeric literal with underscore. 'php-7.4-integer-decimal-multi-underscore' => [ - '/* testPHP74IntDecimalMultiUnderscore */', - [ + 'testMarker' => '/* testPHP74IntDecimalMultiUnderscore */', + 'expected' => [ 'orig_content' => '1_000_000_000', 'content' => '1000000000', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '1000000000', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-7.4-integer-larger-than-intmax-is-float' => [ + 'testMarker' => '/* testPHP74IntLargerThanIntMaxIsFloat */', + 'expected' => [ + 'orig_content' => '10_223_372_036_854_775_810', + 'content' => '10223372036854775810', + 'code' => \T_DNUMBER, + 'type' => 'T_DNUMBER', + 'decimal' => '10223372036854775810', + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float' => [ - '/* testPHP74Float */', - [ + 'testMarker' => '/* testPHP74Float */', + 'expected' => [ 'orig_content' => '107_925_284.88', 'content' => '107925284.88', 'code' => \T_DNUMBER, 'type' => 'T_DNUMBER', 'decimal' => '107925284.88', - 'last_token' => $multiToken ? 2 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-decimal-single-underscore' => [ - '/* testPHP74IntDecimalSingleUnderscore */', - [ + 'testMarker' => '/* testPHP74IntDecimalSingleUnderscore */', + 'expected' => [ 'orig_content' => '135_00', 'content' => '13500', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '13500', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float-exponent-negative' => [ - '/* testPHP74FloatExponentNegative */', - [ + 'testMarker' => '/* testPHP74FloatExponentNegative */', + 'expected' => [ 'orig_content' => '6.674_083e-11', 'content' => '6.674083e-11', 'code' => \T_DNUMBER, 'type' => 'T_DNUMBER', 'decimal' => '6.674083e-11', - 'last_token' => $multiToken ? 3 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float-exponent-positive' => [ - '/* testPHP74FloatExponentPositive */', - [ + 'testMarker' => '/* testPHP74FloatExponentPositive */', + 'expected' => [ 'orig_content' => '6.674_083e+11', 'content' => '6.674083e+11', 'code' => \T_DNUMBER, 'type' => 'T_DNUMBER', 'decimal' => '6.674083e+11', - 'last_token' => $multiToken ? 3 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-decimal-multi-underscore-2' => [ - '/* testPHP74IntDecimalMultiUnderscore2 */', - [ + 'testMarker' => '/* testPHP74IntDecimalMultiUnderscore2 */', + 'expected' => [ 'orig_content' => '299_792_458', 'content' => '299792458', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '299792458', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-hex' => [ - '/* testPHP74IntHex */', - [ + 'testMarker' => '/* testPHP74IntHex */', + 'expected' => [ 'orig_content' => '0xCAFE_F00D', 'content' => '0xCAFEF00D', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '3405705229', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-binary' => [ - '/* testPHP74IntBinary */', - [ + 'testMarker' => '/* testPHP74IntBinary */', + 'expected' => [ 'orig_content' => '0b0101_1111', 'content' => '0b01011111', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '95', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-octal' => [ - '/* testPHP74IntOctal */', - [ + 'testMarker' => '/* testPHP74IntOctal */', + 'expected' => [ 'orig_content' => '0137_041', 'content' => '0137041', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '48673', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float-exponent-multi-underscore' => [ - '/* testPHP74FloatExponentMultiUnderscore */', - [ + 'testMarker' => '/* testPHP74FloatExponentMultiUnderscore */', + 'expected' => [ 'orig_content' => '1_2.3_4e1_23', 'content' => '12.34e123', 'code' => \T_DNUMBER, 'type' => 'T_DNUMBER', 'decimal' => '12.34e123', - 'last_token' => $multiToken ? 3 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], // Make sure the backfill doesn't do more than it should. 'php-7.4-integer-calculation-1' => [ - '/* testPHP74IntCalc1 */', - [ + 'testMarker' => '/* testPHP74IntCalc1 */', + 'expected' => [ 'orig_content' => '667_083', 'content' => '667083', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '667083', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-calculation-2' => [ - '/* testPHP74IntCalc2 */', - [ + 'testMarker' => '/* testPHP74IntCalc2 */', + 'expected' => [ 'orig_content' => '74_083', 'content' => '74083', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '74083', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float-calculation-1' => [ - '/* testPHP74FloatCalc1 */', - [ + 'testMarker' => '/* testPHP74FloatCalc1 */', + 'expected' => [ 'orig_content' => '6.674_08e3', 'content' => '6.67408e3', 'code' => \T_DNUMBER, 'type' => 'T_DNUMBER', 'decimal' => '6.67408e3', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float-calculation-2' => [ - '/* testPHP74FloatCalc2 */', - [ + 'testMarker' => '/* testPHP74FloatCalc2 */', + 'expected' => [ 'orig_content' => '6.674_08e3', 'content' => '6.67408e3', 'code' => \T_DNUMBER, 'type' => 'T_DNUMBER', 'decimal' => '6.67408e3', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-integer-whitespace' => [ - '/* testPHP74IntWhitespace */', - [ + 'testMarker' => '/* testPHP74IntWhitespace */', + 'expected' => [ 'orig_content' => '107_925_284', 'content' => '107925284', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '107925284', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], 'php-7.4-float-comments' => [ - '/* testPHP74FloatComments */', - [ + 'testMarker' => '/* testPHP74FloatComments */', + 'expected' => [ 'orig_content' => '107_925_284', 'content' => '107925284', 'code' => \T_LNUMBER, 'type' => 'T_LNUMBER', 'decimal' => '107925284', - 'last_token' => $multiToken ? 1 : 0, // Offset from $stackPtr. + 'last_token' => 0, // Offset from $stackPtr. ], ], // Invalid numeric literal with underscore. 'php-7.4-invalid-1' => [ - '/* testPHP74Invalid1 */', - [ + 'testMarker' => '/* testPHP74Invalid1 */', + 'expected' => [ 'orig_content' => '100', 'content' => '100', 'code' => \T_LNUMBER, @@ -424,8 +376,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-2' => [ - '/* testPHP74Invalid2 */', - [ + 'testMarker' => '/* testPHP74Invalid2 */', + 'expected' => [ 'orig_content' => '1', 'content' => '1', 'code' => \T_LNUMBER, @@ -435,8 +387,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-3' => [ - '/* testPHP74Invalid3 */', - [ + 'testMarker' => '/* testPHP74Invalid3 */', + 'expected' => [ 'orig_content' => '1', 'content' => '1', 'code' => \T_LNUMBER, @@ -446,8 +398,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-4' => [ - '/* testPHP74Invalid4 */', - [ + 'testMarker' => '/* testPHP74Invalid4 */', + 'expected' => [ 'orig_content' => '1.', 'content' => '1.', 'code' => \T_DNUMBER, @@ -457,8 +409,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-5' => [ - '/* testPHP74Invalid5 */', - [ + 'testMarker' => '/* testPHP74Invalid5 */', + 'expected' => [ 'orig_content' => '0', 'content' => '0', 'code' => \T_LNUMBER, @@ -468,8 +420,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-6' => [ - '/* testPHP74Invalid6 */', - [ + 'testMarker' => '/* testPHP74Invalid6 */', + 'expected' => [ 'orig_content' => '0', 'content' => '0', 'code' => \T_LNUMBER, @@ -479,8 +431,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-7' => [ - '/* testPHP74Invalid7 */', - [ + 'testMarker' => '/* testPHP74Invalid7 */', + 'expected' => [ 'orig_content' => '1', 'content' => '1', 'code' => \T_LNUMBER, @@ -490,8 +442,8 @@ public function dataGetCompleteNumber() ], ], 'php-7.4-invalid-8' => [ - '/* testPHP74Invalid8 */', - [ + 'testMarker' => '/* testPHP74Invalid8 */', + 'expected' => [ 'orig_content' => '1', 'content' => '1', 'code' => \T_LNUMBER, @@ -500,9 +452,100 @@ public function dataGetCompleteNumber() 'last_token' => 0, // Offset from $stackPtr. ], ], + + // PHP 8.1 explicit octal notation. + 'php-8.1-explicit-octal-lowercase' => [ + 'testMarker' => '/* testPHP81ExplicitOctal */', + 'expected' => [ + 'orig_content' => '0o137041', + 'content' => '0o137041', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '48673', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-8.1-explicit-octal-uppercase' => [ + 'testMarker' => '/* testPHP81ExplicitOctalUppercase */', + 'expected' => [ + 'orig_content' => '0O137041', + 'content' => '0O137041', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '48673', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-8.1-explicit-octal-with-separator' => [ + 'testMarker' => '/* testPHP81ExplicitOctalWithSeparator */', + 'expected' => [ + 'orig_content' => '0o137_041', + 'content' => '0o137041', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '48673', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-8.1-invalid-octal-1' => [ + 'testMarker' => '/* testPHP81InvalidExplicitOctal1 */', + 'expected' => [ + 'orig_content' => '0', + 'content' => '0', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '0', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-8.1-invalid-octal-2' => [ + 'testMarker' => '/* testPHP81InvalidExplicitOctal2 */', + 'expected' => [ + 'orig_content' => '0O2', + 'content' => '0O2', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '2', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-8.1-invalid-octal-3' => [ + 'testMarker' => '/* testPHP81InvalidExplicitOctal3 */', + 'expected' => [ + 'orig_content' => '0o2', + 'content' => '0o2', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '2', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-8.1-invalid-octal-4' => [ + 'testMarker' => '/* testPHP81InvalidExplicitOctal4 */', + 'expected' => [ + 'orig_content' => '0o2', + 'content' => '0o2', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '2', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'php-7.4-8.1-invalid-explicit-octal' => [ + 'testMarker' => '/* testPHP74PHP81InvalidExplicitOctal */', + 'expected' => [ + 'orig_content' => '0', + 'content' => '0', + 'code' => \T_LNUMBER, + 'type' => 'T_LNUMBER', + 'decimal' => '0', + 'last_token' => 0, // Offset from $stackPtr. + ], + ], + 'live-coding' => [ - '/* testLiveCoding */', - [ + 'testMarker' => '/* testLiveCoding */', + 'expected' => [ 'orig_content' => '100', 'content' => '100', 'code' => \T_LNUMBER, diff --git a/Tests/Utils/Numbers/GetDecimalValueTest.php b/Tests/Utils/Numbers/GetDecimalValueTest.php index f404a6ae..0dd2fec8 100644 --- a/Tests/Utils/Numbers/GetDecimalValueTest.php +++ b/Tests/Utils/Numbers/GetDecimalValueTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetDecimalValueTest extends TestCase +final class GetDecimalValueTest extends TestCase { /** @@ -80,6 +80,11 @@ public function dataGetDecimalValue() 'octal-int-10' => ['012', '10'], 'octal-int-1024' => ['02000', '1024'], 'octal-int-1024-php-7.4' => ['020_00', '1024'], + + // Octal PHP 8.1 explicit notation. + 'explicit-octal-int-10' => ['0o12', '10'], + 'explicit-octal-int-1024' => ['0O2000', '1024'], + 'explicit-octal-int-1024-php-7.4' => ['0o20_00', '1024'], ]; } @@ -119,6 +124,7 @@ public function dataGetDecimalValueInvalid() 'invalid-hex' => ['0xZBHI28'], 'invalid-binary' => ['0b121457182'], 'invalid-octal' => ['0289'], + 'invalid-octal-explicit-notation' => ['0o289'], ]; } } diff --git a/Tests/Utils/Numbers/NumberTypesTest.php b/Tests/Utils/Numbers/NumberTypesTest.php index 242c8155..60cffb6b 100644 --- a/Tests/Utils/Numbers/NumberTypesTest.php +++ b/Tests/Utils/Numbers/NumberTypesTest.php @@ -20,18 +20,20 @@ * \PHPCSUtils\Utils\Numbers::isOctalInt() and the * \PHPCSUtils\Utils\Numbers::isFloat() method. * + * @coversDefaultClass \PHPCSUtils\Utils\Numbers + * * @group numbers * * @since 1.0.0 */ -class NumberTypesTest extends TestCase +final class NumberTypesTest extends TestCase { /** * Test correctly recognizing an arbitrary string representing a decimal integer. * * @dataProvider dataNumbers - * @covers \PHPCSUtils\Utils\Numbers::isDecimalInt + * @covers ::isDecimalInt * * @param string $input The input string. * @param string $expected The expected output for the various functions. @@ -47,7 +49,7 @@ public function testIsDecimalInt($input, $expected) * Test correctly recognizing an arbitrary string representing a hexidecimal integer. * * @dataProvider dataNumbers - * @covers \PHPCSUtils\Utils\Numbers::isHexidecimalInt + * @covers ::isHexidecimalInt * * @param string $input The input string. * @param string $expected The expected output for the various functions. @@ -63,7 +65,7 @@ public function testIsHexidecimalInt($input, $expected) * Test correctly recognizing an arbitrary string representing a binary integer. * * @dataProvider dataNumbers - * @covers \PHPCSUtils\Utils\Numbers::isBinaryInt + * @covers ::isBinaryInt * * @param string $input The input string. * @param string $expected The expected output for the various functions. @@ -79,7 +81,7 @@ public function testIsBinaryInt($input, $expected) * Test correctly recognizing an arbitrary string representing an octal integer. * * @dataProvider dataNumbers - * @covers \PHPCSUtils\Utils\Numbers::isOctalInt + * @covers ::isOctalInt * * @param string $input The input string. * @param string $expected The expected output for the various functions. @@ -95,7 +97,7 @@ public function testIsOctalInt($input, $expected) * Test correctly recognizing an arbitrary string representing a decimal float. * * @dataProvider dataNumbers - * @covers \PHPCSUtils\Utils\Numbers::isFloat + * @covers ::isFloat * * @param string $input The input string. * @param string $expected The expected output for the various functions. @@ -123,8 +125,8 @@ public static function dataNumbers() return [ // Not strings. 'not-a-string-bool' => [ - true, - [ + 'input' => true, + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -133,8 +135,8 @@ public static function dataNumbers() ], ], 'not-a-string-int' => [ - 10, - [ + 'input' => 10, + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -145,8 +147,8 @@ public static function dataNumbers() // Not numeric strings. 'empty-string' => [ - '', - [ + 'input' => '', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -155,8 +157,8 @@ public static function dataNumbers() ], ], 'string-not-a-number' => [ - 'foobar', - [ + 'input' => 'foobar', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -165,8 +167,8 @@ public static function dataNumbers() ], ], 'string-not-a-number-with-full-stop' => [ - 'foo. bar', - [ + 'input' => 'foo. bar', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -175,8 +177,8 @@ public static function dataNumbers() ], ], 'invalid-hex' => [ - '0xZBHI28', - [ + 'input' => '0xZBHI28', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -185,8 +187,8 @@ public static function dataNumbers() ], ], 'invalid-binary' => [ - '0b121457182', - [ + 'input' => '0b121457182', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -196,8 +198,18 @@ public static function dataNumbers() ], 'invalid-octal' => [ // Note: in PHP 5.x this would still be accepted, though not interpreted correctly. - '0289', - [ + 'input' => '0289', + 'expected' => [ + 'decimal' => false, + 'hex' => false, + 'binary' => false, + 'octal' => false, + 'float' => false, + ], + ], + 'invalid-explicit-octal' => [ + 'input' => '0o289', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -206,8 +218,8 @@ public static function dataNumbers() ], ], 'invalid-float-two-decimal-points' => [ - '1.287.2763', - [ + 'input' => '1.287.2763', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -216,8 +228,8 @@ public static function dataNumbers() ], ], 'invalid-float-plus-no-exponent' => [ - '1.287+2763', - [ + 'input' => '1.287+2763', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -226,8 +238,8 @@ public static function dataNumbers() ], ], 'invalid-float-minus-no-exponent' => [ - '1287-2763', - [ + 'input' => '1287-2763', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -236,8 +248,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-no-multiplier' => [ - '2872e', - [ + 'input' => '2872e', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -246,8 +258,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-plus-no-multiplier' => [ - '1.2872e+', - [ + 'input' => '1.2872e+', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -256,8 +268,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-minus-no-multiplier' => [ - '1.2872e-', - [ + 'input' => '1.2872e-', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -266,8 +278,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-multiplier-float' => [ - '376e2.3', - [ + 'input' => '376e2.3', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -276,8 +288,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-plus-multiplier-float' => [ - '3.76e+2.3', - [ + 'input' => '3.76e+2.3', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -286,8 +298,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-minus-multiplier-float' => [ - '37.6e-2.3', - [ + 'input' => '37.6e-2.3', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -296,8 +308,8 @@ public static function dataNumbers() ], ], 'invalid-float-exponent-plus-minus-multiplier' => [ - '37.6e+-2', - [ + 'input' => '37.6e+-2', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -306,8 +318,8 @@ public static function dataNumbers() ], ], 'invalid-float-double-exponent' => [ - '37.6e2e6', - [ + 'input' => '37.6e2e6', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -318,8 +330,8 @@ public static function dataNumbers() // Decimal numeric strings. 'decimal-single-digit-zero' => [ - '0', - [ + 'input' => '0', + 'expected' => [ 'decimal' => true, 'hex' => false, 'binary' => false, @@ -328,8 +340,8 @@ public static function dataNumbers() ], ], 'decimal-single-digit' => [ - '9', - [ + 'input' => '9', + 'expected' => [ 'decimal' => true, 'hex' => false, 'binary' => false, @@ -338,8 +350,8 @@ public static function dataNumbers() ], ], 'decimal-multi-digit' => [ - '123456', - [ + 'input' => '123456', + 'expected' => [ 'decimal' => true, 'hex' => false, 'binary' => false, @@ -348,8 +360,8 @@ public static function dataNumbers() ], ], 'decimal-multi-digit-php-7.4' => [ - '12_34_56', - [ + 'input' => '12_34_56', + 'expected' => [ 'decimal' => true, 'hex' => false, 'binary' => false, @@ -361,8 +373,8 @@ public static function dataNumbers() // Hexidecimal numeric strings. // phpcs:disable PHPCompatibility.Miscellaneous.ValidIntegers.HexNumericStringFound 'hexidecimal-single-digit-zero' => [ - '0x0', - [ + 'input' => '0x0', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -371,8 +383,8 @@ public static function dataNumbers() ], ], 'hexidecimal-single-digit' => [ - '0xA', - [ + 'input' => '0xA', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -381,8 +393,8 @@ public static function dataNumbers() ], ], 'hexidecimal-multi-digit-all-numbers' => [ - '0x123456', - [ + 'input' => '0x123456', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -391,8 +403,8 @@ public static function dataNumbers() ], ], 'hexidecimal-multi-digit-no-numbers' => [ - '0xABCDEF', - [ + 'input' => '0xABCDEF', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -401,8 +413,8 @@ public static function dataNumbers() ], ], 'hexidecimal-multi-digit-mixed' => [ - '0xAB02F6', - [ + 'input' => '0xAB02F6', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -411,8 +423,8 @@ public static function dataNumbers() ], ], 'hexidecimal-multi-digit-mixed-uppercase-x' => [ - '0XAB953C', - [ + 'input' => '0XAB953C', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -421,8 +433,8 @@ public static function dataNumbers() ], ], 'hexidecimal-multi-digit-php-7.4' => [ - '0x23_6A_3C', - [ + 'input' => '0x23_6A_3C', + 'expected' => [ 'decimal' => false, 'hex' => true, 'binary' => false, @@ -434,8 +446,8 @@ public static function dataNumbers() // Binary numeric strings. 'binary-single-digit-zero' => [ - '0b0', - [ + 'input' => '0b0', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => true, @@ -444,8 +456,8 @@ public static function dataNumbers() ], ], 'binary-single-digit-one' => [ - '0b1', - [ + 'input' => '0b1', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => true, @@ -454,8 +466,8 @@ public static function dataNumbers() ], ], 'binary-multi-digit' => [ - '0b1010', - [ + 'input' => '0b1010', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => true, @@ -464,8 +476,8 @@ public static function dataNumbers() ], ], 'binary-multi-digit-uppercase-b' => [ - '0B1000100100000', - [ + 'input' => '0B1000100100000', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => true, @@ -474,8 +486,8 @@ public static function dataNumbers() ], ], 'binary-multi-digit-php-7.4' => [ - '0b100_000_000_00', - [ + 'input' => '0b100_000_000_00', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => true, @@ -486,8 +498,8 @@ public static function dataNumbers() // Octal numeric strings. 'octal-single-digit-zero' => [ - '00', - [ + 'input' => '00', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -496,8 +508,8 @@ public static function dataNumbers() ], ], 'octal-single-digit' => [ - '07', - [ + 'input' => '07', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -506,8 +518,8 @@ public static function dataNumbers() ], ], 'octal-multi-digit' => [ - '076543210', - [ + 'input' => '076543210', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -516,8 +528,50 @@ public static function dataNumbers() ], ], 'octal-multi-digit-php-7.4' => [ - '020_631_542', - [ + 'input' => '020_631_542', + 'expected' => [ + 'decimal' => false, + 'hex' => false, + 'binary' => false, + 'octal' => true, + 'float' => false, + ], + ], + + // Octal numeric strings using PHP 8.1 explicit octal notation. + 'explicit-octal-single-digit-zero' => [ + 'input' => '0o0', + 'expected' => [ + 'decimal' => false, + 'hex' => false, + 'binary' => false, + 'octal' => true, + 'float' => false, + ], + ], + 'explicit-octal-single-digit' => [ + 'input' => '0O7', + 'expected' => [ + 'decimal' => false, + 'hex' => false, + 'binary' => false, + 'octal' => true, + 'float' => false, + ], + ], + 'explicit-octal-multi-digit' => [ + 'input' => '0o76543210', + 'expected' => [ + 'decimal' => false, + 'hex' => false, + 'binary' => false, + 'octal' => true, + 'float' => false, + ], + ], + 'explicit-octal-multi-digit-php-7.4' => [ + 'input' => '0O20_631_542', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -528,8 +582,8 @@ public static function dataNumbers() // Floating point numeric strings. Also see: decimal numeric strings. 'float-single-digit-dot-zero' => [ - '0.', - [ + 'input' => '0.', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -538,8 +592,8 @@ public static function dataNumbers() ], ], 'float-single-digit-dot' => [ - '1.', - [ + 'input' => '1.', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -548,8 +602,8 @@ public static function dataNumbers() ], ], 'float-multi-digit-dot' => [ - '56458.', - [ + 'input' => '56458.', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -558,8 +612,8 @@ public static function dataNumbers() ], ], 'float-multi-digit-dot-leading-zero' => [ - '0023.', - [ + 'input' => '0023.', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -568,8 +622,8 @@ public static function dataNumbers() ], ], 'float-multi-digit-dot-php-7.4' => [ - '521_879.', - [ + 'input' => '521_879.', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -579,8 +633,8 @@ public static function dataNumbers() ], 'float-dot-single-digit-zero' => [ - '.0', - [ + 'input' => '.0', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -589,8 +643,8 @@ public static function dataNumbers() ], ], 'float-dot-single-digit' => [ - '.2', - [ + 'input' => '.2', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -599,8 +653,8 @@ public static function dataNumbers() ], ], 'float-dot-multi-digit' => [ - '.232746', - [ + 'input' => '.232746', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -609,8 +663,8 @@ public static function dataNumbers() ], ], 'float-dot-multi-digit-trailing-zero' => [ - '.345300', - [ + 'input' => '.345300', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -619,8 +673,8 @@ public static function dataNumbers() ], ], 'float-dot-multi-digit-php-7.4' => [ - '.421_789_8', - [ + 'input' => '.421_789_8', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -630,8 +684,8 @@ public static function dataNumbers() ], 'float-digit-dot-digit-single-zero' => [ - '0.0', - [ + 'input' => '0.0', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -640,8 +694,8 @@ public static function dataNumbers() ], ], 'float-digit-dot-digit-single' => [ - '9.1', - [ + 'input' => '9.1', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -650,8 +704,8 @@ public static function dataNumbers() ], ], 'float-digit-dot-digit-multi' => [ - '7483.2182', - [ + 'input' => '7483.2182', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -660,8 +714,8 @@ public static function dataNumbers() ], ], 'float-digit-dot-digit-multi-leading-zero' => [ - '002781.21928173', - [ + 'input' => '002781.21928173', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -670,8 +724,8 @@ public static function dataNumbers() ], ], 'float-digit-dot-digit-multi-trailing-zero' => [ - '213.2987000', - [ + 'input' => '213.2987000', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -680,8 +734,8 @@ public static function dataNumbers() ], ], 'float-digit-dot-digit-multi-leading-zero-trailing-zero' => [ - '07262.2760', - [ + 'input' => '07262.2760', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -690,8 +744,8 @@ public static function dataNumbers() ], ], 'float-digit-dot-digit-multi--php-7.4' => [ - '07_262.276_720', - [ + 'input' => '07_262.276_720', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -701,8 +755,8 @@ public static function dataNumbers() ], 'float-exponent-digit-dot-digit-zero-exp-single-digit' => [ - '0.0e1', - [ + 'input' => '0.0e1', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -711,8 +765,8 @@ public static function dataNumbers() ], ], 'float-exponent-single-digit-dot-exp-double-digit' => [ - '1.e28', - [ + 'input' => '1.e28', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -721,8 +775,8 @@ public static function dataNumbers() ], ], 'float-exponent-multi-digit-dot-exp-plus-digit' => [ - '56458.e+2', - [ + 'input' => '56458.e+2', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -731,8 +785,8 @@ public static function dataNumbers() ], ], 'float-exponent-multi-digit-dot-leading-zero-exp-minus-digit' => [ - '0023.e-44', - [ + 'input' => '0023.e-44', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -742,8 +796,8 @@ public static function dataNumbers() ], 'float-exponent-dot-single-digit-zero-exp-minus-digit' => [ - '.0e-1', - [ + 'input' => '.0e-1', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -752,8 +806,8 @@ public static function dataNumbers() ], ], 'float-exponent-dot-single-digit-exp-plus-digit-zero' => [ - '.2e+0', - [ + 'input' => '.2e+0', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -762,8 +816,8 @@ public static function dataNumbers() ], ], 'float-exponent-dot-multi-digit-exp-multi-digit' => [ - '.232746e41', - [ + 'input' => '.232746e41', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -772,8 +826,8 @@ public static function dataNumbers() ], ], 'float-exponent-dot-multi-digit-trailing-zero-exp-multi-digit' => [ - '.345300e87', - [ + 'input' => '.345300e87', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -783,8 +837,8 @@ public static function dataNumbers() ], 'float-exponent-digit-dot-digit-single-zero-exp-uppercase' => [ - '0.0E2', - [ + 'input' => '0.0E2', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -793,8 +847,8 @@ public static function dataNumbers() ], ], 'float-exponent-digit-dot-digit-single-exp-uppercase' => [ - '9.1E47', - [ + 'input' => '9.1E47', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -803,8 +857,8 @@ public static function dataNumbers() ], ], 'float-exponent-digit-dot-digit-multi-exp-minus-digit' => [ - '7483.2182e-3', - [ + 'input' => '7483.2182e-3', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -813,8 +867,8 @@ public static function dataNumbers() ], ], 'float-exponent-digit-dot-digit-multi-leading-zero-exp-uppercase' => [ - '002781.21928173E+56', - [ + 'input' => '002781.21928173E+56', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -823,8 +877,8 @@ public static function dataNumbers() ], ], 'float-exponent-digit-dot-digit-multi-trailing-zero-exp-plus-digit' => [ - '213.2987000e+2', - [ + 'input' => '213.2987000e+2', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -833,8 +887,8 @@ public static function dataNumbers() ], ], 'float-exponent-digit-dot-digit-multi-leading-zero-trailing-zero-exp-digit' => [ - '07262.2760e4', - [ + 'input' => '07262.2760e4', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, @@ -843,8 +897,8 @@ public static function dataNumbers() ], ], 'float-exponent-digit-dot-digit-exp-digit-php-7.4' => [ - '6.674_083e+1_1', - [ + 'input' => '6.674_083e+1_1', + 'expected' => [ 'decimal' => false, 'hex' => false, 'binary' => false, diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.inc b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.inc index c03aee8d..60220f03 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.inc +++ b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.inc @@ -6,5 +6,8 @@ class testDeclarationWithComments // phpcs:ignore Stnd.Cat.Sniff -- For reasons. \Package\SubDir /* comment */ \ /* comment */ SomeClass /* comment */ {} +/* testExtendedClassUsingNamespaceOperator */ +class testWithNSOperator extends namespace\Bar {} + /* testExtendedClassStrayComma */ class testExtendedClassStrayComma extends , testClass {} // Intentional parse error. diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php index d07ddd92..5da5a50e 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameDiffTest.php @@ -26,7 +26,7 @@ * * @since 1.0.0 */ -class FindExtendedClassNameDiffTest extends UtilityMethodTestCase +final class FindExtendedClassNameDiffTest extends UtilityMethodTestCase { /** @@ -57,12 +57,16 @@ public function dataFindExtendedClassName() { return [ 'phpcs-annotation-and-comments' => [ - '/* testDeclarationWithComments */', - '\Package\SubDir\SomeClass', + 'testMarker' => '/* testDeclarationWithComments */', + 'expected' => '\Package\SubDir\SomeClass', + ], + 'namespace-operator' => [ + 'testMarker' => '/* testExtendedClassUsingNamespaceOperator */', + 'expected' => 'namespace\Bar', ], 'parse-error-stray-comma' => [ - '/* testExtendedClassStrayComma */', - 'testClass', + 'testMarker' => '/* testExtendedClassStrayComma */', + 'expected' => 'testClass', ], ]; } diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php index 04bb95e0..396ff5dd 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php +++ b/Tests/Utils/ObjectDeclarations/FindExtendedClassNameTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class FindExtendedClassNameTest extends BCFile_FindExtendedClassNameTest +final class FindExtendedClassNameTest extends BCFile_FindExtendedClassNameTest { /** diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.inc b/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.inc index 420ead9d..cbc06538 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.inc +++ b/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.inc @@ -28,6 +28,12 @@ interface testMultiExtendedInterfaceWithComments { } +/* testNamespaceRelativeQualifiedInterface */ +interface testQualifiedInterfaces extends Core\File\RelativeInterface, Another\RelativeInterface {} + +/* testExtendsUsingNamespaceOperator */ +interface testWithNSOperator extends namespace\BarInterface, namespace\Sub\SomeOther {} + // Intentional parse error. Has to be the last test in the file. /* testParseError */ interface testParseError extends testInterface diff --git a/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php b/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php index e4d57b12..3da86aaa 100644 --- a/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php +++ b/Tests/Utils/ObjectDeclarations/FindExtendedInterfaceNamesTest.php @@ -23,7 +23,7 @@ * * @since 1.0.0 */ -class FindExtendedInterfaceNamesTest extends UtilityMethodTestCase +final class FindExtendedInterfaceNamesTest extends UtilityMethodTestCase { /** @@ -77,42 +77,56 @@ public function dataFindExtendedInterfaceNames() { return [ 'not-extended' => [ - '/* testInterface */', - false, + 'testMarker' => '/* testInterface */', + 'expected' => false, ], 'extends-one' => [ - '/* testExtendedInterface */', - ['testInterface'], + 'testMarker' => '/* testExtendedInterface */', + 'expected' => ['testInterface'], ], 'extends-two' => [ - '/* testMultiExtendedInterface */', - [ + 'testMarker' => '/* testMultiExtendedInterface */', + 'expected' => [ 'testInterfaceA', 'testInterfaceB', ], ], 'extends-one-namespaced' => [ - '/* testExtendedNamespacedInterface */', - ['\PHPCSUtils\Tests\ObjectDeclarations\testInterface'], + 'testMarker' => '/* testExtendedNamespacedInterface */', + 'expected' => ['\PHPCSUtils\Tests\ObjectDeclarations\testInterface'], ], 'extends-two-namespaced' => [ - '/* testMultiExtendedNamespacedInterface */', - [ + 'testMarker' => '/* testMultiExtendedNamespacedInterface */', + 'expected' => [ '\PHPCSUtils\Tests\ObjectDeclarations\testInterfaceA', '\PHPCSUtils\Tests\ObjectDeclarations\testFEINInterfaceB', ], ], 'extends-with-comments' => [ - '/* testMultiExtendedInterfaceWithComments */', - [ + 'testMarker' => '/* testMultiExtendedInterfaceWithComments */', + 'expected' => [ 'testInterfaceA', '\PHPCSUtils\Tests\Some\Declarations\testInterfaceB', '\testInterfaceC', ], ], + 'extends-partially-qualified-names' => [ + 'testMarker' => '/* testNamespaceRelativeQualifiedInterface */', + 'expected' => [ + 'Core\File\RelativeInterface', + 'Another\RelativeInterface', + ], + ], + 'extends-using-namespace-operator' => [ + 'testMarker' => '/* testExtendsUsingNamespaceOperator */', + 'expected' => [ + 'namespace\BarInterface', + 'namespace\Sub\SomeOther', + ], + ], 'parse-error' => [ - '/* testParseError */', - false, + 'testMarker' => '/* testParseError */', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.inc b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.inc index 0cd35a9d..46069654 100644 --- a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.inc +++ b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.inc @@ -13,5 +13,8 @@ class testDeclarationWithComments // comment InterfaceB {} +/* testDeclarationMultiImplementedNamespaceOperator */ +class testMultiImplementedNSOperator implements namespace\testInterfaceA, namespace\testInterfaceB {} + /* testMultiImplementedStrayComma */ class testMultiImplementedStrayComma implements testInterfaceA, , testInterfaceB {} // Intentional parse error. diff --git a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php index 1f8f07b8..34706c96 100644 --- a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesDiffTest.php @@ -26,7 +26,7 @@ * * @since 1.0.0 */ -class FindImplementedInterfaceNamesDiffTest extends UtilityMethodTestCase +final class FindImplementedInterfaceNamesDiffTest extends UtilityMethodTestCase { /** @@ -41,7 +41,7 @@ class FindImplementedInterfaceNamesDiffTest extends UtilityMethodTestCase */ public function testFindImplementedInterfaceNames($testMarker, $expected) { - $OOToken = $this->getTargetToken($testMarker, [\T_CLASS, \T_ANON_CLASS, \T_INTERFACE]); + $OOToken = $this->getTargetToken($testMarker, [\T_CLASS, \T_ANON_CLASS, \T_INTERFACE, \T_ENUM]); $result = ObjectDeclarations::findImplementedInterfaceNames(self::$phpcsFile, $OOToken); $this->assertSame($expected, $result); } @@ -57,15 +57,22 @@ public function dataFindImplementedInterfaceNames() { return [ 'phpcs-annotation-and-comments' => [ - '/* testDeclarationWithComments */', - [ + 'testMarker' => '/* testDeclarationWithComments */', + 'expected' => [ '\Vendor\Package\Core\SubDir\SomeInterface', 'InterfaceB', ], ], + 'namespace-operator' => [ + 'testMarker' => '/* testDeclarationMultiImplementedNamespaceOperator */', + 'expected' => [ + 'namespace\testInterfaceA', + 'namespace\testInterfaceB', + ], + ], 'parse-error-stray-comma' => [ - '/* testMultiImplementedStrayComma */', - [ + 'testMarker' => '/* testMultiImplementedStrayComma */', + 'expected' => [ 0 => 'testInterfaceA', 1 => 'testInterfaceB', ], diff --git a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php index fe6bc029..5bcfe651 100644 --- a/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php +++ b/Tests/Utils/ObjectDeclarations/FindImplementedInterfaceNamesTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class FindImplementedInterfaceNamesTest extends BCFile_FindImplInterfaceNamesTest +final class FindImplementedInterfaceNamesTest extends BCFile_FindImplInterfaceNamesTest { /** diff --git a/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.inc b/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.inc index 2d771907..2abe6a38 100644 --- a/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.inc +++ b/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.inc @@ -5,7 +5,7 @@ final // phpcs:ignore Standard.Cat.SniffName -- Just because. class PHPCSAnnotation {} -/* testWithDocblockWithWeirdlyPlacedProperty */ +/* testWithDocblockWithWeirdlyPlacedModifier */ final /** @@ -15,11 +15,21 @@ final * * @phpcs:disable Standard.Cat.SniffName -- Just because. */ -class ClassWithPropertyBeforeDocblock {} +class ClassWithModifierBeforeDocblock {} -/* testParseErrorAbstractFinal */ -final /* comment */ +/* testReadonlyClass */ +readonly class ReadOnlyClass {} - abstract // Intentional parse error, class cannot both be final and abstract. +/* testFinalReadonlyClass */ +final readonly class FinalReadOnlyClass extends Foo {} - class AbstractFinal {} +/* testReadonlyFinalClass */ +readonly /*comment*/ final class ReadOnlyFinalClass {} + +/* testAbstractReadonlyClass */ +abstract readonly class AbstractReadOnlyClass {} + +/* testReadonlyAbstractClass */ +readonly +abstract +class ReadOnlyAbstractClass {} diff --git a/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php b/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php index 3ff4fcbb..95fa8e02 100644 --- a/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/GetClassPropertiesDiffTest.php @@ -25,7 +25,7 @@ * * @since 1.0.0 */ -class GetClassPropertiesDiffTest extends UtilityMethodTestCase +final class GetClassPropertiesDiffTest extends UtilityMethodTestCase { /** @@ -68,24 +68,59 @@ public function dataGetClassProperties() { return [ 'phpcs-annotation' => [ - '/* testPHPCSAnnotations */', - [ + 'testMarker' => '/* testPHPCSAnnotations */', + 'expected' => [ 'is_abstract' => false, 'is_final' => true, + 'is_readonly' => false, ], ], 'unorthodox-docblock-placement' => [ - '/* testWithDocblockWithWeirdlyPlacedProperty */', + 'testMarker' => '/* testWithDocblockWithWeirdlyPlacedModifier */', + 'expected' => [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => false, + ], + ], + 'readonly' => [ + '/* testReadonlyClass */', + [ + 'is_abstract' => false, + 'is_final' => false, + 'is_readonly' => true, + ], + ], + 'final-readonly' => [ + '/* testFinalReadonlyClass */', [ 'is_abstract' => false, 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'readonly-final' => [ + '/* testReadonlyFinalClass */', + [ + 'is_abstract' => false, + 'is_final' => true, + 'is_readonly' => true, + ], + ], + 'abstract-readonly' => [ + '/* testAbstractReadonlyClass */', + [ + 'is_abstract' => true, + 'is_final' => false, + 'is_readonly' => true, ], ], - 'abstract-final-parse-error' => [ - '/* testParseErrorAbstractFinal */', + 'readonly-abstract' => [ + '/* testReadonlyAbstractClass */', [ 'is_abstract' => true, 'is_final' => false, + 'is_readonly' => true, ], ], ]; diff --git a/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php b/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php index 05f271f5..82f7cb19 100644 --- a/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php +++ b/Tests/Utils/ObjectDeclarations/GetClassPropertiesTest.php @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class GetClassPropertiesTest extends BCFile_GetClassPropertiesTest +final class GetClassPropertiesTest extends BCFile_GetClassPropertiesTest { /** @@ -55,4 +55,21 @@ public static function setUpTestFile() self::$caseFile = \dirname(\dirname(__DIR__)) . '/BackCompat/BCFile/GetClassPropertiesTest.inc'; parent::setUpTestFile(); } + + /** + * Data provider. + * + * @see testGetClassProperties() For the array format. + * + * @return array + */ + public function dataGetClassProperties() + { + $data = parent::dataGetClassProperties(); + foreach ($data as $name => $dataset) { + $data[$name][1]['is_readonly'] = false; + } + + return $data; + } } diff --git a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php index e29d9b9d..c23a2b01 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameDiffTest.php @@ -25,7 +25,7 @@ * * @since 1.0.0 */ -class GetNameDiffTest extends UtilityMethodTestCase +final class GetNameDiffTest extends UtilityMethodTestCase { /** @@ -67,8 +67,8 @@ public function dataGetNameNull() { return [ 'live-coding' => [ - '/* testLiveCoding */', - \T_CLASS, + 'testMarker' => '/* testLiveCoding */', + 'targetType' => \T_CLASS, ], ]; } @@ -87,7 +87,7 @@ public function dataGetNameNull() public function testGetName($testMarker, $expected, $targetType = null) { if (isset($targetType) === false) { - $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]; + $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM, \T_FUNCTION]; } $target = $this->getTargetToken($testMarker, $targetType); @@ -106,16 +106,16 @@ public function dataGetName() { return [ 'trait-name-starts-with-number' => [ - '/* testTraitStartingWithNumber */', - '5InvalidNameStartingWithNumber', + 'testMarker' => '/* testTraitStartingWithNumber */', + 'expected' => '5InvalidNameStartingWithNumber', ], 'interface-fully-numeric-name' => [ - '/* testInterfaceFullyNumeric */', - '12345', + 'testMarker' => '/* testInterfaceFullyNumeric */', + 'expected' => '12345', ], 'using-reserved-keyword-as-name' => [ - '/* testInvalidInterfaceName */', - 'switch', + 'testMarker' => '/* testInvalidInterfaceName */', + 'expected' => 'switch', ], ]; } diff --git a/Tests/Utils/ObjectDeclarations/GetNameJSTest.php b/Tests/Utils/ObjectDeclarations/GetNameJSTest.php index c9835127..875761bd 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameJSTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameJSTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetNameJSTest extends BCFile_GetDeclarationNameJSTest +final class GetNameJSTest extends BCFile_GetDeclarationNameJSTest { /** @@ -54,7 +54,7 @@ public static function setUpTestFile() */ public function testInvalidTokenPassed() { - $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); + $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); $target = $this->getTargetToken('/* testInvalidTokenPassed */', \T_STRING); ObjectDeclarations::getName(self::$phpcsFile, $target); @@ -95,7 +95,7 @@ public function testGetDeclarationNameNull($testMarker, $targetType) public function testGetDeclarationName($testMarker, $expected, $targetType = null) { if (isset($targetType) === false) { - $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]; + $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM, \T_FUNCTION]; } $target = $this->getTargetToken($testMarker, $targetType); @@ -112,10 +112,6 @@ public function testGetDeclarationName($testMarker, $expected, $targetType = nul */ public function testGetDeclarationNameES6Method() { - if (\version_compare(static::$phpcsVersion, '3.0.0', '<') === true) { - $this->markTestSkipped('Support for JS ES6 method has not been backfilled for PHPCS 2.x (yet)'); - } - $target = $this->getTargetToken('/* testMethod */', [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]); $result = ObjectDeclarations::getName(self::$phpcsFile, $target); $this->assertSame('methodName', $result); diff --git a/Tests/Utils/ObjectDeclarations/GetNameTest.php b/Tests/Utils/ObjectDeclarations/GetNameTest.php index b41e849f..eb1e1509 100644 --- a/Tests/Utils/ObjectDeclarations/GetNameTest.php +++ b/Tests/Utils/ObjectDeclarations/GetNameTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class GetNameTest extends BCFile_GetDeclarationNameTest +final class GetNameTest extends BCFile_GetDeclarationNameTest { /** @@ -54,7 +54,7 @@ public static function setUpTestFile() */ public function testInvalidTokenPassed() { - $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE or T_TRAIT'); + $this->expectPhpcsException('Token type "T_STRING" is not T_FUNCTION, T_CLASS, T_INTERFACE, T_TRAIT or T_ENUM'); $target = $this->getTargetToken('/* testInvalidTokenPassed */', \T_STRING); ObjectDeclarations::getName(self::$phpcsFile, $target); @@ -95,7 +95,7 @@ public function testGetDeclarationNameNull($testMarker, $targetType) public function testGetDeclarationName($testMarker, $expected, $targetType = null) { if (isset($targetType) === false) { - $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_FUNCTION]; + $targetType = [\T_CLASS, \T_INTERFACE, \T_TRAIT, \T_ENUM, \T_FUNCTION]; } $target = $this->getTargetToken($testMarker, $targetType); diff --git a/Tests/Utils/Operators/IsReferenceDiffTest.inc b/Tests/Utils/Operators/IsReferenceDiffTest.inc deleted file mode 100644 index 2f9f0e04..00000000 --- a/Tests/Utils/Operators/IsReferenceDiffTest.inc +++ /dev/null @@ -1,13 +0,0 @@ -assertFalse(Operators::isReference(self::$phpcsFile, 10000)); - } - - /** - * Test correctly identifying that whether a "bitwise and" token is a reference or not. + * Initialize PHPCS & tokenize the test case file. * - * @dataProvider dataIsReference - * - * @param string $identifier Comment which precedes the test case. - * @param bool $expected Expected function output. + * @beforeClass * * @return void */ - public function testIsReference($identifier, $expected) + public static function setUpTestFile() { - $bitwiseAnd = $this->getTargetToken($identifier, \T_BITWISE_AND); - $result = Operators::isReference(self::$phpcsFile, $bitwiseAnd); - $this->assertSame($expected, $result); + self::$caseFile = \dirname(\dirname(__DIR__)) . '/DummyFile.inc'; + parent::setUpTestFile(); } /** - * Data provider. - * - * @see testIsReference() + * Test passing a non-existent token pointer. * - * @return array + * @return void */ - public function dataIsReference() + public function testNonExistentToken() { - return [ - 'issue-1971-list-first-in-file' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271A */', - true, - ], - 'issue-1971-list-first-in-file-nested' => [ - '/* testTokenizerIssue1971PHPCSlt330gt271B */', - true, - ], - 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ - '/* testTokenizerIssue1284PHPCSlt280A */', - true, - ], - 'issue-1284-short-list-directly-after-close-curly-control-structure-second-item' => [ - '/* testTokenizerIssue1284PHPCSlt280B */', - true, - ], - 'issue-1284-short-array-directly-after-close-curly-control-structure' => [ - '/* testTokenizerIssue1284PHPCSlt280C */', - true, - ], - ]; + $this->assertFalse(Operators::isReference(self::$phpcsFile, 10000)); } } diff --git a/Tests/Utils/Operators/IsReferenceTest.php b/Tests/Utils/Operators/IsReferenceTest.php index fbbce68a..76b04f72 100644 --- a/Tests/Utils/Operators/IsReferenceTest.php +++ b/Tests/Utils/Operators/IsReferenceTest.php @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class IsReferenceTest extends BCFile_IsReferenceTest +final class IsReferenceTest extends BCFile_IsReferenceTest { /** diff --git a/Tests/Utils/Operators/IsShortTernaryTest.inc b/Tests/Utils/Operators/IsShortTernaryTest.inc index 8561039c..a8b2436e 100644 --- a/Tests/Utils/Operators/IsShortTernaryTest.inc +++ b/Tests/Utils/Operators/IsShortTernaryTest.inc @@ -19,24 +19,6 @@ $foo = $foo ? /* deliberately left empty */ // phpcs:ignore Stnd.Cat.Sniff -- For reasons. : 'bar'; -/* testDontConfuseWithNullCoalesce */ -$foo = $foo ?? 0; - -/* testDontConfuseWithNullCoalesceEquals */ -$foo ??= 0; - -class Foo { - /* testDontConfuseWithNullable1 */ - protected ?int $property = 1; - - public function bar( - /* testDontConfuseWithNullable2 */ - ?bool $param - /* testDontConfuseWithNullable3 */ - ) : ?\My\ClassName { - } -} - /* testParseError */ // Intentional parse error. This has to be the last test in the file. $foo = $foo ? diff --git a/Tests/Utils/Operators/IsShortTernaryTest.php b/Tests/Utils/Operators/IsShortTernaryTest.php index c5a66c60..9539f3b6 100644 --- a/Tests/Utils/Operators/IsShortTernaryTest.php +++ b/Tests/Utils/Operators/IsShortTernaryTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsShortTernaryTest extends UtilityMethodTestCase +final class IsShortTernaryTest extends UtilityMethodTestCase { /** @@ -78,91 +78,20 @@ public function dataIsShortTernary() { return [ 'long-ternary' => [ - '/* testLongTernary */', - false, + 'testMarker' => '/* testLongTernary */', + 'expected' => false, ], 'short-ternary-no-space' => [ - '/* testShortTernaryNoSpace */', - true, + 'testMarker' => '/* testShortTernaryNoSpace */', + 'expected' => true, ], 'short-ternary-long-space' => [ - '/* testShortTernaryLongSpace */', - true, + 'testMarker' => '/* testShortTernaryLongSpace */', + 'expected' => true, ], 'short-ternary-comments-annotations' => [ - '/* testShortTernaryWithCommentAndAnnotations */', - true, - ], - ]; - } - - /** - * Safeguard that incorrectly tokenized T_INLINE_THEN or T_INLINE_ELSE tokens are correctly - * rejected as not short ternary. - * - * {@internal None of these are really problematic, but better to be safe than sorry.} - * - * @dataProvider dataIsShortTernaryTokenizerIssues - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int|string $tokenType The token code to look for. - * - * @return void - */ - public function testIsShortTernaryTokenizerIssues($testMarker, $tokenType = \T_INLINE_THEN) - { - $stackPtr = $this->getTargetToken($testMarker, $tokenType); - $result = Operators::isShortTernary(self::$phpcsFile, $stackPtr); - $this->assertFalse($result); - } - - /** - * Data provider. - * - * @see testIsShortTernaryTokenizerIssues() For the array format. - * - * @return array - */ - public function dataIsShortTernaryTokenizerIssues() - { - $targetCoalesce = [\T_INLINE_THEN]; - if (\defined('T_COALESCE')) { - $targetCoalesce[] = \T_COALESCE; - } - - $targetCoalesceAndEquals = $targetCoalesce; - if (\defined('T_COALESCE_EQUAL')) { - $targetCoalesceAndEquals[] = \T_COALESCE_EQUAL; - } - - $targetNullable = [\T_INLINE_THEN]; - if (\defined('T_NULLABLE')) { - $targetNullable[] = \T_NULLABLE; - } - - return [ - 'null-coalesce' => [ - '/* testDontConfuseWithNullCoalesce */', - $targetCoalesce, - ], - 'null-coalesce-equals' => [ - '/* testDontConfuseWithNullCoalesceEquals */', - $targetCoalesceAndEquals, - ], - 'nullable-property' => [ - '/* testDontConfuseWithNullable1 */', - $targetNullable, - ], - 'nullable-param-type' => [ - '/* testDontConfuseWithNullable2 */', - $targetNullable, - ], - 'nullable-return-type' => [ - '/* testDontConfuseWithNullable3 */', - $targetNullable, - ], - 'parse-error' => [ - '/* testParseError */', + 'testMarker' => '/* testShortTernaryWithCommentAndAnnotations */', + 'expected' => true, ], ]; } diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php b/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php index 86c0af65..ef47170d 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php +++ b/Tests/Utils/Operators/IsUnaryPlusMinusJSTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Utils\Operators; -use PHPCSUtils\Tests\Utils\Operators\IsUnaryPlusMinusTest; +use PHPCSUtils\Tests\Utils\Operators\IsUnaryPlusMinusTestCase; /** * Tests for the \PHPCSUtils\Utils\Operators::isUnaryPlusMinus() method. @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class IsUnaryPlusMinusJSTest extends IsUnaryPlusMinusTest +final class IsUnaryPlusMinusJSTest extends IsUnaryPlusMinusTestCase { /** @@ -42,32 +42,32 @@ public function dataIsUnaryPlusMinus() { return [ 'non-unary-plus' => [ - '/* testNonUnaryPlus */', - false, + 'testMarker' => '/* testNonUnaryPlus */', + 'expected' => false, ], 'non-unary-minus' => [ - '/* testNonUnaryMinus */', - false, + 'testMarker' => '/* testNonUnaryMinus */', + 'expected' => false, ], 'unary-minus-colon' => [ - '/* testUnaryMinusColon */', - true, + 'testMarker' => '/* testUnaryMinusColon */', + 'expected' => true, ], 'unary-minus-switch-case' => [ - '/* testUnaryMinusCase */', - true, + 'testMarker' => '/* testUnaryMinusCase */', + 'expected' => true, ], 'unary-minus-ternary-then' => [ - '/* testUnaryMinusTernaryThen */', - true, + 'testMarker' => '/* testUnaryMinusTernaryThen */', + 'expected' => true, ], 'unary-minus-ternary-else' => [ - '/* testUnaryPlusTernaryElse */', - true, + 'testMarker' => '/* testUnaryPlusTernaryElse */', + 'expected' => true, ], 'unary-minus-if-condition' => [ - '/* testUnaryMinusIfCondition */', - true, + 'testMarker' => '/* testUnaryMinusIfCondition */', + 'expected' => true, ], ]; } diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusTest.inc b/Tests/Utils/Operators/IsUnaryPlusMinusTest.inc index fb9f9eee..0ab78a6b 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusTest.inc +++ b/Tests/Utils/Operators/IsUnaryPlusMinusTest.inc @@ -71,7 +71,7 @@ $a = $a ? -1 : + 10; /* testUnaryMinusCoalesce */ -$a = $a ?? -1 : +$a = $a ?? -1 ; /* testUnaryPlusIntReturn */ return +1; @@ -79,6 +79,9 @@ return +1; /* testUnaryMinusFloatReturn */ return -1.1; +/* testUnaryPlusIntExit */ +exit -1; + /* testUnaryPlusPrint */ print +$b; @@ -126,15 +129,27 @@ declare( ticks = +10 ); switch ($a) { /* testUnaryPlusCase */ case +20: - // Something. - break; + /* testUnaryPlusContinue */ + continue +2; /* testUnaryMinusCase */ case -1.23: - // Something. - break; + /* testUnaryPlusBreak */ + break +1; } +/* testUnaryMinusArrowFunction */ +$fn = static fn(DateTime $a, DateTime $b): int => -($a->getTimestamp() <=> $b->getTimestamp()); + +$matcher = match ($a) { + /* testUnaryPlusMatchArrow */ + 'a' => +1, + /* testUnaryMinusMatchArrow */ + 'b', 'c', 'd' => -2, + /* testUnaryMinusMatchDefault */ + default => -3, +}; + // Testing `$a = -+-+10`; $a = /* testSequenceNonUnary1 */ @@ -146,12 +161,6 @@ $a = /* testSequenceUnaryEnd */ + /*comment*/ 10; -/* testPHP74NumericLiteralFloatContainingPlus */ -$a = 6.674_083e+11; - -/* testPHP74NumericLiteralFloatContainingMinus */ -$a = 6.674_083e-1_1; - /* testPHP74NumericLiteralIntCalc1 */ $a = 667_083 - 11; diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php index 68c0c75a..93514299 100644 --- a/Tests/Utils/Operators/IsUnaryPlusMinusTest.php +++ b/Tests/Utils/Operators/IsUnaryPlusMinusTest.php @@ -10,9 +10,7 @@ namespace PHPCSUtils\Tests\Utils\Operators; -use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Utils\Numbers; -use PHPCSUtils\Utils\Operators; +use PHPCSUtils\Tests\Utils\Operators\IsUnaryPlusMinusTestCase; /** * Tests for the \PHPCSUtils\Utils\Operators::isUnaryPlusMinus() method. @@ -23,65 +21,9 @@ * * @since 1.0.0 */ -class IsUnaryPlusMinusTest extends UtilityMethodTestCase +final class IsUnaryPlusMinusTest extends IsUnaryPlusMinusTestCase { - /** - * Test that false is returned when a non-existent token is passed. - * - * @return void - */ - public function testNonExistentToken() - { - $this->assertFalse(Operators::isUnaryPlusMinus(self::$phpcsFile, 10000)); - } - - /** - * Test that false is returned when a non-plus/minus token is passed. - * - * @return void - */ - public function testNotPlusMinusToken() - { - $target = $this->getTargetToken('/* testNonUnaryPlus */', \T_LNUMBER); - $this->assertFalse(Operators::isUnaryPlusMinus(self::$phpcsFile, $target)); - } - - /** - * Test whether a T_PLUS or T_MINUS token is a unary operator. - * - * @dataProvider dataIsUnaryPlusMinus - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param bool $expected The expected boolean return value. - * @param bool $maybeSkip Whether the "should this test be skipped" check should be executed. - * Defaults to false. - * - * @return void - */ - public function testIsUnaryPlusMinus($testMarker, $expected, $maybeSkip = false) - { - if ($maybeSkip === true) { - /* - * Skip the test if this is PHP 7.4 or a PHPCS version which backfills the token sequence - * to one token as in that case, the plus/minus token won't exist - */ - $skipMessage = 'Test irrelevant as the target token won\'t exist'; - if (\version_compare(\PHP_VERSION_ID, '70399', '>') === true) { - $this->markTestSkipped($skipMessage); - } - - if (\version_compare(static::$phpcsVersion, Numbers::UNSUPPORTED_PHPCS_VERSION, '>=') === true) { - $this->markTestSkipped($skipMessage); - } - } - - $stackPtr = $this->getTargetToken($testMarker, [\T_PLUS, \T_MINUS]); - $result = Operators::isUnaryPlusMinus(self::$phpcsFile, $stackPtr); - - $this->assertSame($expected, $result); - } - /** * Data provider. * @@ -93,219 +35,237 @@ public function dataIsUnaryPlusMinus() { return [ 'non-unary-plus' => [ - '/* testNonUnaryPlus */', - false, + 'testMarker' => '/* testNonUnaryPlus */', + 'expected' => false, ], 'non-unary-minus' => [ - '/* testNonUnaryMinus */', - false, + 'testMarker' => '/* testNonUnaryMinus */', + 'expected' => false, ], 'non-unary-plus-arrays' => [ - '/* testNonUnaryPlusArrays */', - false, + 'testMarker' => '/* testNonUnaryPlusArrays */', + 'expected' => false, ], 'unary-minus-arithmetic' => [ - '/* testUnaryMinusArithmetic */', - true, + 'testMarker' => '/* testUnaryMinusArithmetic */', + 'expected' => true, ], 'unary-plus-arithmetic' => [ - '/* testUnaryPlusArithmetic */', - true, + 'testMarker' => '/* testUnaryPlusArithmetic */', + 'expected' => true, ], 'unary-minus-concatenation' => [ - '/* testUnaryMinusConcatenation */', - true, + 'testMarker' => '/* testUnaryMinusConcatenation */', + 'expected' => true, ], 'unary-plus-int-assignment' => [ - '/* testUnaryPlusIntAssignment */', - true, + 'testMarker' => '/* testUnaryPlusIntAssignment */', + 'expected' => true, ], 'unary-minus-variable-assignment' => [ - '/* testUnaryMinusVariableAssignment */', - true, + 'testMarker' => '/* testUnaryMinusVariableAssignment */', + 'expected' => true, ], 'unary-plus-float-assignment' => [ - '/* testUnaryPlusFloatAssignment */', - true, + 'testMarker' => '/* testUnaryPlusFloatAssignment */', + 'expected' => true, ], 'unary-minus-bool-assignment' => [ - '/* testUnaryMinusBoolAssignment */', - true, + 'testMarker' => '/* testUnaryMinusBoolAssignment */', + 'expected' => true, ], 'unary-plus-string-assignment-with-comment' => [ - '/* testUnaryPlusStringAssignmentWithComment */', - true, + 'testMarker' => '/* testUnaryPlusStringAssignmentWithComment */', + 'expected' => true, ], 'unary-minus-string-assignment' => [ - '/* testUnaryMinusStringAssignment */', - true, + 'testMarker' => '/* testUnaryMinusStringAssignment */', + 'expected' => true, ], 'unary-plus-plus-null-assignment' => [ - '/* testUnaryPlusNullAssignment */', - true, + 'testMarker' => '/* testUnaryPlusNullAssignment */', + 'expected' => true, ], 'unary-minus-variable-variable-assignment' => [ - '/* testUnaryMinusVariableVariableAssignment */', - true, + 'testMarker' => '/* testUnaryMinusVariableVariableAssignment */', + 'expected' => true, ], 'unary-plus-int-comparison' => [ - '/* testUnaryPlusIntComparison */', - true, + 'testMarker' => '/* testUnaryPlusIntComparison */', + 'expected' => true, ], 'unary-plus-int-comparison-yoda' => [ - '/* testUnaryPlusIntComparisonYoda */', - true, + 'testMarker' => '/* testUnaryPlusIntComparisonYoda */', + 'expected' => true, ], 'unary-minus-float-comparison' => [ - '/* testUnaryMinusFloatComparison */', - true, + 'testMarker' => '/* testUnaryMinusFloatComparison */', + 'expected' => true, ], 'unary-minus-string-comparison-yoda' => [ - '/* testUnaryMinusStringComparisonYoda */', - true, + 'testMarker' => '/* testUnaryMinusStringComparisonYoda */', + 'expected' => true, ], 'unary-plus-variable-boolean' => [ - '/* testUnaryPlusVariableBoolean */', - true, + 'testMarker' => '/* testUnaryPlusVariableBoolean */', + 'expected' => true, ], 'unary-minus-variable-boolean' => [ - '/* testUnaryMinusVariableBoolean */', - true, + 'testMarker' => '/* testUnaryMinusVariableBoolean */', + 'expected' => true, ], 'unary-plus-logical-xor' => [ - '/* testUnaryPlusLogicalXor */', - true, + 'testMarker' => '/* testUnaryPlusLogicalXor */', + 'expected' => true, ], 'unary-minus-ternary-then' => [ - '/* testUnaryMinusTernaryThen */', - true, + 'testMarker' => '/* testUnaryMinusTernaryThen */', + 'expected' => true, ], 'unary-plus-ternary-else' => [ - '/* testUnaryPlusTernaryElse */', - true, + 'testMarker' => '/* testUnaryPlusTernaryElse */', + 'expected' => true, ], 'unary-minus-coalesce' => [ - '/* testUnaryMinusCoalesce */', - true, + 'testMarker' => '/* testUnaryMinusCoalesce */', + 'expected' => true, ], 'unary-plus-int-return' => [ - '/* testUnaryPlusIntReturn */', - true, + 'testMarker' => '/* testUnaryPlusIntReturn */', + 'expected' => true, ], 'unary-minus-float-return' => [ - '/* testUnaryMinusFloatReturn */', - true, + 'testMarker' => '/* testUnaryMinusFloatReturn */', + 'expected' => true, + ], + 'unary-minus-int-exit' => [ + 'testMarker' => '/* testUnaryPlusIntExit */', + 'expected' => true, ], 'unary-plus-print' => [ - '/* testUnaryPlusPrint */', - true, + 'testMarker' => '/* testUnaryPlusPrint */', + 'expected' => true, ], 'unary-minus-echo' => [ - '/* testUnaryMinusEcho */', - true, + 'testMarker' => '/* testUnaryMinusEcho */', + 'expected' => true, ], 'unary-plus-yield' => [ - '/* testUnaryPlusYield */', - true, + 'testMarker' => '/* testUnaryPlusYield */', + 'expected' => true, ], 'unary-plus-array-access' => [ - '/* testUnaryPlusArrayAccess */', - true, + 'testMarker' => '/* testUnaryPlusArrayAccess */', + 'expected' => true, ], 'unary-minus-string-array-access' => [ - '/* testUnaryMinusStringArrayAccess */', - true, + 'testMarker' => '/* testUnaryMinusStringArrayAccess */', + 'expected' => true, ], 'unary-plus-long-array-assignment' => [ - '/* testUnaryPlusLongArrayAssignment */', - true, + 'testMarker' => '/* testUnaryPlusLongArrayAssignment */', + 'expected' => true, ], 'unary-minus-long-array-assignment-key' => [ - '/* testUnaryMinusLongArrayAssignmentKey */', - true, + 'testMarker' => '/* testUnaryMinusLongArrayAssignmentKey */', + 'expected' => true, ], 'unary-plus-long-array-assignment-value' => [ - '/* testUnaryPlusLongArrayAssignmentValue */', - true, + 'testMarker' => '/* testUnaryPlusLongArrayAssignmentValue */', + 'expected' => true, ], 'unary-plus-short-array-assignment' => [ - '/* testUnaryPlusShortArrayAssignment */', - true, + 'testMarker' => '/* testUnaryPlusShortArrayAssignment */', + 'expected' => true, ], 'non-unary-minus-short-array-assignment' => [ - '/* testNonUnaryMinusShortArrayAssignment */', - false, + 'testMarker' => '/* testNonUnaryMinusShortArrayAssignment */', + 'expected' => false, ], 'unary-minus-casts' => [ - '/* testUnaryMinusCast */', - true, + 'testMarker' => '/* testUnaryMinusCast */', + 'expected' => true, ], 'unary-plus-function-call-param' => [ - '/* testUnaryPlusFunctionCallParam */', - true, + 'testMarker' => '/* testUnaryPlusFunctionCallParam */', + 'expected' => true, ], 'unary-minus-function-call-param' => [ - '/* testUnaryMinusFunctionCallParam */', - true, + 'testMarker' => '/* testUnaryMinusFunctionCallParam */', + 'expected' => true, ], 'unary-plus-declare' => [ - '/* testUnaryPlusDeclare */', - true, + 'testMarker' => '/* testUnaryPlusDeclare */', + 'expected' => true, ], 'unary-plus-switch-case' => [ - '/* testUnaryPlusCase */', - true, + 'testMarker' => '/* testUnaryPlusCase */', + 'expected' => true, + ], + 'unary-plus-continue' => [ + 'testMarker' => '/* testUnaryPlusContinue */', + 'expected' => true, ], 'unary-minus-switch-case' => [ - '/* testUnaryMinusCase */', - true, + 'testMarker' => '/* testUnaryMinusCase */', + 'expected' => true, + ], + 'unary-plus-break' => [ + 'testMarker' => '/* testUnaryPlusBreak */', + 'expected' => true, + ], + 'unary-minus-arrow-function' => [ + 'testMarker' => '/* testUnaryMinusArrowFunction */', + 'expected' => true, + ], + 'unary-plus-match-arrow' => [ + 'testMarker' => '/* testUnaryPlusMatchArrow */', + 'expected' => true, + ], + 'unary-minus-match-arrow' => [ + 'testMarker' => '/* testUnaryMinusMatchArrow */', + 'expected' => true, + ], + 'unary-minus-match-default' => [ + 'testMarker' => '/* testUnaryMinusMatchDefault */', + 'expected' => true, ], 'operator-sequence-non-unary-1' => [ - '/* testSequenceNonUnary1 */', - false, + 'testMarker' => '/* testSequenceNonUnary1 */', + 'expected' => false, ], 'operator-sequence-non-unary-2' => [ - '/* testSequenceNonUnary2 */', - false, + 'testMarker' => '/* testSequenceNonUnary2 */', + 'expected' => false, ], 'operator-sequence-non-unary-3' => [ - '/* testSequenceNonUnary3 */', - false, + 'testMarker' => '/* testSequenceNonUnary3 */', + 'expected' => false, ], 'operator-sequence-unary-end' => [ - '/* testSequenceUnaryEnd */', - true, - ], - 'php-7.4-underscore-float-containing-plus' => [ - '/* testPHP74NumericLiteralFloatContainingPlus */', - false, - true, // Skip for PHP 7.4 & PHPCS 3.5.3+. - ], - 'php-7.4-underscore-float-containing-minus' => [ - '/* testPHP74NumericLiteralFloatContainingMinus */', - false, - true, // Skip for PHP 7.4 & PHPCS 3.5.3+. + 'testMarker' => '/* testSequenceUnaryEnd */', + 'expected' => true, ], 'php-7.4-underscore-int-calculation-1' => [ - '/* testPHP74NumericLiteralIntCalc1 */', - false, + 'testMarker' => '/* testPHP74NumericLiteralIntCalc1 */', + 'expected' => false, ], 'php-7.4-underscore-int-calculation-2' => [ - '/* testPHP74NumericLiteralIntCalc2 */', - false, + 'testMarker' => '/* testPHP74NumericLiteralIntCalc2 */', + 'expected' => false, ], 'php-7.4-underscore-float-calculation-1' => [ - '/* testPHP74NumericLiteralFloatCalc1 */', - false, + 'testMarker' => '/* testPHP74NumericLiteralFloatCalc1 */', + 'expected' => false, ], 'php-7.4-underscore-float-calculation-2' => [ - '/* testPHP74NumericLiteralFloatCalc2 */', - false, + 'testMarker' => '/* testPHP74NumericLiteralFloatCalc2 */', + 'expected' => false, ], 'parse-error' => [ - '/* testParseError */', - false, + 'testMarker' => '/* testParseError */', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/Operators/IsUnaryPlusMinusTestCase.php b/Tests/Utils/Operators/IsUnaryPlusMinusTestCase.php new file mode 100644 index 00000000..cb441f01 --- /dev/null +++ b/Tests/Utils/Operators/IsUnaryPlusMinusTestCase.php @@ -0,0 +1,77 @@ +assertFalse(Operators::isUnaryPlusMinus(self::$phpcsFile, 10000)); + } + + /** + * Test that false is returned when a non-plus/minus token is passed. + * + * @covers \PHPCSUtils\Utils\Operators::isUnaryPlusMinus + * + * @return void + */ + public function testNotPlusMinusToken() + { + $target = $this->getTargetToken('/* testNonUnaryPlus */', \T_LNUMBER); + $this->assertFalse(Operators::isUnaryPlusMinus(self::$phpcsFile, $target)); + } + + /** + * Test whether a T_PLUS or T_MINUS token is a unary operator. + * + * @covers \PHPCSUtils\Utils\Operators::isUnaryPlusMinus + * + * @dataProvider dataIsUnaryPlusMinus + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $expected The expected boolean return value. + * + * @return void + */ + public function testIsUnaryPlusMinus($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, [\T_PLUS, \T_MINUS]); + $result = Operators::isUnaryPlusMinus(self::$phpcsFile, $stackPtr); + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testIsUnaryPlusMinus() For the array format. + * + * @return array + */ + abstract public function dataIsUnaryPlusMinus(); +} diff --git a/Tests/Utils/Orthography/FirstCharTest.php b/Tests/Utils/Orthography/FirstCharTest.php index 53f00584..b474ac4e 100644 --- a/Tests/Utils/Orthography/FirstCharTest.php +++ b/Tests/Utils/Orthography/FirstCharTest.php @@ -24,7 +24,7 @@ * * @since 1.0.0 */ -class FirstCharTest extends TestCase +final class FirstCharTest extends TestCase { /** @@ -70,15 +70,15 @@ public function dataFirstChar() $data = [ // Quotes should be stripped before passing the string. 'double-quoted' => [ - '"This is a test"', - [ + 'input' => '"This is a test"', + 'expected' => [ 'capitalized' => false, 'lowercase' => false, ], ], 'single-quoted' => [ - "'This is a test'", - [ + 'input' => "'This is a test'", + 'expected' => [ 'capitalized' => false, 'lowercase' => false, ], @@ -86,15 +86,15 @@ public function dataFirstChar() // Not starting with a letter. 'start-numeric' => [ - '12 Foostreet', - [ + 'input' => '12 Foostreet', + 'expected' => [ 'capitalized' => false, 'lowercase' => false, ], ], 'start-bracket' => [ - '[Optional]', - [ + 'input' => '[Optional]', + 'expected' => [ 'capitalized' => false, 'lowercase' => false, ], @@ -102,17 +102,17 @@ public function dataFirstChar() // Leading whitespace. 'english-lowercase-leading-whitespace' => [ - ' + 'input' => ' this is a test', - [ + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ], 'english-propercase-leading-whitespace' => [ - ' + 'input' => ' This is a test', - [ + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], @@ -120,43 +120,43 @@ public function dataFirstChar() // First character lowercase. 'english-lowercase' => [ - 'this is a test', - [ + 'input' => 'this is a test', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ], 'russian-lowercase' => [ - 'предназначена для‎', - [ + 'input' => 'предназначена для‎', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ], 'latvian-lowercase' => [ - 'ir domāta', - [ + 'input' => 'ir domāta', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ], 'armenian-lowercase' => [ - 'սա թեստ է', - [ + 'input' => 'սա թեստ է', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ], 'mandinka-lowercase' => [ - 'ŋanniya', - [ + 'input' => 'ŋanniya', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ], 'greek-lowercase' => [ - 'δημιουργήθηκε από', - [ + 'input' => 'δημιουργήθηκε από', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], @@ -164,43 +164,43 @@ public function dataFirstChar() // First character capitalized. 'english-propercase' => [ - 'This is a test', - [ + 'input' => 'This is a test', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'russian-propercase' => [ - 'Дата написания этой книги', - [ + 'input' => 'Дата написания этой книги', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'latvian-propercase' => [ - 'Šodienas datums', - [ + 'input' => 'Šodienas datums', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'armenian-propercase' => [ - 'Սա թեստ է', - [ + 'input' => 'Սա թեստ է', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'igbo-propercase' => [ - 'Ụbọchị tata bụ', - [ + 'input' => 'Ụbọchị tata bụ', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'greek-propercase' => [ - 'Η σημερινή ημερομηνία', - [ + 'input' => 'Η σημερινή ημερομηνία', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], @@ -208,36 +208,36 @@ public function dataFirstChar() // No concept of "case", but starting with a letter. 'arabic' => [ - 'هذا اختبار', - [ + 'input' => 'هذا اختبار', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'pashto' => [ - 'دا یوه آزموینه ده', - [ + 'input' => 'دا یوه آزموینه ده', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'hebrew' => [ - 'זה מבחן', - [ + 'input' => 'זה מבחן', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'chinese-traditional' => [ - '這是一個測試', - [ + 'input' => '這是一個測試', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], ], 'urdu' => [ - 'کا منشاء برائے', - [ + 'input' => 'کا منشاء برائے', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], @@ -257,16 +257,16 @@ public function dataFirstChar() if (\PCRE_VERSION >= 10) { $data['georgian'] = [ - 'ეს ტესტია', - [ + 'input' => 'ეს ტესტია', + 'expected' => [ 'capitalized' => false, 'lowercase' => true, ], ]; } else { $data['georgian'] = [ - 'ეს ტესტია', - [ + 'input' => 'ეს ტესტია', + 'expected' => [ 'capitalized' => true, 'lowercase' => false, ], diff --git a/Tests/Utils/Orthography/IsLastCharPunctuationTest.php b/Tests/Utils/Orthography/IsLastCharPunctuationTest.php index 55b74f60..d177e252 100644 --- a/Tests/Utils/Orthography/IsLastCharPunctuationTest.php +++ b/Tests/Utils/Orthography/IsLastCharPunctuationTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsLastCharPunctuationTest extends TestCase +final class IsLastCharPunctuationTest extends TestCase { /** @@ -59,71 +59,71 @@ public function dataIsLastCharPunctuation() return [ // Quotes should be stripped before passing the string. 'double-quoted' => [ - '"This is a test."', - false, + 'input' => '"This is a test."', + 'expected' => false, ], 'single-quoted' => [ - "'This is a test?'", - false, + 'input' => "'This is a test?'", + 'expected' => false, ], // Invalid end char. 'no-punctuation' => [ - 'This is a test', - false, + 'input' => 'This is a test', + 'expected' => false, ], 'invalid-punctuation' => [ - 'This is a test;', - false, + 'input' => 'This is a test;', + 'expected' => false, ], 'invalid-punctuationtrailing-whitespace' => [ - 'This is a test; ', - false, + 'input' => 'This is a test; ', + 'expected' => false, ], // Valid end char, default charset. 'valid' => [ - 'This is a test.', - true, + 'input' => 'This is a test.', + 'expected' => true, ], 'valid-trailing-whitespace' => [ - 'This is a test. + 'input' => 'This is a test. ', - true, + 'expected' => true, ], // Invalid end char, custom charset. 'invalid-custom' => [ - 'This is a test.', - false, - '!?,;#', + 'input' => 'This is a test.', + 'expected' => false, + 'allowedChars' => '!?,;#', ], // Valid end char, custom charset. 'valid-custom-1' => [ - 'This is a test;', - true, - '!?,;#', + 'input' => 'This is a test;', + 'expected' => true, + 'allowedChars' => '!?,;#', ], 'valid-custom-2' => [ - 'This is a test!', - true, - '!?,;#', + 'input' => 'This is a test!', + 'expected' => true, + 'allowedChars' => '!?,;#', ], 'valid-custom-3' => [ - 'Is this is a test?', - true, - '!?,;#', + 'input' => 'Is this is a test?', + 'expected' => true, + 'allowedChars' => '!?,;#', ], 'valid-custom-4' => [ - 'This is a test,', - true, - '!?,;#', + 'input' => 'This is a test,', + 'expected' => true, + 'allowedChars' => '!?,;#', ], 'valid-custom-5' => [ - 'This is a test#', - true, - '!?,;#', + 'input' => 'This is a test#', + 'expected' => true, + 'allowedChars' => '!?,;#', ], ]; } diff --git a/Tests/Utils/Parentheses/ParenthesesTest.inc b/Tests/Utils/Parentheses/ParenthesesTest.inc index 62522c4d..60d5599e 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.inc +++ b/Tests/Utils/Parentheses/ParenthesesTest.inc @@ -50,6 +50,21 @@ $a = ($b + $c); /* testFunctionCallFnPHPCS353-354 */ $value = $obj->fn(true); +/* testArrowFunctionByReference */ +$fn = fn &($x) => $x; + +/* testIfWithIssetEmpty */ +if ( isset( $a, $b ) && ! empty ($c) ) { + /* testUnset */ + unset($a[1], $b->prop); +} + +/* testEval */ +eval($a . $b . $c ); + +/* testExit */ +if (defined('FOO') || die('message')) {} + // Intentional parse error. This has to be the last test in the file. /* testParseError */ declare(ticks=1 diff --git a/Tests/Utils/Parentheses/ParenthesesTest.php b/Tests/Utils/Parentheses/ParenthesesTest.php index 6cbd3efb..76b365a3 100644 --- a/Tests/Utils/Parentheses/ParenthesesTest.php +++ b/Tests/Utils/Parentheses/ParenthesesTest.php @@ -12,7 +12,6 @@ use PHPCSUtils\BackCompat\BCTokens; use PHPCSUtils\TestUtils\UtilityMethodTestCase; -use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\Parentheses; /** @@ -24,7 +23,7 @@ * * @since 1.0.0 */ -class ParenthesesTest extends UtilityMethodTestCase +final class ParenthesesTest extends UtilityMethodTestCase { /** @@ -149,6 +148,42 @@ class ParenthesesTest extends UtilityMethodTestCase 'marker' => '/* testFunctionCallFnPHPCS353-354 */', 'code' => \T_TRUE, ], + 'testArrowFunctionReturnByRef' => [ + 'marker' => '/* testArrowFunctionByReference */', + 'code' => \T_VARIABLE, + 'content' => '$x', + ], + 'testIfIsset-$b' => [ + 'marker' => '/* testIfWithIssetEmpty */', + 'code' => \T_VARIABLE, + 'content' => '$b', + ], + 'testIfEmpty-$c' => [ + 'marker' => '/* testIfWithIssetEmpty */', + 'code' => \T_VARIABLE, + 'content' => '$c', + ], + 'testUnset-->' => [ + 'marker' => '/* testUnset */', + 'code' => \T_OBJECT_OPERATOR, + ], + 'testUnsetParenthesis' => [ + 'marker' => '/* testUnset */', + 'code' => \T_OPEN_PARENTHESIS, + ], + 'testEval-concat' => [ + 'marker' => '/* testEval */', + 'code' => \T_STRING_CONCAT, + ], + 'testIfExitDie-boolean-or' => [ + 'marker' => '/* testExit */', + 'code' => \T_BOOLEAN_OR, + ], + 'testIfExitDie-message' => [ + 'marker' => '/* testExit */', + 'code' => \T_CONSTANT_ENCAPSED_STRING, + 'content' => "'message'", + ], 'testParseError-1' => [ 'marker' => '/* testParseError */', 'code' => \T_LNUMBER, @@ -169,7 +204,9 @@ class ParenthesesTest extends UtilityMethodTestCase * This array is merged with expected result arrays for various unit tests * to make sure all possible parentheses owners are tested. * - * This array should be kept in sync with the Tokens::$parenthesisOpeners array. + * This array should be kept in sync with the Tokens::$parenthesisOpeners array + * + the extra tokens the Parentheses class allows for. + * * This array isn't auto-generated based on the array in Tokens as for these * tests we want to have access to the token constant names, not just their values. * @@ -190,6 +227,13 @@ class ParenthesesTest extends UtilityMethodTestCase 'T_CATCH' => false, 'T_DECLARE' => false, 'T_FN' => false, + + // Extra tokens. + 'T_ISSET' => false, + 'T_UNSET' => false, + 'T_EMPTY' => false, + 'T_EXIT' => false, + 'T_EVAL' => false, ]; /** @@ -343,7 +387,7 @@ public function testPassingParenthesisTokenToMethodsWhichExpectParenthesisClose( * * @return void */ - public function testPassingParenthesisCloseHandlinginBCLayer() + public function testPassingParenthesisCloseHandlingInBCLayer() { $stackPtr = $this->getTargetToken('/* testListOnCloseParens */', \T_CLOSE_PARENTHESIS); @@ -368,8 +412,6 @@ public function testPassingParenthesisCloseHandlinginBCLayer() /** * Test that a function named fn sees the T_FUNCTION token as owner, not the T_FN token. * - * This specifically tests the BC-layer for arrow functions. - * * @return void */ public function testFunctionNamedFnKeywordNotParenthesesOwner() @@ -582,8 +624,8 @@ public function dataWalkParentheses() { $data = [ 'testIfWithArray-$a' => [ - 'testIfWithArray-$a', - [ + 'testName' => 'testIfWithArray-$a', + 'expectedResults' => [ 'firstOpener' => -2, 'firstCloser' => 19, 'firstOwner' => -4, @@ -599,8 +641,8 @@ public function dataWalkParentheses() ], ], 'testIfWithArray-array' => [ - 'testIfWithArray-array', - [ + 'testName' => 'testIfWithArray-array', + 'expectedResults' => [ 'firstOpener' => -13, 'firstCloser' => 8, 'firstOwner' => -15, @@ -616,8 +658,8 @@ public function dataWalkParentheses() ], ], 'testIfWithArray-$c' => [ - 'testIfWithArray-$c', - [ + 'testName' => 'testIfWithArray-$c', + 'expectedResults' => [ 'firstOpener' => -15, 'firstCloser' => 6, 'firstOwner' => -17, @@ -633,8 +675,8 @@ public function dataWalkParentheses() ], ], 'testWhileWithClosure-$a' => [ - 'testWhileWithClosure-$a', - [ + 'testName' => 'testWhileWithClosure-$a', + 'expectedResults' => [ 'firstOpener' => -9, 'firstCloser' => 30, 'firstOwner' => -11, @@ -650,8 +692,8 @@ public function dataWalkParentheses() ], ], 'testWhileWithClosure-$p' => [ - 'testWhileWithClosure-$p', - [ + 'testName' => 'testWhileWithClosure-$p', + 'expectedResults' => [ 'firstOpener' => -24, 'firstCloser' => 15, 'firstOwner' => -26, @@ -667,8 +709,8 @@ public function dataWalkParentheses() ], ], 'testWhileWithClosure-$result' => [ - 'testWhileWithClosure-$result', - [ + 'testName' => 'testWhileWithClosure-$result', + 'expectedResults' => [ 'firstOpener' => -2, 'firstCloser' => 37, 'firstOwner' => -4, @@ -684,8 +726,8 @@ public function dataWalkParentheses() ], ], 'testArrowFunction-$param' => [ - 'testArrowFunction-$param', - [ + 'testName' => 'testArrowFunction-$param', + 'expectedResults' => [ 'firstOpener' => -10, 'firstCloser' => 11, 'firstOwner' => -11, @@ -701,8 +743,8 @@ public function dataWalkParentheses() ], ], 'testArrowFunction-get' => [ - 'testArrowFunction-get', - [ + 'testName' => 'testArrowFunction-get', + 'expectedResults' => [ 'firstOpener' => -17, 'firstCloser' => 4, 'firstOwner' => -18, @@ -718,8 +760,8 @@ public function dataWalkParentheses() ], ], 'testMethodCalledFn-true' => [ - 'testMethodCalledFn-true', - [ + 'testName' => 'testMethodCalledFn-true', + 'expectedResults' => [ 'firstOpener' => -1, 'firstCloser' => 1, 'firstOwner' => false, @@ -734,9 +776,145 @@ public function dataWalkParentheses() 'lastIfElseOwner' => false, ], ], + 'testArrowFunctionReturnByRef' => [ + 'testName' => 'testArrowFunctionReturnByRef', + 'expectedResults' => [ + 'firstOpener' => -1, + 'firstCloser' => 1, + 'firstOwner' => -4, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => -1, + 'lastCloser' => 1, + 'lastOwner' => -4, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], + 'testIfIsset-$b' => [ + 'testName' => 'testIfIsset-$b', + 'expectedResults' => [ + 'firstOpener' => -8, + 'firstCloser' => 14, + 'firstOwner' => -10, + 'firstScopeOwnerOpener' => -8, + 'firstScopeOwnerCloser' => 14, + 'firstScopeOwnerOwner' => -10, + 'lastOpener' => -5, + 'lastCloser' => 2, + 'lastOwner' => -6, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => -10, + ], + ], + 'testIfEmpty-$c' => [ + 'testName' => 'testIfEmpty-$c', + 'expectedResults' => [ + 'firstOpener' => -19, + 'firstCloser' => 3, + 'firstOwner' => -21, + 'firstScopeOwnerOpener' => -19, + 'firstScopeOwnerCloser' => 3, + 'firstScopeOwnerOwner' => -21, + 'lastOpener' => -1, + 'lastCloser' => 1, + 'lastOwner' => -3, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => -21, + ], + ], + 'testUnset-->' => [ + 'testName' => 'testUnset-->', + 'expectedResults' => [ + 'firstOpener' => -8, + 'firstCloser' => 2, + 'firstOwner' => -9, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => -8, + 'lastCloser' => 2, + 'lastOwner' => -9, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], + 'testUnsetParenthesis' => [ + 'testName' => 'testUnsetParenthesis', + 'expectedResults' => [ + 'firstOpener' => false, + 'firstCloser' => false, + 'firstOwner' => false, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => false, + 'lastCloser' => false, + 'lastOwner' => false, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], + 'testEval-concat' => [ + 'testName' => 'testEval-concat', + 'expectedResults' => [ + 'firstOpener' => -3, + 'firstCloser' => 8, + 'firstOwner' => -4, + 'firstScopeOwnerOpener' => false, + 'firstScopeOwnerCloser' => false, + 'firstScopeOwnerOwner' => false, + 'lastOpener' => -3, + 'lastCloser' => 8, + 'lastOwner' => -4, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => false, + ], + ], + 'testIfExitDie-boolean-or' => [ + 'testName' => 'testIfExitDie-boolean-or', + 'expectedResults' => [ + 'firstOpener' => -6, + 'firstCloser' => 6, + 'firstOwner' => -8, + 'firstScopeOwnerOpener' => -6, + 'firstScopeOwnerCloser' => 6, + 'firstScopeOwnerOwner' => -8, + 'lastOpener' => -6, + 'lastCloser' => 6, + 'lastOwner' => -8, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => -8, + ], + ], + 'testIfExitDie-message' => [ + 'testName' => 'testIfExitDie-message', + 'expectedResults' => [ + 'firstOpener' => -10, + 'firstCloser' => 2, + 'firstOwner' => -12, + 'firstScopeOwnerOpener' => -10, + 'firstScopeOwnerCloser' => 2, + 'firstScopeOwnerOwner' => -12, + 'lastOpener' => -1, + 'lastCloser' => 1, + 'lastOwner' => -2, + 'lastArrayOpener' => false, + 'lastFunctionCloser' => false, + 'lastIfElseOwner' => -12, + ], + ], 'testParseError-1' => [ - 'testParseError-1', - [ + 'testName' => 'testParseError-1', + 'expectedResults' => [ 'firstOpener' => false, 'firstCloser' => false, 'firstOwner' => false, @@ -774,11 +952,6 @@ public function testHasOwner($testName, $expectedResults) // Add expected results for all owner types not listed in the data provider. $expectedResults += $this->ownerDefaults; - if (\defined('T_FN') === false) { - $expectedResults['T_STRING'] = $expectedResults['T_FN']; - unset($expectedResults['T_FN']); - } - foreach ($expectedResults as $ownerType => $expected) { $result = Parentheses::hasOwner(self::$phpcsFile, $stackPtr, \constant($ownerType)); $this->assertSame( @@ -804,134 +977,175 @@ public function dataHasOwner() { return [ 'testIfWithArray-$a' => [ - 'testIfWithArray-$a', - ['T_IF' => true], + 'testName' => 'testIfWithArray-$a', + 'expectedResults' => ['T_IF' => true], ], 'testIfWithArray-array' => [ - 'testIfWithArray-array', - ['T_IF' => true], + 'testName' => 'testIfWithArray-array', + 'expectedResults' => ['T_IF' => true], ], 'testIfWithArray-$c' => [ - 'testIfWithArray-$c', - [ + 'testName' => 'testIfWithArray-$c', + 'expectedResults' => [ 'T_ARRAY' => true, 'T_IF' => true, ], ], 'testElseIfWithClosure-$a' => [ - 'testElseIfWithClosure-$a', - [ + 'testName' => 'testElseIfWithClosure-$a', + 'expectedResults' => [ 'T_CLOSURE' => true, 'T_ELSEIF' => true, ], ], 'testElseIfWithClosure-closure' => [ - 'testElseIfWithClosure-closure', - ['T_ELSEIF' => true], + 'testName' => 'testElseIfWithClosure-closure', + 'expectedResults' => ['T_ELSEIF' => true], ], 'testElseIfWithClosure-$array' => [ - 'testElseIfWithClosure-$array', - ['T_ELSEIF' => true], + 'testName' => 'testElseIfWithClosure-$array', + 'expectedResults' => ['T_ELSEIF' => true], ], 'testForeach-45' => [ - 'testForeach-45', - [ + 'testName' => 'testForeach-45', + 'expectedResults' => [ 'T_ARRAY' => true, 'T_FOREACH' => true, ], ], 'testForeach-$a' => [ - 'testForeach-$a', - [ + 'testName' => 'testForeach-$a', + 'expectedResults' => [ 'T_LIST' => true, 'T_FOREACH' => true, ], ], 'testForeach-$c' => [ - 'testForeach-$c', - [ + 'testName' => 'testForeach-$c', + 'expectedResults' => [ 'T_LIST' => true, 'T_FOREACH' => true, ], ], 'testFunctionwithArray-$param' => [ - 'testFunctionwithArray-$param', - ['T_FUNCTION' => true], + 'testName' => 'testFunctionwithArray-$param', + 'expectedResults' => ['T_FUNCTION' => true], ], 'testFunctionwithArray-2' => [ - 'testFunctionwithArray-2', - [ + 'testName' => 'testFunctionwithArray-2', + 'expectedResults' => [ 'T_ARRAY' => true, 'T_FUNCTION' => true, ], ], 'testForWithTernary-$a' => [ - 'testForWithTernary-$a', - ['T_FOR' => true], + 'testName' => 'testForWithTernary-$a', + 'expectedResults' => ['T_FOR' => true], ], 'testForWithTernary-$c' => [ - 'testForWithTernary-$c', - ['T_FOR' => true], + 'testName' => 'testForWithTernary-$c', + 'expectedResults' => ['T_FOR' => true], ], 'testForWithTernary-$array' => [ - 'testForWithTernary-$array', - ['T_FOR' => true], + 'testName' => 'testForWithTernary-$array', + 'expectedResults' => ['T_FOR' => true], ], 'testWhileWithClosure-$a' => [ - 'testWhileWithClosure-$a', - ['T_WHILE' => true], + 'testName' => 'testWhileWithClosure-$a', + 'expectedResults' => ['T_WHILE' => true], ], 'testWhileWithClosure-$p' => [ - 'testWhileWithClosure-$p', - [ + 'testName' => 'testWhileWithClosure-$p', + 'expectedResults' => [ 'T_CLOSURE' => true, 'T_WHILE' => true, ], ], 'testWhileWithClosure-$result' => [ - 'testWhileWithClosure-$result', - ['T_WHILE' => true], + 'testName' => 'testWhileWithClosure-$result', + 'expectedResults' => ['T_WHILE' => true], ], 'testAnonClass-implements' => [ - 'testAnonClass-implements', - ['T_ANON_CLASS' => true], + 'testName' => 'testAnonClass-implements', + 'expectedResults' => ['T_ANON_CLASS' => true], ], 'testAnonClass-$param' => [ - 'testAnonClass-$param', - [ + 'testName' => 'testAnonClass-$param', + 'expectedResults' => [ 'T_ANON_CLASS' => true, 'T_FUNCTION' => true, ], ], 'testAnonClass-$e' => [ - 'testAnonClass-$e', - [ + 'testName' => 'testAnonClass-$e', + 'expectedResults' => [ 'T_ANON_CLASS' => true, 'T_CATCH' => true, ], ], 'testAnonClass-$a' => [ - 'testAnonClass-$a', - [ + 'testName' => 'testAnonClass-$a', + 'expectedResults' => [ 'T_ANON_CLASS' => true, 'T_WHILE' => true, ], ], 'testArrowFunction-$param' => [ - 'testArrowFunction-$param', - [ + 'testName' => 'testArrowFunction-$param', + 'expectedResults' => [ 'T_ARRAY' => true, 'T_FN' => true, ], ], 'testMethodCalledFn-true' => [ - 'testMethodCalledFn-true', - [], + 'testName' => 'testMethodCalledFn-true', + 'expectedResults' => [], + ], + 'testArrowFunctionReturnByRef' => [ + 'testName' => 'testArrowFunctionReturnByRef', + 'expectedResults' => ['T_FN' => true], + ], + 'testIfIsset-$b' => [ + 'testName' => 'testIfIsset-$b', + 'expectedResults' => [ + 'T_IF' => true, + 'T_ISSET' => true, + ], + ], + 'testIfEmpty-$c' => [ + 'testName' => 'testIfEmpty-$c', + 'expectedResults' => [ + 'T_IF' => true, + 'T_EMPTY' => true, + ], + ], + 'testUnset-->' => [ + 'testName' => 'testUnset-->', + 'expectedResults' => ['T_UNSET' => true], + ], + 'testUnsetParenthesis' => [ + 'testName' => 'testUnsetParenthesis', + 'expectedResults' => [], + ], + 'testEval-concat' => [ + 'testName' => 'testEval-concat', + 'expectedResults' => ['T_EVAL' => true], + ], + 'testIfExitDie-boolean-or' => [ + 'testName' => 'testIfExitDie-boolean-or', + 'expectedResults' => ['T_IF' => true], + ], + 'testIfExitDie-message' => [ + 'testName' => 'testIfExitDie-message', + 'expectedResults' => [ + 'T_IF' => true, + 'T_EXIT' => true, + ], ], 'testParseError-1' => [ - 'testParseError-1', - [], + 'testName' => 'testParseError-1', + 'expectedResults' => [], ], ]; } @@ -1007,59 +1221,59 @@ public function dataFirstOwnerIn() { return [ 'testElseIfWithClosure-$a-elseif' => [ - 'testElseIfWithClosure-$a', - [\T_ELSEIF], - -10, + 'testName' => 'testElseIfWithClosure-$a', + 'validOwners' => [\T_ELSEIF], + 'expected' => -10, ], 'testElseIfWithClosure-$a-array' => [ - 'testElseIfWithClosure-$a', - [\T_ARRAY], - false, + 'testName' => 'testElseIfWithClosure-$a', + 'validOwners' => [\T_ARRAY], + 'expected' => false, ], 'testForeach-45-foreach-for' => [ - 'testForeach-45', - [\T_FOREACH, \T_FOR], - -27, + 'testName' => 'testForeach-45', + 'validOwners' => [\T_FOREACH, \T_FOR], + 'expected' => -27, ], 'testForeach-45-array' => [ - 'testForeach-45', - [\T_ARRAY], - false, + 'testName' => 'testForeach-45', + 'validOwners' => [\T_ARRAY], + 'expected' => false, ], 'testForeach-$a-foreach-for' => [ - 'testForeach-$a', - [\T_FOREACH, \T_FOR], - -43, + 'testName' => 'testForeach-$a', + 'validOwners' => [\T_FOREACH, \T_FOR], + 'expected' => -43, ], 'testForeach-$a-list' => [ - 'testForeach-$a', - [\T_LIST], - false, + 'testName' => 'testForeach-$a', + 'validOwners' => [\T_LIST], + 'expected' => false, ], 'testFunctionwithArray-$param-function-closure' => [ - 'testFunctionwithArray-$param', - [\T_FUNCTION, \T_CLOSURE], - -4, + 'testName' => 'testFunctionwithArray-$param', + 'validOwners' => [\T_FUNCTION, \T_CLOSURE], + 'expected' => -4, ], 'testFunctionwithArray-$param-if-elseif-else' => [ - 'testFunctionwithArray-$param', - [\T_IF, \T_ELSEIF, \T_ELSE], - false, + 'testName' => 'testFunctionwithArray-$param', + 'validOwners' => [\T_IF, \T_ELSEIF, \T_ELSE], + 'expected' => false, ], 'testAnonClass-implements-anon-class' => [ - 'testAnonClass-implements', - [\T_ANON_CLASS], - -8, + 'testName' => 'testAnonClass-implements', + 'validOwners' => [\T_ANON_CLASS], + 'expected' => -8, ], 'testAnonClass-$e-function' => [ - 'testAnonClass-$e', - [\T_FUNCTION], - false, + 'testName' => 'testAnonClass-$e', + 'validOwners' => [\T_FUNCTION], + 'expected' => false, ], 'testAnonClass-$e-catch' => [ - 'testAnonClass-$e', - [\T_CATCH], - false, + 'testName' => 'testAnonClass-$e', + 'validOwners' => [\T_CATCH], + 'expected' => false, ], ]; } @@ -1096,69 +1310,82 @@ public function testLastOwnerIn($testName, $validOwners, $expected) */ public function dataLastOwnerIn() { - $arrowFunctionOwners = Collections::arrowFunctionTokensBC(); - return [ 'testElseIfWithClosure-$a-closure' => [ - 'testElseIfWithClosure-$a', - [\T_CLOSURE], - -3, + 'testName' => 'testElseIfWithClosure-$a', + 'validOwners' => [\T_CLOSURE], + 'expected' => -3, ], 'testElseIfWithClosure-$a-array' => [ - 'testElseIfWithClosure-$a', - [\T_ARRAY], - false, + 'testName' => 'testElseIfWithClosure-$a', + 'validOwners' => [\T_ARRAY], + 'expected' => false, ], 'testForeach-45-array' => [ - 'testForeach-45', - [\T_ARRAY], - -2, + 'testName' => 'testForeach-45', + 'validOwners' => [\T_ARRAY], + 'expected' => -2, ], 'testForeach-45-foreach-for' => [ - 'testForeach-45', - [\T_FOREACH, \T_FOR], - false, + 'testName' => 'testForeach-45', + 'validOwners' => [\T_FOREACH, \T_FOR], + 'expected' => false, ], 'testForeach-$a-foreach-for' => [ - 'testForeach-$a', - [\T_FOREACH, \T_FOR], - false, + 'testName' => 'testForeach-$a', + 'validOwners' => [\T_FOREACH, \T_FOR], + 'expected' => false, ], 'testForeach-$a-list' => [ - 'testForeach-$a', - [\T_LIST], - -6, + 'testName' => 'testForeach-$a', + 'validOwners' => [\T_LIST], + 'expected' => -6, ], 'testFunctionwithArray-$param-function-closure' => [ - 'testFunctionwithArray-$param', - [\T_FUNCTION, \T_CLOSURE], - -4, + 'testName' => 'testFunctionwithArray-$param', + 'validOwners' => [\T_FUNCTION, \T_CLOSURE], + 'expected' => -4, ], 'testFunctionwithArray-$param-if-elseif-else' => [ - 'testFunctionwithArray-$param', - [\T_IF, \T_ELSEIF, \T_ELSE], - false, + 'testName' => 'testFunctionwithArray-$param', + 'validOwners' => [\T_IF, \T_ELSEIF, \T_ELSE], + 'expected' => false, ], 'testAnonClass-implements-anon-class' => [ - 'testAnonClass-implements', - [\T_ANON_CLASS], - -8, + 'testName' => 'testAnonClass-implements', + 'validOwners' => [\T_ANON_CLASS], + 'expected' => -8, ], 'testAnonClass-$e-function' => [ - 'testAnonClass-$e', - [\T_FUNCTION], - false, + 'testName' => 'testAnonClass-$e', + 'validOwners' => [\T_FUNCTION], + 'expected' => false, ], 'testArrowFunction-$param' => [ - 'testArrowFunction-$param', - $arrowFunctionOwners, - -2, + 'testName' => 'testArrowFunction-$param', + 'validOwners' => [\T_FN], + 'expected' => -2, ], 'testAnonClass-$e-catch' => [ - 'testAnonClass-$e', - [\T_CATCH], - -5, + 'testName' => 'testAnonClass-$e', + 'validOwners' => [\T_CATCH], + 'expected' => -5, + ], + 'testArrowFunctionReturnByRef' => [ + 'testName' => 'testArrowFunctionReturnByRef', + 'validOwners' => [\T_FN], + 'expected' => -4, + ], + 'testIfEmpty-$c-unset' => [ + 'testName' => 'testIfEmpty-$c', + 'validOwners' => [\T_UNSET], + 'expected' => false, + ], + 'testIfEmpty-$c-isset-empty' => [ + 'testName' => 'testIfEmpty-$c', + 'validOwners' => [\T_ISSET, \T_EMPTY], + 'expected' => -3, ], ]; } diff --git a/Tests/Utils/PassedParameters/GetParameterCountTest.inc b/Tests/Utils/PassedParameters/GetParameterCountTest.inc index 63c66a72..490a579e 100644 --- a/Tests/Utils/PassedParameters/GetParameterCountTest.inc +++ b/Tests/Utils/PassedParameters/GetParameterCountTest.inc @@ -150,6 +150,22 @@ json_encode(['a' => $a, 'b' => $b, 'c' => $c]); /* testFunctionCall47 */ json_encode(['a' => $a, 'b' => $b, 'c' => $c,] + ['c' => $c, 'd' => $d,]); +/* testFunctionCallFullyQualified */ +\myfunction( $a ); + +/* testFunctionCallFullyQualifiedWithNamespace */ +\My\Named\myfunction( $a ); + +/* testFunctionCallPartiallyQualified */ +Partially\Qualified\myfunction( $a ); + +/* testFunctionCallNamespaceOperator */ +namespace\myfunction( $a ); + +/* testFunctionCallNamedParamsDuplicateName */ +// Error Exception, but not the concern of PHPCSUtils. Should still be handled. +test(param: 1, param: 2); + /* testLongArray1 */ $foo = array( 1, 2, 3, 4, 5, 6, true ); @@ -198,6 +214,11 @@ $bar = ['a' => $a, 'b' => $b, 'c' => (isset($c) ? $c : null)]; /* testShortArray8 */ $bar = [0 => $a, 2 => $b, 6 => (isset($c) ? $c : null)]; +/* testAnonClass */ +$anon = new class( $param1, $param2 ) { + public function __construct($param1, $param2) {} +}; + /* testArrayWithEmptyItem */ // Intentional parse error. $bar = [0 => $a,, 2 => $b]; diff --git a/Tests/Utils/PassedParameters/GetParameterCountTest.php b/Tests/Utils/PassedParameters/GetParameterCountTest.php index 82d57ed2..49d85db4 100644 --- a/Tests/Utils/PassedParameters/GetParameterCountTest.php +++ b/Tests/Utils/PassedParameters/GetParameterCountTest.php @@ -11,6 +11,7 @@ namespace PHPCSUtils\Tests\Utils\PassedParameters; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\PassedParameters; /** @@ -24,7 +25,7 @@ * * @since 1.0.0 */ -class GetParameterCountTest extends UtilityMethodTestCase +final class GetParameterCountTest extends UtilityMethodTestCase { /** @@ -32,17 +33,22 @@ class GetParameterCountTest extends UtilityMethodTestCase * * @dataProvider dataGetParameterCount * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $expected The expected parameter count. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int $expected The expected parameter count. + * @param string $targetContent Optional. The content of the target token to find. + * Defaults to null (ignore content). * * @return void */ - public function testGetParameterCount($testMarker, $expected) + public function testGetParameterCount($testMarker, $expected, $targetContent = null) { - $stackPtr = $this->getTargetToken( - $testMarker, - [\T_STRING, \T_ARRAY, \T_OPEN_SHORT_ARRAY, \T_ISSET, \T_UNSET] - ); + $targetTypes = Collections::nameTokens(); + $targetTypes[\T_ARRAY] = \T_ARRAY; + $targetTypes[\T_OPEN_SHORT_ARRAY] = \T_OPEN_SHORT_ARRAY; + $targetTypes[\T_ISSET] = \T_ISSET; + $targetTypes[\T_UNSET] = \T_UNSET; + + $stackPtr = $this->getTargetToken($testMarker, $targetTypes, $targetContent); $result = PassedParameters::getParameterCount(self::$phpcsFile, $stackPtr); $this->assertSame($expected, $result); } @@ -56,271 +62,302 @@ public function testGetParameterCount($testMarker, $expected) */ public function dataGetParameterCount() { + $php8Names = parent::usesPhp8NameTokens(); + return [ 'function-call-0' => [ - '/* testFunctionCall0 */', - 0, + 'testMarker' => '/* testFunctionCall0 */', + 'expected' => 0, ], 'function-call-1' => [ - '/* testFunctionCall1 */', - 1, + 'testMarker' => '/* testFunctionCall1 */', + 'expected' => 1, ], 'function-call-2' => [ - '/* testFunctionCall2 */', - 2, + 'testMarker' => '/* testFunctionCall2 */', + 'expected' => 2, ], 'function-call-3' => [ - '/* testFunctionCall3 */', - 3, + 'testMarker' => '/* testFunctionCall3 */', + 'expected' => 3, ], 'function-call-4' => [ - '/* testFunctionCall4 */', - 4, + 'testMarker' => '/* testFunctionCall4 */', + 'expected' => 4, ], 'function-call-5' => [ - '/* testFunctionCall5 */', - 5, + 'testMarker' => '/* testFunctionCall5 */', + 'expected' => 5, ], 'function-call-6' => [ - '/* testFunctionCall6 */', - 6, + 'testMarker' => '/* testFunctionCall6 */', + 'expected' => 6, ], 'function-call-7' => [ - '/* testFunctionCall7 */', - 7, + 'testMarker' => '/* testFunctionCall7 */', + 'expected' => 7, ], 'function-call-8' => [ - '/* testFunctionCall8 */', - 1, + 'testMarker' => '/* testFunctionCall8 */', + 'expected' => 1, ], 'function-call-9' => [ - '/* testFunctionCall9 */', - 1, + 'testMarker' => '/* testFunctionCall9 */', + 'expected' => 1, ], 'function-call-10' => [ - '/* testFunctionCall10 */', - 1, + 'testMarker' => '/* testFunctionCall10 */', + 'expected' => 1, ], 'function-call-11' => [ - '/* testFunctionCall11 */', - 2, + 'testMarker' => '/* testFunctionCall11 */', + 'expected' => 2, ], 'function-call-12' => [ - '/* testFunctionCall12 */', - 1, + 'testMarker' => '/* testFunctionCall12 */', + 'expected' => 1, ], 'function-call-13' => [ - '/* testFunctionCall13 */', - 1, + 'testMarker' => '/* testFunctionCall13 */', + 'expected' => 1, ], 'function-call-14' => [ - '/* testFunctionCall14 */', - 1, + 'testMarker' => '/* testFunctionCall14 */', + 'expected' => 1, ], 'function-call-15' => [ - '/* testFunctionCall15 */', - 2, + 'testMarker' => '/* testFunctionCall15 */', + 'expected' => 2, ], 'function-call-16' => [ - '/* testFunctionCall16 */', - 6, + 'testMarker' => '/* testFunctionCall16 */', + 'expected' => 6, ], 'function-call-17' => [ - '/* testFunctionCall17 */', - 6, + 'testMarker' => '/* testFunctionCall17 */', + 'expected' => 6, ], 'function-call-18' => [ - '/* testFunctionCall18 */', - 6, + 'testMarker' => '/* testFunctionCall18 */', + 'expected' => 6, ], 'function-call-19' => [ - '/* testFunctionCall19 */', - 6, + 'testMarker' => '/* testFunctionCall19 */', + 'expected' => 6, ], 'function-call-20' => [ - '/* testFunctionCall20 */', - 6, + 'testMarker' => '/* testFunctionCall20 */', + 'expected' => 6, ], 'function-call-21' => [ - '/* testFunctionCall21 */', - 6, + 'testMarker' => '/* testFunctionCall21 */', + 'expected' => 6, ], 'function-call-22' => [ - '/* testFunctionCall22 */', - 6, + 'testMarker' => '/* testFunctionCall22 */', + 'expected' => 6, ], 'function-call-23' => [ - '/* testFunctionCall23 */', - 3, + 'testMarker' => '/* testFunctionCall23 */', + 'expected' => 3, ], 'function-call-24' => [ - '/* testFunctionCall24 */', - 1, + 'testMarker' => '/* testFunctionCall24 */', + 'expected' => 1, ], 'function-call-25' => [ - '/* testFunctionCall25 */', - 1, + 'testMarker' => '/* testFunctionCall25 */', + 'expected' => 1, ], 'function-call-26' => [ - '/* testFunctionCall26 */', - 1, + 'testMarker' => '/* testFunctionCall26 */', + 'expected' => 1, ], 'function-call-27' => [ - '/* testFunctionCall27 */', - 1, + 'testMarker' => '/* testFunctionCall27 */', + 'expected' => 1, ], 'function-call-28' => [ - '/* testFunctionCall28 */', - 1, + 'testMarker' => '/* testFunctionCall28 */', + 'expected' => 1, ], 'function-call-29' => [ - '/* testFunctionCall29 */', - 1, + 'testMarker' => '/* testFunctionCall29 */', + 'expected' => 1, ], 'function-call-30' => [ - '/* testFunctionCall30 */', - 1, + 'testMarker' => '/* testFunctionCall30 */', + 'expected' => 1, ], 'function-call-31' => [ - '/* testFunctionCall31 */', - 1, + 'testMarker' => '/* testFunctionCall31 */', + 'expected' => 1, ], 'function-call-32' => [ - '/* testFunctionCall32 */', - 1, + 'testMarker' => '/* testFunctionCall32 */', + 'expected' => 1, ], 'function-call-33' => [ - '/* testFunctionCall33 */', - 1, + 'testMarker' => '/* testFunctionCall33 */', + 'expected' => 1, ], 'function-call-34' => [ - '/* testFunctionCall34 */', - 1, + 'testMarker' => '/* testFunctionCall34 */', + 'expected' => 1, ], 'function-call-35' => [ - '/* testFunctionCall35 */', - 1, + 'testMarker' => '/* testFunctionCall35 */', + 'expected' => 1, ], 'function-call-36' => [ - '/* testFunctionCall36 */', - 1, + 'testMarker' => '/* testFunctionCall36 */', + 'expected' => 1, ], 'function-call-37' => [ - '/* testFunctionCall37 */', - 1, + 'testMarker' => '/* testFunctionCall37 */', + 'expected' => 1, ], 'function-call-38' => [ - '/* testFunctionCall38 */', - 1, + 'testMarker' => '/* testFunctionCall38 */', + 'expected' => 1, ], 'function-call-39' => [ - '/* testFunctionCall39 */', - 1, + 'testMarker' => '/* testFunctionCall39 */', + 'expected' => 1, ], 'function-call-40' => [ - '/* testFunctionCall40 */', - 1, + 'testMarker' => '/* testFunctionCall40 */', + 'expected' => 1, ], 'function-call-41' => [ - '/* testFunctionCall41 */', - 1, + 'testMarker' => '/* testFunctionCall41 */', + 'expected' => 1, ], 'function-call-42' => [ - '/* testFunctionCall42 */', - 1, + 'testMarker' => '/* testFunctionCall42 */', + 'expected' => 1, ], 'function-call-43' => [ - '/* testFunctionCall43 */', - 1, + 'testMarker' => '/* testFunctionCall43 */', + 'expected' => 1, ], 'function-call-44' => [ - '/* testFunctionCall44 */', - 1, + 'testMarker' => '/* testFunctionCall44 */', + 'expected' => 1, ], 'function-call-45' => [ - '/* testFunctionCall45 */', - 1, + 'testMarker' => '/* testFunctionCall45 */', + 'expected' => 1, ], 'function-call-46' => [ - '/* testFunctionCall46 */', - 1, + 'testMarker' => '/* testFunctionCall46 */', + 'expected' => 1, ], 'function-call-47' => [ - '/* testFunctionCall47 */', - 1, + 'testMarker' => '/* testFunctionCall47 */', + 'expected' => 1, + ], + 'function-call-fully-qualified' => [ + 'testMarker' => '/* testFunctionCallFullyQualified */', + 'expected' => 1, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'function-call-fully-qualified-with-namespace' => [ + 'testMarker' => '/* testFunctionCallFullyQualifiedWithNamespace */', + 'expected' => 1, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'function-call-partially-qualified' => [ + 'testMarker' => '/* testFunctionCallPartiallyQualified */', + 'expected' => 1, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'function-call-namespace-operator' => [ + 'testMarker' => '/* testFunctionCallNamespaceOperator */', + 'expected' => 1, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'function-call-named-params-duplicate-name' => [ + 'testMarker' => '/* testFunctionCallNamedParamsDuplicateName */', + 'expected' => 2, ], // Long arrays. 'long-array-1' => [ - '/* testLongArray1 */', - 7, + 'testMarker' => '/* testLongArray1 */', + 'expected' => 7, ], 'long-array-2' => [ - '/* testLongArray2 */', - 1, + 'testMarker' => '/* testLongArray2 */', + 'expected' => 1, ], 'long-array-3' => [ - '/* testLongArray3 */', - 6, + 'testMarker' => '/* testLongArray3 */', + 'expected' => 6, ], 'long-array-4' => [ - '/* testLongArray4 */', - 6, + 'testMarker' => '/* testLongArray4 */', + 'expected' => 6, ], 'long-array-5' => [ - '/* testLongArray5 */', - 6, + 'testMarker' => '/* testLongArray5 */', + 'expected' => 6, ], 'long-array-6' => [ - '/* testLongArray6 */', - 3, + 'testMarker' => '/* testLongArray6 */', + 'expected' => 3, ], 'long-array-7' => [ - '/* testLongArray7 */', - 3, + 'testMarker' => '/* testLongArray7 */', + 'expected' => 3, ], 'long-array-8' => [ - '/* testLongArray8 */', - 3, + 'testMarker' => '/* testLongArray8 */', + 'expected' => 3, ], // Short arrays. 'short-array-1' => [ - '/* testShortArray1 */', - 7, + 'testMarker' => '/* testShortArray1 */', + 'expected' => 7, ], 'short-array-2' => [ - '/* testShortArray2 */', - 1, + 'testMarker' => '/* testShortArray2 */', + 'expected' => 1, ], 'short-array-3' => [ - '/* testShortArray3 */', - 6, + 'testMarker' => '/* testShortArray3 */', + 'expected' => 6, ], 'short-array-4' => [ - '/* testShortArray4 */', - 6, + 'testMarker' => '/* testShortArray4 */', + 'expected' => 6, ], 'short-array-5' => [ - '/* testShortArray5 */', - 6, + 'testMarker' => '/* testShortArray5 */', + 'expected' => 6, ], 'short-array-6' => [ - '/* testShortArray6 */', - 3, + 'testMarker' => '/* testShortArray6 */', + 'expected' => 3, ], 'short-array-7' => [ - '/* testShortArray7 */', - 3, + 'testMarker' => '/* testShortArray7 */', + 'expected' => 3, ], 'short-array-8' => [ - '/* testShortArray8 */', - 3, + 'testMarker' => '/* testShortArray8 */', + 'expected' => 3, + ], + + 'anon-class' => [ + 'testMarker' => '/* testAnonClass */', + 'expected' => 2, ], 'array-with-empty-item' => [ - '/* testArrayWithEmptyItem */', - 3, + 'testMarker' => '/* testArrayWithEmptyItem */', + 'expected' => 3, ], ]; } diff --git a/Tests/Utils/PassedParameters/GetParameterFromStackTest.inc b/Tests/Utils/PassedParameters/GetParameterFromStackTest.inc new file mode 100644 index 00000000..a7587ab3 --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParameterFromStackTest.inc @@ -0,0 +1,63 @@ +getTargetToken('/* testNoParams */', \T_STRING); + + $result = PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 2, 'value'); + $this->assertFalse($result); + } + + /** + * Test retrieving the parameter details from a non-function call without passing a valid name + * to make sure that no exception is thrown for the missing parameter name. + * + * @dataProvider dataGetParameterNonFunctionCallNoParamName + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType The type of token to look for. + * + * @return void + */ + public function testGetParameterNonFunctionCallNoParamName($testMarker, $targetType) + { + $stackPtr = $this->getTargetToken($testMarker, $targetType); + $expected = [ + 'start' => ($stackPtr + 5), + 'end' => ($stackPtr + 6), + 'raw' => '$var2', + 'clean' => '$var2', + ]; + + $result = PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 2); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetParameterNonFunctionCallNoParamName() For the array format. + * + * @return array + */ + public function dataGetParameterNonFunctionCallNoParamName() + { + return [ + 'isset' => [ + 'testMarker' => '/* testIsset */', + 'targetType' => \T_ISSET, + ], + 'array' => [ + 'testMarker' => '/* testArray */', + 'targetType' => \T_ARRAY, + ], + ]; + } + + /** + * Test retrieving the parameter details from a function call with only positional parameters + * without passing a valid name to make sure no exception is thrown. + * + * @return void + */ + public function testGetParameterFunctionCallPositionalNoParamName() + { + $stackPtr = $this->getTargetToken('/* testAllParamsPositional */', \T_STRING); + $expected = [ + 'start' => ($stackPtr + 5), + 'end' => ($stackPtr + 6), + 'raw' => "'value'", + 'clean' => "'value'", + ]; + + $result = PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 2); + $this->assertSame($expected, $result); + } + + /** + * Test receiving an expected exception when trying to retrieve the parameter details + * from a function call with only named parameters without passing a valid name. + * + * @return void + */ + public function testGetParameterFunctionCallMissingParamName() + { + $this->expectPhpcsException( + 'To allow for support for PHP 8 named parameters, the $paramNames parameter must be passed.' + ); + + $stackPtr = $this->getTargetToken('/* testAllParamsNamedStandardOrder */', \T_STRING); + + PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 2); + } + + /** + * Test receiving an expected exception when trying to retrieve the parameter details + * from a function call with only positional parameters without passing a valid name with + * the requested parameter offset not being set. + * + * @return void + */ + public function testGetParameterFunctionCallPositionalMissingParamNameNonExistentParam() + { + $this->expectPhpcsException( + 'To allow for support for PHP 8 named parameters, the $paramNames parameter must be passed.' + ); + + $stackPtr = $this->getTargetToken('/* testAllParamsPositional */', \T_STRING); + + PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 10); + } + + /** + * Verify that the $limit parameter used with `PassedParameters::getParameters()` from within the + * `PassedParameters::getParameter()` function call does not interfer with the handling of named parameters. + * + * @dataProvider dataGetParameterFunctionCallWithParamName + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expected The expected function output. + * + * @return void + */ + public function testGetParameterFunctionCallWithParamName($testMarker, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, \T_STRING); + + $expected['start'] += $stackPtr; + $expected['end'] += $stackPtr; + if (isset($expected['name_token'])) { + $expected['name_token'] += $stackPtr; + } + $expected['clean'] = $expected['raw']; + + $result = PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 2, 'value'); + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetParameterFunctionCallWithParamName() For the array format. + * + * @return array + */ + public function dataGetParameterFunctionCallWithParamName() + { + return [ + 'all-named-non-standard-order' => [ + 'testMarker' => '/* testAllParamsNamedNonStandardOrder */', + 'expected' => [ + 'name' => 'value', + 'name_token' => 48, + 'start' => 50, + 'end' => 51, + 'raw' => "'value'", + ], + ], + 'mixed-positional-and-named-target-non-named' => [ + 'testMarker' => '/* testMixedPositionalAndNamedParams */', + 'expected' => [ + 'start' => 6, + 'end' => 8, + 'raw' => "'value'", + ], + ], + ]; + } + + /** + * Test retrieving the details for a specific parameter from a function call or construct. + * + * @dataProvider dataGetParameterFromStack + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedName The expected result array for the $name parameter. + * @param array|false $expectedExpires The expected result array for the $expires_or_options parameter. + * @param array|false $expectedHttpOnly The expected result array for the $httponly parameter. + * + * @return void + */ + public function testGetParameterFromStack($testMarker, $expectedName, $expectedExpires, $expectedHttpOnly) + { + $stackPtr = $this->getTargetToken($testMarker, \T_STRING); + $parameters = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + + /* + * Test $name parameter. Param name passed as string. + */ + $expected = false; + if ($expectedName !== false) { + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + $expected = $expectedName; + $expected['start'] += $stackPtr; + $expected['end'] += $stackPtr; + if (isset($expected['name_token'])) { + $expected['name_token'] += $stackPtr; + } + $expected['clean'] = $expected['raw']; + } + + $result = PassedParameters::getParameterFromStack($parameters, 1, 'name'); + $this->assertSame($expected, $result, 'Expected output for parameter 1 ("name") did not match'); + + /* + * Test $expires_or_options parameter. Param name passed as array with alternative names. + */ + $expected = false; + if ($expectedExpires !== false) { + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + $expected = $expectedExpires; + $expected['start'] += $stackPtr; + $expected['end'] += $stackPtr; + if (isset($expected['name_token'])) { + $expected['name_token'] += $stackPtr; + } + $expected['clean'] = $expected['raw']; + } + + $result = PassedParameters::getParameterFromStack($parameters, 3, ['expires_or_options', 'expires', 'options']); + $this->assertSame($expected, $result, 'Expected output for parameter 3 ("expires_or_options") did not match'); + + /* + * Test $httponly parameter. Param name passed as array. + */ + $expected = false; + if ($expectedHttpOnly !== false) { + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + $expected = $expectedHttpOnly; + $expected['start'] += $stackPtr; + $expected['end'] += $stackPtr; + if (isset($expected['name_token'])) { + $expected['name_token'] += $stackPtr; + } + $expected['clean'] = $expected['raw']; + } + + $result = PassedParameters::getParameterFromStack($parameters, 7, ['httponly']); + $this->assertSame($expected, $result, 'Expected output for parameter 7 ("httponly") did not match'); + } + + /** + * Data provider. + * + * @see testGetParameterFromStack() For the array format. + * + * @return array + */ + public function dataGetParameterFromStack() + { + return [ + 'all-params-all-positional' => [ + 'testMarker' => '/* testAllParamsPositional */', + 'expectedName' => [ + 'start' => 2, + 'end' => 3, + 'raw' => "'name'", + ], + 'expectedExpires' => [ + 'start' => 8, + 'end' => 25, + 'raw' => 'time() + (60 * 60 * 24)', + ], + 'expectedHttpOnly' => [ + 'start' => 36, + 'end' => 38, + 'raw' => 'false', + ], + ], + 'all-params-all-named-standard-order' => [ + 'testMarker' => '/* testAllParamsNamedStandardOrder */', + 'expectedName' => [ + 'name' => 'name', + 'name_token' => 4, + 'start' => 6, + 'end' => 7, + 'raw' => "'name'", + ], + 'expectedExpires' => [ + 'name' => 'expires_or_options', + 'name_token' => 18, + 'start' => 20, + 'end' => 37, + 'raw' => 'time() + (60 * 60 * 24)', + ], + 'expectedHttpOnly' => [ + 'name' => 'httponly', + 'name_token' => 62, + 'start' => 64, + 'end' => 66, + 'raw' => 'false', + ], + ], + 'all-params-all-named-random-order' => [ + 'testMarker' => '/* testAllParamsNamedNonStandardOrder */', + 'expectedName' => [ + 'name' => 'name', + 'name_token' => 34, + 'start' => 36, + 'end' => 37, + 'raw' => "'name'", + ], + 'expectedExpires' => [ + 'name' => 'expires_or_options', + 'name_token' => 4, + 'start' => 6, + 'end' => 23, + 'raw' => 'time() + (60 * 60 * 24)', + ], + 'expectedHttpOnly' => [ + 'name' => 'httponly', + 'name_token' => 55, + 'start' => 57, + 'end' => 58, + 'raw' => 'false', + ], + ], + 'all-params-mixed-positional-and-named' => [ + 'testMarker' => '/* testMixedPositionalAndNamedParams */', + 'expectedName' => [ + 'start' => 2, + 'end' => 4, + 'raw' => "'name'", + ], + 'expectedExpires' => [ + 'start' => 10, + 'end' => 28, + 'raw' => 'time() + (60 * 60 * 24)', + ], + 'expectedHttpOnly' => [ + 'name' => 'httponly', + 'name_token' => 46, + 'start' => 48, + 'end' => 49, + 'raw' => 'false', + ], + ], + 'select-params-mixed-positional-and-named' => [ + 'testMarker' => '/* testMixedPositionalAndNamedParamsNotAllOptionalSet */', + 'expectedName' => [ + 'start' => 2, + 'end' => 4, + 'raw' => "'name'", + ], + 'expectedExpires' => [ + 'name' => 'expires_or_options', + 'name_token' => 8, + 'start' => 10, + 'end' => 27, + 'raw' => 'time() + (60 * 60 * 24)', + ], + 'expectedHttpOnly' => false, + ], + 'select-params-mixed-positional-and-named-old-name' => [ + 'testMarker' => '/* testMixedPositionalAndNamedParamsOldName */', + 'expectedName' => [ + 'start' => 2, + 'end' => 4, + 'raw' => "'name'", + ], + 'expectedExpires' => [ + 'name' => 'expires', + 'name_token' => 8, + 'start' => 10, + 'end' => 27, + 'raw' => 'time() + (60 * 60 * 24)', + ], + 'expectedHttpOnly' => false, + ], + ]; + } + + /** + * Test retrieving the parameter details from a function call with a named parameter after a variadic one. + * + * This is supported since PHP 8.1. + * + * @dataProvider dataGetParameterFromStackNamedAfterVariadic + * + * @param string $offset The positional offfset to pass. + * @param array $names The parameter names to pass. + * @param array|false $expected The expected result array for the parameter. + * + * @return void + */ + public function testGetParameterFromStackNamedAfterVariadic($offset, $names, $expected) + { + $stackPtr = $this->getTargetToken('/* testPHP81NamedParamAfterVariadic */', \T_STRING); + + if ($expected !== false) { + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + $expected['start'] += $stackPtr; + $expected['end'] += $stackPtr; + if (isset($expected['name_token'])) { + $expected['name_token'] += $stackPtr; + } + $expected['clean'] = $expected['raw']; + } + + $parameters = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + $result = PassedParameters::getParameterFromStack($parameters, $offset, $names); + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetParameterFromStackNamedAfterVariadic() For the array format. + * + * @return array + */ + public function dataGetParameterFromStackNamedAfterVariadic() + { + return [ + 'first param, positional' => [ + 'offset' => 1, + 'names' => ['none'], + 'expected' => [ + 'start' => 2, + 'end' => 2, + 'raw' => '$positional', + ], + ], + 'second param, positional, variadic' => [ + 'offset' => 2, + 'names' => ['none'], + 'expected' => [ + 'start' => 4, + 'end' => 6, + 'raw' => '...$variadic', + ], + ], + 'named param "namedA"' => [ + 'offset' => 5, + 'names' => ['alternative', 'namedA'], + 'expected' => [ + 'name' => 'namedA', + 'name_token' => 9, + 'start' => 11, + 'end' => 12, + 'raw' => '$valueA', + ], + ], + 'named param "namedB"' => [ + // Position intentionally set to 2 to collide with the variadic param (which may contain named params). + 'offset' => 2, + 'names' => ['namedB'], + 'expected' => [ + 'name' => 'namedB', + 'name_token' => 15, + 'start' => 17, + 'end' => 18, + 'raw' => '$valueB', + ], + ], + ]; + } +} diff --git a/Tests/Utils/PassedParameters/GetParametersNamedTest.inc b/Tests/Utils/PassedParameters/GetParametersNamedTest.inc new file mode 100644 index 00000000..61cb163a --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParametersNamedTest.inc @@ -0,0 +1,92 @@ +getPos(skip: false), + count: /* testNestedFunctionCallInner2 */ count(array_or_countable: $array), + value: 50 +); + +/* testNamespacedFQNFunction */ +\Fully\Qualified\function_name(label: $string, more:false); + +/* testVariableFunction */ +$fn(label: $string, more:false); + +/* testClassInstantiationStatic */ +$obj = new static(label: $string, more:false); + +/* testAnonClass */ +$anon = new class(label: $string, more: false) { + public function __construct($label, $more) {} +}; + +function myfoo( $💩💩💩, $Пасха, $_valid) {} +/* testNonAsciiNames */ +foo(💩💩💩: [], Пасха: 'text', _valid: 123); + +/* testMixedPositionalAndNamedArgsWithTernary */ +foo( $cond ? true : false, name: $value2 ); + +/* testNamedArgWithTernary */ +foo( label: $cond ? true : false, more: $cond ? CONSTANT_A : CONSTANT_B ); + +/* testTernaryWithFunctionCallsInThenElse */ +echo $cond ? foo( label: $something ) : /* testTernaryWithFunctionCallsInElse */ bar( more: $something_else ); + +/* testCompileErrorNamedBeforePositional */ +// Not the concern of PHPCSUtils. Should still be handled. +test(param: $bar, $foo); + +/* testDuplicateName */ +// Error Exception, but not the concern of PHPCSUtils. Should still be handled. +test(param: 1, param: 2); + +/* testIncorrectOrderWithVariadic */ +// Error Exception, but not the concern of PHPCSUtils. Should still be handled. +array_fill(start_index: 0, ...[100, 50]); + +/* testPHP81NamedParamAfterVariadic */ +// Prior to PHP 8.1, this was a compile error, but this is now supported. +test(...$values, param: $value); + +/* testParseErrorNoValue */ +// Not the concern of PHPCSUtils. Should still be handled (but currently isn't). +//test(param1:, param2:); + +/* testParseErrorDynamicName */ +// Parse error. Ignore. +function_name($variableStoringParamName: $value); + +/* testReservedKeywordAsName */ +// Note: do not remove any of these - some are testing very specific cross-version tokenizer issues. +foobar( + abstract: $value, + class: $value, + const: $value, + function: $value, + iterable: $value, + match: $value, + protected: $value, + object: $value, + parent: $value, +); diff --git a/Tests/Utils/PassedParameters/GetParametersNamedTest.php b/Tests/Utils/PassedParameters/GetParametersNamedTest.php new file mode 100644 index 00000000..75c446dc --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParametersNamedTest.php @@ -0,0 +1,587 @@ +getTargetToken($testMarker, [$targetType], $targetContent); + + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + foreach ($expected as $key => $value) { + $expected[$key]['start'] += $stackPtr; + $expected[$key]['end'] += $stackPtr; + + if (isset($value['name_token'])) { + $expected[$key]['name_token'] += $stackPtr; + } + } + + $result = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + + foreach ($result as $key => $value) { + $this->assertArrayHasKey('clean', $value); + + // The GetTokensAsString functions have their own tests, no need to duplicate it here. + unset($result[$key]['clean']); + } + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetParameters() For the array format. + * + * @return array + */ + public function dataGetParameters() + { + $php8Names = parent::usesPhp8NameTokens(); + + return [ + 'only-positional-args' => [ + 'testMarker' => '/* testPositionalArgs */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 2, + 'raw' => 'START_INDEX', + ], + 2 => [ + 'start' => 4, + 'end' => ($php8Names === true) ? 5 : 6, + 'raw' => '\COUNT', + ], + 3 => [ + 'start' => ($php8Names === true) ? 7 : 8, + 'end' => ($php8Names === true) ? 8 : 11, + 'raw' => 'MyNS\VALUE', + ], + ], + ], + 'named-args' => [ + 'testMarker' => '/* testNamedArgs */', + 'targetType' => \T_STRING, + 'expected' => [ + 'start_index' => [ + 'name' => 'start_index', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '0', + ], + 'count' => [ + 'name' => 'count', + 'name_token' => 8, + 'start' => 10, + 'end' => 11, + 'raw' => '100', + ], + 'value' => [ + 'name' => 'value', + 'name_token' => 14, + 'start' => 16, + 'end' => 17, + 'raw' => '50', + ], + ], + ], + 'named-args-multiline' => [ + 'testMarker' => '/* testNamedArgsMultiline */', + 'targetType' => \T_STRING, + 'expected' => [ + 'start_index' => [ + 'name' => 'start_index', + 'name_token' => 4, + 'start' => 7, + 'end' => 8, + 'raw' => '0', + ], + 'count' => [ + 'name' => 'count', + 'name_token' => 12, + 'start' => 15, + 'end' => 16, + 'raw' => '100', + ], + 'value' => [ + 'name' => 'value', + 'name_token' => 20, + 'start' => 23, + 'end' => 24, + 'raw' => '50', + ], + ], + ], + 'named-args-whitespace-comments' => [ + 'testMarker' => '/* testNamedArgsWithWhitespaceAndComments */', + 'targetType' => \T_STRING, + 'expected' => [ + 'start_index' => [ + 'name' => 'start_index', + 'name_token' => 4, + 'start' => 7, + 'end' => 8, + 'raw' => '0', + ], + 'count' => [ + 'name' => 'count', + 'name_token' => 13, + 'start' => 18, + 'end' => 19, + 'raw' => '100', + ], + 'value' => [ + 'name' => 'value', + 'name_token' => 22, + 'start' => 24, + 'end' => 25, + 'raw' => '50', + ], + ], + ], + 'mixed-positional-and-named-args' => [ + 'testMarker' => '/* testMixedPositionalAndNamedArgs */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 2, + 'raw' => '$string', + ], + 'double_encode' => [ + 'name' => 'double_encode', + 'name_token' => 5, + 'start' => 7, + 'end' => 8, + 'raw' => 'false', + ], + ], + ], + 'named-args-nested-function-call-outer' => [ + 'testMarker' => '/* testNestedFunctionCallOuter */', + 'targetType' => \T_STRING, + 'expected' => [ + 'start_index' => [ + 'name' => 'start_index', + 'name_token' => 4, + 'start' => 6, + 'end' => 17, + 'raw' => '/* testNestedFunctionCallInner1 */ $obj->getPos(skip: false)', + ], + 'count' => [ + 'name' => 'count', + 'name_token' => 21, + 'start' => 23, + 'end' => 32, + 'raw' => '/* testNestedFunctionCallInner2 */ count(array_or_countable: $array)', + ], + 'value' => [ + 'name' => 'value', + 'name_token' => 36, + 'start' => 38, + 'end' => 40, + 'raw' => '50', + ], + ], + ], + 'named-args-nested-function-call-inner-1' => [ + 'testMarker' => '/* testNestedFunctionCallInner1 */', + 'targetType' => \T_STRING, + 'expected' => [ + 'skip' => [ + 'name' => 'skip', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => 'false', + ], + ], + ], + 'named-args-nested-function-call-inner-2' => [ + 'testMarker' => '/* testNestedFunctionCallInner2 */', + 'targetType' => \T_STRING, + 'expected' => [ + 'array_or_countable' => [ + 'name' => 'array_or_countable', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '$array', + ], + ], + ], + 'named-args-in-fqn-function-call' => [ + 'testMarker' => '/* testNamespacedFQNFunction */', + 'targetType' => ($php8Names === true) ? \T_NAME_FULLY_QUALIFIED : \T_STRING, + 'expected' => [ + 'label' => [ + 'name' => 'label', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '$string', + ], + 'more' => [ + 'name' => 'more', + 'name_token' => 8, + 'start' => 10, + 'end' => 10, + 'raw' => 'false', + ], + ], + 'targetContent' => ($php8Names === true) ? null : 'function_name', + ], + 'named-args-in-variable-function-call' => [ + 'testMarker' => '/* testVariableFunction */', + 'targetType' => \T_VARIABLE, + 'expected' => [ + 'label' => [ + 'name' => 'label', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '$string', + ], + 'more' => [ + 'name' => 'more', + 'name_token' => 8, + 'start' => 10, + 'end' => 10, + 'raw' => 'false', + ], + ], + ], + 'named-args-in-class-instantiation-with-static' => [ + 'testMarker' => '/* testClassInstantiationStatic */', + 'targetType' => \T_STATIC, + 'expected' => [ + 'label' => [ + 'name' => 'label', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '$string', + ], + 'more' => [ + 'name' => 'more', + 'name_token' => 8, + 'start' => 10, + 'end' => 10, + 'raw' => 'false', + ], + ], + ], + 'named-args-in-anon-class-instantiation' => [ + 'testMarker' => '/* testAnonClass */', + 'targetType' => \T_ANON_CLASS, + 'expected' => [ + 'label' => [ + 'name' => 'label', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '$string', + ], + 'more' => [ + 'name' => 'more', + 'name_token' => 8, + 'start' => 10, + 'end' => 11, + 'raw' => 'false', + ], + ], + ], + 'named-args-non-ascii-names' => [ + 'testMarker' => '/* testNonAsciiNames */', + 'targetType' => \T_STRING, + 'expected' => [ + '💩💩💩' => [ + 'name' => '💩💩💩', + 'name_token' => 2, + 'start' => 4, + 'end' => 6, + 'raw' => '[]', + ], + 'Пасха' => [ + 'name' => 'Пасха', + 'name_token' => 9, + 'start' => 11, + 'end' => 12, + 'raw' => "'text'", + ], + '_valid' => [ + 'name' => '_valid', + 'name_token' => 15, + 'start' => 17, + 'end' => 18, + 'raw' => '123', + ], + ], + ], + 'mixed-positional-and-named-args-with-ternary' => [ + 'testMarker' => '/* testMixedPositionalAndNamedArgsWithTernary */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 11, + 'raw' => '$cond ? true : false', + ], + 'name' => [ + 'name' => 'name', + 'name_token' => 14, + 'start' => 16, + 'end' => 18, + 'raw' => '$value2', + ], + ], + ], + 'named-args-with-ternary' => [ + 'testMarker' => '/* testNamedArgWithTernary */', + 'targetType' => \T_STRING, + 'expected' => [ + 'label' => [ + 'name' => 'label', + 'name_token' => 3, + 'start' => 5, + 'end' => 14, + 'raw' => '$cond ? true : false', + ], + 'more' => [ + 'name' => 'more', + 'name_token' => 17, + 'start' => 19, + 'end' => 29, + 'raw' => '$cond ? CONSTANT_A : CONSTANT_B', + ], + ], + ], + 'ternary-with-function-call-in-then' => [ + 'testMarker' => '/* testTernaryWithFunctionCallsInThenElse */', + 'targetType' => \T_STRING, + 'expected' => [ + 'label' => [ + 'name' => 'label', + 'name_token' => 3, + 'start' => 5, + 'end' => 7, + 'raw' => '$something', + ], + ], + ], + 'ternary-with-function-call-in-else' => [ + 'testMarker' => '/* testTernaryWithFunctionCallsInElse */', + 'targetType' => \T_STRING, + 'expected' => [ + 'more' => [ + 'name' => 'more', + 'name_token' => 3, + 'start' => 5, + 'end' => 7, + 'raw' => '$something_else', + ], + ], + ], + 'named-args-compile-error-named-before-positional' => [ + 'testMarker' => '/* testCompileErrorNamedBeforePositional */', + 'targetType' => \T_STRING, + 'expected' => [ + 'param' => [ + 'name' => 'param', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '$bar', + ], + 2 => [ + 'start' => 7, + 'end' => 8, + 'raw' => '$foo', + ], + ], + ], + 'named-args-error-exception-duplicate-name' => [ + 'testMarker' => '/* testDuplicateName */', + 'targetType' => \T_STRING, + 'expected' => [ + 'param' => [ + 'name' => 'param', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '1', + ], + 2 => [ + 'name' => 'param', + 'name_token' => 8, + 'start' => 10, + 'end' => 11, + 'raw' => '2', + ], + ], + ], + 'named-args-error-exception-incorrect-order-variadic' => [ + 'testMarker' => '/* testIncorrectOrderWithVariadic */', + 'targetType' => \T_STRING, + 'expected' => [ + 'start_index' => [ + 'name' => 'start_index', + 'name_token' => 2, + 'start' => 4, + 'end' => 5, + 'raw' => '0', + ], + 2 => [ + 'start' => 7, + 'end' => 14, + 'raw' => '...[100, 50]', + ], + ], + ], + // Prior to PHP 8.1, this was a compile error, but this is now supported. + 'named-args-after-variadic' => [ + 'testMarker' => '/* testPHP81NamedParamAfterVariadic */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 3, + 'raw' => '...$values', + ], + 'param' => [ + 'name' => 'param', + 'name_token' => 6, + 'start' => 8, + 'end' => 9, + 'raw' => '$value', + ], + ], + ], + 'named-args-parse-error-dynamic-name' => [ + 'testMarker' => '/* testParseErrorDynamicName */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 5, + 'raw' => '$variableStoringParamName: $value', + ], + ], + ], + 'named-args-using-reserved-keywords' => [ + 'testMarker' => '/* testReservedKeywordAsName */', + 'targetType' => \T_STRING, + 'expected' => [ + 'abstract' => [ + 'name' => 'abstract', + 'name_token' => 4, + 'start' => 6, + 'end' => 7, + 'raw' => '$value', + ], + 'class' => [ + 'name' => 'class', + 'name_token' => 11, + 'start' => 13, + 'end' => 14, + 'raw' => '$value', + ], + 'const' => [ + 'name' => 'const', + 'name_token' => 18, + 'start' => 20, + 'end' => 21, + 'raw' => '$value', + ], + 'function' => [ + 'name' => 'function', + 'name_token' => 25, + 'start' => 27, + 'end' => 28, + 'raw' => '$value', + ], + 'iterable' => [ + 'name' => 'iterable', + 'name_token' => 32, + 'start' => 34, + 'end' => 35, + 'raw' => '$value', + ], + 'match' => [ + 'name' => 'match', + 'name_token' => 39, + 'start' => 41, + 'end' => 42, + 'raw' => '$value', + ], + 'protected' => [ + 'name' => 'protected', + 'name_token' => 46, + 'start' => 48, + 'end' => 49, + 'raw' => '$value', + ], + 'object' => [ + 'name' => 'object', + 'name_token' => 53, + 'start' => 55, + 'end' => 56, + 'raw' => '$value', + ], + 'parent' => [ + 'name' => 'parent', + 'name_token' => 60, + 'start' => 62, + 'end' => 63, + 'raw' => '$value', + ], + ], + ], + ]; + } +} diff --git a/Tests/Utils/PassedParameters/GetParametersSkipShortArrayCheckTest.inc b/Tests/Utils/PassedParameters/GetParametersSkipShortArrayCheckTest.inc new file mode 100644 index 00000000..876260d4 --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParametersSkipShortArrayCheckTest.inc @@ -0,0 +1,29 @@ + 1, 'b' => 2 ]; + +/* testShortList */ +[ 'a' => $a, 'b' => $b ] = $array; + +/* testArrayAssign */ +$array[] = 'foo'; + +/* testArrayAccess */ +$foo = $array[$keys['key']]; + +/* testShortListWithEmptyItemsBefore */ +[, , $a] = $array; + +/* testShortListWithEmptyItemsAfter */ +[$a,,] = $array; + +/* testShortListWithAllEmptyItems */ +// Not allowed, but not our concern. +[,,] = $array; diff --git a/Tests/Utils/PassedParameters/GetParametersSkipShortArrayCheckTest.php b/Tests/Utils/PassedParameters/GetParametersSkipShortArrayCheckTest.php new file mode 100644 index 00000000..cc90aaf6 --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParametersSkipShortArrayCheckTest.php @@ -0,0 +1,241 @@ +expectPhpcsException( + 'The hasParameters() method expects a function call, array, isset or unset token to be passed.' + ); + } + + $target = $this->getTargetToken($testMarker, [$targetType]); + $hasParams = PassedParameters::hasParameters(self::$phpcsFile, $target); + + if ($expectException === false) { + $this->assertIsBool($hasParams); + } + } + + /** + * Test retrieving the parameter details for valid and invalid constructs when the + * `$isShortArray` parameter is set to TRUE. + * + * @dataProvider dataTestCases + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType The type of token to look for. + * @param bool $ignore Not used in this test. + * @param array $expected The expected return value. + * + * @return void + */ + public function testGetParametersSkipShortArrayCheck($testMarker, $targetType, $ignore, $expected) + { + $stackPtr = $this->getTargetToken($testMarker, [$targetType]); + $result = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 0, true); + + $this->assertIsArray($result); + + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + foreach ($expected as $key => $value) { + $expected[$key]['start'] = ($stackPtr + $value['start']); + $expected[$key]['end'] = ($stackPtr + $value['end']); + } + + foreach ($result as $key => $value) { + // The GetTokensAsString functions have their own tests, no need to duplicate it here. + unset($result[$key]['clean']); + } + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetParametersSkipShortArrayCheck() For the array format. + * @see testHasParametersDontSkipShortArrayCheck() For the array format. + * + * @return array + */ + public function dataTestCases() + { + return [ + 'no-params' => [ + 'testMarker' => '/* testNoParams */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'ignore' => false, + 'expected' => [], + ], + 'long-array' => [ + 'testMarker' => '/* testLongArray */', + 'targetType' => \T_ARRAY, + 'ignore' => false, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 3, + 'raw' => '1', + ], + 2 => [ + 'start' => 5, + 'end' => 7, + 'raw' => '2', + ], + ], + ], + 'short-array' => [ + 'testMarker' => '/* testShortArray */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'ignore' => false, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 6, + 'raw' => "'a' => 1", + ], + 2 => [ + 'start' => 8, + 'end' => 14, + 'raw' => "'b' => 2", + ], + ], + ], + 'short-list' => [ + 'testMarker' => '/* testShortList */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'ignore' => true, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 6, + 'raw' => '\'a\' => $a', + ], + 2 => [ + 'start' => 8, + 'end' => 14, + 'raw' => '\'b\' => $b', + ], + ], + ], + 'array-assign' => [ + 'testMarker' => '/* testArrayAssign */', + 'targetType' => \T_OPEN_SQUARE_BRACKET, + 'ignore' => true, + 'expected' => [], + ], + 'array-access' => [ + 'testMarker' => '/* testArrayAccess */', + 'targetType' => \T_OPEN_SQUARE_BRACKET, + 'ignore' => true, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 4, + 'raw' => '$keys[\'key\']', + ], + ], + ], + 'short-list-with-empties-before' => [ + 'testMarker' => '/* testShortListWithEmptyItemsBefore */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'ignore' => true, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 0, + 'raw' => '', + ], + 2 => [ + 'start' => 2, + 'end' => 2, + 'raw' => '', + ], + 3 => [ + 'start' => 4, + 'end' => 5, + 'raw' => '$a', + ], + ], + ], + 'short-list-with-empties-after' => [ + 'testMarker' => '/* testShortListWithEmptyItemsAfter */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'ignore' => true, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 1, + 'raw' => '$a', + ], + 2 => [ + 'start' => 3, + 'end' => 2, + 'raw' => '', + ], + ], + ], + 'short-list-with-all-empties' => [ + 'testMarker' => '/* testShortListWithAllEmptyItems */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'ignore' => true, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 0, + 'raw' => '', + ], + 2 => [ + 'start' => 2, + 'end' => 1, + 'raw' => '', + ], + ], + ], + ]; + } +} diff --git a/Tests/Utils/PassedParameters/GetParametersTest.inc b/Tests/Utils/PassedParameters/GetParametersTest.inc index 594156fa..593dd19f 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.inc +++ b/Tests/Utils/PassedParameters/GetParametersTest.inc @@ -119,3 +119,27 @@ if ( isset( /* testUnset */ unset( $variable, $object->property, static::$property, $array[$name], ); + +/* testAnonClass */ +$anon = new class( $param1, $param2 ) { + public function __construct($param1, $param2) {} +}; + +/* testPHP74UnpackingInLongArrayExpression */ +$arr4 = array(...$arr1, ...arrGen(), ...new ArrayIterator(['a', 'b', 'c'])); + +/* testPHP74UnpackingInShortArrayExpression */ +// Also includes code sample for PHP 8.1 unpacking with string keys. +$fruits = ['banana', ...$parts, 'watermelon', ...["a" => 2],]; + +/* testPHP80FunctionCallInAttribute */ +#[AttributeAttachedToClosure([1, 2, 3])] +$closure = function() {}; + +/* testPHP80SkippingOverAttributes */ +$result = function_call( + $value, + #[MyAttribute()] + #[AnotherAttribute([1, 2, 3])] + function() { /* do something */} +); diff --git a/Tests/Utils/PassedParameters/GetParametersTest.php b/Tests/Utils/PassedParameters/GetParametersTest.php index 15c67af1..a3187514 100644 --- a/Tests/Utils/PassedParameters/GetParametersTest.php +++ b/Tests/Utils/PassedParameters/GetParametersTest.php @@ -10,7 +10,7 @@ namespace PHPCSUtils\Tests\Utils\PassedParameters; -use PHPCSUtils\BackCompat\Helper; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Utils\PassedParameters; @@ -20,13 +20,14 @@ * * @covers \PHPCSUtils\Utils\PassedParameters::getParameters * @covers \PHPCSUtils\Utils\PassedParameters::getParameter + * @covers \PHPCSUtils\Utils\PassedParameters::getParameterFromStack * @covers \PHPCSUtils\Utils\PassedParameters::hasParameters * * @group passedparameters * * @since 1.0.0 */ -class GetParametersTest extends UtilityMethodTestCase +final class GetParametersTest extends UtilityMethodTestCase { /** @@ -91,9 +92,9 @@ public function dataGetParameters() { return [ 'function-call' => [ - '/* testFunctionCall */', - \T_STRING, - [ + 'testMarker' => '/* testFunctionCall */', + 'targetType' => \T_STRING, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 3, @@ -132,9 +133,9 @@ public function dataGetParameters() ], ], 'function-call-nested' => [ - '/* testFunctionCallNestedFunctionCall */', - \T_STRING, - [ + 'testMarker' => '/* testFunctionCallNestedFunctionCall */', + 'targetType' => \T_STRING, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 9, @@ -143,9 +144,9 @@ public function dataGetParameters() ], ], 'another-function-call' => [ - '/* testAnotherFunctionCall */', - \T_STRING, - [ + 'testMarker' => '/* testAnotherFunctionCall */', + 'targetType' => \T_STRING, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 2, @@ -180,9 +181,9 @@ public function dataGetParameters() ], 'function-call-trailing-comma' => [ - '/* testFunctionCallTrailingComma */', - \T_STRING, - [ + 'testMarker' => '/* testFunctionCallTrailingComma */', + 'targetType' => \T_STRING, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 5, @@ -191,9 +192,9 @@ public function dataGetParameters() ], ], 'function-call-nested-short-array' => [ - '/* testFunctionCallNestedShortArray */', - \T_STRING, - [ + 'testMarker' => '/* testFunctionCallNestedShortArray */', + 'targetType' => \T_STRING, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 34, @@ -202,9 +203,9 @@ public function dataGetParameters() ], ], 'function-call-nested-array-nested-closure-with-commas' => [ - '/* testFunctionCallNestedArrayNestedClosureWithCommas */', - \T_STRING, - [ + 'testMarker' => '/* testFunctionCallNestedArrayNestedClosureWithCommas */', + 'targetType' => \T_STRING, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 90, @@ -228,9 +229,9 @@ public function dataGetParameters() // Long array. 'long-array' => [ - '/* testLongArrayNestedFunctionCalls */', - \T_ARRAY, - [ + 'testMarker' => '/* testLongArrayNestedFunctionCalls */', + 'targetType' => \T_ARRAY, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 8, @@ -266,9 +267,9 @@ public function dataGetParameters() // Short array. 'short-array' => [ - '/* testShortArrayNestedFunctionCalls */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortArrayNestedFunctionCalls */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 1 => [ 'start' => 1, 'end' => 1, @@ -302,9 +303,9 @@ public function dataGetParameters() ], ], 'short-array-with-keys-ternary-and-null-coalesce' => [ - '/* testShortArrayWithKeysTernaryAndNullCoalesce */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortArrayWithKeysTernaryAndNullCoalesce */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 1 => [ 'start' => 1, 'end' => 7, @@ -319,10 +320,7 @@ public function dataGetParameters() ], 3 => [ 'start' => 31, - // Account for null coalesce tokenization difference. - 'end' => (Helper::getVersion() === '2.6.0' && \PHP_VERSION_ID < 59999) - ? 53 - : 51, + 'end' => 51, 'raw' => '\'hey\' => $baz ?? [\'one\'] ?? [\'two\']', @@ -332,9 +330,9 @@ public function dataGetParameters() // Nested arrays. 'nested-arrays-top-level' => [ - '/* testNestedArraysToplevel */', - \T_ARRAY, - [ + 'testMarker' => '/* testNestedArraysToplevel */', + 'targetType' => \T_ARRAY, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 38, @@ -358,9 +356,9 @@ public function dataGetParameters() // Array containing closure. 'short-array-nested-closure-with-commas' => [ - '/* testShortArrayNestedClosureWithCommas */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortArrayNestedClosureWithCommas */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 1 => [ 'start' => 1, 'end' => 38, @@ -380,9 +378,9 @@ public function dataGetParameters() // Array containing anonymous class. 'short-array-nested-anon-class' => [ - '/* testShortArrayNestedAnonClass */', - \T_OPEN_SHORT_ARRAY, - [ + 'testMarker' => '/* testShortArrayNestedAnonClass */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ 1 => [ 'start' => 1, 'end' => 72, @@ -413,9 +411,9 @@ public function test( $foo, $bar ) { // Array arrow function and yield. 'long-array-nested-arrow-function-with-yield' => [ - '/* testLongArrayArrowFunctionWithYield */', - \T_ARRAY, - [ + 'testMarker' => '/* testLongArrayArrowFunctionWithYield */', + 'targetType' => \T_ARRAY, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 8, @@ -436,9 +434,9 @@ public function test( $foo, $bar ) { // Function calling closure in variable. 'variable-function-call' => [ - '/* testVariableFunctionCall */', - \T_VARIABLE, - [ + 'testMarker' => '/* testVariableFunctionCall */', + 'targetType' => \T_VARIABLE, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 2, @@ -457,9 +455,9 @@ public function test( $foo, $bar ) { ], ], 'static-variable-function-call' => [ - '/* testStaticVariableFunctionCall */', - \T_VARIABLE, - [ + 'testMarker' => '/* testStaticVariableFunctionCall */', + 'targetType' => \T_VARIABLE, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 4, @@ -473,9 +471,9 @@ public function test( $foo, $bar ) { ], ], 'isset' => [ - '/* testIsset */', - \T_ISSET, - [ + 'testMarker' => '/* testIsset */', + 'targetType' => \T_ISSET, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 4, @@ -499,9 +497,9 @@ public function test( $foo, $bar ) { ], ], 'unset' => [ - '/* testUnset */', - \T_UNSET, - [ + 'testMarker' => '/* testUnset */', + 'targetType' => \T_UNSET, + 'expected' => [ 1 => [ 'start' => 2, 'end' => 3, @@ -524,9 +522,148 @@ public function test( $foo, $bar ) { ], ], ], + 'anon-class' => [ + 'testMarker' => '/* testAnonClass */', + 'targetType' => \T_ANON_CLASS, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 3, + 'raw' => '$param1', + ], + 2 => [ + 'start' => 5, + 'end' => 7, + 'raw' => '$param2', + ], + ], + ], + + // PHP 7.4 argument unpacking array expressions. + 'long-array-with-argument-unpacking-via-spread-operator' => [ + 'testMarker' => '/* testPHP74UnpackingInLongArrayExpression */', + 'targetType' => \T_ARRAY, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 3, + 'raw' => '...$arr1', + ], + 2 => [ + 'start' => 5, + 'end' => 9, + 'raw' => '...arrGen()', + ], + 3 => [ + 'start' => 11, + 'end' => 26, + 'raw' => "...new ArrayIterator(['a', 'b', 'c'])", + ], + ], + ], + 'short-array-with-argument-unpacking-via-spread-operator' => [ + 'testMarker' => '/* testPHP74UnpackingInShortArrayExpression */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => [ + 1 => [ + 'start' => 1, + 'end' => 1, + 'raw' => "'banana'", + ], + 2 => [ + 'start' => 3, + 'end' => 5, + 'raw' => '...$parts', + ], + 3 => [ + 'start' => 7, + 'end' => 8, + 'raw' => "'watermelon'", + ], + 4 => [ + 'start' => 10, + 'end' => 18, + 'raw' => '...["a" => 2]', + ], + ], + ], + + // PHP 8.0: function calls in attributes. + 'function-call-within-an-attribute' => [ + 'testMarker' => '/* testPHP80FunctionCallInAttribute */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 10, + 'raw' => '[1, 2, 3]', + ], + ], + ], + + // PHP 8.0: skipping over attributes. + 'function-call-with-attributes-attached-to-passed-closure' => [ + 'testMarker' => '/* testPHP80SkippingOverAttributes */', + 'targetType' => \T_STRING, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 4, + 'raw' => '$value', + ], + 2 => [ + 'start' => 6, + 'end' => 39, + 'raw' => '#[MyAttribute()] + #[AnotherAttribute([1, 2, 3])] + function() { /* do something */}', + ], + ], + ], ]; } + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testGetParametersResultIsCached() + { + // The test case used is specifically selected as the raw and the clean param values will be the same. + $methodName = 'PHPCSUtils\\Utils\\PassedParameters::getParameters'; + $cases = $this->dataGetParameters(); + $testMarker = $cases['isset']['testMarker']; + $targetType = $cases['isset']['targetType']; + $expected = $cases['isset']['expected']; + + $stackPtr = $this->getTargetToken($testMarker, [$targetType]); + + // Translate offsets to exact token positions and set the "clean" key. + foreach ($expected as $key => $value) { + $expected[$key]['start'] = ($stackPtr + $value['start']); + $expected[$key]['end'] = ($stackPtr + $value['end']); + $expected[$key]['clean'] = $value['raw']; + } + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-0"); + $resultSecondRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } + /** * Test retrieving the details for a specific parameter from a function call or construct. * @@ -570,120 +707,120 @@ public function dataGetParameter() { return [ 'function-call-param-4' => [ - '/* testFunctionCall */', - \T_STRING, - 4, - [ + 'testMarker' => '/* testFunctionCall */', + 'targetType' => \T_STRING, + 'paramPosition' => 4, + 'expected' => [ 'start' => 11, 'end' => 12, 'raw' => '4', ], ], 'function-call-nested-param-1' => [ - '/* testFunctionCallNestedFunctionCall */', - \T_STRING, - 1, - [ + 'testMarker' => '/* testFunctionCallNestedFunctionCall */', + 'targetType' => \T_STRING, + 'paramPosition' => 1, + 'expected' => [ 'start' => 2, 'end' => 9, 'raw' => 'dirname( __FILE__ )', ], ], 'another-function-call-param-1' => [ - '/* testAnotherFunctionCall */', - \T_STRING, - 1, - [ + 'testMarker' => '/* testAnotherFunctionCall */', + 'targetType' => \T_STRING, + 'paramPosition' => 1, + 'expected' => [ 'start' => 2, 'end' => 2, 'raw' => '$stHour', ], ], 'another-function-call-param-6' => [ - '/* testAnotherFunctionCall */', - \T_STRING, - 6, - [ + 'testMarker' => '/* testAnotherFunctionCall */', + 'targetType' => \T_STRING, + 'paramPosition' => 6, + 'expected' => [ 'start' => 22, 'end' => 26, 'raw' => '$arrStDt[2]', ], ], 'long-array-nested-function-calls-param-3' => [ - '/* testLongArrayNestedFunctionCalls */', - \T_ARRAY, - 3, - [ + 'testMarker' => '/* testLongArrayNestedFunctionCalls */', + 'targetType' => \T_ARRAY, + 'paramPosition' => 3, + 'expected' => [ 'start' => 16, 'end' => 26, 'raw' => 'why(5, 1, 2)', ], ], 'simple-long-array-param-1' => [ - '/* testSimpleLongArray */', - \T_ARRAY, - 1, - [ + 'testMarker' => '/* testSimpleLongArray */', + 'targetType' => \T_ARRAY, + 'paramPosition' => 1, + 'expected' => [ 'start' => 2, 'end' => 3, 'raw' => '1', ], ], 'simple-long-array-param-7' => [ - '/* testSimpleLongArray */', - \T_ARRAY, - 7, - [ + 'testMarker' => '/* testSimpleLongArray */', + 'targetType' => \T_ARRAY, + 'paramPosition' => 7, + 'expected' => [ 'start' => 20, 'end' => 22, 'raw' => 'true', ], ], 'long-array-with-keys-param-' => [ - '/* testLongArrayWithKeys */', - \T_ARRAY, - 2, - [ + 'testMarker' => '/* testLongArrayWithKeys */', + 'targetType' => \T_ARRAY, + 'paramPosition' => 2, + 'expected' => [ 'start' => 8, 'end' => 13, 'raw' => '\'b\' => $b', ], ], 'short-array-more-nested-function-calls-param-1' => [ - '/* testShortArrayMoreNestedFunctionCalls */', - \T_OPEN_SHORT_ARRAY, - 1, - [ + 'testMarker' => '/* testShortArrayMoreNestedFunctionCalls */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'paramPosition' => 1, + 'expected' => [ 'start' => 1, 'end' => 13, 'raw' => 'str_replace("../", "/", trim($value))', ], ], 'short-array-with-keys-and-ternary-param-3' => [ - '/* testShortArrayWithKeysAndTernary */', - \T_OPEN_SHORT_ARRAY, - 3, - [ + 'testMarker' => '/* testShortArrayWithKeysAndTernary */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'paramPosition' => 3, + 'expected' => [ 'start' => 14, 'end' => 32, 'raw' => '6 => (isset($c) ? $c : null)', ], ], 'nested-arrays-level-2-param-1' => [ - '/* testNestedArraysLevel2 */', - \T_ARRAY, - 1, - [ + 'testMarker' => '/* testNestedArraysLevel2 */', + 'targetType' => \T_ARRAY, + 'paramPosition' => 1, + 'expected' => [ 'start' => 2, 'end' => 2, 'raw' => '1', ], ], 'nested-arrays-level-1-param-2' => [ - '/* testNestedArraysLevel1 */', - \T_OPEN_SHORT_ARRAY, - 2, - [ + 'testMarker' => '/* testNestedArraysLevel1 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'paramPosition' => 2, + 'expected' => [ 'start' => 9, 'end' => 21, 'raw' => '1 => [1,2,3]', diff --git a/Tests/Utils/PassedParameters/GetParametersWithLimitTest.inc b/Tests/Utils/PassedParameters/GetParametersWithLimitTest.inc new file mode 100644 index 00000000..aa0e5880 --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParametersWithLimitTest.inc @@ -0,0 +1,55 @@ + 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => true ); + +/* testShortArrayWithKeys */ +$foo = [ + 'a' => 1, + 'b' => 2, + 'c' => 3, + 'd' => 4, + 'e' => 5, + 'f' => 6, + 'g' => true, +]; + +/* + * NOTE: the below test code is duplicate, but the cache tests need unique $stackPtrs to + * prevent the result of earlier tests poluting the results of the caching tests. + */ + +/* testCachedWithLimit */ +$foo = array( 1, 2, 3, 4, 5, 6, true ); + +/* testCachedWithoutLimitWhenTotalItemsLessThanLimit */ +$foo = array( 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => true ) + +/* testCachedWithoutLimitWhenTotalItemsEqualsLimit */ +$foo = [ + 'a' => 1, + 'b' => 2, + 'c' => 3, + 'd' => 4, + 'e' => 5, + 'f' => 6, + 'g' => true, +]; + +/* testRetrievedFromCacheWhenCachePreviouslySetWithoutLimit */ +myfunction( 1, 2, 3, 4, 5, 6, true ); + +/* testRetrievedFromScratchIfNoSuitableCacheFound */ +myfunction( 1, 2, 3, 4, 5, 6, true ); diff --git a/Tests/Utils/PassedParameters/GetParametersWithLimitTest.php b/Tests/Utils/PassedParameters/GetParametersWithLimitTest.php new file mode 100644 index 00000000..bfcb271b --- /dev/null +++ b/Tests/Utils/PassedParameters/GetParametersWithLimitTest.php @@ -0,0 +1,370 @@ +getTargetToken('/* testNoParams */', \T_ARRAY); + + $result = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 3); + $this->assertSame([], $result); + $this->assertCount(0, $result); + + // Limit is automatically applied to getParameter(). + $result = PassedParameters::getParameter(self::$phpcsFile, $stackPtr, 3); + $this->assertFalse($result); + } + + /** + * Test passing an invalid limit. + * + * @dataProvider dataGetParametersWithIneffectiveLimit + * + * @param mixed $limit Parameter value for the $limit parameter. + * + * @return void + */ + public function testGetParametersWithIneffectiveLimit($limit) + { + $stackPtr = $this->getTargetToken('/* testFunctionCall */', \T_STRING); + + $result = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, $limit); + $this->assertNotEmpty($result); + $this->assertCount(7, $result); + } + + /** + * Data provider. + * + * @see testGetParametersWithIneffectiveLimit() For the array format. + * + * @return array + */ + public function dataGetParametersWithIneffectiveLimit() + { + return [ + 'invalid-limit-wrong-type-null' => [null], + 'invalid-limit-wrong-type-bool' => [true], + 'invalid-limit-wrong-type-string' => ['10'], + 'invalid-limit-negative-int' => [-10], + 'valid-limit-set-to-0 = no-limit' => [0], + 'valid-limit-higher-than-param-count' => [10], + ]; + } + + /** + * Test retrieving the parameter details from a function call or construct. + * + * @dataProvider dataGetParametersWithLimit + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType The type of token to look for. + * @param array $limit The number of parameters to limit this call to. + * Should match the expected count. + * @param array $expected Optional. The expected return value. Only tested when not empty. + * + * @return void + */ + public function testGetParametersWithLimit($testMarker, $targetType, $limit, $expected = []) + { + $stackPtr = $this->getTargetToken($testMarker, [$targetType]); + + $result = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, $limit); + $this->assertNotEmpty($result); + $this->assertCount($limit, $result); + + if (empty($expected) === true) { + return; + } + + // Start/end token position values in the expected array are set as offsets + // in relation to the target token. + // Change these to exact positions based on the retrieved stackPtr. + foreach ($expected as $key => $value) { + $expected[$key]['start'] = ($stackPtr + $value['start']); + $expected[$key]['end'] = ($stackPtr + $value['end']); + } + + foreach ($result as $key => $value) { + // The GetTokensAsString functions have their own tests, no need to duplicate it here. + unset($result[$key]['clean']); + } + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetParametersWithLimit() For the array format. + * + * @return array + */ + public function dataGetParametersWithLimit() + { + return [ + 'function-call' => [ + 'testMarker' => '/* testFunctionCall */', + 'targetType' => \T_STRING, + 'limit' => 2, + ], + 'long-array-no-keys' => [ + 'testMarker' => '/* testSimpleLongArray */', + 'targetType' => \T_ARRAY, + 'limit' => 1, + 'expected' => [ + 1 => [ + 'start' => 2, + 'end' => 3, + 'raw' => '1', + ], + ], + ], + 'short-array-no-keys' => [ + 'testMarker' => '/* testSimpleShortArray */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'limit' => 5, + ], + 'long-array-with-keys' => [ + 'testMarker' => '/* testLongArrayWithKeys */', + 'targetType' => \T_ARRAY, + 'limit' => 7, + ], + 'short-array-with-keys' => [ + 'testMarker' => '/* testShortArrayWithKeys */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'limit' => 4, + ], + ]; + } + + /** + * Verify that the build-in caching is used when caching is enabled and that the caching keeps track + * of the used limit. + * + * @return void + */ + public function testResultIsCachedWithLimit() + { + // Can't re-use test cases for these tests, as in that case, the cache _may_ already be set (for 0 limit). + $methodName = 'PHPCSUtils\\Utils\\PassedParameters::getParameters'; + $testMarker = '/* testCachedWithLimit */'; + $stackPtr = $this->getTargetToken($testMarker, \T_ARRAY); + $limit = 1; + $expected = [ + 1 => [ + 'start' => 2 + $stackPtr, + 'end' => 3 + $stackPtr, + 'raw' => '1', + 'clean' => '1', + ], + ]; + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, $limit); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-$limit"); + $resultSecondRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, $limit); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } + + /** + * Verify that when a previous query for the same token was made with a limit which was more than + * the item count, the result was cached as if no limit was set. + * + * @return void + */ + public function testResultIsCachedWithoutLimitWhenTotalItemsLessThanLimit() + { + // Can't re-use test cases for these tests, as in that case, the cache _may_ already be set (for 0 limit). + $methodName = 'PHPCSUtils\\Utils\\PassedParameters::getParameters'; + $testMarker = '/* testCachedWithoutLimitWhenTotalItemsLessThanLimit */'; + $stackPtr = $this->getTargetToken($testMarker, \T_ARRAY); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 10); + $isCachedWithLimit = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-10"); + $isCachedWithoutLimit = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-0"); + $resultSecondRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 10); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertCount(7, $resultFirstRun, 'Count of first result did not match expectation'); + $this->assertFalse($isCachedWithLimit, 'Cache::isCached() found a cached value with key "ptr-10"'); + $this->assertTrue($isCachedWithoutLimit, 'Cache::isCached() did not find a cached value with key "ptr-0"'); + $this->assertCount(7, $resultSecondRun, 'Count of second result did not match expectation'); + } + + /** + * Verify that when a previous query for the same token was made with a limit which matched the item count, + * the result was cached as if no limit was set. + * + * @return void + */ + public function testResultIsCachedWithoutLimitWhenTotalItemsEqualsLimit() + { + // Can't re-use test cases for these tests, as in that case, the cache _may_ already be set (for 0 limit). + $methodName = 'PHPCSUtils\\Utils\\PassedParameters::getParameters'; + $testMarker = '/* testCachedWithoutLimitWhenTotalItemsEqualsLimit */'; + $stackPtr = $this->getTargetToken($testMarker, \T_OPEN_SHORT_ARRAY); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 7); + $isCachedWithLimit = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-7"); + $isCachedWithoutLimit = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-0"); + $resultSecondRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 7); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertCount(7, $resultFirstRun, 'Count of first result did not match expectation'); + $this->assertFalse($isCachedWithLimit, 'Cache::isCached() found a cached value with key "ptr-7"'); + $this->assertTrue($isCachedWithoutLimit, 'Cache::isCached() did not find a cached value with key "ptr-0"'); + $this->assertCount(7, $resultSecondRun, 'Count of second result did not match expectation'); + } + + /** + * Verify that when a previous query for the same token without limit was made, the result + * cache is used to retrieve the limited result. + * + * @return void + */ + public function testResultIsRetrievedFromCacheWhenCachePreviouslySetWithoutLimit() + { + // Can't re-use test cases for these tests, as in that case, the cache _may_ already be set (for 0 limit). + $methodName = 'PHPCSUtils\\Utils\\PassedParameters::getParameters'; + $testMarker = '/* testRetrievedFromCacheWhenCachePreviouslySetWithoutLimit */'; + $stackPtr = $this->getTargetToken($testMarker, \T_STRING); + $limit = 2; + $expected = [ + 1 => [ + 'start' => 2 + $stackPtr, + 'end' => 3 + $stackPtr, + 'raw' => '1', + 'clean' => '1', + ], + 2 => [ + 'start' => 5 + $stackPtr, + 'end' => 6 + $stackPtr, + 'raw' => '2', + 'clean' => '2', + ], + ]; + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-0"); + $resultSecondRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, $limit); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertCount(7, $resultFirstRun, 'Count of first result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() did not find a cached value with key "ptr-0"'); + $this->assertSame($expected, $resultSecondRun, 'Second result did not match the expected result'); + } + + /** + * Verify that when a previous query for the same token was made with a limit which was less than the total + * number of items and the current limit does not match, the function will not use the cache. + * + * @return void + */ + public function testResultIsRetrievedFromScratchIfNoSuitableCacheFound() + { + static $firstRun = true; + + // Can't re-use test cases for this test, as in that case, the cache _may_ already be set (for 0 limit). + $methodName = 'PHPCSUtils\\Utils\\PassedParameters::getParameters'; + $testMarker = '/* testRetrievedFromScratchIfNoSuitableCacheFound */'; + $stackPtr = $this->getTargetToken($testMarker, \T_STRING); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 2); + $isCachedWithLimit2 = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-2"); + $isCachedWithLimit4pre = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-4"); + $isCachedWithoutLimit = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-0"); + $resultSecondRun = PassedParameters::getParameters(self::$phpcsFile, $stackPtr, 4); + $isCachedWithLimit4post = Cache::isCached(self::$phpcsFile, $methodName, "$stackPtr-4"); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertCount(2, $resultFirstRun, 'Count of first result did not match expectation'); + $this->assertTrue($isCachedWithLimit2, 'Cache::isCached() did not find a cached value with key "ptr-2"'); + if ($firstRun === true) { + $this->assertFalse($isCachedWithLimit4pre, 'Cache::isCached() found a cached value with key "ptr-4"'); + } else { + $this->assertTrue($isCachedWithLimit4pre, 'Cache::isCached() did not find a cached value with key "ptr-4"'); + } + $this->assertFalse($isCachedWithoutLimit, 'Cache::isCached() found a cached value with key "ptr-0"'); + $this->assertCount(4, $resultSecondRun, 'Count of second result did not match expectation'); + $this->assertTrue($isCachedWithLimit4post, 'Cache::isCached() did not find a cached value with key "ptr-4"'); + + $firstRun = false; + } +} diff --git a/Tests/Utils/PassedParameters/HasParametersTest.inc b/Tests/Utils/PassedParameters/HasParametersTest.inc index 3c05a5c7..cf69b775 100644 --- a/Tests/Utils/PassedParameters/HasParametersTest.inc +++ b/Tests/Utils/PassedParameters/HasParametersTest.inc @@ -5,8 +5,14 @@ interface NotAFunctionCallOrArray {} class Foo { public function Bar() { - /* testNotACallToConstructor */ - $a = self::some_method(); + /* testNotACallToConstructor1 */ + $a = parent::SOME_CONSTANT; + + /* testNotACallToConstructor2 */ + $a = static::some_method(); + + /* testNotACallToConstructor3 */ + $a = $obj instanceof self; } } @@ -27,6 +33,17 @@ some_function( /*nothing here*/ ); /* testNoParamsFunctionCall4 */ $closure(/*nothing here*/); +class HierarchyKeywordsNoParens { + public static function getInstance() { + /* testNoParamsFunctionCall5 */ + $a = new self; + /* testNoParamsFunctionCall6 */ + $a = new static; + /* testNoParamsFunctionCall7 */ + $a = new parent; + } +} + // Function calls: has parameters. /* testHasParamsFunctionCall1 */ @@ -35,13 +52,43 @@ some_function( 1 ); /* testHasParamsFunctionCall2 */ $closure(1,2,3); -class Bar { +class HierarchyKeywordsWithParam { public static function getInstance() { /* testHasParamsFunctionCall3 */ - return new self(true); + $a = new self(true); + /* testHasParamsFunctionCall4 */ + $a = new static(true); + /* testHasParamsFunctionCall5 */ + $a = new parent(true); } } +class HierarchyKeywordsAsMethodNames { + public function self() {} + public function static() {} + public function parent() { + /* testHasParamsFunctionCall6 */ + $a = self::self(true); + /* testHasParamsFunctionCall7 */ + $a = $this->static(true); + /* testHasParamsFunctionCall8 */ + $a = $this->parent(true); + } +} + +/* testNoParamsFunctionCallFullyQualified */ +\myfunction( ); + +/* testHasParamsFunctionCallFullyQualifiedWithNamespace */ +\My\Named\myfunction( $a ); + +/* testNoParamsFunctionCallPartiallyQualified */ +Partially\Qualified\myfunction(); + +/* testHasParamsFunctionCallNamespaceOperator */ +namespace\myfunction( $a ); + + // Arrays: no parameters. /* testNoParamsLongArray1 */ @@ -107,6 +154,26 @@ unset( ); +/* testNoParamsNoParensAnonClass */ +$anon = new class extends FooBar {}; + +/* testNoParamsWithParensAnonClass */ +$anon = new class() {}; + +/* testHasParamsAnonClass */ +$anon = new class( $param1, $param2 ) {}; + +/* testPHP81FirstClassCallableNotFunctionCallGlobalFunction */ +$fn = strlen(...); + +/* testPHP81FirstClassCallableNotFunctionCallOOMethod */ +$fn = $this->method( + ... +); + +/* testPHP81FirstClassCallableNotFunctionCallVariableStaticOOMethod */ +$fn = $name1::$name2( /*comment*/ ...); + // Intentional parse error. /* testNoCloseParenthesis */ $array = array(1, 2, 3 diff --git a/Tests/Utils/PassedParameters/HasParametersTest.php b/Tests/Utils/PassedParameters/HasParametersTest.php index 36290a5e..8e25394c 100644 --- a/Tests/Utils/PassedParameters/HasParametersTest.php +++ b/Tests/Utils/PassedParameters/HasParametersTest.php @@ -8,9 +8,10 @@ * @link https://github.com/PHPCSStandards/PHPCSUtils */ -namespace PHPCSUtils\Tests\Utils\Operators; +namespace PHPCSUtils\Tests\Utils\PassedParameters; use PHPCSUtils\TestUtils\UtilityMethodTestCase; +use PHPCSUtils\Tokens\Collections; use PHPCSUtils\Utils\PassedParameters; /** @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class HasParametersTest extends UtilityMethodTestCase +final class HasParametersTest extends UtilityMethodTestCase { /** @@ -58,18 +59,48 @@ public function testNotAnAcceptedTokenException() /** * Test receiving an expected exception when T_SELF is passed not preceeded by `new`. * + * @dataProvider dataNotACallToConstructor + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType The type of token to look for. + * * @return void */ - public function testNotACallToConstructor() + public function testNotACallToConstructor($testMarker, $targetType) { $this->expectPhpcsException( 'The hasParameters() method expects a function call, array, isset or unset token to be passed.' ); - $self = $this->getTargetToken('/* testNotACallToConstructor */', \T_SELF); + $self = $this->getTargetToken($testMarker, $targetType); PassedParameters::hasParameters(self::$phpcsFile, $self); } + /** + * Data provider. + * + * @see testNotACallToConstructor() For the array format. + * + * @return array + */ + public function dataNotACallToConstructor() + { + return [ + 'parent' => [ + 'testMarker' => '/* testNotACallToConstructor1 */', + 'targetType' => \T_PARENT, + ], + 'static' => [ + 'testMarker' => '/* testNotACallToConstructor2 */', + 'targetType' => \T_STATIC, + ], + 'self' => [ + 'testMarker' => '/* testNotACallToConstructor3 */', + 'targetType' => \T_SELF, + ], + ]; + } + /** * Test receiving an expected exception when T_OPEN_SHORT_ARRAY is passed but represents a short list. * @@ -83,7 +114,7 @@ public function testNotAShortArray() $self = $this->getTargetToken( '/* testShortListNotShortArray */', - [\T_OPEN_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET] + Collections::shortArrayListOpenTokensBC() ); PassedParameters::hasParameters(self::$phpcsFile, $self); } @@ -93,15 +124,17 @@ public function testNotAShortArray() * * @dataProvider dataHasParameters * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int|string $targetType The type of token to look for. - * @param bool $expected Whether or not the function/array has parameters/values. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $targetType The type of token to look for. + * @param bool $expected Whether or not the function/array has parameters/values. + * @param string $targetContent Optional. The content of the target token to find. + * Defaults to null (ignore content). * * @return void */ - public function testHasParameters($testMarker, $targetType, $expected) + public function testHasParameters($testMarker, $targetType, $expected, $targetContent = null) { - $stackPtr = $this->getTargetToken($testMarker, $targetType); + $stackPtr = $this->getTargetToken($testMarker, $targetType, $targetContent); $result = PassedParameters::hasParameters(self::$phpcsFile, $stackPtr); $this->assertSame($expected, $result); } @@ -115,156 +148,261 @@ public function testHasParameters($testMarker, $targetType, $expected) */ public function dataHasParameters() { + $php8Names = parent::usesPhp8NameTokens(); + return [ // Function calls. 'no-params-function-call-1' => [ - '/* testNoParamsFunctionCall1 */', - \T_STRING, - false, + 'testMarker' => '/* testNoParamsFunctionCall1 */', + 'targetType' => \T_STRING, + 'expected' => false, ], 'no-params-function-call-2' => [ - '/* testNoParamsFunctionCall2 */', - \T_STRING, - false, + 'testMarker' => '/* testNoParamsFunctionCall2 */', + 'targetType' => \T_STRING, + 'expected' => false, ], 'no-params-function-call-3' => [ - '/* testNoParamsFunctionCall3 */', - \T_STRING, - false, + 'testMarker' => '/* testNoParamsFunctionCall3 */', + 'targetType' => \T_STRING, + 'expected' => false, ], 'no-params-function-call-4' => [ - '/* testNoParamsFunctionCall4 */', - \T_VARIABLE, - false, + 'testMarker' => '/* testNoParamsFunctionCall4 */', + 'targetType' => \T_VARIABLE, + 'expected' => false, + ], + 'no-params-function-call-5-new-self' => [ + 'testMarker' => '/* testNoParamsFunctionCall5 */', + 'targetType' => \T_SELF, + 'expected' => false, ], + 'no-params-function-call-6-new-static' => [ + 'testMarker' => '/* testNoParamsFunctionCall6 */', + 'targetType' => \T_STATIC, + 'expected' => false, + ], + 'no-params-function-call-7-new-parent' => [ + 'testMarker' => '/* testNoParamsFunctionCall7 */', + 'targetType' => \T_PARENT, + 'expected' => false, + ], + 'has-params-function-call-1' => [ - '/* testHasParamsFunctionCall1 */', - \T_STRING, - true, + 'testMarker' => '/* testHasParamsFunctionCall1 */', + 'targetType' => \T_STRING, + 'expected' => true, ], 'has-params-function-call-2' => [ - '/* testHasParamsFunctionCall2 */', - \T_VARIABLE, - true, + 'testMarker' => '/* testHasParamsFunctionCall2 */', + 'targetType' => \T_VARIABLE, + 'expected' => true, + ], + 'has-params-function-call-3-new-self' => [ + 'testMarker' => '/* testHasParamsFunctionCall3 */', + 'targetType' => \T_SELF, + 'expected' => true, + ], + 'has-params-function-call-4-new-static' => [ + 'testMarker' => '/* testHasParamsFunctionCall4 */', + 'targetType' => \T_STATIC, + 'expected' => true, + ], + 'has-params-function-call-5-new-parent' => [ + 'testMarker' => '/* testHasParamsFunctionCall5 */', + 'targetType' => \T_PARENT, + 'expected' => true, ], - 'has-params-function-call-3' => [ - '/* testHasParamsFunctionCall3 */', - // In PHPCS < 2.8.0, self in "new self" is tokenized as T_STRING. - [\T_SELF, \T_STRING], - true, + 'has-params-function-call-6-self-as-method-name' => [ + 'testMarker' => '/* testHasParamsFunctionCall6 */', + 'targetType' => \T_STRING, + 'expected' => true, + 'targetContent' => 'self', + ], + 'has-params-function-call-7-static-as-method-name' => [ + 'testMarker' => '/* testHasParamsFunctionCall7 */', + 'targetType' => \T_STRING, + 'expected' => true, + 'targetContent' => 'static', + ], + 'has-params-function-call-8-parent-as-method-name' => [ + 'testMarker' => '/* testHasParamsFunctionCall8 */', + 'targetType' => \T_STRING, + 'expected' => true, + 'targetContent' => 'parent', + ], + + 'no-params-function-call-fully-qualified' => [ + 'testMarker' => '/* testNoParamsFunctionCallFullyQualified */', + 'targetType' => ($php8Names === true) ? \T_NAME_FULLY_QUALIFIED : \T_STRING, + 'expected' => false, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'has-params-function-call-fully-qualified-with-namespace' => [ + 'testMarker' => '/* testHasParamsFunctionCallFullyQualifiedWithNamespace */', + 'targetType' => ($php8Names === true) ? \T_NAME_FULLY_QUALIFIED : \T_STRING, + 'expected' => true, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'no-params-function-call-partially-qualified' => [ + 'testMarker' => '/* testNoParamsFunctionCallPartiallyQualified */', + 'targetType' => ($php8Names === true) ? \T_NAME_QUALIFIED : \T_STRING, + 'expected' => false, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', + ], + 'has-params-function-call-namespace-operator-relative' => [ + 'testMarker' => '/* testHasParamsFunctionCallNamespaceOperator */', + 'targetType' => ($php8Names === true) ? \T_NAME_RELATIVE : \T_STRING, + 'expected' => true, + 'targetContent' => ($php8Names === true) ? null : 'myfunction', ], // Arrays. 'no-params-long-array-1' => [ - '/* testNoParamsLongArray1 */', - \T_ARRAY, - false, + 'testMarker' => '/* testNoParamsLongArray1 */', + 'targetType' => \T_ARRAY, + 'expected' => false, ], 'no-params-long-array-2' => [ - '/* testNoParamsLongArray2 */', - \T_ARRAY, - false, + 'testMarker' => '/* testNoParamsLongArray2 */', + 'targetType' => \T_ARRAY, + 'expected' => false, ], 'no-params-long-array-3' => [ - '/* testNoParamsLongArray3 */', - \T_ARRAY, - false, + 'testMarker' => '/* testNoParamsLongArray3 */', + 'targetType' => \T_ARRAY, + 'expected' => false, ], 'no-params-long-array-4' => [ - '/* testNoParamsLongArray4 */', - \T_ARRAY, - false, + 'testMarker' => '/* testNoParamsLongArray4 */', + 'targetType' => \T_ARRAY, + 'expected' => false, ], 'no-params-short-array-1' => [ - '/* testNoParamsShortArray1 */', - \T_OPEN_SHORT_ARRAY, - false, + 'testMarker' => '/* testNoParamsShortArray1 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => false, ], 'no-params-short-array-2' => [ - '/* testNoParamsShortArray2 */', - \T_OPEN_SHORT_ARRAY, - false, + 'testMarker' => '/* testNoParamsShortArray2 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => false, ], 'no-params-short-array-3' => [ - '/* testNoParamsShortArray3 */', - \T_OPEN_SHORT_ARRAY, - false, + 'testMarker' => '/* testNoParamsShortArray3 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => false, ], 'no-params-short-array-4' => [ - '/* testNoParamsShortArray4 */', - \T_OPEN_SHORT_ARRAY, - false, + 'testMarker' => '/* testNoParamsShortArray4 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => false, ], 'has-params-long-array-1' => [ - '/* testHasParamsLongArray1 */', - \T_ARRAY, - true, + 'testMarker' => '/* testHasParamsLongArray1 */', + 'targetType' => \T_ARRAY, + 'expected' => true, ], 'has-params-long-array-2' => [ - '/* testHasParamsLongArray2 */', - \T_ARRAY, - true, + 'testMarker' => '/* testHasParamsLongArray2 */', + 'targetType' => \T_ARRAY, + 'expected' => true, ], 'has-params-long-array-3' => [ - '/* testHasParamsLongArray3 */', - \T_ARRAY, - true, + 'testMarker' => '/* testHasParamsLongArray3 */', + 'targetType' => \T_ARRAY, + 'expected' => true, ], 'has-params-short-array-1' => [ - '/* testHasParamsShortArray1 */', - \T_OPEN_SHORT_ARRAY, - true, + 'testMarker' => '/* testHasParamsShortArray1 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => true, ], 'has-params-short-array-2' => [ - '/* testHasParamsShortArray2 */', - \T_OPEN_SHORT_ARRAY, - true, + 'testMarker' => '/* testHasParamsShortArray2 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => true, ], 'has-params-short-array-3' => [ - '/* testHasParamsShortArray3 */', - \T_OPEN_SHORT_ARRAY, - true, + 'testMarker' => '/* testHasParamsShortArray3 */', + 'targetType' => \T_OPEN_SHORT_ARRAY, + 'expected' => true, ], // Isset. 'no-params-isset' => [ - '/* testNoParamsIsset */', - \T_ISSET, - false, + 'testMarker' => '/* testNoParamsIsset */', + 'targetType' => \T_ISSET, + 'expected' => false, ], 'has-params-isset' => [ - '/* testHasParamsIsset */', - \T_ISSET, - true, + 'testMarker' => '/* testHasParamsIsset */', + 'targetType' => \T_ISSET, + 'expected' => true, ], // Unset. 'no-params-unset' => [ - '/* testNoParamsUnset */', - \T_UNSET, - false, + 'testMarker' => '/* testNoParamsUnset */', + 'targetType' => \T_UNSET, + 'expected' => false, ], 'has-params-unset' => [ - '/* testHasParamsUnset */', - \T_UNSET, - true, + 'testMarker' => '/* testHasParamsUnset */', + 'targetType' => \T_UNSET, + 'expected' => true, + ], + + // Anonymous class instantiation. + 'no-params-no-parens-anon-class' => [ + 'testMarker' => '/* testNoParamsNoParensAnonClass */', + 'targetType' => \T_ANON_CLASS, + 'expected' => false, + ], + 'no-params-with-parens-anon-class' => [ + 'testMarker' => '/* testNoParamsWithParensAnonClass */', + 'targetType' => \T_ANON_CLASS, + 'expected' => false, + ], + 'has-params-anon-class' => [ + 'testMarker' => '/* testHasParamsAnonClass */', + 'targetType' => \T_ANON_CLASS, + 'expected' => true, + ], + + // PHP 8.1 first class callables are callbacks, not function calls. + 'no-params-php81-first-class-callable-global-function' => [ + 'testMarker' => '/* testPHP81FirstClassCallableNotFunctionCallGlobalFunction */', + 'targetType' => \T_STRING, + 'expected' => false, + ], + 'no-params-php81-first-class-callable-oo-method' => [ + 'testMarker' => '/* testPHP81FirstClassCallableNotFunctionCallOOMethod */', + 'targetType' => \T_STRING, + 'expected' => false, + ], + 'no-params-php81-first-class-callable-variable-static-oo-method' => [ + 'testMarker' => '/* testPHP81FirstClassCallableNotFunctionCallVariableStaticOOMethod */', + 'targetType' => \T_VARIABLE, + 'expected' => false, + 'targetContent' => '$name2', ], // Defensive coding against parse errors and live coding. 'defense-in-depth-no-close-parens' => [ - '/* testNoCloseParenthesis */', - \T_ARRAY, - false, + 'testMarker' => '/* testNoCloseParenthesis */', + 'targetType' => \T_ARRAY, + 'expected' => false, ], 'defense-in-depth-no-open-parens' => [ - '/* testNoOpenParenthesis */', - \T_STRING, - false, + 'testMarker' => '/* testNoOpenParenthesis */', + 'targetType' => \T_STRING, + 'expected' => false, ], 'defense-in-depth-live-coding' => [ - '/* testLiveCoding */', - \T_ARRAY, - false, + 'testMarker' => '/* testLiveCoding */', + 'targetType' => \T_ARRAY, + 'expected' => false, ], ]; } diff --git a/Tests/Utils/Scopes/IsOOConstantTest.inc b/Tests/Utils/Scopes/IsOOConstantTest.inc index 3654d886..31259737 100644 --- a/Tests/Utils/Scopes/IsOOConstantTest.inc +++ b/Tests/Utils/Scopes/IsOOConstantTest.inc @@ -33,7 +33,18 @@ interface MyInterface { } trait MyTrait { - // Intentional parse error. Constants are not allowed in traits. + // Prior to PHP 8.2, this was a parse error. Since PHP 8.2, constants are allowed in traits. /* testTraitConst */ const BAR = false; } + +enum Suit: string +{ + /* testEnumConst */ + const FOO = 'bar'; + + case Hearts = 'H'; + case Diamonds = 'D'; + case Clubs = 'C'; + case Spades = 'S'; +} diff --git a/Tests/Utils/Scopes/IsOOConstantTest.php b/Tests/Utils/Scopes/IsOOConstantTest.php index 4f898b40..911514d0 100644 --- a/Tests/Utils/Scopes/IsOOConstantTest.php +++ b/Tests/Utils/Scopes/IsOOConstantTest.php @@ -16,17 +16,19 @@ /** * Tests for the \PHPCSUtils\Utils\Scopes::isOOConstant() method. * + * @coversDefaultClass \PHPCSUtils\Utils\Scopes + * * @group scopes * * @since 1.0.0 */ -class IsOOConstantTest extends UtilityMethodTestCase +final class IsOOConstantTest extends UtilityMethodTestCase { /** * Test passing a non-existent token pointer. * - * @covers \PHPCSUtils\Utils\Scopes::isOOConstant + * @covers ::isOOConstant * * @return void */ @@ -39,7 +41,7 @@ public function testNonExistentToken() /** * Test passing a non const token. * - * @covers \PHPCSUtils\Utils\Scopes::isOOConstant + * @covers ::isOOConstant * * @return void */ @@ -54,8 +56,8 @@ public function testNonConstToken() * * @dataProvider dataIsOOConstant * - * @covers \PHPCSUtils\Utils\Scopes::isOOConstant - * @covers \PHPCSUtils\Utils\Scopes::validDirectScope + * @covers ::isOOConstant + * @covers ::validDirectScope * * @param string $testMarker The comment which prefaces the target token in the test file. * @param bool $expected The expected function return value. @@ -80,32 +82,36 @@ public function dataIsOOConstant() { return [ 'global-const' => [ - '/* testGlobalConst */', - false, + 'testMarker' => '/* testGlobalConst */', + 'expected' => false, ], 'function-const' => [ - '/* testFunctionConst */', - false, + 'testMarker' => '/* testFunctionConst */', + 'expected' => false, ], 'class-const' => [ - '/* testClassConst */', - true, + 'testMarker' => '/* testClassConst */', + 'expected' => true, ], 'method-const' => [ - '/* testClassMethodConst */', - false, + 'testMarker' => '/* testClassMethodConst */', + 'expected' => false, ], 'anon-class-const' => [ - '/* testAnonClassConst */', - true, + 'testMarker' => '/* testAnonClassConst */', + 'expected' => true, ], 'interface-const' => [ - '/* testInterfaceConst */', - true, + 'testMarker' => '/* testInterfaceConst */', + 'expected' => true, ], 'trait-const' => [ - '/* testTraitConst */', - false, + 'testMarker' => '/* testTraitConst */', + 'expected' => true, + ], + 'enum-const' => [ + 'testMarker' => '/* testEnumConst */', + 'expected' => true, ], ]; } diff --git a/Tests/Utils/Scopes/IsOOMethodTest.inc b/Tests/Utils/Scopes/IsOOMethodTest.inc index d4e0c2ec..2da0bfbe 100644 --- a/Tests/Utils/Scopes/IsOOMethodTest.inc +++ b/Tests/Utils/Scopes/IsOOMethodTest.inc @@ -38,3 +38,17 @@ trait MyTrait { /* testTraitMethod */ public function something() {} } + +enum Suit implements Colorful +{ + case Hearts; + + /* testEnumMethod */ + public function color(): string { + /* testEnumNestedFunction */ + function nested() {} + + /* testEnumNestedClosure */ + $c = function() {}; + } +} diff --git a/Tests/Utils/Scopes/IsOOMethodTest.php b/Tests/Utils/Scopes/IsOOMethodTest.php index 877bdf4f..540cdb93 100644 --- a/Tests/Utils/Scopes/IsOOMethodTest.php +++ b/Tests/Utils/Scopes/IsOOMethodTest.php @@ -16,17 +16,19 @@ /** * Tests for the \PHPCSUtils\Utils\Scopes::isOOMethod() method. * + * @coversDefaultClass \PHPCSUtils\Utils\Scopes + * * @group scopes * * @since 1.0.0 */ -class IsOOMethodTest extends UtilityMethodTestCase +final class IsOOMethodTest extends UtilityMethodTestCase { /** * Test passing a non-existent token pointer. * - * @covers \PHPCSUtils\Utils\Scopes::isOOMethod + * @covers ::isOOMethod * * @return void */ @@ -39,7 +41,7 @@ public function testNonExistentToken() /** * Test passing a non function token. * - * @covers \PHPCSUtils\Utils\Scopes::isOOMethod + * @covers ::isOOMethod * * @return void */ @@ -54,8 +56,8 @@ public function testNonFunctionToken() * * @dataProvider dataIsOOMethod * - * @covers \PHPCSUtils\Utils\Scopes::isOOMethod - * @covers \PHPCSUtils\Utils\Scopes::validDirectScope + * @covers ::isOOMethod + * @covers ::validDirectScope * * @param string $testMarker The comment which prefaces the target token in the test file. * @param bool $expected The expected function return value. @@ -80,44 +82,56 @@ public function dataIsOOMethod() { return [ 'global-function' => [ - '/* testGlobalFunction */', - false, + 'testMarker' => '/* testGlobalFunction */', + 'expected' => false, ], 'nested-function' => [ - '/* testNestedFunction */', - false, + 'testMarker' => '/* testNestedFunction */', + 'expected' => false, ], 'nested-closure' => [ - '/* testNestedClosure */', - false, + 'testMarker' => '/* testNestedClosure */', + 'expected' => false, ], 'class-method' => [ - '/* testClassMethod */', - true, + 'testMarker' => '/* testClassMethod */', + 'expected' => true, ], 'class-nested-function' => [ - '/* testClassNestedFunction */', - false, + 'testMarker' => '/* testClassNestedFunction */', + 'expected' => false, ], 'class-nested-closure' => [ - '/* testClassNestedClosure */', - false, + 'testMarker' => '/* testClassNestedClosure */', + 'expected' => false, ], 'class-abstract-method' => [ - '/* testClassAbstractMethod */', - true, + 'testMarker' => '/* testClassAbstractMethod */', + 'expected' => true, ], 'anon-class-method' => [ - '/* testAnonClassMethod */', - true, + 'testMarker' => '/* testAnonClassMethod */', + 'expected' => true, ], 'interface-method' => [ - '/* testInterfaceMethod */', - true, + 'testMarker' => '/* testInterfaceMethod */', + 'expected' => true, ], 'trait-method' => [ - '/* testTraitMethod */', - true, + 'testMarker' => '/* testTraitMethod */', + 'expected' => true, + ], + 'enum-method' => [ + 'testMarker' => '/* testEnumMethod */', + 'expected' => true, + ], + 'enum-nested-function' => [ + 'testMarker' => '/* testEnumNestedFunction */', + 'expected' => false, + ], + 'enum-nested-closure' => [ + 'testMarker' => '/* testEnumNestedClosure */', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/Scopes/IsOOPropertyTest.inc b/Tests/Utils/Scopes/IsOOPropertyTest.inc index 9385111a..d765c0c5 100644 --- a/Tests/Utils/Scopes/IsOOPropertyTest.inc +++ b/Tests/Utils/Scopes/IsOOPropertyTest.inc @@ -87,3 +87,12 @@ if ( has_filter( 'comments_open' ) === false ) { /* testFunctionCallParameter */ }, $priority, 2 ); } + +enum MyEnum { + // Intentional parse error. Properties are not allowed in enums. + /* testEnumProp */ + public $enumProp = false; + + /* testEnumMethodParameter */ + public function something($param = false); +} diff --git a/Tests/Utils/Scopes/IsOOPropertyTest.php b/Tests/Utils/Scopes/IsOOPropertyTest.php index 566d6640..5e3f9c04 100644 --- a/Tests/Utils/Scopes/IsOOPropertyTest.php +++ b/Tests/Utils/Scopes/IsOOPropertyTest.php @@ -16,17 +16,19 @@ /** * Tests for the \PHPCSUtils\Utils\Scopes::isOOProperty method. * + * @coversDefaultClass \PHPCSUtils\Utils\Scopes + * * @group scopes * * @since 1.0.0 */ -class IsOOPropertyTest extends UtilityMethodTestCase +final class IsOOPropertyTest extends UtilityMethodTestCase { /** * Test passing a non-existent token pointer. * - * @covers \PHPCSUtils\Utils\Scopes::isOOProperty + * @covers ::isOOProperty * * @return void */ @@ -39,7 +41,7 @@ public function testNonExistentToken() /** * Test passing a non variable token. * - * @covers \PHPCSUtils\Utils\Scopes::isOOProperty + * @covers ::isOOProperty * * @return void */ @@ -54,8 +56,8 @@ public function testNonVariableToken() * * @dataProvider dataIsOOProperty * - * @covers \PHPCSUtils\Utils\Scopes::isOOProperty - * @covers \PHPCSUtils\Utils\Scopes::validDirectScope + * @covers ::isOOProperty + * @covers ::validDirectScope * * @param string $testMarker The comment which prefaces the target token in the test file. * @param bool $expected The expected function return value. @@ -80,100 +82,108 @@ public function dataIsOOProperty() { return [ 'global-var' => [ - '/* testGlobalVar */', - false, + 'testMarker' => '/* testGlobalVar */', + 'expected' => false, ], 'function-param' => [ - '/* testFunctionParameter */', - false, + 'testMarker' => '/* testFunctionParameter */', + 'expected' => false, ], 'function-local-var' => [ - '/* testFunctionLocalVar */', - false, + 'testMarker' => '/* testFunctionLocalVar */', + 'expected' => false, ], 'class-property-public' => [ - '/* testClassPropPublic */', - true, + 'testMarker' => '/* testClassPropPublic */', + 'expected' => true, ], 'class-property-var' => [ - '/* testClassPropVar */', - true, + 'testMarker' => '/* testClassPropVar */', + 'expected' => true, ], 'class-property-static-protected' => [ - '/* testClassPropStaticProtected */', - true, + 'testMarker' => '/* testClassPropStaticProtected */', + 'expected' => true, ], 'method-param' => [ - '/* testMethodParameter */', - false, + 'testMarker' => '/* testMethodParameter */', + 'expected' => false, ], 'method-local-var' => [ - '/* testMethodLocalVar */', - false, + 'testMarker' => '/* testMethodLocalVar */', + 'expected' => false, ], 'anon-class-property-private' => [ - '/* testAnonClassPropPrivate */', - true, + 'testMarker' => '/* testAnonClassPropPrivate */', + 'expected' => true, ], 'anon-class-method-param' => [ - '/* testAnonMethodParameter */', - false, + 'testMarker' => '/* testAnonMethodParameter */', + 'expected' => false, ], 'anon-class-method-local-var' => [ - '/* testAnonMethodLocalVar */', - false, + 'testMarker' => '/* testAnonMethodLocalVar */', + 'expected' => false, ], 'interface-property' => [ - '/* testInterfaceProp */', - false, + 'testMarker' => '/* testInterfaceProp */', + 'expected' => false, ], 'interface-method-param' => [ - '/* testInterfaceMethodParameter */', - false, + 'testMarker' => '/* testInterfaceMethodParameter */', + 'expected' => false, ], 'trait-property' => [ - '/* testTraitProp */', - true, + 'testMarker' => '/* testTraitProp */', + 'expected' => true, ], 'trait-method-param' => [ - '/* testTraitMethodParameter */', - false, + 'testMarker' => '/* testTraitMethodParameter */', + 'expected' => false, ], 'class-multi-property-1' => [ - '/* testClassMultiProp1 */', - true, + 'testMarker' => '/* testClassMultiProp1 */', + 'expected' => true, ], 'class-multi-property-2' => [ - '/* testClassMultiProp2 */', - true, + 'testMarker' => '/* testClassMultiProp2 */', + 'expected' => true, ], 'class-multi-property-3' => [ - '/* testClassMultiProp3 */', - true, + 'testMarker' => '/* testClassMultiProp3 */', + 'expected' => true, ], 'global-var-obj-access' => [ - '/* testGlobalVarObj */', - false, + 'testMarker' => '/* testGlobalVarObj */', + 'expected' => false, ], 'nested-anon-class-property' => [ - '/* testNestedAnonClassProp */', - true, + 'testMarker' => '/* testNestedAnonClassProp */', + 'expected' => true, ], 'double-nested-anon-class-property' => [ - '/* testDoubleNestedAnonClassProp */', - true, + 'testMarker' => '/* testDoubleNestedAnonClassProp */', + 'expected' => true, ], 'double-nested-anon-class-method-param' => [ - '/* testDoubleNestedAnonClassMethodParameter */', - false, + 'testMarker' => '/* testDoubleNestedAnonClassMethodParameter */', + 'expected' => false, ], 'double-nested-anon-class-method-local-var' => [ - '/* testDoubleNestedAnonClassMethodLocalVar */', - false, + 'testMarker' => '/* testDoubleNestedAnonClassMethodLocalVar */', + 'expected' => false, ], 'function-call-param' => [ - '/* testFunctionCallParameter */', - false, + 'testMarker' => '/* testFunctionCallParameter */', + 'expected' => false, + ], + 'enum-property' => [ + 'testMarker' => '/* testEnumProp */', + 'expected' => false, + ], + 'enum-method-param' => [ + 'testMarker' => '/* testEnumMethodParameter */', + 'expected' => false, ], ]; } diff --git a/Tests/Utils/TextStrings/GetCompleteTextStringTest.inc b/Tests/Utils/TextStrings/GetCompleteTextStringTest.inc index a425ac4e..1fd52e64 100644 --- a/Tests/Utils/TextStrings/GetCompleteTextStringTest.inc +++ b/Tests/Utils/TextStrings/GetCompleteTextStringTest.inc @@ -43,6 +43,18 @@ third line fourth line EOD; +/* testMultipleProblemEmbedsInSingleLineDoubleQuotedString */ +echo "My ${foo["${bar}"]} and ${foo["${bar['baz']}"]} and also ${foo->{"${'a'}"}}"; + +/* testProblemEmbedAtEndOfLineInMultiLineDoubleQuotedString */ +echo "Testing ${foo["${bar['baz']}"]} +and more ${foo["${bar}"]} testing"; + +/* testMultilineProblemEmbedInMultiLineDoubleQuotedString */ +echo "Testing ${foo["${bar + ['baz'] +}"]} and more testing"; + /* testTextStringAtEndOfFile */ // This has to be the last test in the file without a new line after it. echo 'first line diff --git a/Tests/Utils/TextStrings/GetCompleteTextStringTest.php b/Tests/Utils/TextStrings/GetCompleteTextStringTest.php index 0a8bc022..5a80ee38 100644 --- a/Tests/Utils/TextStrings/GetCompleteTextStringTest.php +++ b/Tests/Utils/TextStrings/GetCompleteTextStringTest.php @@ -10,19 +10,22 @@ namespace PHPCSUtils\Tests\Utils\TextStrings; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Utils\TextStrings; /** - * Tests for the \PHPCSUtils\Utils\TextStrings::getCompleteTextString() method. + * Tests for the \PHPCSUtils\Utils\TextStrings::getCompleteTextString() and + * \PHPCSUtils\Utils\TextStrings::getEndOfCompleteTextString() methods. * * @covers \PHPCSUtils\Utils\TextStrings::getCompleteTextString + * @covers \PHPCSUtils\Utils\TextStrings::getEndOfCompleteTextString * * @group textstrings * * @since 1.0.0 */ -class GetCompleteTextStringTest extends UtilityMethodTestCase +final class GetCompleteTextStringTest extends UtilityMethodTestCase { /** @@ -40,24 +43,32 @@ class GetCompleteTextStringTest extends UtilityMethodTestCase /** * Test passing a non-existent token pointer. * + * @dataProvider dataExceptions + * + * @param string $method The name of the method to test the exception for. + * * @return void */ - public function testNonExistentToken() + public function testNonExistentToken($method) { $this->expectPhpcsException( '$stackPtr must be of type T_START_HEREDOC, T_START_NOWDOC, T_CONSTANT_ENCAPSED_STRING' . ' or T_DOUBLE_QUOTED_STRING' ); - TextStrings::getCompleteTextString(self::$phpcsFile, 100000); + TextStrings::$method(self::$phpcsFile, 100000); } /** * Test receiving an expected exception when a non text string is passed. * + * @dataProvider dataExceptions + * + * @param string $method The name of the method to test the exception for. + * * @return void */ - public function testNotATextStringException() + public function testNotATextStringException($method) { $this->expectPhpcsException( '$stackPtr must be of type T_START_HEREDOC, T_START_NOWDOC, T_CONSTANT_ENCAPSED_STRING' @@ -65,16 +76,20 @@ public function testNotATextStringException() ); $next = $this->getTargetToken('/* testNotATextString */', \T_RETURN); - TextStrings::getCompleteTextString(self::$phpcsFile, $next); + TextStrings::$method(self::$phpcsFile, $next); } /** * Test receiving an expected exception when a text string token is not the first token * of a multi-line text string. * + * @dataProvider dataExceptions + * + * @param string $method The name of the method to test the exception for. + * * @return void */ - public function testNotFirstTextStringException() + public function testNotFirstTextStringException($method) { $this->expectPhpcsException('$stackPtr must be the start of the text string'); @@ -84,7 +99,20 @@ public function testNotFirstTextStringException() 'second line ' ); - TextStrings::getCompleteTextString(self::$phpcsFile, $next); + TextStrings::$method(self::$phpcsFile, $next); + } + + /** + * Data provider. + * + * @return array + */ + public function dataExceptions() + { + return [ + 'getCompleteTextString' => ['getCompleteTextString'], + 'getEndOfCompleteTextString' => ['getEndOfCompleteTextString'], + ]; } /** @@ -120,66 +148,120 @@ public function dataGetCompleteTextString() { return [ 'single-line-constant-encapsed-string' => [ - '/* testSingleLineConstantEncapsedString */', - 'single line text string', - "'single line text string'", + 'testMarker' => '/* testSingleLineConstantEncapsedString */', + 'expected' => 'single line text string', + 'expectedWithQuotes' => "'single line text string'", ], 'multi-line-constant-encapsed-string' => [ - '/* testMultiLineConstantEncapsedString */', - 'first line + 'testMarker' => '/* testMultiLineConstantEncapsedString */', + 'expected' => 'first line second line third line fourth line', - '"first line + 'expectedWithQuotes' => '"first line second line third line fourth line"', ], 'single-line-double-quoted-string' => [ - '/* testSingleLineDoubleQuotedString */', - 'single $line text string', - '"single $line text string"', + 'testMarker' => '/* testSingleLineDoubleQuotedString */', + 'expected' => 'single $line text string', + 'expectedWithQuotes' => '"single $line text string"', ], 'multi-line-double-quoted-string' => [ - '/* testMultiLineDoubleQuotedString */', - 'first line + 'testMarker' => '/* testMultiLineDoubleQuotedString */', + 'expected' => 'first line second $line third line fourth line', - '"first line + 'expectedWithQuotes' => '"first line second $line third line fourth line"', ], 'heredoc' => [ - '/* testHeredocString */', - 'first line + 'testMarker' => '/* testHeredocString */', + 'expected' => 'first line second $line third line fourth line', - 'first line + 'expectedWithQuotes' => 'first line second $line third line fourth line', ], 'nowdoc' => [ - '/* testNowdocString */', - 'first line + 'testMarker' => '/* testNowdocString */', + 'expected' => 'first line second line third line fourth line', - 'first line + 'expectedWithQuotes' => 'first line second line third line fourth line', ], + + 'Single line double quoted string containing problem embeds' => [ + 'testMarker' => '/* testMultipleProblemEmbedsInSingleLineDoubleQuotedString */', + 'expected' => + 'My ${foo["${bar}"]} and ${foo["${bar[\'baz\']}"]} and also ${foo->{"${\'a\'}"}}', + 'expectedWithQuotes' => + '"My ${foo["${bar}"]} and ${foo["${bar[\'baz\']}"]} and also ${foo->{"${\'a\'}"}}"', + ], + 'Multi-line double quoted string containing problem embeds' => [ + 'testMarker' => '/* testProblemEmbedAtEndOfLineInMultiLineDoubleQuotedString */', + 'expected' => 'Testing ${foo["${bar[\'baz\']}"]} +and more ${foo["${bar}"]} testing', + 'expectedWithQuotes' => '"Testing ${foo["${bar[\'baz\']}"]} +and more ${foo["${bar}"]} testing"', + ], + 'Multi-line double quoted string containing multi-line problem embed' => [ + 'testMarker' => '/* testMultilineProblemEmbedInMultiLineDoubleQuotedString */', + 'expected' => 'Testing ${foo["${bar + [\'baz\'] +}"]} and more testing', + 'expectedWithQuotes' => '"Testing ${foo["${bar + [\'baz\'] +}"]} and more testing"', + ], + 'text-string-at-end-of-file' => [ - '/* testTextStringAtEndOfFile */', - 'first line + 'testMarker' => '/* testTextStringAtEndOfFile */', + 'expected' => 'first line last line', - "'first line + 'expectedWithQuotes' => "'first line last line'", ], ]; } + + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testResultIsCached() + { + $methodName = 'PHPCSUtils\\Utils\\TextStrings::getEndOfCompleteTextString'; + $stackPtr = $this->getTargetToken('/* testMultiLineDoubleQuotedString */', $this->targets); + $expected = $stackPtr + 3; + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = TextStrings::getEndOfCompleteTextString(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, $stackPtr); + $resultSecondRun = TextStrings::getEndOfCompleteTextString(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } } diff --git a/Tests/Utils/TextStrings/GetEndOfCompleteTextStringTest.inc b/Tests/Utils/TextStrings/GetEndOfCompleteTextStringTest.inc new file mode 100644 index 00000000..b9890ed8 --- /dev/null +++ b/Tests/Utils/TextStrings/GetEndOfCompleteTextStringTest.inc @@ -0,0 +1,68 @@ +bar"; +/* testProperty2 */ +"{$foo->bar}"; + +/* testMethod1 */ +"{$foo->bar()}"; + +/* testClosure1 */ +"{$foo()}"; + +/* testChain1 */ +"{$foo['bar']->baz()()}"; + +/* testVariableVar1 */ +"${$bar}"; +/* testVariableVar2 */ +"${(foo)}"; +/* testVariableVar3 */ +"${foo->bar}"; + +/* testNested1 */ +"${foo["${bar}"]}"; +/* testNested2 */ +"${foo["${bar['baz']}"]}"; +/* testNested3 */ +"${foo->{$baz}}"; +/* testNested4 */ +"${foo->{${'a'}}}"; +/* testNested5 */ +"${foo->{"${'a'}"}}"; + +/* testNestedWithCurliesWithinPlainTokens */ +"${foo["${bar['b{a}z']}"]}"; + +/* testMultipleProblemEmbedsInSingleLineString */ +"My ${foo["${bar}"]} and ${foo["${bar['baz']}"]} and ${foo->{"${'a'}"}}"; + +/* testProblemEmbedAtEndOfLineInMultiLineString */ +"Testing ${foo["${bar['baz']}"]} +and more testing"; + +/* testMultilineProblemEmbedInMultiLineString */ +"Testing ${foo["${bar + ['baz'] +}"]} and more testing"; + +/* testParseError */ +"${foo["${bar diff --git a/Tests/Utils/TextStrings/GetEndOfCompleteTextStringTest.php b/Tests/Utils/TextStrings/GetEndOfCompleteTextStringTest.php new file mode 100644 index 00000000..f16d3053 --- /dev/null +++ b/Tests/Utils/TextStrings/GetEndOfCompleteTextStringTest.php @@ -0,0 +1,164 @@ +getTargetToken($testMarker, \T_DOUBLE_QUOTED_STRING); + $result = TextStrings::getEndOfCompleteTextString(self::$phpcsFile, $stackPtr); + + $this->assertSame($expectedContent, GetTokensAsString::normal(self::$phpcsFile, $stackPtr, $result)); + } + + /** + * Data provider. + * + * @see testGetEndOfDoubleQuotedString() For the array format. + * + * @return array + */ + public function dataGetEndOfDoubleQuotedString() + { + return [ + 'Simple embedded variable 1' => [ + 'testMarker' => '/* testSimple1 */', + 'expectedContent' => '"$foo"', + ], + 'Simple embedded variable 2' => [ + 'testMarker' => '/* testSimple2 */', + 'expectedContent' => '"{$foo}"', + ], + 'Simple embedded variable 3' => [ + 'testMarker' => '/* testSimple3 */', + 'expectedContent' => '"${foo}"', + ], + 'Embedded array access 1' => [ + 'testMarker' => '/* testDIM1 */', + 'expectedContent' => '"$foo[bar]"', + ], + 'Embedded array access 2' => [ + 'testMarker' => '/* testDIM2 */', + 'expectedContent' => '"{$foo[\'bar\']}"', + ], + 'Embedded array access 3' => [ + 'testMarker' => '/* testDIM3 */', + 'expectedContent' => '"${foo[\'bar\']}"', + ], + 'Embedded property access 1' => [ + 'testMarker' => '/* testProperty1 */', + 'expectedContent' => '"$foo->bar"', + ], + 'Embedded property access 2' => [ + 'testMarker' => '/* testProperty2 */', + 'expectedContent' => '"{$foo->bar}"', + ], + 'Embedded method call 1' => [ + 'testMarker' => '/* testMethod1 */', + 'expectedContent' => '"{$foo->bar()}"', + ], + 'Embedded closure call 1' => [ + 'testMarker' => '/* testClosure1 */', + 'expectedContent' => '"{$foo()}"', + ], + 'Embedded chained array access -> method call -> call' => [ + 'testMarker' => '/* testChain1 */', + 'expectedContent' => '"{$foo[\'bar\']->baz()()}"', + ], + 'Embedded variable variable 1' => [ + 'testMarker' => '/* testVariableVar1 */', + 'expectedContent' => '"${$bar}"', + ], + 'Embedded variable variable 2' => [ + 'testMarker' => '/* testVariableVar2 */', + 'expectedContent' => '"${(foo)}"', + ], + 'Embedded variable variable 3' => [ + 'testMarker' => '/* testVariableVar3 */', + 'expectedContent' => '"${foo->bar}"', + ], + 'Embedded nested variable variable 1' => [ + 'testMarker' => '/* testNested1 */', + 'expectedContent' => '"${foo["${bar}"]}"', + ], + 'Embedded nested variable variable 2' => [ + 'testMarker' => '/* testNested2 */', + 'expectedContent' => '"${foo["${bar[\'baz\']}"]}"', + ], + 'Embedded nested variable variable 3' => [ + 'testMarker' => '/* testNested3 */', + 'expectedContent' => '"${foo->{$baz}}"', + ], + 'Embedded nested variable variable 4' => [ + 'testMarker' => '/* testNested4 */', + 'expectedContent' => '"${foo->{${\'a\'}}}"', + ], + 'Embedded nested variable variable 5' => [ + 'testMarker' => '/* testNested5 */', + 'expectedContent' => '"${foo->{"${\'a\'}"}}"', + ], + 'Embedded nested variable variable 2 with curlies within plain token' => [ + 'testMarker' => '/* testNestedWithCurliesWithinPlainTokens */', + 'expectedContent' => '"${foo["${bar[\'b{a}z\']}"]}"', + ], + 'Multiple problem embeds in single line text string' => [ + 'testMarker' => '/* testMultipleProblemEmbedsInSingleLineString */', + 'expectedContent' => '"My ${foo["${bar}"]} and ${foo["${bar[\'baz\']}"]} and ${foo->{"${\'a\'}"}}"', + ], + 'Problem embed at end of line in multi-line text string' => [ + 'testMarker' => '/* testProblemEmbedAtEndOfLineInMultiLineString */', + 'expectedContent' => '"Testing ${foo["${bar[\'baz\']}"]} +and more testing"', + ], + 'Multi-line problem embed in multi-line text string' => [ + 'testMarker' => '/* testMultilineProblemEmbedInMultiLineString */', + 'expectedContent' => '"Testing ${foo["${bar + [\'baz\'] +}"]} and more testing"', + ], + + 'Parse error at end of file' => [ + 'testMarker' => '/* testParseError */', + 'expectedContent' => '"${foo["${bar +', + ], + ]; + } +} diff --git a/Tests/Utils/TextStrings/InterpolatedVariablesTest.php b/Tests/Utils/TextStrings/InterpolatedVariablesTest.php new file mode 100644 index 00000000..5e590f62 --- /dev/null +++ b/Tests/Utils/TextStrings/InterpolatedVariablesTest.php @@ -0,0 +1,617 @@ + + */ + private $embeds = [ + // Simple. + '$foo', + '{$foo}', + '${foo}', + + // DIM. + '$foo[2]', + '$foo[-12]', + '{$foo[0]}', + '${foo[132]}', + '$foo[bar]', + '{$foo[\'bar\']}', + '${foo[\'bar\']}', + '{$foo[8][35]}', + '{$foo[10][\'bar\']}', + '{$foo[\'bar\'][\'baz\']}', + '{$foo[\'bar\'][12]}', + + // Property. + '$foo->bar', + '{$foo->bar}', + '$foo?->bar', + '{$foo?->bar}', + '{${beers::$ale}}', + '${beers::$ale}', + + // Class constant. + '{${beers::softdrink}}', + '${beers::softdrink}', + + // Method. + '{$foo->bar()}', + '{$foo?->bar()}', + '{${$object->getName()}}', + '{${$object?->getName()}}', + + // Closure/Function call. + '{$foo()}', + '{${getName()}}', + '{${getName( $test )}}', + '{${getName( \'abc\' )}}', + '${substr(\'laruence\', 0, 2)}', + + // Chain. + '{$foo[42]->baz()()}', + '{$foo[\'bar\']->baz()()}', + '{$foo[42]?->baz()()}', + '{$foo[\'bar\']?->baz()()}', + '{$obj->values[3]->name}', + '{$obj->values[5]?->name}', + + // Variable variables. + '${$bar}', + '{$$bar}', + '${(foo)}', + '${foo->bar}', + '{$foo->$bar}', + '{$foo?->$bar}', + + // Nested. + '${foo["${bar}"]}', + '${foo["${ba23}"]}', + '${foo["${bar[3]}"]}', + '${foo["${bar[\'baz\']}"]}', + '${foo->{$baz}}', + '${foo->{${\'a\'}}}', + '${foo->{"${\'a\'}"}}', + '${foo?->{$baz}}', + '${foo?->{${\'a\'}}}', + '${foo?->{"${\'a\'}"}}', + '{$foo->{$baz[1]}}', + + // Using non-ascii UTF8 variable names. + '$IÑTËRNÂTÎÔNÀLÍŽÆTIØN', + '${IÑTËRNÂTÎÔNÀLÍŽÆTIØN}', + '$Iñtërnâtîônàlížætiøn[nât]', + '$Iñtërnâtîônàlížætiøn?->îôn', + '$МояРабота', + '${$МояРабота}', + '$💟', + '$💟[◾]', + '$😝->🤞', + ]; + + /** + * Collections of phrases to use during the test. + * + * Phrases used will be selected at random. + * + * @var array + */ + private $phrases = [ + 'single line' => "%s this is nonsense %s\tbut that's not the point %s", + 'single line, embed followed by non-space 1' => '%s- dash %s+ plus %s', + 'single line, embed followed by non-space 2' => '%s. dash %s= plus %s', + 'single line, embed followed by non-space 3' => '%s` dash %s%% plus %s', + 'single line, embed followed by non-space 4' => '%s\\ dash %s) plus %s', + 'single line, embed followed by non-space 5' => '%s] dash %s} plus %s', + 'single line, embed followed by non-space 6' => '%s\' dash %s# plus %s', + 'single line, contains escaped non-embed 1' => '%s this {\$name} foo %s but that\'s \$mane[not] the point %s', + 'single line, contains escaped non-embed 2' => '%s this $\{name} foo %s but that\'s \$mane->not the point %s', + 'multi line' => "%s this is\nnonsense %s but\nthat's not the point %s", + 'multi line, empty first line' => "\n%s this is\nnonsense %s but\nthat's not the point %s", + 'multi line, empty last line' => "%s this is\nnonsense %s but\nthat's not the point %s\n", + ]; + + /** + * Test getting embedded variables and expressions from an arbitrary text string. + * + * @dataProvider dataEmbedsInPhrases + * + * @param string $input The input string. + * @param array $expected The expected function output of the respective functions. + * + * @return void + */ + public function testGetEmbeds($input, $expected) + { + $this->assertSame($expected['get'], \array_values(TextStrings::getEmbeds($input))); + } + + /** + * Test getting embedded variables and expressions from an arbitrary text string and verify the offset + * at which the embed was found is correctly set as well. + * + * @dataProvider dataEscaping + * @dataProvider dataSpecificCases + * + * @param string $input The input string. + * @param array $expected The expected function output of the respective functions. + * + * @return void + */ + public function testGetEmbedsAndCheckOffset($input, $expected) + { + $this->assertSame($expected['get'], TextStrings::getEmbeds($input)); + } + + /** + * Test stripping embedded variables and expressions from an arbitrary text string. + * + * @dataProvider dataEmbedsInPhrases + * @dataProvider dataEscaping + * @dataProvider dataSpecificCases + * + * @param string $input The input string. + * @param array $expected The expected function output of the respective functions. + * + * @return void + */ + public function testStripEmbeds($input, $expected) + { + $this->assertSame($expected['stripped'], TextStrings::stripEmbeds($input)); + } + + /** + * Data provider. + * + * @see testGetEmbeds() For the array format. + * @see testStripEmbeds() For the array format. + * + * @return array + */ + public function dataEmbedsInPhrases() + { + $data = []; + foreach ($this->embeds as $embed) { + $data[$embed . '| Plain embed (heredoc)'] = [ + 'input' => $embed, + 'expected' => [ + 'get' => [$embed], + 'stripped' => '', + ], + ]; + $data[$embed . '| Double quoted embed'] = [ + 'input' => '"' . $embed . '"', + 'expected' => [ + 'get' => [$embed], + 'stripped' => '""', + ], + ]; + + // Plain, no double quotes (heredoc). + $phraseKey = \array_rand($this->phrases); + $dataKey = $embed . '| Embed at start of plain phrase in: ' . $phraseKey; + $data[$dataKey] = [ + 'input' => \sprintf($this->phrases[$phraseKey], $embed, '', ''), + 'expected' => [ + 'get' => [$embed], + 'stripped' => \sprintf($this->phrases[$phraseKey], '', '', ''), + ], + ]; + + $phraseKey = \array_rand($this->phrases); + $dataKey = $embed . '| Embed in middle of plain phrase in: ' . $phraseKey; + $data[$dataKey] = [ + 'input' => \sprintf($this->phrases[$phraseKey], '', $embed, ''), + 'expected' => [ + 'get' => [$embed], + 'stripped' => \sprintf($this->phrases[$phraseKey], '', '', ''), + ], + ]; + + $phraseKey = \array_rand($this->phrases); + $dataKey = $embed . '| Embed at end of plain phrase in: ' . $phraseKey; + $data[$dataKey] = [ + 'input' => \sprintf($this->phrases[$phraseKey], '', '', $embed), + 'expected' => [ + 'get' => [$embed], + 'stripped' => \sprintf($this->phrases[$phraseKey], '', '', ''), + ], + ]; + + // Phrase in double quotes. + $phraseKey = \array_rand($this->phrases); + $dataKey = $embed . '| Embed at start of quoted phrase in: ' . $phraseKey; + $data[$dataKey] = [ + 'input' => '"' . \sprintf($this->phrases[$phraseKey], $embed, '', '') . '"', + 'expected' => [ + 'get' => [$embed], + 'stripped' => '"' . \sprintf($this->phrases[$phraseKey], '', '', '') . '"', + ], + ]; + + $phraseKey = \array_rand($this->phrases); + $dataKey = $embed . '| Embed in middle of quoted phrase in: ' . $phraseKey; + $data[$dataKey] = [ + 'input' => '"' . \sprintf($this->phrases[$phraseKey], '', $embed, '') . '"', + 'expected' => [ + 'get' => [$embed], + 'stripped' => '"' . \sprintf($this->phrases[$phraseKey], '', '', '') . '"', + ], + ]; + + $phraseKey = \array_rand($this->phrases); + $dataKey = $embed . '| Embed at end of quoted phrase in: ' . $phraseKey; + $data[$dataKey] = [ + 'input' => '"' . \sprintf($this->phrases[$phraseKey], '', '', $embed) . '"', + 'expected' => [ + 'get' => [$embed], + 'stripped' => '"' . \sprintf($this->phrases[$phraseKey], '', '', '') . '"', + ], + ]; + } + + return $data; + } + + /** + * Data provider. + * + * @see testGetEmbedsAndCheckOffset() For the array format. + * @see testStripEmbeds() For the array format. + * + * @return array + */ + public function dataEscaping() + { + $embedAtEnd = '"Foo: %s%s"'; + $embedAtStart = '%s%s Foo'; // Not, no double quotes! + $data = []; + + for ($i = 0; $i < 10; $i++) { + $escaped = (($i % 2) !== 0); + $slashes = \str_repeat('\\', $i); + $offset = 6 + $i; + + $dataKey = "Escaping handling test, embed at start: slashes before \$ - $i slashes = "; + $dataKey .= ($escaped === true) ? 'escaped' : 'not escaped'; + $data[$dataKey] = [ + 'input' => \sprintf($embedAtStart, $slashes, '$foo'), + 'expected' => [ + 'get' => ($escaped === true) ? [] : [$i => '$foo'], + 'stripped' => ($escaped === true) + ? \sprintf($embedAtStart, $slashes, '$foo') + : \sprintf($embedAtStart, $slashes, ''), + ], + ]; + + $dataKey = "Escaping handling test, embed at start: slashes before { - $i slashes = "; + $dataKey .= ($escaped === true) ? 'escaped' : 'not escaped'; + $data[$dataKey] = [ + 'input' => \sprintf($embedAtStart, $slashes, '{$foo}'), + 'expected' => [ + 'get' => ($escaped === true) ? [($i + 1) => '$foo'] : [$i => '{$foo}'], + 'stripped' => ($escaped === true) + ? \sprintf($embedAtStart, $slashes, '{}') + : \sprintf($embedAtStart, $slashes, ''), + ], + ]; + + $dataKey = "Escaping handling test, embed at end: slashes before \$ - $i slashes = "; + $dataKey .= ($escaped === true) ? 'escaped' : 'not escaped'; + $data[$dataKey] = [ + 'input' => \sprintf($embedAtEnd, $slashes, '$foo'), + 'expected' => [ + 'get' => ($escaped === true) ? [] : [$offset => '$foo'], + 'stripped' => ($escaped === true) + ? \sprintf($embedAtEnd, $slashes, '$foo') + : \sprintf($embedAtEnd, $slashes, ''), + ], + ]; + + $dataKey = "Escaping handling test, embed at end: slashes before { - $i slashes = "; + $dataKey .= ($escaped === true) ? 'escaped' : 'not escaped'; + $data[$dataKey] = [ + 'input' => \sprintf($embedAtEnd, $slashes, '{$foo}'), + 'expected' => [ + 'get' => ($escaped === true) ? [($offset + 1) => '$foo'] : [$offset => '{$foo}'], + 'stripped' => ($escaped === true) + ? \sprintf($embedAtEnd, $slashes, '{}') + : \sprintf($embedAtEnd, $slashes, ''), + ], + ]; + } + + return $data; + } + + /** + * Data provider. + * + * @see testGetEmbedsAndCheckOffset() For the array format. + * @see testStripEmbeds() For the array format. + * + * @return array + */ + public function dataSpecificCases() + { + return [ + // No embeds. + 'Text string without any embeds' => [ + 'input' => '"He drank some orange juice."', + 'expected' => [ + 'get' => [], + 'stripped' => '"He drank some orange juice."', + ], + ], + 'Text string without any valid embeds - not a valid variable name 1' => [ + 'input' => '"He drank some orange $--."', + 'expected' => [ + 'get' => [], + 'stripped' => '"He drank some orange $--."', + ], + ], + 'Text string without any valid embeds - not a valid variable name 2' => [ + 'input' => '"He drank some orange $\name."', + 'expected' => [ + 'get' => [], + 'stripped' => '"He drank some orange $\name."', + ], + ], + + // Variations on embeds not tested via the above generated test cases. + 'No braces, one character variable name' => [ + 'input' => '"This is $g"', + 'expected' => [ + 'get' => [ + 9 => '$g', + ], + 'stripped' => '"This is "', + ], + ], + 'Wrappped in outer braces with space between brace and dollar' => [ + 'input' => '"This is { $great}"', + 'expected' => [ + 'get' => [ + 11 => '$great', + ], + 'stripped' => '"This is { }"', + ], + ], + + 'Text string containing multiple embeds 1' => [ + 'input' => '"$people->john drank some $juices[0] juice."', + 'expected' => [ + 'get' => [ + 1 => '$people->john', + 26 => '$juices[0]', + ], + 'stripped' => '" drank some juice."', + ], + ], + 'Text string containing multiple embeds 2' => [ + 'input' => '"$people->john then said hello to $people->jane."', + 'expected' => [ + 'get' => [ + 1 => '$people->john', + 34 => '$people->jane', + ], + 'stripped' => '" then said hello to ."', + ], + ], + 'Text string containing multiple embeds 3' => [ + 'input' => '"$people->john\'s wife greeted $people->robert."', + 'expected' => [ + 'get' => [ + 1 => '$people->john', + // Note: the backslash escaping the ' will be removed, so doesn't count for offset. + 30 => '$people->robert', + ], + 'stripped' => '"\'s wife greeted ."', + ], + ], + 'Text string containing multiple embeds 4' => [ + 'input' => '"This is the value of the var named $name: {${$name}}"', + 'expected' => [ + 'get' => [ + 36 => '$name', + 43 => '{${$name}}', + ], + 'stripped' => '"This is the value of the var named : "', + ], + ], + 'Text string containing multiple embeds 5 (nothing between embeds, plain)' => [ + 'input' => '"This is the value of the var named $name$name"', + 'expected' => [ + 'get' => [ + 36 => '$name', + 41 => '$name', + ], + 'stripped' => '"This is the value of the var named "', + ], + ], + 'Text string containing multiple embeds 6 (nothing between embeds, outer braces)' => [ + 'input' => '"This is the value of the var named {$name}{$name}"', + 'expected' => [ + 'get' => [ + 36 => '{$name}', + 43 => '{$name}', + ], + 'stripped' => '"This is the value of the var named "', + ], + ], + 'Text string containing multiple embeds 7 (nothing between embeds, inner braces)' => [ + 'input' => '"This is the value of the var named ${name}${name}"', + 'expected' => [ + 'get' => [ + 36 => '${name}', + 43 => '${name}', + ], + 'stripped' => '"This is the value of the var named "', + ], + ], + 'Text string containing multiple embeds 8 (nothing between embeds, mixed)' => [ + 'input' => '"This is the value of the var named $name${name}{$name}"', + 'expected' => [ + 'get' => [ + 36 => '$name', + 41 => '${name}', + 48 => '{$name}', + ], + 'stripped' => '"This is the value of the var named "', + ], + ], + + // These can't be tested via the generated code as it won't work without braces. + 'Embed without braces, variable variable will not work' => [ + 'input' => '"$$bar"', + 'expected' => [ + 'get' => [ + 2 => '$bar', + ], + 'stripped' => '"$"', + ], + ], + 'Embed in outer braces followed by number' => [ + 'input' => '"This square is {$square->width}00 centimeters broad."', + 'expected' => [ + 'get' => [ + 16 => '{$square->width}', + ], + 'stripped' => '"This square is 00 centimeters broad."', + ], + ], + 'Embed in inner braces followed by number' => [ + 'input' => '"This square is ${square->width}00 centimeters broad."', + 'expected' => [ + 'get' => [ + 16 => '${square->width}', + ], + 'stripped' => '"This square is 00 centimeters broad."', + ], + ], + 'Without braces, multi-level array access does not work' => [ + 'input' => '"This works: {$arr[4][3]}, but this doesn\'t: $arr[3][4]"', + 'expected' => [ + 'get' => [ + 13 => '{$arr[4][3]}', + // Note: the backslash escaping the ' will be removed, so doesn't count for offset. + 45 => '$arr[3]', + ], + 'stripped' => '"This works: , but this doesn\'t: [4]"', + ], + ], + 'Without braces, multi-level property access does not work' => [ + 'input' => '"This works: {$obj->prop->key}, but this doesn\'t: $obj->prop->key"', + 'expected' => [ + 'get' => [ + 13 => '{$obj->prop->key}', + // Note: the backslash escaping the ' will be removed, so doesn't count for offset. + 50 => '$obj->prop', + ], + 'stripped' => '"This works: , but this doesn\'t: ->key"', + ], + ], + 'Embed in braces, multi-level array access, string key missing quotes' => [ + 'input' => '"This interprets the key foo as a constant: {$arr[foo][3]}"', + 'expected' => [ + 'get' => [ + 44 => '{$arr[foo][3]}', + ], + 'stripped' => '"This interprets the key foo as a constant: "', + ], + ], + + // Multi-line expressions. + 'Embed in dollar brace, multi-line expression' => [ + 'input' => '"Testing ${foo["${bar + [\'baz\'] +}"]} and more testing"', + 'expected' => [ + 'get' => [ + 9 => '${foo["${bar + [\'baz\'] +}"]}', + ], + 'stripped' => '"Testing and more testing"', + ], + ], + 'Embed in braces, multi-line expression' => [ + 'input' => '"Testing {${foo["${bar + [\'baz\'] +}"]}} and more testing"', + 'expected' => [ + 'get' => [ + 9 => '{${foo["${bar + [\'baz\'] +}"]}}', + ], + 'stripped' => '"Testing and more testing"', + ], + ], + ]; + } + + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testResultIsCached() + { + $methodName = 'PHPCSUtils\\Utils\\TextStrings::getStripEmbeds'; + $input = '"This is the $value of {$name}"'; + $expected = [ + 'embeds' => [ + 13 => '$value', + 23 => '{$name}', + ], + 'remaining' => '"This is the of "', + ]; + + // Verify the caching works. + $origStatus = NoFileCache::$enabled; + NoFileCache::$enabled = true; + + $resultFirstRun = TextStrings::getStripEmbeds($input); + $isCached = NoFileCache::isCached($methodName, \md5($input)); + $resultSecondRun = TextStrings::getStripEmbeds($input); + + if ($origStatus === false) { + NoFileCache::clear(); + } + NoFileCache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'NoFileCache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } +} diff --git a/Tests/Utils/TextStrings/StripQuotesTest.php b/Tests/Utils/TextStrings/StripQuotesTest.php index 51c34d28..56faac11 100644 --- a/Tests/Utils/TextStrings/StripQuotesTest.php +++ b/Tests/Utils/TextStrings/StripQuotesTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class StripQuotesTest extends TestCase +final class StripQuotesTest extends TestCase { /** @@ -51,43 +51,43 @@ public function dataStripQuotes() { return [ 'simple-string-double-quotes' => [ - '"dir_name"', - 'dir_name', + 'input' => '"dir_name"', + 'expected' => 'dir_name', ], 'simple-string-single-quotes' => [ - "'soap.wsdl_cache'", - 'soap.wsdl_cache', + 'input' => "'soap.wsdl_cache'", + 'expected' => 'soap.wsdl_cache', ], 'string-with-escaped-quotes-within-1' => [ - '"arbitrary-\'string\" with\' quotes within"', - 'arbitrary-\'string\" with\' quotes within', + 'input' => '"arbitrary-\'string\" with\' quotes within"', + 'expected' => 'arbitrary-\'string\" with\' quotes within', ], 'string-with-escaped-quotes-within-2' => [ - '"\'quoted_name\'"', - '\'quoted_name\'', + 'input' => '"\'quoted_name\'"', + 'expected' => '\'quoted_name\'', ], 'string-with-different-quotes-at-start-of-string' => [ - "'\"quoted\" start of string'", - '"quoted" start of string', + 'input' => "'\"quoted\" start of string'", + 'expected' => '"quoted" start of string', ], 'incomplete-quote-set-only-start-quote' => [ - "'no stripping when there is only a start quote", - "'no stripping when there is only a start quote", + 'input' => "'no stripping when there is only a start quote", + 'expected' => "'no stripping when there is only a start quote", ], 'incomplete-quote-set-only-end-quote' => [ - 'no stripping when there is only an end quote"', - 'no stripping when there is only an end quote"', + 'input' => 'no stripping when there is only an end quote"', + 'expected' => 'no stripping when there is only an end quote"', ], 'start-end-quote-mismatch' => [ - "'no stripping when quotes at start/end are mismatched\"", - "'no stripping when quotes at start/end are mismatched\"", + 'input' => "'no stripping when quotes at start/end are mismatched\"", + 'expected' => "'no stripping when quotes at start/end are mismatched\"", ], 'multi-line-string-single-quotes' => [ - "'some + 'input' => "'some text and more'", - 'some + 'expected' => 'some text and more', diff --git a/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.php b/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.php index 35c94af1..b550bce2 100644 --- a/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.php +++ b/Tests/Utils/UseStatements/SplitAndMergeImportUseStatementTest.php @@ -14,15 +14,17 @@ use PHPCSUtils\Utils\UseStatements; /** - * Tests for the \PHPCSUtils\Utils\UseStatements::splitAndMergeImportUseStatement() method. + * Tests for the \PHPCSUtils\Utils\UseStatements::splitAndMergeImportUseStatement() + * and the \PHPCSUtils\Utils\UseStatements::mergeImportUseStatements() method. * * @covers \PHPCSUtils\Utils\UseStatements::splitAndMergeImportUseStatement + * @covers \PHPCSUtils\Utils\UseStatements::mergeImportUseStatements * * @group usestatements * * @since 1.0.0 */ -class SplitAndMergeImportUseStatementTest extends UtilityMethodTestCase +final class SplitAndMergeImportUseStatementTest extends UtilityMethodTestCase { /** @@ -54,32 +56,32 @@ public function dataSplitAndMergeImportUseStatement() { $data = [ 'name-plain' => [ - '/* testUseNamePlainAliased */', - [ + 'testMarker' => '/* testUseNamePlainAliased */', + 'expected' => [ 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], 'function' => [], 'const' => [], ], ], 'function-plain' => [ - '/* testUseFunctionPlain */', - [ + 'testMarker' => '/* testUseFunctionPlain */', + 'expected' => [ 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], 'function' => ['myFunction' => 'MyNamespace\myFunction'], 'const' => [], ], ], 'const-plain' => [ - '/* testUseConstPlain */', - [ + 'testMarker' => '/* testUseConstPlain */', + 'expected' => [ 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], 'function' => ['myFunction' => 'MyNamespace\myFunction'], 'const' => ['MY_CONST' => 'MyNamespace\MY_CONST'], ], ], 'group-mixed' => [ - '/* testGroupUseMixed */', - [ + 'testMarker' => '/* testGroupUseMixed */', + 'expected' => [ 'name' => [ 'ClassAlias' => 'MyNamespace\YourClass', 'ClassName' => 'Some\NS\ClassName', @@ -97,9 +99,9 @@ public function dataSplitAndMergeImportUseStatement() ], ], 'trait-use' => [ - '/* testTraitUse */', + 'testMarker' => '/* testTraitUse */', // Same as previous. - [ + 'expected' => [ 'name' => [ 'ClassAlias' => 'MyNamespace\YourClass', 'ClassName' => 'Some\NS\ClassName', @@ -120,8 +122,8 @@ public function dataSplitAndMergeImportUseStatement() $previousUse = []; foreach ($data as $key => $value) { - $data[$key][] = $previousUse; - $previousUse = $value[1]; + $data[$key]['previousUse'] = $previousUse; + $previousUse = $value['expected']; } return $data; diff --git a/Tests/Utils/UseStatements/SplitImportUseStatementTest.inc b/Tests/Utils/UseStatements/SplitImportUseStatementTest.inc index 29e01e6a..e9daecf2 100644 --- a/Tests/Utils/UseStatements/SplitImportUseStatementTest.inc +++ b/Tests/Utils/UseStatements/SplitImportUseStatementTest.inc @@ -29,7 +29,7 @@ use function MyNamespace\myFunction ?> use function Vendor\YourNamespace\yourFunction as FunctionAlias; /* testUseFunctionMultiple */ -use /* comment */ function foo\math\sin, foo\math\cos as FooCos, foo\math\cosh; +use /* comment */ function foo\math\sin,foo\math\cos as FooCos,foo\math\cosh; /* testUseConstPlainUppercaseConstKeyword */ use CONST MyNamespace\MY_CONST; @@ -69,6 +69,10 @@ use Some\NS\ { AnotherLevel, }; +/* testUsePlainReservedKeyword */ +// Intentional parse error - use of reserved keyword in namespace. +use Vendor\break\ClassName; + /* testUseFunctionPlainReservedKeyword */ // Intentional parse error - use of reserved keyword in namespace. use function Vendor\YourNamespace\switch\yourFunction; diff --git a/Tests/Utils/UseStatements/SplitImportUseStatementTest.php b/Tests/Utils/UseStatements/SplitImportUseStatementTest.php index 28f7edf6..bbc99642 100644 --- a/Tests/Utils/UseStatements/SplitImportUseStatementTest.php +++ b/Tests/Utils/UseStatements/SplitImportUseStatementTest.php @@ -10,6 +10,7 @@ namespace PHPCSUtils\Tests\Utils\UseStatements; +use PHPCSUtils\Internal\Cache; use PHPCSUtils\TestUtils\UtilityMethodTestCase; use PHPCSUtils\Utils\UseStatements; @@ -22,7 +23,7 @@ * * @since 1.0.0 */ -class SplitImportUseStatementTest extends UtilityMethodTestCase +final class SplitImportUseStatementTest extends UtilityMethodTestCase { /** @@ -110,24 +111,24 @@ public function dataSplitImportUseStatement() { return [ 'plain' => [ - '/* testUsePlain */', - [ + 'testMarker' => '/* testUsePlain */', + 'expected' => [ 'name' => ['MyClass' => 'MyNamespace\MyClass'], 'function' => [], 'const' => [], ], ], 'plain-aliased' => [ - '/* testUsePlainAliased */', - [ + 'testMarker' => '/* testUsePlainAliased */', + 'expected' => [ 'name' => ['ClassAlias' => 'MyNamespace\YourClass'], 'function' => [], 'const' => [], ], ], 'multiple-with-comments' => [ - '/* testUseMultipleWithComments */', - [ + 'testMarker' => '/* testUseMultipleWithComments */', + 'expected' => [ 'name' => [ 'ClassABC' => 'Vendor\Foo\ClassA', 'InterfaceB' => 'Vendor\Bar\InterfaceB', @@ -138,24 +139,24 @@ public function dataSplitImportUseStatement() ], ], 'function-plain-ends-on-close-tag' => [ - '/* testUseFunctionPlainEndsOnCloseTag */', - [ + 'testMarker' => '/* testUseFunctionPlainEndsOnCloseTag */', + 'expected' => [ 'name' => [], 'function' => ['myFunction' => 'MyNamespace\myFunction'], 'const' => [], ], ], 'function-plain-aliased' => [ - '/* testUseFunctionPlainAliased */', - [ + 'testMarker' => '/* testUseFunctionPlainAliased */', + 'expected' => [ 'name' => [], 'function' => ['FunctionAlias' => 'Vendor\YourNamespace\yourFunction'], 'const' => [], ], ], 'function-multiple' => [ - '/* testUseFunctionMultiple */', - [ + 'testMarker' => '/* testUseFunctionMultiple */', + 'expected' => [ 'name' => [], 'function' => [ 'sin' => 'foo\math\sin', @@ -166,24 +167,24 @@ public function dataSplitImportUseStatement() ], ], 'const-plain-uppercase-const-keyword' => [ - '/* testUseConstPlainUppercaseConstKeyword */', - [ + 'testMarker' => '/* testUseConstPlainUppercaseConstKeyword */', + 'expected' => [ 'name' => [], 'function' => [], 'const' => ['MY_CONST' => 'MyNamespace\MY_CONST'], ], ], 'const-plain-aliased' => [ - '/* testUseConstPlainAliased */', - [ + 'testMarker' => '/* testUseConstPlainAliased */', + 'expected' => [ 'name' => [], 'function' => [], 'const' => ['CONST_ALIAS' => 'MyNamespace\YOUR_CONST'], ], ], 'const-multiple' => [ - '/* testUseConstMultiple */', - [ + 'testMarker' => '/* testUseConstMultiple */', + 'expected' => [ 'name' => [], 'function' => [], 'const' => [ @@ -193,8 +194,8 @@ public function dataSplitImportUseStatement() ], ], 'group' => [ - '/* testGroupUse */', - [ + 'testMarker' => '/* testGroupUse */', + 'expected' => [ 'name' => [ 'SomeClassA' => 'some\namespacing\SomeClassA', 'SomeClassB' => 'some\namespacing\deeper\level\SomeClassB', @@ -205,8 +206,8 @@ public function dataSplitImportUseStatement() ], ], 'group-function-trailing-comma' => [ - '/* testGroupUseFunctionTrailingComma */', - [ + 'testMarker' => '/* testGroupUseFunctionTrailingComma */', + 'expected' => [ 'name' => [], 'function' => [ 'Msin' => 'bar\math\Msin', @@ -217,8 +218,8 @@ public function dataSplitImportUseStatement() ], ], 'group-const' => [ - '/* testGroupUseConst */', - [ + 'testMarker' => '/* testGroupUseConst */', + 'expected' => [ 'name' => [], 'function' => [], 'const' => [ @@ -228,8 +229,8 @@ public function dataSplitImportUseStatement() ], ], 'group-mixed' => [ - '/* testGroupUseMixed */', - [ + 'testMarker' => '/* testGroupUseMixed */', + 'expected' => [ 'name' => [ 'ClassName' => 'Some\NS\ClassName', 'AnotherLevel' => 'Some\NS\AnotherLevel', @@ -241,49 +242,58 @@ public function dataSplitImportUseStatement() 'const' => ['SOME_CONSTANT' => 'Some\NS\Constants\CONSTANT_NAME'], ], ], + + 'parse-error-plain-reserved-keyword' => [ + 'testMarker' => '/* testUsePlainReservedKeyword */', + 'expected' => [ + 'name' => ['ClassName' => 'Vendor\break\ClassName'], + 'function' => [], + 'const' => [], + ], + ], 'parse-error-function-plain-reserved-keyword' => [ - '/* testUseFunctionPlainReservedKeyword */', - [ + 'testMarker' => '/* testUseFunctionPlainReservedKeyword */', + 'expected' => [ 'name' => [], 'function' => ['yourFunction' => 'Vendor\YourNamespace\switch\yourFunction'], 'const' => [], ], ], 'parse-error-const-plain-reserved-keyword' => [ - '/* testUseConstPlainReservedKeyword */', - [ + 'testMarker' => '/* testUseConstPlainReservedKeyword */', + 'expected' => [ 'name' => [], 'function' => [], 'const' => ['yourConst' => 'Vendor\YourNamespace\function\yourConst'], ], ], 'parse-error-plain-alias-reserved-keyword' => [ - '/* testUsePlainAliasReservedKeyword */', - [ + 'testMarker' => '/* testUsePlainAliasReservedKeyword */', + 'expected' => [ 'name' => ['class' => 'Vendor\YourNamespace\ClassName'], 'function' => [], 'const' => [], ], ], 'parse-error-plain-alias-reserved-keyword-function' => [ - '/* testUsePlainAliasReservedKeywordFunction */', - [ + 'testMarker' => '/* testUsePlainAliasReservedKeywordFunction */', + 'expected' => [ 'name' => ['function' => 'Vendor\YourNamespace\ClassName'], 'function' => [], 'const' => [], ], ], 'parse-error-plain-alias-reserved-keyword-const' => [ - '/* testUsePlainAliasReservedKeywordConst */', - [ - 'name' => [], + 'testMarker' => '/* testUsePlainAliasReservedKeywordConst */', + 'expected' => [ + 'name' => ['const' => 'Vendor\YourNamespace\ClassName'], 'function' => [], 'const' => [], ], ], 'parse-error' => [ - '/* testParseError */', - [ + 'testMarker' => '/* testParseError */', + 'expected' => [ 'name' => [], 'function' => [], 'const' => [], @@ -291,4 +301,36 @@ public function dataSplitImportUseStatement() ], ]; } + + /** + * Verify that the build-in caching is used when caching is enabled. + * + * @return void + */ + public function testResultIsCached() + { + $methodName = 'PHPCSUtils\\Utils\\UseStatements::splitImportUseStatement'; + $cases = $this->dataSplitImportUseStatement(); + $testMarker = $cases['multiple-with-comments']['testMarker']; + $expected = $cases['multiple-with-comments']['expected']; + + $stackPtr = $this->getTargetToken($testMarker, \T_USE); + + // Verify the caching works. + $origStatus = Cache::$enabled; + Cache::$enabled = true; + + $resultFirstRun = UseStatements::splitImportUseStatement(self::$phpcsFile, $stackPtr); + $isCached = Cache::isCached(self::$phpcsFile, $methodName, $stackPtr); + $resultSecondRun = UseStatements::splitImportUseStatement(self::$phpcsFile, $stackPtr); + + if ($origStatus === false) { + Cache::clear(); + } + Cache::$enabled = $origStatus; + + $this->assertSame($expected, $resultFirstRun, 'First result did not match expectation'); + $this->assertTrue($isCached, 'Cache::isCached() could not find the cached value'); + $this->assertSame($resultFirstRun, $resultSecondRun, 'Second result did not match first'); + } } diff --git a/Tests/Utils/UseStatements/UseTypeTest.inc b/Tests/Utils/UseStatements/UseTypeTest.inc index cd0582ed..883beeb5 100644 --- a/Tests/Utils/UseStatements/UseTypeTest.inc +++ b/Tests/Utils/UseStatements/UseTypeTest.inc @@ -48,6 +48,28 @@ interface InterfaceUsingTrait { use SomeTrait; } +/* + * Test specific issue with PHPCS < 3 where the case/default parse errors below would cause them + * to have a case/default condition, though without a switch. + */ +use FoobarA as Case; +/* testUseImportPHPCS2CaseNoSwitchA */ +use FoobarB as Foo; +/* testUseImportPHPCS2CaseNoSwitchB */ +use FoobarC as Default; +/* testUseImportPHPCS2DefaultNoSwitchA */ +use FoobarD as Bar; + +class PHPCS2ScopeConditionIssue { + use TraitA { oldfunction as case; } + /* testUseImportPHPCS2CaseNoSwitchC */ + use TraitB { oldfunction as Baz; } + /* testUseImportPHPCS2CaseNoSwitchD */ + use TraitC { oldfunction as default; } + /* testUseImportPHPCS2DefaultNoSwitchB */ + use TraitD { oldfunction as Fool; } +} + // Intentional parse error. Live coding. This has to be the last test in the file. /* testLiveCoding */ use \ No newline at end of file diff --git a/Tests/Utils/UseStatements/UseTypeTest.php b/Tests/Utils/UseStatements/UseTypeTest.php index 4faef85f..81faabb9 100644 --- a/Tests/Utils/UseStatements/UseTypeTest.php +++ b/Tests/Utils/UseStatements/UseTypeTest.php @@ -28,7 +28,7 @@ * * @since 1.0.0 */ -class UseTypeTest extends UtilityMethodTestCase +final class UseTypeTest extends UtilityMethodTestCase { /** @@ -122,96 +122,147 @@ public function dataUseType() { return [ 'import-1' => [ - '/* testUseImport1 */', - [ + 'testMarker' => '/* testUseImport1 */', + 'expected' => [ 'closure' => false, 'import' => true, 'trait' => false, ], ], 'import-2' => [ - '/* testUseImport2 */', - [ + 'testMarker' => '/* testUseImport2 */', + 'expected' => [ 'closure' => false, 'import' => true, 'trait' => false, ], ], 'import-3' => [ - '/* testUseImport3 */', - [ + 'testMarker' => '/* testUseImport3 */', + 'expected' => [ 'closure' => false, 'import' => true, 'trait' => false, ], ], 'import-4' => [ - '/* testUseImport4 */', - [ + 'testMarker' => '/* testUseImport4 */', + 'expected' => [ 'closure' => false, 'import' => true, 'trait' => false, ], ], 'closure' => [ - '/* testClosureUse */', - [ + 'testMarker' => '/* testClosureUse */', + 'expected' => [ 'closure' => true, 'import' => false, 'trait' => false, ], ], 'trait' => [ - '/* testUseTrait */', - [ + 'testMarker' => '/* testUseTrait */', + 'expected' => [ 'closure' => false, 'import' => false, 'trait' => true, ], ], 'closure-in-nested-class' => [ - '/* testClosureUseNestedInClass */', - [ + 'testMarker' => '/* testClosureUseNestedInClass */', + 'expected' => [ 'closure' => true, 'import' => false, 'trait' => false, ], ], 'trait-in-nested-anon-class' => [ - '/* testUseTraitInNestedAnonClass */', - [ + 'testMarker' => '/* testUseTraitInNestedAnonClass */', + 'expected' => [ 'closure' => false, 'import' => false, 'trait' => true, ], ], 'trait-in-trait' => [ - '/* testUseTraitInTrait */', - [ + 'testMarker' => '/* testUseTraitInTrait */', + 'expected' => [ 'closure' => false, 'import' => false, 'trait' => true, ], ], 'closure-nested-in-trait' => [ - '/* testClosureUseNestedInTrait */', - [ + 'testMarker' => '/* testClosureUseNestedInTrait */', + 'expected' => [ 'closure' => true, 'import' => false, 'trait' => false, ], ], 'trait-in-interface' => [ - '/* testUseTraitInInterface */', - [ + 'testMarker' => '/* testUseTraitInInterface */', + 'expected' => [ 'closure' => false, 'import' => false, 'trait' => false, ], ], + + // Tests related to a specific issue with scope setting in PHPCS 2.x. + 'parse-error-import-use-case-no-switch-1' => [ + 'testMarker' => '/* testUseImportPHPCS2CaseNoSwitchA */', + 'expected' => [ + 'closure' => false, + 'import' => true, + 'trait' => false, + ], + ], + 'parse-error-import-use-case-no-switch-2' => [ + 'testMarker' => '/* testUseImportPHPCS2CaseNoSwitchB */', + 'expected' => [ + 'closure' => false, + 'import' => true, + 'trait' => false, + ], + ], + 'parse-error-import-use-default-no-switch' => [ + 'testMarker' => '/* testUseImportPHPCS2DefaultNoSwitchA */', + 'expected' => [ + 'closure' => false, + 'import' => true, + 'trait' => false, + ], + ], + 'parse-error-trait-use-case-no-switch-1' => [ + 'testMarker' => '/* testUseImportPHPCS2CaseNoSwitchC */', + 'expected' => [ + 'closure' => false, + 'import' => false, + 'trait' => true, + ], + ], + 'parse-error-trait-use-case-no-switch-2' => [ + 'testMarker' => '/* testUseImportPHPCS2CaseNoSwitchD */', + 'expected' => [ + 'closure' => false, + 'import' => false, + 'trait' => true, + ], + ], + 'parse-error-trait-use-default-no-switch' => [ + 'testMarker' => '/* testUseImportPHPCS2DefaultNoSwitchB */', + 'expected' => [ + 'closure' => false, + 'import' => false, + 'trait' => true, + ], + ], + 'live-coding' => [ - '/* testLiveCoding */', - [ + 'testMarker' => '/* testLiveCoding */', + 'expected' => [ 'closure' => false, 'import' => false, 'trait' => false, diff --git a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc index 4cfc073d..affc1f2e 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc +++ b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.inc @@ -5,3 +5,24 @@ interface Base /* testInterfaceProperty */ protected $anonymous; } + +enum Suit +{ + /* testEnumProperty */ + protected $anonymous; +} + +$anon = class() { + /* testPHP82PseudoTypeTrue */ + public true $pseudoTypeTrue; + + /* testPHP82NullablePseudoTypeTrue */ + static protected ?true $pseudoTypeNullableTrue; + + /* testPHP82PseudoTypeTrueInUnion */ + private int|string|true $pseudoTypeTrueInUnion; + + /* testPHP82PseudoTypeFalseAndTrue */ + // Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. + readonly true|FALSE $pseudoTypeFalseAndTrue; +}; diff --git a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php index 2dfa66bb..544d6707 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php +++ b/Tests/Utils/Variables/GetMemberPropertiesDiffTest.php @@ -25,7 +25,7 @@ * * @since 1.0.0 */ -class GetMemberPropertiesDiffTest extends UtilityMethodTestCase +final class GetMemberPropertiesDiffTest extends UtilityMethodTestCase { /** @@ -41,15 +41,124 @@ public function testNonExistentToken() } /** - * Test receiving an expected exception when an (invalid) interface property is passed. + * Test receiving an expected exception when an (invalid) interface or enum property is passed. + * + * @dataProvider dataNotClassPropertyException + * + * @param string $testMarker Comment which precedes the test case. * * @return void */ - public function testNotClassPropertyException() + public function testNotClassPropertyException($testMarker) { $this->expectPhpcsException('$stackPtr is not a class member var'); - $variable = $this->getTargetToken('/* testInterfaceProperty */', \T_VARIABLE); + $variable = $this->getTargetToken($testMarker, \T_VARIABLE); Variables::getMemberProperties(self::$phpcsFile, $variable); } + + /** + * Data provider. + * + * @see testNotClassPropertyException() + * + * @return array + */ + public function dataNotClassPropertyException() + { + return [ + 'interface property' => ['/* testInterfaceProperty */'], + 'enum property' => ['/* testEnumProperty */'], + ]; + } + + /** + * Test the getMemberProperties() method. + * + * @dataProvider dataGetMemberProperties + * + * @param string $identifier Comment which precedes the test case. + * @param bool $expected Expected function output. + * + * @return void + */ + public function testGetMemberProperties($identifier, $expected) + { + $variable = $this->getTargetToken($identifier, \T_VARIABLE); + $result = Variables::getMemberProperties(self::$phpcsFile, $variable); + + if (isset($expected['type_token']) && $expected['type_token'] !== false) { + $expected['type_token'] += $variable; + } + if (isset($expected['type_end_token']) && $expected['type_end_token'] !== false) { + $expected['type_end_token'] += $variable; + } + + $this->assertSame($expected, $result); + } + + /** + * Data provider. + * + * @see testGetMemberProperties() + * + * @return array + */ + public function dataGetMemberProperties() + { + return [ + 'php8.2-pseudo-type-true' => [ + '/* testPHP82PseudoTypeTrue */', + [ + 'scope' => 'public', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'true', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-true-nullable' => [ + '/* testPHP82NullablePseudoTypeTrue */', + [ + 'scope' => 'protected', + 'scope_specified' => true, + 'is_static' => true, + 'is_readonly' => false, + 'type' => '?true', + 'type_token' => -2, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => true, + ], + ], + 'php8.2-pseudo-type-true-in-union' => [ + '/* testPHP82PseudoTypeTrueInUnion */', + [ + 'scope' => 'private', + 'scope_specified' => true, + 'is_static' => false, + 'is_readonly' => false, + 'type' => 'int|string|true', + 'type_token' => -6, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + 'php8.2-pseudo-type-invalid-true-false-union' => [ + '/* testPHP82PseudoTypeFalseAndTrue */', + [ + 'scope' => 'public', + 'scope_specified' => false, + 'is_static' => false, + 'is_readonly' => true, + 'type' => 'true|FALSE', + 'type_token' => -4, // Offset from the T_VARIABLE token. + 'type_end_token' => -2, // Offset from the T_VARIABLE token. + 'nullable_type' => false, + ], + ], + ]; + } } diff --git a/Tests/Utils/Variables/GetMemberPropertiesTest.php b/Tests/Utils/Variables/GetMemberPropertiesTest.php index d4d4c34e..619f7a2f 100644 --- a/Tests/Utils/Variables/GetMemberPropertiesTest.php +++ b/Tests/Utils/Variables/GetMemberPropertiesTest.php @@ -21,7 +21,7 @@ * * @since 1.0.0 */ -class GetMemberPropertiesTest extends BCFile_GetMemberPropertiesTest +final class GetMemberPropertiesTest extends BCFile_GetMemberPropertiesTest { /** @@ -68,13 +68,12 @@ public function dataGetMemberProperties() $data = parent::dataGetMemberProperties(); /* - * Remove the data set related to the invalid interface property. - * This will now throw an exception instead. + * Remove the data set related to the invalid interface/enum properties. + * These will now throw an exception instead. */ foreach ($data as $key => $value) { - if ($value[0] === '/* testInterfaceProperty */') { + if ($value[0] === '/* testInterfaceProperty */' || $value[0] === '/* testEnumProperty */') { unset($data[$key]); - break; } } diff --git a/Tests/Utils/Variables/IsPHPReservedVarNameTest.php b/Tests/Utils/Variables/IsPHPReservedVarNameTest.php index ed310da1..5b1729d2 100644 --- a/Tests/Utils/Variables/IsPHPReservedVarNameTest.php +++ b/Tests/Utils/Variables/IsPHPReservedVarNameTest.php @@ -22,7 +22,7 @@ * * @since 1.0.0 */ -class IsPHPReservedVarNameTest extends TestCase +final class IsPHPReservedVarNameTest extends TestCase { /** diff --git a/Tests/Utils/Variables/IsSuperglobalTest.php b/Tests/Utils/Variables/IsSuperglobalTest.php index cb5cf3f6..57019d49 100644 --- a/Tests/Utils/Variables/IsSuperglobalTest.php +++ b/Tests/Utils/Variables/IsSuperglobalTest.php @@ -24,7 +24,7 @@ * * @since 1.0.0 */ -class IsSuperglobalTest extends UtilityMethodTestCase +final class IsSuperglobalTest extends UtilityMethodTestCase { /** @@ -43,16 +43,16 @@ public function testNonExistentToken() * * @dataProvider dataIsSuperglobal * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param bool $expected The expected function return value. - * @param int|string $testTargetType Optional. The token type for the target token in the test file. - * @param string $testTargetValue Optional. The token content for the target token in the test file. + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param bool $expected The expected function return value. + * @param int|string $targetType Optional. The token type for the target token in the test file. + * @param string $targetValue Optional. The token content for the target token in the test file. * * @return void */ - public function testIsSuperglobal($testMarker, $expected, $testTargetType = \T_VARIABLE, $testTargetValue = null) + public function testIsSuperglobal($testMarker, $expected, $targetType = \T_VARIABLE, $targetValue = null) { - $stackPtr = $this->getTargetToken($testMarker, $testTargetType, $testTargetValue); + $stackPtr = $this->getTargetToken($testMarker, $targetType, $targetValue); $result = Variables::isSuperglobal(self::$phpcsFile, $stackPtr); $this->assertSame($expected, $result); } @@ -68,70 +68,70 @@ public function dataIsSuperglobal() { return [ 'not-a-variable' => [ - '/* testNotAVariable */', - false, - \T_RETURN, + 'testMarker' => '/* testNotAVariable */', + 'expected' => false, + 'targetType' => \T_RETURN, ], 'not-a-reserved-var' => [ - '/* testNotAReservedVar */', - false, + 'testMarker' => '/* testNotAReservedVar */', + 'expected' => false, ], 'reserved-var-not-superglobal' => [ - '/* testReservedVarNotSuperglobal */', - false, + 'testMarker' => '/* testReservedVarNotSuperglobal */', + 'expected' => false, ], 'reserved-var-superglobal' => [ - '/* testReservedVarIsSuperglobal */', - true, + 'testMarker' => '/* testReservedVarIsSuperglobal */', + 'expected' => true, ], 'array-key-not-a-reserved-var' => [ - '/* testGLOBALSArrayKeyNotAReservedVar */', - false, - \T_CONSTANT_ENCAPSED_STRING, + 'testMarker' => '/* testGLOBALSArrayKeyNotAReservedVar */', + 'expected' => false, + 'targetType' => \T_CONSTANT_ENCAPSED_STRING, ], 'array-key-variable' => [ - '/* testGLOBALSArrayKeyVar */', - false, - \T_VARIABLE, - '$something', + 'testMarker' => '/* testGLOBALSArrayKeyVar */', + 'expected' => false, + 'targetType' => \T_VARIABLE, + 'targetValue' => '$something', ], 'array-key-reserved-var-not-superglobal' => [ - '/* testGLOBALSArrayKeyReservedVar */', - false, - \T_VARIABLE, - '$php_errormsg', + 'testMarker' => '/* testGLOBALSArrayKeyReservedVar */', + 'expected' => false, + 'targetType' => \T_VARIABLE, + 'targetValue' => '$php_errormsg', ], 'array-key-var-superglobal' => [ - '/* testGLOBALSArrayKeySuperglobal */', - true, - \T_VARIABLE, - '$_COOKIE', + 'testMarker' => '/* testGLOBALSArrayKeySuperglobal */', + 'expected' => true, + 'targetType' => \T_VARIABLE, + 'targetValue' => '$_COOKIE', ], 'array-key-not-single-string' => [ - '/* testGLOBALSArrayKeyNotSingleString */', - false, - \T_CONSTANT_ENCAPSED_STRING, + 'testMarker' => '/* testGLOBALSArrayKeyNotSingleString */', + 'expected' => false, + 'targetType' => \T_CONSTANT_ENCAPSED_STRING, ], 'array-key-interpolated-var' => [ - '/* testGLOBALSArrayKeyInterpolatedVar */', - false, - \T_DOUBLE_QUOTED_STRING, + 'testMarker' => '/* testGLOBALSArrayKeyInterpolatedVar */', + 'expected' => false, + 'targetType' => \T_DOUBLE_QUOTED_STRING, ], 'array-key-string-superglobal' => [ - '/* testGLOBALSArrayKeySingleStringSuperglobal */', - true, - \T_CONSTANT_ENCAPSED_STRING, + 'testMarker' => '/* testGLOBALSArrayKeySingleStringSuperglobal */', + 'expected' => true, + 'targetType' => \T_CONSTANT_ENCAPSED_STRING, ], 'array-key-var-superglobal-with-array-access' => [ - '/* testGLOBALSArrayKeySuperglobalWithKey */', - true, - \T_VARIABLE, - '$_GET', + 'testMarker' => '/* testGLOBALSArrayKeySuperglobalWithKey */', + 'expected' => true, + 'targetType' => \T_VARIABLE, + 'targetValue' => '$_GET', ], 'array-key-not-globals-array' => [ - '/* testSuperglobalKeyNotGLOBALSArray */', - false, - \T_CONSTANT_ENCAPSED_STRING, + 'testMarker' => '/* testSuperglobalKeyNotGLOBALSArray */', + 'expected' => false, + 'targetType' => \T_CONSTANT_ENCAPSED_STRING, ], ]; } diff --git a/Tests/Xtra/Messages/HasNewLineSupportTest.inc b/Tests/Xtra/Messages/HasNewLineSupportTest.inc new file mode 100644 index 00000000..1c97c6ad --- /dev/null +++ b/Tests/Xtra/Messages/HasNewLineSupportTest.inc @@ -0,0 +1,4 @@ +expectOutputString($expected); + $this->setOutputCallback([$this, 'normalizeOutput']); + + /* + * Create the error. + */ + $stackPtr = $this->getTargetToken('/* testMessageWithNewLine */', \T_CONSTANT_ENCAPSED_STRING); + + self::$phpcsFile->addError( + // phpcs:ignore Generic.Files.LineLength.TooLong + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nAenean felis urna, dictum vitae lobortis vitae, maximus nec enim. Etiam euismod placerat efficitur. Nulla eu felis ipsum.\nCras vitae ultrices turpis. Ut consectetur ligula in justo tincidunt mattis.\n\nAliquam fermentum magna id venenatis placerat. Curabitur lobortis nulla sit amet consequat fermentum. Aenean malesuada tristique aliquam. Donec eget placerat nisl.\n\nMorbi mollis, risus vel venenatis accumsan, urna dolor faucibus risus, ut congue purus augue vel ipsum.\nCurabitur nec dolor est. Suspendisse nec quam non ligula aliquam tempus. Donec laoreet maximus leo, in eleifend odio interdum vitae.", + $stackPtr, + self::CODE + ); + + /* + * Generate the actual output to test. + */ + $config = self::$phpcsFile->config; + $config->colors = false; + $config->reportWidth = 120; + $reporter = new Reporter($config); + $reportClass = new Full(); + $reportData = $reporter->prepareFileReport(self::$phpcsFile); + + $reportClass->generateFileReport( + $reportData, + self::$phpcsFile, + self::$phpcsFile->config->showSources, + $config->reportWidth + ); + } + + /** + * Normalize the output to allow for OS-independent comparison. + * + * @param string $output Generated output. + * + * @return string + */ + public function normalizeOutput($output) + { + // Remove potential color codes. + $output = \preg_replace('`\\033\[[0-9]+m`', '', $output); + + $output = \explode(\PHP_EOL, \trim($output)); + // Remove: line with filename. + \array_shift($output); + + return \implode("\n", $output); + } +} diff --git a/Tests/Xtra/README.md b/Tests/Xtra/README.md new file mode 100644 index 00000000..97cff0dd --- /dev/null +++ b/Tests/Xtra/README.md @@ -0,0 +1,10 @@ +# Xtra Tests + +This is a directory for tests not directly related to functionality within PHPCSUtils. + +These tests safeguard functionality from PHP_CodeSniffer for which PHPCS itself does not have suffiencient test coverage. + +In most cases, these type of tests should be pulled to PHP_CodeSniffer itself, but if testing this within the PHPCS native test framework would be difficult, tests can be placed here. +Tests can also be added here for functionality for which PHPCS just doesn't have enough tests or temporarily, while waiting for a test PR to be merged in PHPCS itself. + +Note: these tests are run in CI in a separate test run called "risky" as these tests may start failing without notice due to changes in PHPCS itself. diff --git a/Tests/Xtra/Tokens/TokenNameTest.php b/Tests/Xtra/Tokens/TokenNameTest.php new file mode 100644 index 00000000..b72c9a85 --- /dev/null +++ b/Tests/Xtra/Tokens/TokenNameTest.php @@ -0,0 +1,74 @@ +assertSame($expected, Tokens::tokenName($tokenCode)); + } + + /** + * Data provider. + * + * @see testTokenName() For the array format. + * + * @return array + */ + public function dataTokenName() + { + return [ + 'PHP native token: T_ECHO' => [ + 'tokenCode' => \T_ECHO, + 'expected' => 'T_ECHO', + ], + 'PHP native token: T_FUNCTION' => [ + 'tokenCode' => \T_FUNCTION, + 'expected' => 'T_FUNCTION', + ], + 'PHPCS native token: T_CLOSURE' => [ + 'tokenCode' => \T_CLOSURE, + 'expected' => 'T_CLOSURE', + ], + 'PHPCS native token: T_STRING_CONCAT' => [ + 'tokenCode' => \T_STRING_CONCAT, + 'expected' => 'T_STRING_CONCAT', + ], + ]; + } +} diff --git a/Tests/bootstrap.php b/Tests/bootstrap.php index 6812f447..8e660fb9 100644 --- a/Tests/bootstrap.php +++ b/Tests/bootstrap.php @@ -14,6 +14,9 @@ namespace PHPCSUtils\Tests; +use PHPCSUtils\Internal\Cache; +use PHPCSUtils\Internal\NoFileCache; + if (\defined('PHP_CODESNIFFER_IN_TESTS') === false) { \define('PHP_CODESNIFFER_IN_TESTS', true); } @@ -27,32 +30,32 @@ \define('PHP_CODESNIFFER_VERBOSITY', 0); } +if (\is_dir(\dirname(__DIR__) . '/vendor') && \file_exists(\dirname(__DIR__) . '/vendor/autoload.php')) { + $vendorDir = \dirname(__DIR__) . '/vendor'; +} else { + echo 'Please run `composer install` before attempting to run the unit tests. +You can still run the tests using a PHPUnit phar file, but some test dependencies need to be available. +'; + die(1); +} + // Get the PHPCS dir from an environment variable. $phpcsDir = \getenv('PHPCS_DIR'); // This may be a Composer install. -if ($phpcsDir === false && \is_dir(\dirname(__DIR__) . '/vendor/squizlabs/php_codesniffer')) { - $vendorDir = \dirname(__DIR__) . '/vendor'; - $phpcsDir = $vendorDir . '/squizlabs/php_codesniffer'; +if ($phpcsDir === false && \is_dir($vendorDir . '/squizlabs/php_codesniffer')) { + $phpcsDir = $vendorDir . '/squizlabs/php_codesniffer'; } elseif ($phpcsDir !== false) { $phpcsDir = \realpath($phpcsDir); } // Try and load the PHPCS autoloader. if ($phpcsDir !== false && \file_exists($phpcsDir . '/autoload.php')) { - // PHPCS 3.x. require_once $phpcsDir . '/autoload.php'; // Pre-load the token back-fills to prevent undefined constant notices. require_once $phpcsDir . '/src/Util/Tokens.php'; -} elseif ($phpcsDir !== false && \file_exists($phpcsDir . '/CodeSniffer.php')) { - // PHPCS 2.x. - require_once $phpcsDir . '/CodeSniffer.php'; - - // Pre-load the token back-fills to prevent undefined constant notices. - require_once $phpcsDir . '/CodeSniffer/Tokens.php'; } else { -// @todo: change URL!!!! echo 'Uh oh... can\'t find PHPCS. If you use Composer, please run `composer install`. @@ -62,28 +65,35 @@ die(1); } -// Load the composer autoload if available. -if (isset($vendorDir) && \file_exists($vendorDir . '/autoload.php')) { - require_once $vendorDir . '/autoload.php'; -} else { +if (\defined('__PHPUNIT_PHAR__')) { + // Testing via a PHPUnit phar. + + // Load the PHPUnit Polyfills autoloader. + require_once $vendorDir . '/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php'; + /* * Autoloader specifically for the test files. * Fixes issues with PHPUnit not being able to find test classes being extended when running * in a non-Composer context. */ - \spl_autoload_register(function ($class) { + \spl_autoload_register(function ($fqClassName) { // Only try & load our own classes. - if (\stripos($class, 'PHPCSUtils\Tests\\') !== 0) { + if (\stripos($fqClassName, 'PHPCSUtils\Tests\\') !== 0) { return; } // Strip namespace prefix 'PHPCSUtils\Tests\'. - $class = \substr($class, 17); - $file = \realpath(__DIR__) . \DIRECTORY_SEPARATOR . \strtr($class, '\\', \DIRECTORY_SEPARATOR) . '.php'; + $relativeClass = \substr($fqClassName, 17); + $file = \realpath(__DIR__) . \DIRECTORY_SEPARATOR + . \strtr($relativeClass, '\\', \DIRECTORY_SEPARATOR) . '.php'; + if (\file_exists($file)) { include_once $file; } }); +} else { + // Testing via a Composer setup. + require_once $vendorDir . '/autoload.php'; } /* @@ -94,4 +104,24 @@ */ require_once \dirname(__DIR__) . '/phpcsutils-autoload.php'; -unset($phpcsDir, $vendorDir); +/* + * Determine whether to run the test suite with caching enabled or disabled. + * + * Use `` in a `phpunit.xml` file + * or set the ENV variable on an OS-level. + * + * If the ENV variable has not been set, the tests will run with caching turned OFF. + */ +if (\defined('PHPCSUTILS_USE_CACHE') === false) { + $useCache = \getenv('PHPCSUTILS_USE_CACHE'); + if ($useCache === false) { + Cache::$enabled = false; + NoFileCache::$enabled = false; + } else { + $useCache = \filter_var($useCache, \FILTER_VALIDATE_BOOLEAN); + Cache::$enabled = $useCache; + NoFileCache::$enabled = $useCache; + } +} + +unset($phpcsDir, $vendorDir, $useCache); diff --git a/composer.json b/composer.json index 061965bf..041d9c35 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name" : "phpcsstandards/phpcsutils", "description" : "A suite of utility functions for use with PHP_CodeSniffer", "type" : "phpcodesniffer-standard", - "keywords" : [ "phpcs", "phpcbf", "standards", "php_codesniffer", "phpcs2", "phpcs3", "tokens", "utility", "phpcodesniffer-standard" ], + "keywords" : [ "phpcs", "phpcbf", "standards", "static analysis", "php_codesniffer", "phpcs3", "tokens", "utility", "phpcodesniffer-standard" ], "license" : "LGPL-3.0-or-later", "homepage": "https://phpcsutils.com/", "authors" : [ @@ -23,16 +23,16 @@ }, "require" : { "php" : ">=5.4", - "squizlabs/php_codesniffer" : "^2.6.0 || ^3.1.0 || 4.0.x-dev@dev", + "squizlabs/php_codesniffer" : "^3.7.1 || 4.0.x-dev@dev", "dealerdirect/phpcodesniffer-composer-installer" : "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7" }, "require-dev" : { - "php-parallel-lint/php-parallel-lint": "^1.2.0", - "php-parallel-lint/php-console-highlighter": "^0.5", - "phpunit/phpunit" : "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" - }, - "conflict": { - "squizlabs/php_codesniffer": "3.5.3" + "ext-filter": "*", + "phpcsstandards/phpcsdevcs": "^1.1.3", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "php-parallel-lint/php-console-highlighter": "^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.3", + "yoast/phpunit-polyfills": "^1.0.1" }, "minimum-stability": "dev", "prefer-stable": true, @@ -44,29 +44,21 @@ "PHPCSUtils\\Tests\\": "Tests/" } }, + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, "scripts" : { "lint": [ "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git" ], - "install-devcs": [ - "composer require phpcsstandards/phpcsdevcs:\"^1.0\" --no-suggest --update-no-dev" - ], - "remove-devcs": [ - "composer remove phpcsstandards/phpcsdevcs --update-no-dev" - ], "checkcs": [ - "@install-devcs", - "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs", - "@remove-devcs" + "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" ], "fixcs": [ - "@install-devcs", - "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf", - "@remove-devcs" - ], - "travis-checkcs": [ - "@install-devcs", - "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs" + "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf" ], "test": [ "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" @@ -77,5 +69,10 @@ "coverage-local": [ "@php ./vendor/phpunit/phpunit/phpunit --coverage-html ./build/coverage-html" ] + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } diff --git a/docs/_config.yml b/docs/_config.yml index 285eb8e2..94fb97db 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -8,19 +8,19 @@ github: [metadata] url: "https://phpcsutils.com" plugins: - - jekyll-github-metadata - - jemoji - - jekyll-mentions - - jekyll-seo-tag - - jekyll-sitemap + - jekyll-github-metadata + - jemoji + - jekyll-mentions + - jekyll-seo-tag + - jekyll-sitemap phpcsutils: - packagist: phpcsstandards/phpcsutils + packagist: phpcsstandards/phpcsutils # Theme info. title: PHPCSUtils description: "A suite of utility functions for use with PHP_CodeSniffer." -logo: +logo: show_downloads: false google_analytics: @@ -33,4 +33,34 @@ twitter: author: twitter: jrf_nl -exclude: ['CNAME', '.gitignore', 'Gemfile', '*.bak', '*.orig'] +# Needed so the select HTML tags do not get removed *sigh* +commonmark: + options: ["SMART", "FOOTNOTES", "UNSAFE"] + extensions: ["strikethrough", "autolink", "table"] + +# Files to exclude when generating the site. +exclude: + - .sass-cache/ + - .jekyll-cache/ + - gemfiles/ + - Gemfile + - Gemfile.lock + - node_modules/ + - vendor/bundle/ + - vendor/cache/ + - vendor/gems/ + - vendor/ruby/ + - CNAME + - CONTRIBUTING.md + - LICENSE + - README.md + - apigen.neon + - buildtool.py + - Vagrantfile + - vagrant-provision.sh + - .gitignore + - .github + - .jekyll-metadata + - '*.bak' + - '*.orig' + - runit.bat diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index e9d910d8..949126ab 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -16,17 +16,13 @@

{{ site.title | default: site.github.repository_name }}

- + {% if site.logo %} Logo {% endif %}

{{ site.description | default: site.github.project_tagline }}

- {% if site.github.is_project_page %} -

Visit the Project on GitHub {{ site.github.repository_nwo }}

- {% endif %} -

Read the Documentation

+ {% if site.github.latest_release.tag_name %} +

Latest release: {{ site.github.latest_release.tag_name }}

+ {% endif %} + {% if site.show_downloads %}
{% endif %} -

+

Visit the Project on GitHub {{ site.github.repository_nwo }}

-
+

diff --git a/docs/assets/css/style.scss b/docs/assets/css/style.scss index d6f81c22..6d9185f7 100644 --- a/docs/assets/css/style.scss +++ b/docs/assets/css/style.scss @@ -89,13 +89,13 @@ p code { } /* FAQ */ -#faq h4 { +.faq h3 { font-size: 18px; line-height: 1.1; margin-top: 0; } -#faq h4::first-letter, #faq h4 + p::first-letter { +.faq h3::first-letter, .faq h3 + p::first-letter { color:#267CB9; font-weight: bold; } diff --git a/docs/index.md b/docs/index.md index b84fc2b5..ee6793dc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,81 +9,82 @@ seo: type: Organisation --- -Features -------------------------------------------- +## Features -[PHPCSUtils](https://github.com/PHPCSStandards/PHPCSUtils) is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) (or "PHPCS" for short). +[PHPCSUtils][phpcsutils-repo] is a set of utilities to aid developers of sniffs for [PHP_CodeSniffer] (or "PHPCS" for short). This package offers the following features:
-### Use the latest version of PHP_CodeSniffer native utility functions. +### An ever-growing number of utility functions for use with PHP_CodeSniffer -Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard. +Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a DocBlock, PHPCSUtils has got you covered! -Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 2.6.0 and up. +Includes improved versions of the PHPCS native utility functions and plenty of new utility functions. -### Several abstract sniff classes which your sniffs can extend. +These functions are compatible with PHPCS 3.7.1 up to PHPCS `master`. -These classes take most of the heavy lifting away for some frequently occurring sniff types. - -### A collection of static properties and methods for often-used token groups. +### A collection of static properties and methods for often-used token groups Collections of related tokens often-used and needed for sniffs. These are additional "token groups" to compliment the ones available through the PHPCS native `PHP_CodeSniffer\Util\Tokens` class. -### An ever-growing number of utility functions for use with PHP_CodeSniffer. - -Whether you need to split an `array` into the individual items, are trying to determine which variables are being assigned to in a `list()` or are figuring out whether a function has a DocBlock, PHPCSUtils has got you covered! +### Several abstract sniff classes which your sniffs can extend -Includes improved versions of the PHPCS native utility functions and plenty of new utility functions. - -These functions are, of course, compatible with PHPCS 2.6.0 up to PHPCS `master`. +These classes take most of the heavy lifting away for some frequently occurring sniff types. ### Test utilities An abstract `UtilityMethodTestCase` class to support testing of your utility methods written for PHP_CodeSniffer. -Compatible with both PHPCS 2.x as well as 3.x. Supports PHPUnit 4.x up to 9.x. +Supports PHPUnit 4.x up to 9.x. -### Backward compatibility layer +### Use the latest version of PHP_CodeSniffer native utility functions -A `PHPCS23Utils` standard which allows sniffs to work in both PHPCS 2.x and 3.x, as well as a few helper functions for external standards which still want to support both PHP_CodeSniffer 2.x as well as 3.x. +Normally to use the latest version of PHP_CodeSniffer native utility functions, you would have to raise the minimum requirements of your external PHPCS standard. + +Now you won't have to anymore. This package allows you to use the latest version of those utility functions in all PHP_CodeSniffer versions from PHPCS 3.7.1 and up. ### Fully documented -To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation](https://phpcsutils.com/). +To see detailed information about all the available abstract sniffs, utility functions and PHPCS helper functions, have a read through the [extensive documentation][phpcsutils-web].
-Minimum Requirements -------------------------------------------- + +## Minimum Requirements * PHP 5.4 or higher. -* [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.6.0+, 3.1.0+ (with the exception of PHPCS 3.5.3). +* [PHP_CodeSniffer] 3.7.1+. * Recommended PHP extensions for optimal functionality: - PCRE with Unicode support (normally enabled by default) -Integrating PHPCSUtils in your external PHPCS standard -------------------------------------------- +## Integrating PHPCSUtils in your external PHPCS standard -### Composer-based with a minimum PHPCS requirement of PHPCS 3.1.0 +### Composer-based -If your external PHP_CodeSniffer standard only supports Composer-based installs and has a minimum PHPCS requirement of PHP_CodeSniffer 3.1.0, integrating PHPCSUtils is pretty straight forward. +If your external PHP_CodeSniffer standard only supports Composer-based installs, integrating PHPCSUtils is pretty straight forward. Run the following from the root of your external PHPCS standard's project: -
composer require {{ site.phpcsutils.packagist }}:"^1.0"
+
composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
+composer require {{ site.phpcsutils.packagist }}:"^1.0"
 
No further action needed. You can start using all the utility functions, abstract sniff classes and other features of PHPCSUtils straight away. -> :information_source: The PHPCSUtils package includes the [DealerDirect Composer PHPCS plugin](https://github.com/Dealerdirect/phpcodesniffer-composer-installer). +> :information_source: The PHPCSUtils package includes the [Composer PHPCS plugin]. > > This plugin will automatically register PHPCSUtils (and your own external standard) with PHP_CodeSniffer, so you and your users don't have to worry about this anymore. > > :warning: Note: if your end-user installation instructions include instructions on adding a Composer PHPCS plugin or on manually registering your standard with PHPCS using the `--config-set installed_paths` command, you can remove those instructions as they are no longer needed. +> +> :information_source: As of Composer 2.2, Composer will [ask for permission](https://blog.packagist.com/composer-2-2/#more-secure-plugin-execution) to allow the Composer PHPCS plugin to execute code. For the plugin to be functional, permission needs to be granted. +> This can be done ahead of time by instructing your users to run the following command before installing your standard: +> +>
composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
+> 
#### Running your unit tests @@ -94,104 +95,83 @@ If you have your own unit test suite to test your sniffs, make sure to load the If you intend to use the test utilities provided in the `PHPCSUtils/TestUtils` directory, make sure you also load the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file in your PHPUnit bootstrap file. -### Composer-based with a minimum PHPCS requirement of PHPCS 2.6.0 - -Follow the above instructions for use with PHPCS 3.x. - -In addition to that, add the following to the `ruleset.xml` file of your standard(s): -```xml - - -``` - -> :information_source: The `PHPCS23Utils` "standard" does not add any real sniffs, it only makes sure that the Utility functions will work in PHPCS 2.x as well. - -#### Running your unit tests - -If your standard supports both PHPCS 2.x as well as 3.x, you are bound to already have a PHPUnit `bootstrap.php` file in place. - -To allow the unit tests to find the relevant files for PHPCSUtils, make sure that the bootstrap loads both the Composer `vendor/autoload.php` file, as well as the `vendor/phpcsstandards/phpcsutils/phpcsutils-autoload.php` file. - - - -Frequently Asked Questions -------- +## Frequently Asked Questions -
+
-#### Q: How does this all work without an external standard needing to register an autoloader? +### Q: How does this all work without an external standard needing to register an autoloader? A: As PHPCSUtils is registered with PHPCS as an external standard and PHPCSUtils complies with the naming requirements of PHPCS, the PHPCS native autoloader will automatically take care of loading the classes used from PHPCSUtils. -#### Q: What does the `PHPCS23Utils` standard do? - -A: All the `PHPCS23Utils` standard does is load the `phpcsutils-autoload.php` file. - -PHPCS 3.x uses namespaces, while PHPCS 2.x does not. The `phpcsutils-autoload.php` file creates `class_alias`-es for the most commonly used PHPCS classes, including all PHPCS classes used by PHPCSUtils. That way, both your external standard as well as PHPCSUtils can refer to the PHPCS 3.x class names and the code will still work in PHPCS 2.x. - -#### Q: Why is PHP_CodeSniffer 3.5.3 not supported? - -A: The backfill for PHP 7.4 numeric literals with underscores in PHP_CodeSniffer 3.5.3 is broken and there is no way to reliably provide support for anything to do with numbers or `T_STRING` tokens when using PHP_CodeSniffer 3.5.3 as the tokens returned by the tokenizer are unpredictable and unreliable. - -The backfill was fixed in PHP_CodeSniffer 3.5.4. - -#### Q: Any other problematic PHPCS versions? - -A: Well, the arrow function backfill which was added in PHPCS 3.5.3 is still causing problems. In a very limited set of circumstances, it will even hang the Tokenizer. A fix for [one particular such problem](https://github.com/squizlabs/php_codesniffer/issues/2926) has been committed to `master`, but is not (yet) in a released version. It is expected to be released in PHP_CodeSniffer 3.5.6. - -As the Tokenizer hanging is a problem unrelated to PHPCSUtils and not something which can be mitigated from within PHPCSUtils in any conceivable way, PHPCSUtils won't block installation in combination with PHPCS 3.5.4 and 3.5.5. - -There are several other issues which can not be worked around, like scope closers being set incorrectly and throwing the scope setting off for the rest of the file, so not withstanding that PHPCSUtils can work around a lot of issues, it is still highly recommended to advise your end-users to always use the latest version of PHPCS for the most reliable results. - -#### Q: Does using PHPCSUtils have any effect on the PHPCS native sniffs? +### Q: Does using PHPCSUtils have any effect on the PHPCS native sniffs? A: No. PHPCSUtils will only work for those sniffs which explicitly use the PHPCSUtils functionality. If your standard includes both PHPCS native sniffs as well as your own sniffs, your own sniffs can benefit from the back-compat layer offered by PHPCSUtils, as well as from the additional utility functions. However, the PHPCS native sniffs will not receive those benefits, as PHPCS itself does not use PHPCSUtils. -#### Q: Do the utilities work with javascript/CSS files? +### Q: Do the utilities work with javascript/CSS files? -A: JS/CSS support will be removed from PHP_CodeSniffer in PHPCS 4.x. -While at this time, some of the utilies _may_ work with JS/CSS files, PHPCSUtils does not offer formal support for JS/CSS sniffing with PHP_CodeSniffer and will stop any existing support once PHPCS 4.x has been released. +A: JS/CSS support will be removed from `PHP_CodeSniffer` in PHPCS 4.x. +While at this time, some of the utilities _may_ work with JS/CSS files, PHPCSUtils does not offer formal support for JS/CSS sniffing with `PHP_CodeSniffer` and will stop any existing support once PHPCS 4.x has been released. -#### Q: Are all file encodings supported? +### Q: Are all file encodings supported? A: No. The UTF-8 file encoding is the only officially supported encoding. Support for other encodings may incidentally work, but is not officially supported. > **It is recommended to advise your users to save their files as UTF-8 encoded for the best results.** -PHP_CodeSniffer 3.x will default to UTF-8 as the expected file encoding. -If your standard supports PHP_CodeSniffer 2.x, it is recommended to set the expected encoding in the ruleset to `utf-8`, like so: `` or to advise users to use the CLI option `--encoding=utf-8`. +Note: `PHP_CodeSniffer` 3.x defaults to UTF-8 as the expected file encoding. + +
+ +## Potential Support Questions from your End-Users -Potential Support Questions from your End-Users -------- +
-#### Q: A user reports a fatal "class not found" error for a class from PHPCSUtils. +### Q: A user reports a fatal "class not found" error for a class from PHPCSUtils 1. Check that the version of PHPCSUtils the user has installed complies with the minimum version of PHPCSUtils your standard requires. If not, they will need to upgrade. 2. If the version is correct, this indicates that the end-user does not have PHPCSUtils installed and/or registered with PHP_CodeSniffer. - Please review your standard's installation instructions to make sure that PHPCSUtils will be installed when those are followed. - Inform the user to install PHPCSUtils and register it with PHP_CodeSniffer. +--- + > :bulb: **Pro-tip**: if you want to prevent the fatal error and show a _friendlier_ error message instead, add `` to your standard's `ruleset.xml` file. > -> With that in place, PHP_CodeSniffer will show a _"ERROR: the "PHPCSUtils" coding standard is not installed."_ message if PHPCSUtils is missing as soon as the ruleset loading is finished. +> With that in place, `PHP_CodeSniffer` will show a _"ERROR: the "PHPCSUtils" coding standard is not installed."_ message if PHPCSUtils is missing as soon as the ruleset loading is finished. + +--- > :bulb: **Pro-tip**: provide upgrade instructions for your end-users. For Composer-based installs, those should look like this: ->
composer update your/cs-package --with-dependencies
+>
+> 
composer update your/cs-package --with-[all-]dependencies
 > 
+> > That way, when the user updates your coding standards package, they will automatically also update PHPCSUtils. +--- +
-Contributing -------- +## Contributing + Contributions to this project are welcome. Clone the repo, branch off from `develop`, make your changes, commit them and send in a pull request. If you are unsure whether the changes you are proposing would be welcome, please open an issue first to discuss your proposal. -License -------- -This code is released under the [GNU Lesser General Public License (LGPLv3)](http://www.gnu.org/copyleft/lesser.html). + +## License + +This code is released under the [GNU Lesser General Public License (LGPLv3)](https://www.gnu.org/copyleft/lesser.html). + + +[PHP_CodeSniffer]: https://github.com/squizlabs/PHP_CodeSniffer +[Composer PHPCS plugin]: https://github.com/PHPCSStandards/composer-installer +[phpcsutils-repo]: https://github.com/PHPCSStandards/PHPCSUtils +[phpcsutils-web]: https://phpcsutils.com/ +[phpcsutils-packagist]: https://packagist.org/packages/phpcsstandards/phpcsutils +[phpcsutils-releases]: https://github.com/PHPCSStandards/PHPCSUtils/releases +[phpcsutils-tests-gha]: https://github.com/PHPCSStandards/PHPCSUtils/actions/workflows/test.yml diff --git a/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html b/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html index d65c9501..33b518f7 100644 --- a/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html +++ b/docs/phpdoc/classes/PHPCSUtils-AbstractSniffs-AbstractArrayDeclarationSniff.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
-

PHPCSUtils

- -
- -
-
-

Abstract sniff to easily examine all parts of an array declaration.

@@ -101,15 +156,26 @@
1.0.0 - -
+ + + +
+ since +
+
+ 1.0.0-alpha4 + +

Dropped support for PHPCS < 3.7.1.

+
+ +

- Interfaces, Classes and Traits + Interfaces, Classes, Traits and Enums

@@ -118,6 +184,7 @@

+ @@ -127,129 +194,129 @@

-
- $arrayCloser +
+ $arrayCloser -  : int +  : int
The stack pointer to the array closer.
- $arrayItems + $arrayItems -  : array +  : array<string|int, mixed>
A multi-dimentional array with information on each array item.
- $arrayOpener + $arrayOpener -  : int +  : int
The stack pointer to the array opener.
- $itemCount + $itemCount -  : int +  : int
How many items are in the array.
- $singleLine + $singleLine -  : bool +  : bool
Whether or not the array is single line.
- $stackPtr + $stackPtr -  : int +  : int
The stack pointer to the array keyword or the short array open token.
- $tokens + $tokens -  : array +  : array<string|int, mixed>
The token stack for the current file being examined.
- __construct() + __construct() -  : void +  : void
Set up this class.
- getActualArrayKey() + getActualArrayKey() -  : string|int|void +  : string|int|void
Determine what the actual array key would be.
- process() + process() -  : void +  : void
Processes this test when one of its tokens is encountered.
- processArray() + processArray() -  : void +  : void
Process every part of the array declaration.
- processArrow() + processArrow() -  : true|void +  : true|void
Process the double arrow.
- processComma() + processComma() -  : true|void +  : true|void
Process the comma after an array item.
- processKey() + processKey() -  : true|void +  : true|void
Process the tokens in an array key.
- processNoKey() + processNoKey() -  : true|void +  : true|void
Process an array item without an array key.
- processOpenClose() + processOpenClose() -  : true|void +  : true|void
Process the array opener and closer.
- processValue() + processValue() -  : true|void +  : true|void
Process the tokens in an array value.
- register() + register() -  : array +  : array<string|int, mixed>
Returns an array of tokens this test wants to listen for.
@@ -263,7 +330,7 @@

Properties - +

@@ -318,21 +388,22 @@
>

$arrayItems - +

+ 85 + +

A multi-dimentional array with information on each array item.

protected - array + array<string|int, mixed> $arrayItems @@ -342,9 +413,12 @@

'end' => int, // The stack pointer to the last token in the array item. 'raw' => string, // A string with the contents of all tokens between `start` and `end`. 'clean' => string, // Same as `raw`, but all comment tokens have been stripped out. -)

+) + + +
Tags @@ -355,8 +429,9 @@
1.0.0 - -
+ + + @@ -369,15 +444,16 @@
>

$arrayOpener - +

+ 57 + +

The stack pointer to the array opener.

@@ -389,6 +465,7 @@

+

Tags @@ -399,8 +476,9 @@
1.0.0 - -
+ + + @@ -413,15 +491,16 @@
>

$itemCount - +

+ 94 + +

How many items are in the array.

@@ -433,6 +512,7 @@

+

Tags @@ -443,8 +523,9 @@
1.0.0 - -
+ + + @@ -457,15 +538,16 @@
>

$singleLine - +

+ 103 + +

Whether or not the array is single line.

@@ -477,6 +559,7 @@

+

Tags @@ -487,8 +570,9 @@
1.0.0 - -
+ + + @@ -501,15 +585,16 @@
>

$stackPtr - +

+ 39 + +

The stack pointer to the array keyword or the short array open token.

@@ -521,6 +606,7 @@

+

Tags @@ -531,8 +617,9 @@
1.0.0 - -
+ + + @@ -545,26 +632,28 @@
>

$tokens - +

+ 48 + +

The token stack for the current file being examined.

protected - array + array<string|int, mixed> $tokens +
Tags @@ -575,8 +664,9 @@
1.0.0 - -
+ + + @@ -585,7 +675,7 @@

Methods - +

>

getActualArrayKey() - +

+ 456 + +

Determine what the actual array key would be.

public - getActualArrayKey(File $phpcsFile, int $startPtr, int $endPtr) : string|int|void + getActualArrayKey(File $phpcsFile, int $startPtr, int $endPtr) : string|int|void

Helper function for processsing array keys in the processKey() function. -Using this method is up to the sniff implementation in the child class.

+Using this method is up to the sniff implementation in the child class.

+
Parameters
@@ -667,7 +759,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -676,7 +769,8 @@
Parameters

The stack pointer to the first token in the "key" part of -an array item.

+an array item.

+
@@ -685,7 +779,8 @@
Parameters

The stack pointer to the last token in the "key" part of -an array item.

+an array item.

+
@@ -701,15 +796,17 @@
1.0.0 - -
+ + +
Return values
string|int|void

The string or integer array key or void if the array key could not -reliably be determined.

+reliably be determined.

+ @@ -721,22 +818,24 @@
Return values
>

process() - +

+ 179 + +

Processes this test when one of its tokens is encountered.

public - final process(File $phpcsFile, int $stackPtr) : void + final process(File $phpcsFile, int $stackPtr) : void

This method fills the properties with relevant information for examining the array -and then passes off to the \PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff::processArray() method.

+and then passes off to the AbstractArrayDeclarationSniff::processArray() method.

+
Parameters
@@ -746,7 +845,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -756,7 +856,8 @@
Parameters

The position in the PHP_CodeSniffer file's token stack where the token -was found.

+was found.

+
@@ -772,10 +873,15 @@
1.0.0 - -
+ + + +
Return values
+ void + — +
>

processArray() - +

+ 231 + +

Process every part of the array declaration.

public - processArray(File $phpcsFile) : void + processArray(File $phpcsFile) : void

Controller which calls the individual process...() methods for each part of the array.

-

The method starts by calling the \PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff::processOpenClose() method +

The method starts by calling the AbstractArrayDeclarationSniff::processOpenClose() method and subsequently calls the following methods for each array item:

- - - - - - - - - - - - - - - - - - - - - - - - - -
Unkeyed arraysKeyed arrays
processNoKey()processKey()
-processArrow()
processValue()processValue()
processComma()processComma()
+

Unkeyed arrays | Keyed arrays +-------------- | ------------ +processNoKey() | processKey()

+
    +
  • +
             | processArrow()
    +
    +
  • +
+

processValue() | processValue() +processComma() | processComma()

This is the default logic for the sniff, but can be overloaded in a concrete child class -if needed.

+if needed.

+
Parameters
@@ -840,7 +933,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -856,10 +950,15 @@
1.0.0 - -
+ + + +
Return values
+ void + — +
>

processArrow() - +

+ 382 + +

Process the double arrow.

public - processArrow(File $phpcsFile, int $arrowPtr, int $itemNr) : true|void + processArrow(File $phpcsFile, int $arrowPtr, int $itemNr) : true|void -

Optional method to be implemented in concrete child classes. By default, this method does nothing.

+

Optional method to be implemented in concrete child classes. By default, this method does nothing.

+
Parameters
@@ -894,7 +995,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -902,7 +1004,8 @@
Parameters
: int
-

The stack pointer to the double arrow for the array item.

+

The stack pointer to the double arrow for the array item.

+
@@ -911,7 +1014,8 @@
Parameters

Which item in the array is being handled. -1-based, i.e. the first item is item 1, the second 2 etc.

+1-based, i.e. the first item is item 1, the second 2 etc.

+
@@ -927,14 +1031,9 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
Return values
@@ -942,7 +1041,8 @@
Return values

Returning TRUE will short-circuit the array item loop and stop processing. In effect, this means that the sniff will not examine the array value or -comma for this array item and will not process any array items after this one.

+comma for this array item and will not process any array items after this one.

+
@@ -954,21 +1054,23 @@
Return values
>

processComma() - +

+ 434 + +

Process the comma after an array item.

public - processComma(File $phpcsFile, int $commaPtr, int $itemNr) : true|void + processComma(File $phpcsFile, int $commaPtr, int $itemNr) : true|void -

Optional method to be implemented in concrete child classes. By default, this method does nothing.

+

Optional method to be implemented in concrete child classes. By default, this method does nothing.

+
Parameters
@@ -978,7 +1080,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -986,7 +1089,8 @@
Parameters
: int
-

The stack pointer to the comma.

+

The stack pointer to the comma.

+
@@ -995,7 +1099,8 @@
Parameters

Which item in the array is being handled. -1-based, i.e. the first item is item 1, the second 2 etc.

+1-based, i.e. the first item is item 1, the second 2 etc.

+
@@ -1011,14 +1116,9 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
Return values
@@ -1026,7 +1126,8 @@
Return values

Returning TRUE will short-circuit the array item loop and stop processing. In effect, this means that the sniff will not process any array items -after this one.

+after this one.

+ @@ -1038,23 +1139,25 @@
Return values
>

processKey() - +

+ 329 + +

Process the tokens in an array key.

public - processKey(File $phpcsFile, int $startPtr, int $endPtr, int $itemNr) : true|void + processKey(File $phpcsFile, int $startPtr, int $endPtr, int $itemNr) : true|void

Optional method to be implemented in concrete child classes. By default, this method does nothing.

Note: The $startPtr and $endPtr do not discount whitespace or comments, but are all inclusive -to allow for examining all tokens in an array key.

+to allow for examining all tokens in an array key.

+
Parameters
@@ -1064,7 +1167,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -1073,7 +1177,8 @@
Parameters

The stack pointer to the first token in the "key" part of -an array item.

+an array item.

+
@@ -1082,7 +1187,8 @@
Parameters

The stack pointer to the last token in the "key" part of -an array item.

+an array item.

+
@@ -1091,7 +1197,8 @@
Parameters

Which item in the array is being handled. -1-based, i.e. the first item is item 1, the second 2 etc.

+1-based, i.e. the first item is item 1, the second 2 etc.

+
@@ -1107,22 +1214,19 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
see
- AbstractArrayDeclarationSniff::getActualArrayKey() -

Optional helper function.

+ AbstractArrayDeclarationSniff::getActualArrayKey() + +

Optional helper function.

+
-
+
Return values
@@ -1130,7 +1234,8 @@
Return values

Returning TRUE will short-circuit the array item loop and stop processing. In effect, this means that the sniff will not examine the double arrow, the array -value or comma for this array item and will not process any array items after this one.

+value or comma for this array item and will not process any array items after this one.

+ @@ -1142,23 +1247,25 @@
Return values
>

processNoKey() - +

+ 359 + +

Process an array item without an array key.

public - processNoKey(File $phpcsFile, int $startPtr, int $itemNr) : true|void + processNoKey(File $phpcsFile, int $startPtr, int $itemNr) : true|void

Optional method to be implemented in concrete child classes. By default, this method does nothing.

Note: This method is not intended for processing the array value. Use the -\PHPCSUtils\AbstractSniffs\AbstractArrayDeclarationSniff::processValue() method to implement processing of the array value.

+AbstractArrayDeclarationSniff::processValue() method to implement processing of the array value.

+
Parameters
@@ -1168,7 +1275,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -1178,7 +1286,8 @@
Parameters

The stack pointer to the first token in the array item, which in this case will be the first token of the array -value part of the array item.

+value part of the array item.

+
@@ -1187,7 +1296,8 @@
Parameters

Which item in the array is being handled. -1-based, i.e. the first item is item 1, the second 2 etc.

+1-based, i.e. the first item is item 1, the second 2 etc.

+
@@ -1203,22 +1313,19 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
see
- AbstractArrayDeclarationSniff::processValue() -

Method to process the array value.

+ AbstractArrayDeclarationSniff::processValue() + +

Method to process the array value.

+
-
+
Return values
@@ -1226,7 +1333,8 @@
Return values

Returning TRUE will short-circuit the array item loop and stop processing. In effect, this means that the sniff will not examine the array value or -comma for this array item and will not process any array items after this one.

+comma for this array item and will not process any array items after this one.

+ @@ -1238,21 +1346,23 @@
Return values
>

processOpenClose() - +

+ 298 + +

Process the array opener and closer.

public - processOpenClose(File $phpcsFile, int $openPtr, int $closePtr) : true|void + processOpenClose(File $phpcsFile, int $openPtr, int $closePtr) : true|void -

Optional method to be implemented in concrete child classes. By default, this method does nothing.

+

Optional method to be implemented in concrete child classes. By default, this method does nothing.

+
Parameters
@@ -1262,7 +1372,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -1270,7 +1381,8 @@
Parameters
: int
-

The position of the array opener token in the token stack.

+

The position of the array opener token in the token stack.

+
@@ -1278,7 +1390,8 @@
Parameters
: int
-

The position of the array closer token in the token stack.

+

The position of the array closer token in the token stack.

+
@@ -1294,14 +1407,9 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
Return values
@@ -1309,7 +1417,8 @@
Return values

Returning TRUE will short-circuit the sniff and stop processing. In effect, this means that the sniff will not examine the individual -array items if TRUE is returned.

+array items if TRUE is returned.

+ @@ -1321,23 +1430,25 @@
Return values
>

processValue() - +

+ 411 + +

Process the tokens in an array value.

public - processValue(File $phpcsFile, int $startPtr, int $endPtr, int $itemNr) : true|void + processValue(File $phpcsFile, int $startPtr, int $endPtr, int $itemNr) : true|void

Optional method to be implemented in concrete child classes. By default, this method does nothing.

Note: The $startPtr and $endPtr do not discount whitespace or comments, but are all inclusive -to allow for examining all tokens in an array value.

+to allow for examining all tokens in an array value.

+
Parameters
@@ -1347,7 +1458,8 @@
Parameters

The PHP_CodeSniffer file where the -token was found.

+token was found.

+
@@ -1356,7 +1468,8 @@
Parameters

The stack pointer to the first token in the "value" part of -an array item.

+an array item.

+
@@ -1365,7 +1478,8 @@
Parameters

The stack pointer to the last token in the "value" part of -an array item.

+an array item.

+
@@ -1374,7 +1488,8 @@
Parameters

Which item in the array is being handled. -1-based, i.e. the first item is item 1, the second 2 etc.

+1-based, i.e. the first item is item 1, the second 2 etc.

+
@@ -1390,14 +1505,9 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
Return values
@@ -1405,7 +1515,8 @@
Return values

Returning TRUE will short-circuit the array item loop and stop processing. In effect, this means that the sniff will not examine the comma for this -array item and will not process any array items after this one.

+array item and will not process any array items after this one.

+ @@ -1417,19 +1528,20 @@
Return values
>

register() - +

+ 158 + +

Returns an array of tokens this test wants to listen for.

public - register() : array + register() : array<string|int, mixed> @@ -1444,39 +1556,105 @@
1.0.0 - -
-
- codeCoverageIgnore -
-
- -
+ + +
Return values
- array + array<string|int, mixed> — - -
+ + -

Search results

-
    -
-
+ +
+
+
+

Search results

+ +
+
+
    +
    +
    +
    - + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html index 4b3c7c11..c90e7047 100644 --- a/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html +++ b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCFile.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
    -

    PHPCSUtils

    - -
    - -
    -
    -

    PHPCS native utility functions.

    @@ -92,20 +147,7 @@

    Additionally, this class works round the following tokenizer issues for any affected utility functions:

      -
    • Array return type declarations were incorrectly tokenized to T_ARRAY_HINT -instead of T_RETURN_TYPE in some circumstances prior to PHPCS 2.8.0.
    • -
    • T_NULLABLE was not available prior to PHPCS 2.8.0 and utility functions did -not take nullability of types into account.
    • -
    • The PHPCS native ignore annotations were not available prior to PHPCS 3.2.0.
    • -
    • The way return types were tokenized has changed in PHPCS 3.3.0. -Previously a lot of them were tokenized as T_RETURN_HINT. For namespaced -classnames this only tokenized the classname, not the whole return type. -Now tokenization is "normalized" with most tokens being T_STRING, including -array return type declarations.
    • -
    • Typed properties were not recognized prior to PHPCS 3.5.0, including the -? nullability token not being converted to T_NULLABLE.
    • -
    • Arrow functions were not recognized properly until PHPCS 3.5.3/4.
    • -
    • General PHP cross-version incompatibilities.
    • +
    • None at this time.

    Most functions in this class will have a related twin-function in the relevant class in the PHPCSUtils\Utils namespace. @@ -114,7 +156,8 @@

    improved functionality, but will generally be fully compatible with the PHPCS native functions. The differences between the functions here and the twin functions are documented -in the docblock of the respective twin-function.

    +in the docblock of the respective twin-function.

    +

    @@ -127,16 +170,29 @@
    File -

    Original source of these utility methods.

    + +

    Original source of these utility methods.

    +
    -
    +
    since
    1.0.0 - -
    + + + +
    + since +
    +
    + 1.0.0-alpha4 + +

    Dropped support for PHPCS < 3.7.1.

    +
    + +
    @@ -150,95 +206,95 @@

    -
    - findEndOfStatement() +
    + findEndOfStatement() -  : int +  : int
    Returns the position of the last non-whitespace token in a statement.
    - findExtendedClassName() + findExtendedClassName() -  : string|false +  : string|false
    Returns the name of the class that the specified class extends.
    - findImplementedInterfaceNames() + findImplementedInterfaceNames() -  : array|false +  : array<string|int, mixed>|false
    -
    Returns the names of the interfaces that the specified class implements.
    +
    Returns the names of the interfaces that the specified class or enum implements.
    - findStartOfStatement() + findStartOfStatement() -  : int +  : int
    Returns the position of the first non-whitespace token in a statement.
    - getClassProperties() + getClassProperties() -  : array +  : array<string|int, mixed>
    Returns the implementation properties of a class.
    - getCondition() + getCondition() -  : int|false +  : int|false
    Return the position of the condition for the passed token.
    - getDeclarationName() + getDeclarationName() -  : string|null +  : string|null
    -
    Returns the declaration names for classes, interfaces, traits, and functions.
    +
    Returns the declaration name for classes, interfaces, traits, enums, and functions.
    - getMemberProperties() + getMemberProperties() -  : array +  : array<string|int, mixed>
    Returns the visibility and implementation properties of a class member var.
    - getMethodParameters() + getMethodParameters() -  : array +  : array<string|int, mixed>
    Returns the method parameters for the specified function token.
    - getMethodProperties() + getMethodProperties() -  : array +  : array<string|int, mixed>
    Returns the visibility and implementation properties of a method.
    - getTokensAsString() + getTokensAsString() -  : string +  : string
    Returns the content of the tokens from the specified start position in the token stack for the specified length.
    - hasCondition() + hasCondition() -  : bool +  : bool
    Determine if the passed token has a condition of one of the passed types.
    - isReference() + isReference() -  : bool +  : bool
    Determine if the passed token is a reference operator.
    @@ -253,7 +309,7 @@

    Methods - +

    >

    findEndOfStatement() - +

    + 658 + +

    Returns the position of the last non-whitespace token in a statement.

    public - static findEndOfStatement(File $phpcsFile, int $start[, int|string|array $ignore = null ]) : int + static findEndOfStatement(File $phpcsFile, int $start[, int|string|array<string|int, mixed> $ignore = null ]) : int

    PHPCS cross-version compatible version of the `File::findEndOfStatement() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 2.1.0.
    • -
    • PHPCS 2.6.2: New optional $ignore parameter to selectively ignore stop points.
    • -
    • PHPCS 2.7.1: Improved handling of short arrays, PHPCS #1203.
    • -
    • PHPCS 3.3.0: Bug fix: end of statement detection when passed a scope opener, PHPCS #1863.
    • -
    • PHPCS 3.5.0: Improved handling of group use statements.
    • -
    • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions.
    • -
    • PHPCS 3.5.4: Improved support for PHP 7.4 T_FN arrow functions.
    • -
    • PHPCS 3.5.5: Improved support for PHP 7.4 T_FN arrow functions, PHPCS #2895.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +

    Parameters
    @@ -297,7 +349,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -305,15 +358,17 @@
    Parameters
    : int
    -

    The position to start searching from in the token stack.

    +

    The position to start searching from in the token stack.

    +
    $ignore - : int|string|array + : int|string|array<string|int, mixed> = null
    -

    Token types that should not be considered stop points.

    +

    Token types that should not be considered stop points.

    +
    @@ -329,24 +384,19 @@
    File::findEndOfStatement() -

    Original source.

    + +

    Original source.

    +
    -
    +
    since
    1.0.0 - -
    -
    - since -
    -
    - 1.0.0-alpha2 -

    Added BC support for PHP 7.4 arrow functions.

    - -
    + + +
    Return values
    @@ -363,30 +413,29 @@
    Return values
    >

    findExtendedClassName() - +

    + 739 + +

    Returns the name of the class that the specified class extends.

    public - static findExtendedClassName(File $phpcsFile, int $stackPtr) : string|false + static findExtendedClassName(File $phpcsFile, int $stackPtr) : string|false

    (works for classes, anonymous classes and interfaces)

    PHPCS cross-version compatible version of the File::findExtendedClassName() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 1.2.0.
    • -
    • PHPCS 2.8.0: Now supports anonymous classes.
    • -
    • PHPCS 3.1.0: Now supports interfaces extending interfaces (incorrectly, only supporting -single interface extension).
    • -
    • PHPCS 3.3.2: Fixed bug causing bleed through with nested classes, PHPCS#2127.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -395,7 +444,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -403,7 +453,8 @@
    Parameters
    : int
    -

    The stack position of the class or interface.

    +

    The stack position of the class or interface.

    +
    @@ -419,31 +470,37 @@
    File::findExtendedClassName() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - ObjectDeclarations::findExtendedClassName() -

    PHPCSUtils native improved version.

    + ObjectDeclarations::findExtendedClassName() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    Return values
    string|false

    The extended class name or FALSE on error or if there -is no extended class name.

    +is no extended class name.

    + @@ -455,26 +512,28 @@
    Return values
    >

    findImplementedInterfaceNames() - +

    + 764 + + -

    Returns the names of the interfaces that the specified class implements.

    +

    Returns the names of the interfaces that the specified class or enum implements.

    public - static findImplementedInterfaceNames(File $phpcsFile, int $stackPtr) : array|false + static findImplementedInterfaceNames(File $phpcsFile, int $stackPtr) : array<string|int, mixed>|false

    PHPCS cross-version compatible version of the File::findImplementedInterfaceNames() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 2.7.0.
    • -
    • PHPCS 2.8.0: Now supports anonymous classes.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -483,7 +542,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -491,7 +551,8 @@
    Parameters
    : int
    -

    The stack position of the class.

    +

    The stack position of the class or enum token.

    +
    @@ -507,31 +568,37 @@
    File::findImplementedInterfaceNames() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - ObjectDeclarations::findImplementedInterfaceNames() -

    PHPCSUtils native improved version.

    + ObjectDeclarations::findImplementedInterfaceNames() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    Return values
    - array|false + array<string|int, mixed>|false

    Array with names of the implemented interfaces or FALSE on -error or if there are no implemented interface names.

    +error or if there are no implemented interface names.

    + @@ -543,27 +610,28 @@
    Return values
    >

    findStartOfStatement() - +

    + 634 + +

    Returns the position of the first non-whitespace token in a statement.

    public - static findStartOfStatement(File $phpcsFile, int $start[, int|string|array $ignore = null ]) : int + static findStartOfStatement(File $phpcsFile, int $start[, int|string|array<string|int, mixed> $ignore = null ]) : int

    PHPCS cross-version compatible version of the File::findStartOfStatement() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 2.1.0.
    • -
    • PHPCS 2.6.2: New optional $ignore parameter to selectively ignore stop points.
    • -
    • PHPCS 3.5.5: Added support for PHP 7.4 T_FN arrow functions.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -572,7 +640,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -580,15 +649,17 @@
    Parameters
    : int
    -

    The position to start searching from in the token stack.

    +

    The position to start searching from in the token stack.

    +
    $ignore - : int|string|array + : int|string|array<string|int, mixed> = null
    -

    Token types that should not be considered stop points.

    +

    Token types that should not be considered stop points.

    +
    @@ -604,24 +675,19 @@
    File::findStartOfStatement() -

    Original source.

    + +

    Original source.

    +
    -
    +
    since
    1.0.0 - -
    -
    - since -
    -
    - 1.0.0-alpha2 -

    Added BC support for PHP 7.4 arrow functions.

    - -
    + + +
    Return values
    @@ -638,34 +704,34 @@
    Return values
    >

    getClassProperties() - +

    + 555 + +

    Returns the implementation properties of a class.

    public - static getClassProperties(File $phpcsFile, int $stackPtr) : array + static getClassProperties(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

    The format of the return value is:

    array(
       'is_abstract' => false, // TRUE if the abstract keyword was found.
       'is_final'    => false, // TRUE if the final keyword was found.
    -);
    +); +

    PHPCS cross-version compatible version of the File::getClassProperties() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 1.3.0.
    • -
    • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to -\PHP_CodeSniffer\Exceptions\TokenizerException.
    • -
    • PHPCS 3.5.0: The Exception thrown changed from a \PHP_CodeSniffer\Exceptions\TokenizerException -to\PHP_CodeSniffer\Exceptions\RuntimeException.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -674,7 +740,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -683,7 +750,8 @@
    Parameters

    The position in the stack of the T_CLASS -token to acquire the properties for.

    +token to acquire the properties for.

    +
    @@ -699,37 +767,44 @@
    File::getClassProperties() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - ObjectDeclarations::getClassProperties() -

    PHPCSUtils native improved version.

    + ObjectDeclarations::getClassProperties() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    throws
    RuntimeException -

    If the specified position is not a -T_CLASS token.

    + +

    If the specified position is not a +T_CLASS token.

    +
    -
    +
    Return values
    - array + array<string|int, mixed> — @@ -742,27 +817,28 @@
    Return values
    >

    getCondition() - +

    + 713 + +

    Return the position of the condition for the passed token.

    public - static getCondition(File $phpcsFile, int $stackPtr, int|string $type[, bool $first = true ]) : int|false + static getCondition(File $phpcsFile, int $stackPtr, int|string $type[, bool $first = true ]) : int|false

    PHPCS cross-version compatible version of the File::getCondition() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 1.3.0.
    • -
    • PHPCS 3.5.4: New $first parameter which allows for the closest matching token to be returned. -By default, it continues to return the first matched token found from the top of the file.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -771,7 +847,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -779,7 +856,8 @@
    Parameters
    : int
    -

    The position of the token we are checking.

    +

    The position of the token we are checking.

    +
    @@ -787,7 +865,8 @@
    Parameters
    : int|string
    -

    The type of token to search for.

    +

    The type of token to search for.

    +
    @@ -798,7 +877,8 @@
    Parameters

    If true, will return the matched condition furthest away from the passed token. If false, will return the matched condition -closest to the passed token.

    +closest to the passed token.

    +
    @@ -814,39 +894,37 @@
    File::getCondition() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - Conditions::getCondition() -

    More versatile alternative.

    + Conditions::getCondition() + +

    More versatile alternative.

    +
    -
    +
    since
    1.0.0 - -
    -
    - since -
    -
    - 1.0.0-alpha2 -

    Added support for the PHPCS 3.5.4 $first parameter.

    - -
    + + +
    Return values
    int|false

    Integer stack pointer to the condition or FALSE if the token -does not have the condition.

    +does not have the condition.

    + @@ -858,43 +936,28 @@
    Return values
    >

    getDeclarationName() - +

    + 98 + + -

    Returns the declaration names for classes, interfaces, traits, and functions.

    +

    Returns the declaration name for classes, interfaces, traits, enums, and functions.

    public - static getDeclarationName(File $phpcsFile, int $stackPtr) : string|null + static getDeclarationName(File $phpcsFile, int $stackPtr) : string|null

    PHPCS cross-version compatible version of the File::getDeclarationName() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • PHPCS 2.8.0: Returns null when passed an anonymous class. Previously, the method -would throw a "token not of an accepted type" exception.
    • -
    • PHPCS 2.9.0: Returns null when passed a PHP closure. Previously, the method -would throw a "token not of an accepted type" exception.
    • -
    • PHPCS 3.0.0: Added support for ES6 class/method syntax.
    • -
    • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to -\PHP_CodeSniffer\Exceptions\RuntimeException.
    • -
    • PHPCS 3.5.3: Allow for functions to be called fn for backwards compatibility. -Related to PHP 7.4 T_FN arrow functions.
    • -
    • PHPCS 3.5.5: Remove arrow function work-around which is no longer needed due to -a change in the tokenization of arrow functions.
    • +
    • The upstream method has received no significant updates since PHPCS 3.7.1.
    -

    Note:

    -
      -
    • For ES6 classes in combination with PHPCS 2.x, passing a T_STRING token to -this method will be accepted for JS files.
    • -
    • Support for JS ES6 method syntax has not been back-filled for PHPCS < 3.0.0. -and sniffing JS files is not officially supported by PHPCSUtils.
    • -
    +
    Parameters
    @@ -903,7 +966,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -913,7 +977,8 @@
    Parameters

    The position of the declaration token which declared the class, interface, -trait, or function.

    +trait, enum or function.

    +
    @@ -929,49 +994,50 @@
    File::getDeclarationName() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - ObjectDeclarations::getName() -

    PHPCSUtils native improved version.

    + ObjectDeclarations::getName() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    -
    - since -
    -
    - 1.0.0-alpha2 -

    Added BC support for PHP 7.4 arrow functions.

    - -
    + + +
    throws
    RuntimeException -

    If the specified token is not of type -T_FUNCTION, T_CLASS, T_TRAIT, or T_INTERFACE.

    + +

    If the specified token is not of type +T_FUNCTION, T_CLASS, T_ANON_CLASS, +T_CLOSURE, T_TRAIT, T_ENUM or T_INTERFACE.

    +
    -
    +
    Return values
    string|null — -

    The name of the class, interface, trait, or function; +

    The name of the class, interface, trait, enum, or function; or NULL if the function or class is anonymous or -in case of a parse error/live coding.

    +in case of a parse error/live coding.

    +
    @@ -983,55 +1049,43 @@
    Return values
    >

    getMemberProperties() - +

    + 519 + +

    Returns the visibility and implementation properties of a class member var.

    public - static getMemberProperties(File $phpcsFile, int $stackPtr) : array + static getMemberProperties(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

    The format of the return value is:

    array(
       'scope'           => string,  // Public, private, or protected.
       'scope_specified' => boolean, // TRUE if the scope was explicitly specified.
       'is_static'       => boolean, // TRUE if the static keyword was found.
    +  'is_readonly'     => boolean, // TRUE if the readonly keyword was found.
       'type'            => string,  // The type of the var (empty if no type specified).
       'type_token'      => integer, // The stack pointer to the start of the type
                                     // or FALSE if there is no type.
       'type_end_token'  => integer, // The stack pointer to the end of the type
                                     // or FALSE if there is no type.
    -  'nullable_type'   => boolean, // TRUE if the type is nullable.
    -);
    + 'nullable_type' => boolean, // TRUE if the type is preceded by the + // nullability operator. +); +

    PHPCS cross-version compatible version of the `File::getMemberProperties() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to -\PHP_CodeSniffer\Exceptions\TokenizerException.
    • -
    • PHPCS 3.4.0: Fixed method params being recognized as properties, PHPCS#2214.
    • -
    • PHPCS 3.5.0: New "type", "type_token", "type_end_token" and "nullable_type" array indexes. -
        -
      • The "type" index contains the type of the member var, or a blank string -if not specified.
      • -
      • If the type is nullable, "type" will contain the leading ?.
      • -
      • If a type is specified, the position of the first token in the type will -be set in a "type_token" array index.
      • -
      • If a type is specified, the position of the last token in the type will -be set in a "type_end_token" array index.
      • -
      • If the type is nullable, a "nullable_type" array index will also be set to true.
      • -
      • If the type contains namespace information, it will be cleaned of whitespace -and comments in the "type" value.
      • -
    • -
    • PHPCS 3.5.0: The Exception thrown changed from a \PHP_CodeSniffer\Exceptions\TokenizerException -to \PHP_CodeSniffer\Exceptions\RuntimeException.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -1040,7 +1094,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -1049,7 +1104,8 @@
    Parameters

    The position in the stack of the T_VARIABLE token to -acquire the properties for.

    +acquire the properties for.

    +
    @@ -1065,38 +1121,45 @@
    File::getMemberProperties() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - Variables::getMemberProperties() -

    PHPCSUtils native improved version.

    + Variables::getMemberProperties() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    throws
    RuntimeException -

    If the specified position is not a + +

    If the specified position is not a T_VARIABLE token, or if the position is not -a class member variable.

    +a class member variable.

    +
    -
    +
    Return values
    - array + array<string|int, mixed> — @@ -1109,19 +1172,20 @@
    Return values
    >

    getMethodParameters() - +

    + 171 + +

    Returns the method parameters for the specified function token.

    public - static getMethodParameters(File $phpcsFile, int $stackPtr) : array + static getMethodParameters(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

    Also supports passing in a T_USE token for a closure use group.

    Each parameter is in the following format:

    @@ -1129,6 +1193,7 @@

    'name' => '$var', // The variable name. 'token' => integer, // The stack pointer to the variable name. 'content' => string, // The full content of the variable definition. + 'has_attributes' => boolean, // Does the parameter have one or more attributes attached ? 'pass_by_reference' => boolean, // Is the variable passed by reference? 'reference_token' => integer, // The stack pointer to the reference operator // or FALSE if the param is not passed by reference. @@ -1140,54 +1205,30 @@

    // or FALSE if there is no type hint. 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint // or FALSE if there is no type hint. - 'nullable_type' => boolean, // TRUE if the var type is nullable. + 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability + // operator. 'comma_token' => integer, // The stack pointer to the comma after the param // or FALSE if this is the last param. -) +) +

    Parameters with default values have the following additional array indexes:

      'default'             => string,  // The full content of the default value.
       'default_token'       => integer, // The stack pointer to the start of the default value.
    -  'default_equal_token' => integer, // The stack pointer to the equals sign.
    + 'default_equal_token' => integer, // The stack pointer to the equals sign. + +

    Parameters declared using PHP 8 constructor property promotion, have these additional array indexes:

    +
      'property_visibility' => string,  // The property visibility as declared.
    +  'visibility_token'    => integer, // The stack pointer to the visibility modifier token.
    +  'property_readonly'   => bool,    // TRUE if the readonly keyword was found.
    +  'readonly_token'      => integer, // The stack pointer to the readonly modifier token.
    +

    PHPCS cross-version compatible version of the File::getMethodParameters() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • PHPCS 2.8.0: Now recognises self as a valid type declaration.
    • -
    • PHPCS 2.8.0: The return array now contains a new "token" index containing the stack pointer -to the variable.
    • -
    • PHPCS 2.8.0: The return array now contains a new "content" index containing the raw content -of the param definition.
    • -
    • PHPCS 2.8.0: Added support for nullable types. -The return array now contains a new "nullable_type" index set to true or false -for each method parameter.
    • -
    • PHPCS 2.8.0: Added support for closures.
    • -
    • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to -\PHP_CodeSniffer\Exceptions\TokenizerException.
    • -
    • PHPCS 3.3.0: The return array now contains a new "type_hint_token" array index. -Provides the position in the token stack of the first token in the type declaration.
    • -
    • PHPCS 3.3.1: Fixed incompatibility with PHP 7.3.
    • -
    • PHPCS 3.5.0: The Exception thrown changed from a \PHP_CodeSniffer\Exceptions\TokenizerException -to \PHP_CodeSniffer\Exceptions\RuntimeException.
    • -
    • PHPCS 3.5.0: Added support for closure USE groups.
    • -
    • PHPCS 3.5.0: The return array now contains yet more more information. -
        -
      • If a type hint is specified, the position of the last token in the hint will be -set in a "type_hint_end_token" array index.
      • -
      • If a default is specified, the position of the first token in the default value -will be set in a "default_token" array index.
      • -
      • If a default is specified, the position of the equals sign will be set in a -"default_equal_token" array index.
      • -
      • If the param is not the last, the position of the comma will be set in a -"comma_token" array index.
      • -
      • If the param is passed by reference, the position of the reference operator -will be set in a "reference_token" array index.
      • -
      • If the param is variable length, the position of the variadic operator will -be set in a "variadic_token" array index.
      • -
    • -
    • PHPCS 3.5.3: Fixed a bug where the "type_hint_end_token" array index for a type hinted -parameter would bleed through to the next (non-type hinted) parameter.
    • -
    • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions.
    • -

    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -1196,7 +1237,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -1205,7 +1247,8 @@
    Parameters

    The position in the stack of the function token -to acquire the parameters for.

    +to acquire the parameters for.

    +
    @@ -1221,46 +1264,65 @@
    File::getMethodParameters() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - FunctionDeclarations::getParameters() -

    PHPCSUtils native improved version.

    + FunctionDeclarations::getParameters() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    since
    1.0.0-alpha2 -

    Added BC support for PHP 7.4 arrow functions.

    + +

    Added support for PHP 7.4 arrow functions.

    +
    -
    + +
    + since +
    +
    + 1.0.0-alpha4 + +

    Added support for PHP 8.0 identifier name tokens.

    +
    + +
    throws
    RuntimeException -

    If the specified $stackPtr is not of + +

    If the specified $stackPtr is not of type T_FUNCTION, T_CLOSURE, T_USE, -or T_FN.

    +or T_FN.

    +
    -
    +
    Return values
    - array + array<string|int, mixed> — @@ -1273,57 +1335,45 @@
    Return values
    >

    getMethodProperties() - +

    + 473 + +

    Returns the visibility and implementation properties of a method.

    public - static getMethodProperties(File $phpcsFile, int $stackPtr) : array + static getMethodProperties(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

    The format of the return value is:

    array(
    -  'scope'                => 'public', // Public, private, or protected
    -  'scope_specified'      => true,     // TRUE if the scope keyword was found.
    -  'return_type'          => '',       // The return type of the method.
    -  'return_type_token'    => integer,  // The stack pointer to the start of the return type
    -                                      // or FALSE if there is no return type.
    -  'nullable_return_type' => false,    // TRUE if the return type is nullable.
    -  'is_abstract'          => false,    // TRUE if the abstract keyword was found.
    -  'is_final'             => false,    // TRUE if the final keyword was found.
    -  'is_static'            => false,    // TRUE if the static keyword was found.
    -  'has_body'             => false,    // TRUE if the method has a body
    -);
    + 'scope' => 'public', // Public, private, or protected + 'scope_specified' => true, // TRUE if the scope keyword was found. + 'return_type' => '', // The return type of the method. + 'return_type_token' => integer, // The stack pointer to the start of the return type + // or FALSE if there is no return type. + 'return_type_end_token' => integer, // The stack pointer to the end of the return type + // or FALSE if there is no return type. + 'nullable_return_type' => false, // TRUE if the return type is preceded by + // the nullability operator. + 'is_abstract' => false, // TRUE if the abstract keyword was found. + 'is_final' => false, // TRUE if the final keyword was found. + 'is_static' => false, // TRUE if the static keyword was found. + 'has_body' => false, // TRUE if the method has a body +); +

    PHPCS cross-version compatible version of the File::getMethodProperties() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • PHPCS 3.0.0: Removed the "is_closure" array index which was always false anyway.
    • -
    • PHPCS 3.0.0: The Exception thrown changed from a PHP_CodeSniffer_Exception to -\PHP_CodeSniffer\Exceptions\TokenizerException.
    • -
    • PHPCS 3.3.0: New "return_type", "return_type_token" and "nullable_return_type" array indexes. -
        -
      • The "return_type" index contains the return type of the function or closer, -or a blank string if not specified.
      • -
      • If the return type is nullable, the return type will contain the leading ?.
      • -
      • A "nullable_return_type" array index in the return value will also be set to true.
      • -
      • If the return type contains namespace information, it will be cleaned of -whitespace and comments.
      • -
      • To access the original return value string, use the main tokens array.
      • -
    • -
    • PHPCS 3.4.0: New "has_body" array index. -false if the method has no body (as with abstract and interface methods) -or true otherwise.
    • -
    • PHPCS 3.5.0: The Exception thrown changed from a \PHP_CodeSniffer\Exceptions\TokenizerException -to \PHP_CodeSniffer\Exceptions\RuntimeException.
    • -
    • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -1332,7 +1382,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -1341,7 +1392,8 @@
    Parameters

    The position in the stack of the function token to -acquire the properties for.

    +acquire the properties for.

    +
    @@ -1357,53 +1409,44 @@
    File::getMethodProperties() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - FunctionDeclarations::getProperties() -

    PHPCSUtils native improved version.

    + FunctionDeclarations::getProperties() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    -
    - since -
    -
    - 1.0.0-alpha2 -

    Added BC support for PHP 7.4 arrow functions.

    - -
    -
    - since -
    -
    - 1.0.0-alpha3 -

    Added support for PHP 8.0 static return type (expected in future PHPCS release).

    - -
    + + +
    throws
    RuntimeException -

    If the specified position is not a -T_FUNCTION, T_CLOSURE, or T_FN token.

    + +

    If the specified position is not a +T_FUNCTION, T_CLOSURE, or T_FN token.

    +
    -
    +
    Return values
    - array + array<string|int, mixed> — @@ -1416,34 +1459,29 @@
    Return values
    >

    getTokensAsString() - +

    + 610 + +

    Returns the content of the tokens from the specified start position in the token stack for the specified length.

    public - static getTokensAsString(File $phpcsFile, int $start, int $length[, bool $origContent = false ]) : string + static getTokensAsString(File $phpcsFile, int $start, int $length[, bool $origContent = false ]) : string

    PHPCS cross-version compatible version of the File::getTokensAsString() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • PHPCS 3.3.0: New $origContent parameter to optionally return original -(non tab-replaced) content.
    • -
    • PHPCS 3.4.0: -
        -
      • Now throws a RuntimeException if the $start param is invalid. -This stops an infinite loop when the function is passed invalid data.
      • -
      • If the $length param is invalid, an empty string will be returned.
      • -
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -1452,7 +1490,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -1460,7 +1499,8 @@
    Parameters
    : int
    -

    The position to start from in the token stack.

    +

    The position to start from in the token stack.

    +
    @@ -1468,7 +1508,8 @@
    Parameters
    : int
    -

    The length of tokens to traverse from the start pos.

    +

    The length of tokens to traverse from the start pos.

    +
    @@ -1477,7 +1518,8 @@
    Parameters
    = false

    Whether the original content or the tab replaced -content should be used.

    +content should be used.

    +
    @@ -1493,38 +1535,46 @@
    File::getTokensAsString() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - GetTokensAsString -

    Related set of functions.

    + GetTokensAsString + +

    Related set of functions.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    throws
    RuntimeException -

    If the specified start position does not exist.

    + +

    If the specified start position does not exist.

    +
    -
    +
    Return values
    string — -

    The token contents.

    +

    The token contents.

    +
    @@ -1536,26 +1586,28 @@
    Return values
    >

    hasCondition() - +

    + 683 + +

    Determine if the passed token has a condition of one of the passed types.

    public - static hasCondition(File $phpcsFile, int $stackPtr, int|string|array $types) : bool + static hasCondition(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $types) : bool

    PHPCS cross-version compatible version of the File::hasCondition() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • This method has received no significant code updates since PHPCS 2.6.0.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -1564,7 +1616,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -1572,15 +1625,17 @@
    Parameters
    : int
    -

    The position of the token we are checking.

    +

    The position of the token we are checking.

    +
    $types - : int|string|array + : int|string|array<string|int, mixed>
    -

    The type(s) of tokens to search for.

    +

    The type(s) of tokens to search for.

    +
    @@ -1596,24 +1651,29 @@
    File::hasCondition() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - Conditions::hasCondition() -

    PHPCSUtils native alternative.

    + Conditions::hasCondition() + +

    PHPCSUtils native alternative.

    +
    -
    +
    since
    1.0.0 - -
    + + +
    Return values
    @@ -1630,38 +1690,28 @@
    Return values
    >

    isReference() - +

    + 580 + +

    Determine if the passed token is a reference operator.

    public - static isReference(File $phpcsFile, int $stackPtr) : bool + static isReference(File $phpcsFile, int $stackPtr) : bool

    PHPCS cross-version compatible version of the File::isReference() method.

    Changelog for the PHPCS native function:

    • Introduced in PHPCS 0.0.5.
    • -
    • PHPCS 3.1.1: Bug fix: misidentification of reference vs bitwise operator, PHPCS#1604/#1609. -
        -
      • An array assignment of a calculated value with a bitwise and operator in it, -was being misidentified as a reference.
      • -
      • A calculated default value for a function parameter with a bitwise and operator -in it, was being misidentified as a reference.
      • -
      • New by reference was not recognized as a reference.
      • -
      • References to class properties with self::, parent::, static::, -namespace\ClassName::, classname:: were not recognized as references.
      • -
    • -
    • PHPCS 3.5.3: Added support for PHP 7.4 T_FN arrow functions returning by reference.
    • -
    • PHPCS 3.5.6: Bug fix: the reference operator for closures declared to return by reference was -not recognized as a reference. PHPCS#2977.
    • -
    +
  • The upstream method has received no significant updates since PHPCS 3.7.1.
  • + +
    Parameters
    @@ -1670,7 +1720,8 @@
    Parameters
    : File
    -

    The file being scanned.

    +

    The file being scanned.

    +
    @@ -1678,7 +1729,8 @@
    Parameters
    : int
    -

    The position of the T_BITWISE_AND token.

    +

    The position of the T_BITWISE_AND token.

    +
    @@ -1694,59 +1746,128 @@
    File::isReference() -

    Original source.

    + +

    Original source.

    +
    -
    +
    see
    - Operators::isReference() -

    PHPCSUtils native improved version.

    + Operators::isReference() + +

    PHPCSUtils native improved version.

    +
    -
    +
    since
    1.0.0 - -
    -
    - since -
    -
    - 1.0.0-alpha2 -

    Added BC support for PHP 7.4 arrow functions.

    - -
    + + +
    Return values
    bool

    TRUE if the specified token position represents a reference. -FALSE if the token represents a bitwise operator.

    +FALSE if the token represents a bitwise operator.

    + - -
    + + -

    Search results

    -
      -
    -
    + +
    +
    +
    +

    Search results

    + +
    +
    +
      +
      +
      +
      - +
      + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html index f3d20243..31571c11 100644 --- a/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html +++ b/docs/phpdoc/classes/PHPCSUtils-BackCompat-BCTokens.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
      -

      PHPCSUtils

      - -
      - -
      -
      -

      Token arrays related utility methods.

      -

      PHPCS provides a number of static token arrays in the \PHP_CodeSniffer\Util\Tokens +

      PHPCS provides a number of static token arrays in the Tokens class. Some of these token arrays will not be available in older PHPCS versions. Some will not contain the same set of tokens across PHPCS versions.

      @@ -100,12 +155,17 @@

      across PHPCS versions.

      The names of the PHPCS native token arrays translate one-on-one to the methods in this class:

        -
      • PHP_CodeSniffer\Util\Tokens::$emptyTokens => PHPCSUtils\BackCompat\BCTokens::emptyTokens()
      • -
      • PHP_CodeSniffer\Util\Tokens::$operators => PHPCSUtils\BackCompat\BCTokens::operators()
      • +
      • +PHP_CodeSniffer\Util\Tokens::$emptyTokens => PHPCSUtils\BackCompat\BCTokens::emptyTokens() +
      • +
      • +PHP_CodeSniffer\Util\Tokens::$operators => PHPCSUtils\BackCompat\BCTokens::operators() +
      • ... etc

      The order of the tokens in the arrays may differ between the PHPCS native token arrays and -the token arrays returned by this class.

      +the token arrays returned by this class.

      +
      @@ -118,8 +178,19 @@
      1.0.0 - -
      + + + +
      + since +
      +
      + 1.0.0-alpha4 + +

      Dropped support for PHPCS < 3.7.1.

      +
      + +
      @@ -133,167 +204,181 @@

      -
      - __callStatic() +
      + __callStatic() -  : array +  : array<string|int, mixed>
      Handle calls to (undeclared) methods for token arrays which haven't received any -changes since PHPCS 2.6.0.
      +changes since PHPCS 3.7.1.
      - arithmeticTokens() + arithmeticTokens() -  : array +  : array<string|int, mixed>
      -
      Tokens that represent arithmetic operators.
      +
      - assignmentTokens() + assignmentTokens() -  : array +  : array<string|int, mixed>
      -
      Tokens that represent assignment operators.
      +
      - blockOpeners() + blockOpeners() -  : array +  : array<string|int, mixed>
      - booleanOperators() + booleanOperators() -  : array +  : array<string|int, mixed>
      - bracketTokens() + bracketTokens() -  : array +  : array<string|int, mixed>
      - castTokens() + castTokens() -  : array +  : array<string|int, mixed>
      - commentTokens() + commentTokens() -  : array +  : array<string|int, mixed>
      - comparisonTokens() + comparisonTokens() -  : array +  : array<string|int, mixed>
      -
      Tokens that represent comparison operators.
      +
      + +
      + contextSensitiveKeywords() + +  : array<string|int, mixed> +
      +
      - emptyTokens() + emptyTokens() -  : array +  : array<string|int, mixed>
      - equalityTokens() + equalityTokens() -  : array +  : array<string|int, mixed>
      - functionNameTokens() + functionNameTokens() -  : array +  : array<string|int, mixed>
      Tokens that represent the names of called functions.
      - heredocTokens() + heredocTokens() -  : array +  : array<string|int, mixed>
      - includeTokens() + includeTokens() -  : array +  : array<string|int, mixed>
      - methodPrefixes() + magicConstants() -  : array +  : array<string|int, mixed>
      - ooScopeTokens() + methodPrefixes() -  : array +  : array<string|int, mixed>
      -
      Tokens that open class and object scopes.
      +
      - operators() + ooScopeTokens() -  : array +  : array<string|int, mixed>
      -
      Tokens that perform operations.
      +
      - parenthesisOpeners() + operators() -  : array +  : array<string|int, mixed>
      -
      Token types that open parentheses.
      +
      - phpcsCommentTokens() + parenthesisOpeners() -  : array +  : array<string|int, mixed>
      -
      Tokens that are comments containing PHPCS instructions.
      +
      - scopeModifiers() + phpcsCommentTokens() -  : array +  : array<string|int, mixed>
      - scopeOpeners() + scopeModifiers() -  : array +  : array<string|int, mixed>
      - stringTokens() + scopeOpeners() -  : array +  : array<string|int, mixed>
      - textStringTokens() + stringTokens() -  : array +  : array<string|int, mixed>
      -
      Tokens that represent text strings.
      +
      + +
      + textStringTokens() + +  : array<string|int, mixed> +
      +
      @@ -306,7 +391,7 @@

      Methods - +

      >

      __callStatic() - +

      + 90 + +

      Handle calls to (undeclared) methods for token arrays which haven't received any -changes since PHPCS 2.6.0.

      +changes since PHPCS 3.7.1.

      public - static __callStatic(string $name, array $args) : array + static __callStatic(string $name, array<string|int, mixed> $args) : array<string|int, mixed>
      Parameters
      @@ -339,16 +425,18 @@
      Parameters
      : string
      -

      The name of the method which has been called.

      +

      The name of the method which has been called.

      +
      $args - : array + : array<string|int, mixed>

      Any arguments passed to the method. -Unused as none of the methods take arguments.

      +Unused as none of the methods take arguments.

      +
      @@ -364,14 +452,26 @@

      1.0.0 - -
      + + + +
      + throws +
      +
      + InvalidTokenArray + +

      When an invalid token array is requested.

      +
      + +
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array

      +

      <int|string> => <int|string> Token array

      +
      @@ -383,58 +483,30 @@
      Return values
      >

      arithmeticTokens() - +

      + 0 -

      Tokens that represent arithmetic operators.

      + + public - static arithmeticTokens() : array + static arithmeticTokens() : array<string|int, mixed> -

      Retrieve the PHPCS arithmetic tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 0.5.0.
      • -
      • PHPCS 2.9.0: The PHP 5.6 T_POW token was added to the array. -The T_POW token was introduced in PHPCS 2.4.0.
      • -
      +

      Tokens that represent arithmetic operators.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$arithmeticTokens -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array or an empty array for PHPCS versions in -which the PHPCS native comment tokens did not exist yet.

      - +
      Return values >

      assignmentTokens() - +

      + 0 -

      Tokens that represent assignment operators.

      + + public - static assignmentTokens() : array + static assignmentTokens() : array<string|int, mixed> -

      Retrieve the PHPCS assignment tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 0.0.5.
      • -
      • PHPCS 2.9.0: The PHP 7.4 T_COALESCE_EQUAL token was added to the array. -The T_COALESCE_EQUAL token was introduced in PHPCS 2.8.1.
      • -
      • PHPCS 3.2.0: The JS T_ZSR_EQUAL token was added to the array. -The T_ZSR_EQUAL token was introduced in PHPCS 2.8.0.
      • -
      +

      Tokens that represent assignments.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$assignmentTokens -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      - +
      Return values >

      blockOpeners() - +

      + + public - static blockOpeners() : array + static blockOpeners() : array<string|int, mixed> -

      Tokens that open code blocks.

      +

      Tokens that open code blocks.

      +
      Return values
      - array + array<string|int, mixed> — @@ -540,26 +585,28 @@
      Return values
      >

      booleanOperators() - +

      + + public - static booleanOperators() : array + static booleanOperators() : array<string|int, mixed> -

      Tokens that perform boolean operations.

      +

      Tokens that perform boolean operations.

      +
      Return values
      - array + array<string|int, mixed> — @@ -572,26 +619,28 @@
      Return values
      >

      bracketTokens() - +

      + + public - static bracketTokens() : array + static bracketTokens() : array<string|int, mixed> -

      Tokens that represent brackets and parenthesis.

      +

      Tokens that represent brackets and parenthesis.

      +
      Return values
      - array + array<string|int, mixed> — @@ -604,26 +653,28 @@
      Return values
      >

      castTokens() - +

      + + public - static castTokens() : array + static castTokens() : array<string|int, mixed> -

      Tokens that represent type casting.

      +

      Tokens that represent type casting.

      +
      Return values
      - array + array<string|int, mixed> — @@ -636,26 +687,28 @@
      Return values
      >

      commentTokens() - +

      + + public - static commentTokens() : array + static commentTokens() : array<string|int, mixed> -

      Tokens that are comments.

      +

      Tokens that are comments.

      +
      Return values
      - array + array<string|int, mixed> — @@ -668,60 +721,65 @@
      Return values
      >

      comparisonTokens() - +

      + 0 -

      Tokens that represent comparison operators.

      + + public - static comparisonTokens() : array + static comparisonTokens() : array<string|int, mixed> -

      Retrieve the PHPCS comparison tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 0.5.0.
      • -
      • PHPCS 2.9.0: The PHP 7.0 T_COALESCE token was added to the array. -The T_COALESCE token was introduced in PHPCS 2.6.1.
      • -
      • PHPCS 2.9.0: The PHP 7.0 T_SPACESHIP token was added to the array. -The T_SPACESHIP token was introduced in PHPCS 2.5.1.
      • -
      +

      Tokens that represent comparison operator.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$comparisonTokens -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      + + +
      +
      +

      + contextSensitiveKeywords() + +

      + + + + + public + static contextSensitiveKeywords() : array<string|int, mixed> + +

      Tokens representing context sensitive keywords in PHP.

      +
      + + +
      Return values
      + array<string|int, mixed> + — + +
      Return values >

      emptyTokens() - +

      + + public - static emptyTokens() : array + static emptyTokens() : array<string|int, mixed> -

      Tokens that don't represent code.

      +

      Tokens that don't represent code.

      +
      Return values
      - array + array<string|int, mixed> — @@ -763,26 +823,28 @@
      Return values
      >

      equalityTokens() - +

      + + public - static equalityTokens() : array + static equalityTokens() : array<string|int, mixed> -

      Tokens that represent equality comparisons.

      +

      Tokens that represent equality comparisons.

      +
      Return values
      - array + array<string|int, mixed> — @@ -795,26 +857,29 @@
      Return values
      >

      functionNameTokens() - +

      + 116 + +

      Tokens that represent the names of called functions.

      public - static functionNameTokens() : array + static functionNameTokens() : array<string|int, mixed>

      Retrieve the PHPCS function name tokens array in a cross-version compatible manner.

      Changelog for the PHPCS native array:

      • Introduced in PHPCS 2.3.3.
      • -
      • PHPCS 3.1.0: T_SELF and T_STATIC added to the array.
      • -
      +
    • PHPCS 3.7.2: T_PARENT added to the array.
    • +
    • PHPCS 4.0.0: T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED and T_NAME_RELATIVE added to the array.
    • + + @@ -828,22 +893,26 @@
      Tokens::$functionNameTokens -

      Original array.

      + +

      Original array.

      +
      -
      +
      since
      1.0.0 - -
      + + +
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      +

      <int|string> => <int|string> Token array.

      +
      @@ -855,26 +924,28 @@
      Return values
      >

      heredocTokens() - +

      + + public - static heredocTokens() : array + static heredocTokens() : array<string|int, mixed> -

      Tokens that make up a heredoc string.

      +

      Tokens that make up a heredoc string.

      +
      Return values
      - array + array<string|int, mixed> — @@ -887,26 +958,62 @@
      Return values
      >

      includeTokens() - +

      + + public - static includeTokens() : array + static includeTokens() : array<string|int, mixed> -

      Tokens that include files.

      +

      Tokens that include files.

      +
      Return values
      - array + array<string|int, mixed> + — + + + +
      +

      + magicConstants() + +

      + + + + + public + static magicConstants() : array<string|int, mixed> + +

      Tokens representing PHP magic constants.

      +
      + + + + +
      Return values
      + array<string|int, mixed> — @@ -919,26 +1026,28 @@
      Return values
      >

      methodPrefixes() - +

      + + public - static methodPrefixes() : array + static methodPrefixes() : array<string|int, mixed> -

      Tokens that can prefix a method name.

      +

      Tokens that can prefix a method name.

      +
      Return values
      - array + array<string|int, mixed> — @@ -951,55 +1060,30 @@
      Return values
      >

      ooScopeTokens() - +

      + 0 -

      Tokens that open class and object scopes.

      + + public - static ooScopeTokens() : array + static ooScopeTokens() : array<string|int, mixed> -

      Retrieve the OO scope tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 3.1.0.
      • -
      +

      Tokens that open class and object scopes.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$ooScopeTokens -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      - +
      Return values >

      operators() - +

      + 0 -

      Tokens that perform operations.

      + + public - static operators() : array + static operators() : array<string|int, mixed> -

      Retrieve the PHPCS operator tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 0.0.5.
      • -
      • PHPCS 2.6.1: The PHP 7.0 T_COALESCE token was backfilled and added to the array.
      • -
      • PHPCS 2.8.1: The PHP 7.4 T_COALESCE_EQUAL token was backfilled and (incorrectly) -added to the array.
      • -
      • PHPCS 2.9.0: The T_COALESCE_EQUAL token was removed from the array.
      • -
      +

      Tokens that perform operations.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$operators -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      - +
      Return values >

      parenthesisOpeners() - +

      + 0 -

      Token types that open parentheses.

      + + public - static parenthesisOpeners() : array + static parenthesisOpeners() : array<string|int, mixed> -

      Retrieve the PHPCS parenthesis openers tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 0.0.5.
      • -
      • PHPCS 3.5.0: T_LIST and T_ANON_CLASS added to the array.
      • -
      -

      Note: While T_LIST and T_ANON_CLASS will be included in the return value for this -method, the associated parentheses will not have the 'parenthesis_owner' index set -until PHPCS 3.5.0. Use the \PHPCSUtils\Utils\Parentheses::getOwner() -or \PHPCSUtils\Utils\Parentheses::hasOwner() methods if you need to check for -a T_LIST or T_ANON_CLASS parentheses owner.

      +

      Token types that open parenthesis.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$parenthesisOpeners -

      Original array.

      - -
      -
      - see -
      -
      - Parentheses -

      Class holding utility methods for -working with the 'parenthesis_...' -index keys in a token array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      - +
      Return values >

      phpcsCommentTokens() - +

      + 0 -

      Tokens that are comments containing PHPCS instructions.

      + + public - static phpcsCommentTokens() : array + static phpcsCommentTokens() : array<string|int, mixed> -

      Retrieve the PHPCS comment tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 3.2.3. The PHPCS comment tokens, however, were introduced in -PHPCS 3.2.0.
      • -
      +

      Tokens that are comments containing PHPCS instructions.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$phpcsCommentTokens -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <string> => <string> Token array or an empty array for PHPCS -versions in which the PHPCS native annotation -tokens did not exist yet.

      - +
      Return values >

      scopeModifiers() - +

      + + public - static scopeModifiers() : array + static scopeModifiers() : array<string|int, mixed> -

      Tokens that represent scope modifiers.

      +

      Tokens that represent scope modifiers.

      +
      Return values
      - array + array<string|int, mixed> — @@ -1242,26 +1230,28 @@
      Return values
      >

      scopeOpeners() - +

      + + public - static scopeOpeners() : array + static scopeOpeners() : array<string|int, mixed> -

      Tokens that are allowed to open scopes.

      +

      Tokens that are allowed to open scopes.

      +
      Return values
      - array + array<string|int, mixed> — @@ -1274,28 +1264,30 @@
      Return values
      >

      stringTokens() - +

      + + public - static stringTokens() : array + static stringTokens() : array<string|int, mixed>

      Tokens that represent strings. -Note that T_STRINGS are NOT represented in this list as this list -is about text strings.

      +Note that T_STRINGs are NOT represented in this list as this list +is about text strings.

      +
      Return values
      - array + array<string|int, mixed> — @@ -1308,74 +1300,120 @@
      Return values
      >

      textStringTokens() - +

      + 0 -

      Tokens that represent text strings.

      + + public - static textStringTokens() : array + static textStringTokens() : array<string|int, mixed> -

      Retrieve the PHPCS text string tokens array in a cross-version compatible manner.

      -

      Changelog for the PHPCS native array:

      -
        -
      • Introduced in PHPCS 2.9.0.
      • -
      +

      Tokens that represent text strings.

      +
      -
      - Tags - -
      -
      -
      - see -
      -
      - Tokens::$textStringTokens -

      Original array.

      - -
      -
      - since -
      -
      - 1.0.0 - -
      -
      Return values
      - array + array<string|int, mixed> — -

      <int|string> => <int|string> Token array.

      - +
      - -
      + + -

      Search results

      -
        -
      -
      + +
      +
      +
      +

      Search results

      + +
      +
      +
        +
        +
        +
        - +
        + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html b/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html index cd707a24..d85492c5 100644 --- a/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html +++ b/docs/phpdoc/classes/PHPCSUtils-BackCompat-Helper.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
        -

        PHPCSUtils

        - -
        - -
        -
        -

        Utility methods to retrieve (configuration) information from PHP_CodeSniffer.

        -

        PHP_CodeSniffer cross-version compatibility helper for PHPCS 2.x vs PHPCS 3.x.

        -

        A number of PHPCS classes were split up into several classes in PHPCS 3.x -Those classes cannot be aliased as they don't represent the same object. -This class provides helper methods for functions which were contained in -one of these classes and which are commonly used by external standards.

        +

        PHP_CodeSniffer cross-version compatibility helper.

        +
        @@ -103,10 +155,22 @@
        1.0.0 -

        The initial methods in this class have been ported over from -the external PHPCompatibility & WPCS standards.

        + +

        The initial methods in this class have been ported over from +the external PHPCompatibility & WPCS standards.

        +
        + +
        +
        + since +
        +
        + 1.0.0-alpha4 + +

        Dropped support for PHPCS < 3.7.1.

        +
        -
        + @@ -121,60 +185,60 @@

        - DEFAULT_TABWIDTH + DEFAULT_TABWIDTH -  = 4 +  = 4
        The default tab width used by PHP_CodeSniffer.
        -
        - getCommandLineData() +
        + getCommandLineData() -  : string|null +  : string|null
        Get the value of a CLI overrulable single PHP_CodeSniffer config key.
        - getConfigData() + getConfigData() -  : string|null +  : string|null
        Get the value of a single PHP_CodeSniffer config key.
        - getEncoding() + getEncoding() -  : string +  : string
        Get the applicable (file) encoding as passed to PHP_CodeSniffer from the command-line or the ruleset.
        - getTabWidth() + getTabWidth() -  : int +  : int
        Get the applicable tab width as passed to PHP_CodeSniffer from the command-line or the ruleset.
        - getVersion() + getVersion() -  : string +  : string
        Get the PHP_CodeSniffer version number.
        - ignoreAnnotations() + ignoreAnnotations() -  : bool +  : bool
        Check whether the "--ignore-annotations" option is in effect.
        - setConfigData() + setConfigData() -  : bool +  : bool
        Pass config data to PHP_CodeSniffer.
        @@ -186,25 +250,26 @@

        Constants - +

        DEFAULT_TABWIDTH - +

        + 36 + +

        The default tab width used by PHP_CodeSniffer.

        public - int + int DEFAULT_TABWIDTH = 4 @@ -212,6 +277,7 @@

        +

        Tags @@ -222,8 +288,9 @@
        1.0.0 - -
        + + +

        @@ -234,7 +301,7 @@

        Methods - +

        >

        getCommandLineData() - +

        + 113 + +

        Get the value of a CLI overrulable single PHP_CodeSniffer config key.

        public - static getCommandLineData(File $phpcsFile, string $key) : string|null + static getCommandLineData(File $phpcsFile, string $key) : string|null

        Use this for config keys which can be set in the CodeSniffer.conf file, -on the command-line or in a ruleset.

        +on the command-line or in a ruleset.

        +
        Parameters
        @@ -268,7 +337,8 @@
        Parameters
        : File
        -

        The file being processed.

        +

        The file being processed.

        +
        @@ -276,7 +346,8 @@
        Parameters
        : string
        -

        The name of the config value.

        +

        The name of the config value.

        +
        @@ -292,8 +363,9 @@
        1.0.0 - -
        + + +
        Return values
        @@ -310,19 +382,20 @@
        Return values
        >

        getConfigData() - +

        + 95 + +

        Get the value of a single PHP_CodeSniffer config key.

        public - static getConfigData(string $key) : string|null + static getConfigData(string $key) : string|null
        Parameters
        @@ -332,7 +405,8 @@
        Parameters
        : string
        -

        The name of the config value.

        +

        The name of the config value.

        +
        @@ -347,18 +421,21 @@
        see
        - Helper::getCommandLineData() -

        Alternative for the same which is more reliable -if the $phpcsFile object is available.

        + Helper::getCommandLineData() + +

        Alternative for the same which is more reliable +if the $phpcsFile object is available.

        +
        -
        +
        since
        1.0.0 - -
        + + +
        Return values
        @@ -375,20 +452,21 @@
        Return values
        >

        getEncoding() - +

        + 153 + +

        Get the applicable (file) encoding as passed to PHP_CodeSniffer from the command-line or the ruleset.

        public - static getEncoding([File|null $phpcsFile = null ]) : string + static getEncoding([File|null $phpcsFile = null ]) : string
        Parameters
        @@ -398,7 +476,8 @@
        Parameters
        : File|null = null
        -

        Optional. The current file being processed.

        +

        Optional. The current file being processed.

        +
        @@ -414,15 +493,17 @@
        1.0.0-alpha3 - -
        + + +
        Return values
        string

        Encoding. Defaults to the PHPCS native default, which is 'utf-8' -for PHPCS 3.x and was 'iso-8859-1' for PHPCS 2.x.

        +for PHPCS 3.x.

        + @@ -434,20 +515,21 @@
        Return values
        >

        getTabWidth() - +

        + 132 + +

        Get the applicable tab width as passed to PHP_CodeSniffer from the command-line or the ruleset.

        public - static getTabWidth(File $phpcsFile) : int + static getTabWidth(File $phpcsFile) : int
        Parameters
        @@ -457,7 +539,8 @@
        Parameters
        : File
        -

        The file being processed.

        +

        The file being processed.

        +
        @@ -473,14 +556,16 @@
        1.0.0 - -
        + + +
        Return values
        int — -

        Tab width. Defaults to the PHPCS native default of 4.

        +

        Tab width. Defaults to the PHPCS native default of 4.

        +
        @@ -492,19 +577,20 @@
        Return values
        >

        getVersion() - +

        + 45 + +

        Get the PHP_CodeSniffer version number.

        public - static getVersion() : string + static getVersion() : string @@ -519,8 +605,9 @@
        1.0.0 - -
        + + +
        Return values
        @@ -537,19 +624,20 @@
        Return values
        >

        ignoreAnnotations() - +

        + 185 + +

        Check whether the "--ignore-annotations" option is in effect.

        public - static ignoreAnnotations([File|null $phpcsFile = null ]) : bool + static ignoreAnnotations([File|null $phpcsFile = null ]) : bool
        Parameters
        @@ -559,7 +647,8 @@
        Parameters
        : File|null = null
        -

        Optional. The current file being processed.

        +

        Optional. The current file being processed.

        +
        @@ -575,14 +664,16 @@
        1.0.0 - -
        + + +
        Return values
        bool — -

        TRUE if annotations should be ignored, FALSE otherwise.

        +

        TRUE if annotations should be ignored, FALSE otherwise.

        +
        @@ -594,19 +685,20 @@
        Return values
        >

        setConfigData() - +

        + 68 + +

        Pass config data to PHP_CodeSniffer.

        public - static setConfigData(string $key, string|null $value[, bool $temp = false ][, Config $config = null ]) : bool + static setConfigData(string $key, string|null $value[, bool $temp = false ][, Config $config = null ]) : bool
        Parameters
        @@ -616,7 +708,8 @@
        Parameters
        : string
        -

        The name of the config value.

        +

        The name of the config value.

        +
        @@ -625,7 +718,8 @@
        Parameters

        The value to set. If null, the config entry -is deleted, reverting it to the default value.

        +is deleted, reverting it to the default value.

        +
        @@ -634,7 +728,8 @@
        Parameters
        = false

        Set this config data temporarily for this script run. -This will not write the config data to the config file.

        +This will not write the config data to the config file.

        +
        @@ -646,7 +741,8 @@
        Parameters
        This parameter is required for PHPCS 4.x, optional for PHPCS 3.x and not possible to pass for PHPCS 2.x. Passing the $phpcsFile->config property should work -in PHPCS 3.x and higher.

        +in PHPCS 3.x and higher.

        + @@ -662,34 +758,107 @@
        1.0.0 - -
        + + +
        Return values
        bool — -

        Whether the setting of the data was successfull.

        +

        Whether the setting of the data was successfull.

        +
        - -
        + + -

        Search results

        -
          -
        -
        + +
        +
        +
        +

        Search results

        + +
        +
        +
          +
          +
          +
          - +
          + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Exceptions-InvalidTokenArray.html b/docs/phpdoc/classes/PHPCSUtils-Exceptions-InvalidTokenArray.html new file mode 100644 index 00000000..0fb2c5fa --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Exceptions-InvalidTokenArray.html @@ -0,0 +1,344 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
          +

          PHPCSUtils

          + + + + + +
          + +
          +
          + + + + +
          + + +
          +

          + InvalidTokenArray + + + extends RuntimeException + + +
          + in package + +
          + + +

          + + + +

          Exception thrown when an non-existent token array is requested.

          + + + +
          + Tags + +
          +
          +
          + since +
          +
          + 1.0.0-alpha4 + + +
          +
          + + + + + + +

          + Table of Contents + +

          + +
          +
          + create() + +  : InvalidTokenArray +
          +
          Create a new invalid token array exception with a standardized text.
          + +
          + + + + + + + +
          +

          + Methods + +

          +
          +

          + create() + +

          + + +

          Create a new invalid token array exception with a standardized text.

          + + + public + static create(string $name) : InvalidTokenArray + + +
          Parameters
          +
          +
          + $name + : string +
          +
          +

          The name of the token array requested.

          +
          + +
          +
          + + +
          + Tags + +
          +
          +
          + since +
          +
          + 1.0.0-alpha4 + + +
          +
          + +
          Return values
          + InvalidTokenArray + — + + +
          +
          + + + + +
          +
          +
          +
          +

          Search results

          + +
          +
          +
            +
            +
            +
            +
            +
            + + +
            + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestFileNotFound.html b/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestFileNotFound.html new file mode 100644 index 00000000..572b3357 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestFileNotFound.html @@ -0,0 +1,363 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
            +

            PHPCSUtils

            + + + + + +
            + +
            +
            + + + + +
            + + +
            +

            + TestFileNotFound + + + extends BadMethodCallException + + +
            + in package + +
            + + +

            + + + +

            Exception thrown when the UtilityMethodTestCase::getTargetToken() method is run without a +tokenized test case file being available.

            + + + +
            + Tags + +
            +
            +
            + since +
            +
            + 1.0.0-alpha4 + + +
            +
            + + + + + + +

            + Table of Contents + +

            + +
            +
            + __construct() + +  : void +
            +
            Create a new "test file not found" exception with a standardized text.
            + +
            + + + + + + + +
            +

            + Methods + +

            +
            +

            + __construct() + +

            + + +

            Create a new "test file not found" exception with a standardized text.

            + + + public + __construct([string $message = '' ], int $code[, Throwable|null $previous = null ]) : void + + +
            Parameters
            +
            +
            + $message + : string + = ''
            +
            +

            The Exception message to throw.

            +
            + +
            +
            + $code + : int +
            +
            +

            The Exception code.

            +
            + +
            +
            + $previous + : Throwable|null + = null
            +
            +

            The previous exception used for the exception chaining.

            +
            + +
            +
            + + +
            + Tags + +
            +
            +
            + since +
            +
            + 1.0.0-alpha4 + + +
            +
            + +
            Return values
            + void + — + + +
            +
            + + + + +
            +
            +
            +
            +

            Search results

            + +
            +
            +
              +
              +
              +
              +
              +
              + + +
              + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestMarkerNotFound.html b/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestMarkerNotFound.html new file mode 100644 index 00000000..fa4e9f61 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestMarkerNotFound.html @@ -0,0 +1,353 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
              +

              PHPCSUtils

              + + + + + +
              + +
              +
              + + + + +
              + + +
              +

              + TestMarkerNotFound + + + extends OutOfBoundsException + + +
              + in package + +
              + + +

              + + + +

              Exception thrown when a delimiter comment can not be found in a test case file.

              + + + +
              + Tags + +
              +
              +
              + since +
              +
              + 1.0.0-alpha4 + + +
              +
              + + + + + + +

              + Table of Contents + +

              + +
              +
              + create() + +  : TestMarkerNotFound +
              +
              Create a new "test marker not found" exception with a standardized text.
              + +
              + + + + + + + +
              +

              + Methods + +

              +
              +

              + create() + +

              + + +

              Create a new "test marker not found" exception with a standardized text.

              + + + public + static create(string $marker, string $file) : TestMarkerNotFound + + +
              Parameters
              +
              +
              + $marker + : string +
              +
              +

              The delimiter comment.

              +
              + +
              +
              + $file + : string +
              +
              +

              The file in which the delimiter was not found.

              +
              + +
              +
              + + +
              + Tags + +
              +
              +
              + since +
              +
              + 1.0.0-alpha4 + + +
              +
              + +
              Return values
              + TestMarkerNotFound + — + + +
              +
              + + + + +
              +
              +
              +
              +

              Search results

              + +
              +
              +
                +
                +
                +
                +
                +
                + + +
                + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestTargetNotFound.html b/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestTargetNotFound.html new file mode 100644 index 00000000..1f575981 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Exceptions-TestTargetNotFound.html @@ -0,0 +1,362 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                +

                PHPCSUtils

                + + + + + +
                + +
                +
                + + + + +
                + + +
                +

                + TestTargetNotFound + + + extends OutOfBoundsException + + +
                + in package + +
                + + +

                + + + +

                Exception thrown when a test target token can not be found in a test case file.

                + + + +
                + Tags + +
                +
                +
                + since +
                +
                + 1.0.0-alpha4 + + +
                +
                + + + + + + +

                + Table of Contents + +

                + +
                +
                + create() + +  : TestMarkerNotFound +
                +
                Create a new "test target token not found" exception with a standardized text.
                + +
                + + + + + + + +
                +

                + Methods + +

                +
                +

                + create() + +

                + + +

                Create a new "test target token not found" exception with a standardized text.

                + + + public + static create(string $marker, string $content, string $file) : TestMarkerNotFound + + +
                Parameters
                +
                +
                + $marker + : string +
                +
                +

                The delimiter comment.

                +
                + +
                +
                + $content + : string +
                +
                +

                The (optional) target token content.

                +
                + +
                +
                + $file + : string +
                +
                +

                The file in which the target token was not found.

                +
                + +
                +
                + + +
                + Tags + +
                +
                +
                + since +
                +
                + 1.0.0-alpha4 + + +
                +
                + +
                Return values
                + TestMarkerNotFound + — + + +
                +
                + + + + +
                +
                +
                +
                +

                Search results

                + +
                +
                +
                  +
                  +
                  +
                  +
                  +
                  + + +
                  + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html b/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html index 0db696f9..0aea13fb 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html +++ b/docs/phpdoc/classes/PHPCSUtils-Fixers-SpacesFixer.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                  -

                  PHPCSUtils

                  - -
                  - -
                  -
                  -

                  Utility to check and, if necessary, fix the whitespace between two tokens.

                  @@ -98,8 +153,9 @@
                  1.0.0 - -
                  + + + @@ -113,10 +169,10 @@

                  -
                  - checkAndFix() +
                  + checkAndFix() -  : void +  : void
                  Check the whitespace between two tokens, throw an error if it doesn't match the expected whitespace and if relevant, fix it.
                  @@ -132,7 +188,7 @@

                  Methods - +

                  >

                  checkAndFix() - +

                  + +

                  Check the whitespace between two tokens, throw an error if it doesn't match the expected whitespace and if relevant, fix it.

                  public - static checkAndFix(File $phpcsFile, int $stackPtr, int $secondPtr, string|int $expectedSpaces, string $errorTemplate[, string $errorCode = 'Found' ][, string $errorType = 'error' ], int $errorSeverity[, string $metricName = '' ]) : void + static checkAndFix(File $phpcsFile, int $stackPtr, int $secondPtr, string|int $expectedSpaces, string $errorTemplate[, string $errorCode = 'Found' ][, string $errorType = 'error' ], int $errorSeverity[, string $metricName = '' ]) : void

                  Note:

                    @@ -167,14 +224,15 @@

                  • If 'newline' is expected and multiple new lines are encountered, this will be accepted as valid. No assumptions are made about whether additional blank lines are allowed or not. -If exactly one line is desired, combine this fixer with the \PHPCSUtils\Fixers\BlankLineFixer +If exactly one line is desired, combine this fixer with the BlankLineFixer (upcoming).
                  • The fixer will not leave behind any trailing spaces on the original line when fixing to 'newline', but it will not correct existing trailing spaces when there already is a new line in place.
                  • This method can optionally record a metric for this check which will be displayed when the end-user requests the "info" report.
                  • -

                  + +

                  Parameters
                  @@ -183,7 +241,8 @@
                  Parameters
                  : File
                  -

                  The file being scanned.

                  +

                  The file being scanned.

                  +
                  @@ -192,7 +251,8 @@
                  Parameters

                  The position of the token which should be used -when reporting an issue.

                  +when reporting an issue.

                  +
                  @@ -202,8 +262,9 @@
                  Parameters

                  The stack pointer to the second token. This token can be before or after the $stackPtr, -but should only be seperated from the $stackPtr -by whitespace and/or comments/annotations.

                  +but should only be separated from the $stackPtr +by whitespace and/or comments/annotations.

                  +
                  @@ -216,7 +277,8 @@
                  Parameters
                  • (int) Number of spaces. Must be 0 or more.
                  • (string) 'newline'.
                  • -
                  + +
                  @@ -230,9 +292,12 @@
                  Parameters
                  "new line", so no need to include that in the template. This string should contain two placeholders:

                    -
                  • %1$s = expected spaces phrase.
                  • -
                  • %2$s = found spaces phrase.
                  • -
                  +
                • +%1$s = expected spaces phrase.
                • +
                • +%2$s = found spaces phrase.
                • + +
                  @@ -241,10 +306,11 @@
                  Parameters
                  = 'Found'

                  A violation code unique to the sniff message. -Defaults to "Found". +Defaults to "Found". It is strongly recommended to change this if this fixer is used for different errors in the -same sniff.

                  +same sniff.

                  +
                  @@ -253,7 +319,8 @@
                  Parameters
                  = 'error'

                  Optional. Whether to report the issue as a -"warning" or an "error". Defaults to "error".

                  +"warning" or an "error". Defaults to "error".

                  +
                  @@ -263,7 +330,8 @@
                  Parameters

                  Optional. The severity level for this message. A value of 0 will be converted into the default -severity level.

                  +severity level.

                  +
                  @@ -273,7 +341,8 @@
                  Parameters

                  Optional. The name of the metric to record. This can be a short description phrase. -Leave empty to not record metrics.

                  +Leave empty to not record metrics.

                  +
                  @@ -289,55 +358,137 @@
                  1.0.0 - -
                  + + +
                  throws
                  RuntimeException -

                  If the tokens passed do not exist or are whitespace -tokens.

                  + +

                  If the tokens passed do not exist or are whitespace +tokens.

                  +
                  -
                  +
                  throws
                  RuntimeException -

                  If $expectedSpaces is not a valid value.

                  + +

                  If $expectedSpaces is not a valid value.

                  +
                  -
                  +
                  throws
                  RuntimeException -

                  If the tokens passed are separated by more than just -empty (whitespace + comments/annotations) tokens.

                  + +

                  If the tokens passed are separated by more than just +empty (whitespace + comments/annotations) tokens.

                  +
                  -
                  +
                  +
                  Return values
                  + void + — + - -
                  + + -

                  Search results

                  -
                    -
                  -
                  + +
                  +
                  +
                  +

                  Search results

                  + +
                  +
                  +
                    +
                    +
                    +
                    - +
                    + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html b/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html index 57816530..ef8db937 100644 --- a/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html +++ b/docs/phpdoc/classes/PHPCSUtils-TestUtils-UtilityMethodTestCase.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                    -

                    PHPCSUtils

                    - -
                    - -
                    -
                    -

                    Base class for use when testing utility methods for PHP_CodeSniffer.

                    -

                    This class is compatible with PHP_CodeSniffer 2.x as well as 3.x.

                    -

                    This class is compatible with PHPUnit 4.5 - 9.x providing the PHPCSUtils +

                    This class is compatible with PHP_CodeSniffer 3.x and contains preliminary compatibility with 4.x +based on its currently known state/roadmap.

                    +

                    This class is compatible with PHPUnit 4.5 - 9.x providing the PHPCSUtils autoload file is included in the test bootstrap. For more information about that, please consult the project's README.

                    To allow for testing of tab vs space content, the tabWidth is set to 4 by default.

                    @@ -99,7 +155,8 @@

                    <?php
                     
                     /* testTestCaseDescription * /
                    -const BAR = false;
                    +const BAR = false; +

                    Test file path/to/ClassUnderTestUnitTest.php:

                    <?php
                     
                    @@ -144,18 +201,20 @@ 

                    array('/* testTestCaseDescription * /', false), ); } -}

                    +} +

                    Note:

                    • Remove the space between the comment closers * / for a working example.
                    • Each test case separator comment MUST start with /* test. -This is to allow the \PHPCSUtils\TestUtils\UtilityMethodTestCase::getTargetToken() method to +This is to allow the UtilityMethodTestCase::getTargetToken() method to distinquish between the test separation comments and comments which may be part of the test case.
                    • The test case file and unit test file should be placed in the same directory.
                    • For working examples using this abstract class, have a look at the unit tests for the PHPCSUtils utility functions themselves.
                    • -

                    + +
                    @@ -168,8 +227,19 @@
                    1.0.0 - -
                    + + + +
                    + since +
                    +
                    + 1.0.0-alpha4 + +

                    Dropped support for PHPCS < 3.7.1.

                    +
                    + +
                    @@ -183,84 +253,91 @@

                    -
                    - $caseFile +
                    + $caseFile -  : string +  : string
                    Full path to the test case file associated with the concrete test class.
                    - $fileExtension + $fileExtension -  : string +  : string
                    The file extension of the test case file (without leading dot).
                    - $phpcsFile + $phpcsFile -  : File +  : File
                    The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file.
                    - $phpcsVersion + $phpcsVersion -  : string +  : string
                    The PHPCS version the tests are being run on.
                    - $selectedSniff + $selectedSniff -  : array +  : array<string|int, mixed>
                    Set the name of a sniff to pass to PHPCS to limit the run (and force it to record errors).
                    - $tabWidth + $tabWidth -  : int +  : int
                    The tab width setting to use when tokenizing the file.
                    - expectPhpcsException() + expectPhpcsException() -  : void +  : void
                    Helper method to tell PHPUnit to expect a PHPCS Exception in a PHPUnit and PHPCS cross-version compatible manner.
                    - getTargetToken() + getTargetToken() -  : int +  : int
                    Get the token pointer for a target token based on a specific comment.
                    - resetTestFile() + resetTestFile() -  : void +  : void
                    -
                    Clean up after finished test.
                    +
                    Clean up after finished test by resetting all static properties to their default values.
                    - setUpTestFile() + setUpTestFile() -  : void +  : void
                    Initialize PHPCS & tokenize the test case file.
                    - skipJSCSSTestsOnPHPCS4() + skipJSCSSTestsOnPHPCS4() -  : void +  : void
                    Skip JS and CSS related tests on PHPCS 4.x.
                    +
                    + usesPhp8NameTokens() + +  : bool +
                    +
                    Check whether or not the PHP 8.0 identifier name tokens will be in use.
                    +
                    @@ -271,7 +348,7 @@

                    Properties - +

                    >

                    $caseFile - +

                    + 140 + +

                    Full path to the test case file associated with the concrete test class.

                    @@ -302,9 +380,11 @@

                    Optional. If left empty, the case file will be presumed to be in the same directory and named the same as the test class, but with an -"inc" file extension.

                    +"inc" file extension.

                    +

                    +

                    Tags @@ -315,8 +395,9 @@
                    1.0.0 - -
                    + + + @@ -329,15 +410,16 @@
                    >

                    $fileExtension - +

                    + 127 + +

                    The file extension of the test case file (without leading dot).

                    @@ -347,10 +429,12 @@

                    $fileExtension = 'inc' -

                    This allows concrete test classes to overrule the default "inc" with, for instance, -"js" or "css" when applicable.

                    +

                    This allows concrete test classes to overrule the default "inc" with, for instance, +"js" or "css" when applicable.

                    +
                    +

                    Tags @@ -361,8 +445,9 @@
                    1.0.0 - -
                    + + + @@ -375,15 +460,16 @@
                    >

                    $phpcsFile - +

                    + 160 + +

                    The \PHP_CodeSniffer\Files\File object containing the parsed contents of the test case file.

                    @@ -395,6 +481,7 @@

                    +

                    Tags @@ -405,8 +492,9 @@
                    1.0.0 - -
                    + + + @@ -419,15 +507,16 @@
                    >

                    $phpcsVersion - +

                    + 115 + +

                    The PHPCS version the tests are being run on.

                    @@ -439,6 +528,7 @@

                    +

                    Tags @@ -449,8 +539,9 @@
                    1.0.0-alpha3 - -
                    + + + @@ -463,30 +554,33 @@
                    >

                    $selectedSniff - +

                    + 174 + +

                    Set the name of a sniff to pass to PHPCS to limit the run (and force it to record errors).

                    protected - static array + static array<string|int, mixed> $selectedSniff = ['Dummy.Dummy.Dummy']

                    Normally, this propery won't need to be overloaded, but for utility methods which record violations and contain fixers, setting a dummy sniff name equal to the sniff name passed in the error code for addError()/addWarning() during the test, will allow for testing -the recording of these violations, as well as testing the fixer.

                    +the recording of these violations, as well as testing the fixer.

                    + +
                    Tags @@ -497,8 +591,9 @@
                    1.0.0 - -
                    + + + @@ -511,15 +606,16 @@
                    >

                    $tabWidth - +

                    + 151 + +

                    The tab width setting to use when tokenizing the file.

                    @@ -529,9 +625,11 @@

                    $tabWidth = 4 -

                    This allows for test case files to use a different tab width than the default.

                    +

                    This allows for test case files to use a different tab width than the default.

                    +
                    +

                    Tags @@ -542,8 +640,9 @@
                    1.0.0 - -
                    + + + @@ -552,7 +651,7 @@

                    Methods - +

                    >

                    expectPhpcsException() - +

                    + 407 + +

                    Helper method to tell PHPUnit to expect a PHPCS Exception in a PHPUnit and PHPCS cross-version compatible manner.

                    public - expectPhpcsException(string $msg[, string $type = 'runtime' ]) : void + expectPhpcsException(string $msg[, string $type = 'runtime' ]) : void
                    Parameters
                    @@ -585,7 +685,8 @@
                    Parameters
                    : string
                    -

                    The expected exception message.

                    +

                    The expected exception message.

                    +
                    @@ -594,7 +695,8 @@
                    Parameters
                    = 'runtime'

                    The PHPCS native exception type to expect. Either 'runtime' or 'tokenizer'. -Defaults to 'runtime'.

                    +Defaults to 'runtime'.

                    +
                    @@ -610,37 +712,43 @@
                    1.0.0 - -
                    + + + +
                    Return values
                    + void + — +

                    getTargetToken() - +

                    + 346 + +

                    Get the token pointer for a target token based on a specific comment.

                    public - getTargetToken(string $commentString, int|string|array $tokenType[, string $tokenContent = null ]) : int + static getTargetToken(string $commentString, int|string|array<string|int, mixed> $tokenType[, string $tokenContent = null ]) : int

                    Note: the test delimiter comment MUST start with /* test to allow this function to distinguish between comments used in a test and test delimiters.

                    -

                    If the delimiter comment is not found, the test will automatically be failed.

                    +
                    Parameters
                    @@ -650,15 +758,17 @@
                    Parameters

                    The complete delimiter comment to look for as a string. -This string should include the comment opener and closer.

                    +This string should include the comment opener and closer.

                    +
                    $tokenType - : int|string|array + : int|string|array<string|int, mixed>
                    -

                    The type of token(s) to look for.

                    +

                    The type of token(s) to look for.

                    +
                    @@ -666,7 +776,8 @@
                    Parameters
                    : string = null
                    -

                    Optional. The token content for the target token.

                    +

                    Optional. The token content for the target token.

                    +
                    @@ -682,8 +793,50 @@
                    1.0.0 - -
                    + + + +
                    + since +
                    +
                    + 1.0.0-alpha4 + +

                    Will throw an exception whether the delimiter comment or the target +token is not found.

                    +
                    + +
                    +
                    + since +
                    +
                    + 1.0.0-alpha4 + +

                    This method is now static, which allows for it to be used in "set up before class".

                    +
                    + +
                    +
                    + throws +
                    +
                    + TestMarkerNotFound + +

                    When the delimiter comment for the test was not found.

                    +
                    + +
                    +
                    + throws +
                    +
                    + TestTargetNotFound + +

                    When the target token cannot be found.

                    +
                    + +
                    Return values
                    @@ -700,22 +853,24 @@
                    Return values
                    >

                    resetTestFile() - +

                    + 294 -

                    Clean up after finished test.

                    + + +

                    Clean up after finished test by resetting all static properties to their default values.

                    public - static resetTestFile() : void + static resetTestFile() : void -

                    Note: This is a PHPUnit cross-version compatible \PHPUnit\Framework\TestCase::tearDownAfterClass() -method.

                    +

                    Note: This is a PHPUnit cross-version compatible TestCase::tearDownAfterClass() +method.

                    +
                    @@ -729,16 +884,22 @@
                    1.0.0 - -
                    + + +
                    afterClass
                    - -
                    + + + +
                    Return values
                    + void + — +
                    >

                    setUpTestFile() - +

                    + 193 + +

                    Initialize PHPCS & tokenize the test case file.

                    public - static setUpTestFile() : void + static setUpTestFile() : void

                    The test case file for a unit test class has to be in the same directory directory and use the same file name as the test class, using the .inc extension -or be explicitly set using the \PHPCSUtils\TestUtils\UtilityMethodTestCase::$fileExtension/ -\PHPCSUtils\TestUtils\UtilityMethodTestCase::$caseFile properties.

                    -

                    Note: This is a PHPUnit cross-version compatible \PHPUnit\Framework\TestCase::setUpBeforeClass() -method.

                    +or be explicitly set using the UtilityMethodTestCase::$fileExtension/ +UtilityMethodTestCase::$caseFile properties.

                    +

                    Note: This is a PHPUnit cross-version compatible TestCase::setUpBeforeClass() +method.

                    + @@ -782,16 +945,22 @@
                    1.0.0 - -
                    + + +
                    beforeClass
                    - -
                    + + + +
                    Return values
                    + void + — +
                    >

                    skipJSCSSTestsOnPHPCS4() - +

                    + 269 + +

                    Skip JS and CSS related tests on PHPCS 4.x.

                    public - skipJSCSSTestsOnPHPCS4() : void + skipJSCSSTestsOnPHPCS4() : void

                    PHPCS 4.x drops support for the JS and CSS tokenizers. This method takes care of automatically skipping tests involving JS/CSS case files when the tests are being run with PHPCS 4.x.

                    -

                    Note: This is a PHPUnit cross-version compatible \PHPUnit\Framework\TestCase::setUp() -method.

                    +

                    Note: This is a PHPUnit cross-version compatible TestCase::setUp() +method.

                    + @@ -834,35 +1005,165 @@
                    1.0.0-alpha3 - -
                    + + +
                    before
                    - -
                    + + + +
                    Return values
                    + void + — + + +
                    +
                    +

                    + usesPhp8NameTokens() + +

                    + + +

                    Check whether or not the PHP 8.0 identifier name tokens will be in use.

                    + + + public + static usesPhp8NameTokens() : bool + +

                    The expected token positions/token counts for certain tokens will differ depending +on whether the PHP 8.0 identifier name tokenization is used or the PHP < 8.0 +identifier name tokenization.

                    +

                    Tests can use this method to determine which flavour of tokenization to expect and +to set test expectations accordingly.

                    +
                    + + + +
                    + Tags + +
                    +
                    +
                    + since +
                    +
                    + 1.0.0 + + +
                    +
                    + +
                    Return values
                    + bool + — +
                    - -
                    + + -

                    Search results

                    -
                      -
                    -
                    + +
                    +
                    +
                    +

                    Search results

                    + +
                    +
                    +
                      +
                      +
                      +
                      - +
                      + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html b/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html index b6883d66..d582b7c5 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html +++ b/docs/phpdoc/classes/PHPCSUtils-Tokens-Collections.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                      -

                      PHPCSUtils

                      - -
                      - -
                      -
                      -

                      Collections of related tokens as often used and needed for sniffs.

                      These are additional "token groups" to compliment the ones available through the PHPCS -native \PHP_CodeSniffer\Util\Tokens class.

                      +native Tokens class.

                      +
                      @@ -100,24 +156,50 @@
                      Tokens -

                      PHPCS native token groups.

                      + +

                      PHPCS native token groups.

                      +
                      -
                      +
                      see
                      - BCTokens -

                      Backward compatible version of the PHPCS native token groups.

                      + BCTokens + +

                      Backward compatible version of the PHPCS native token groups.

                      +
                      -
                      +
                      since
                      1.0.0 - -
                      + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Dropped support for PHPCS < 3.7.1.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Direct property access is deprecated for forward-compatibility reasons. +Use the methods of the same name as the property instead.

                      +
                      + +
                      @@ -131,243 +213,481 @@

                      -
                      - $alternativeControlStructureSyntaxCloserTokens +
                      + $alternativeControlStructureSyntaxCloserTokens -  : array +  : array<string|int, mixed>
                      -
                      Alternative control structure syntax closer keyword tokens.
                      +
                      DEPRECATED: Tokens representing alternative control structure syntax closer keywords.
                      - $alternativeControlStructureSyntaxTokens + $alternativeControlStructureSyntaxTokens -  : array +  : array<string|int, mixed>
                      -
                      Control structures which can use the alternative control structure syntax.
                      +
                      DEPRECATED: Tokens for control structures which can use the alternative control structure syntax.
                      - $arrayTokens + $arrayTokens -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used to create arrays.
                      +
                      DEPRECATED: Tokens which are used to create arrays.
                      - $arrayTokensBC + $arrayTokensBC -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used to create arrays.
                      +
                      DEPRECATED: Tokens which are used to create arrays (PHPCS cross-version compatible).
                      - $classModifierKeywords + $classModifierKeywords -  : array +  : array<string|int, mixed>
                      -
                      Modifier keywords which can be used for a class declaration.
                      +
                      DEPRECATED: Modifier keywords which can be used for a class declaration.
                      - $closedScopes + $closedScopes -  : array +  : array<string|int, mixed>
                      -
                      List of tokens which represent "closed" scopes.
                      +
                      DEPRECATED: List of tokens which represent "closed" scopes.
                      - $controlStructureTokens + $controlStructureTokens -  : array +  : array<string|int, mixed>
                      -
                      Control structure tokens.
                      +
                      DEPRECATED: Control structure tokens.
                      - $incrementDecrementOperators + $incrementDecrementOperators -  : array +  : array<string|int, mixed>
                      -
                      Increment/decrement operator tokens.
                      +
                      DEPRECATED: Increment/decrement operator tokens.
                      - $listTokens + $listTokens -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used to create lists.
                      +
                      DEPRECATED: Tokens which are used to create lists.
                      - $listTokensBC + $listTokensBC -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used to create lists.
                      +
                      DEPRECATED: Tokens which are used to create lists (PHPCS cross-version compatible).
                      - $magicConstants + $magicConstants -  : array +  : array<string|int, mixed>
                      -
                      Tokens for the PHP magic constants.
                      +
                      DEPRECATED: Tokens for the PHP magic constants.
                      - $namespaceDeclarationClosers + $namespaceDeclarationClosers -  : array +  : array<string|int, mixed>
                      -
                      List of tokens which can end a namespace declaration statement.
                      +
                      DEPRECATED: List of tokens which can end a namespace declaration statement.
                      - $objectOperators + $objectOperators -  : array +  : array<string|int, mixed>
                      -
                      Object operators.
                      +
                      DEPRECATED: Object operator tokens.
                      - $OOCanExtend + $OOCanExtend -  : array +  : array<string|int, mixed>
                      -
                      OO structures which can use the "extends" keyword.
                      +
                      DEPRECATED: OO structures which can use the "extends" keyword.
                      - $OOCanImplement + $OOCanImplement -  : array +  : array<string|int, mixed>
                      -
                      OO structures which can use the "implements" keyword.
                      +
                      DEPRECATED: OO structures which can use the "implements" keyword.
                      - $OOConstantScopes + $OOConstantScopes -  : array +  : array<string|int, mixed>
                      -
                      OO scopes in which constants can be declared.
                      +
                      DEPRECATED: OO scopes in which constants can be declared.
                      - $OOHierarchyKeywords + $OOHierarchyKeywords -  : array +  : array<string|int, mixed>
                      -
                      Tokens types used for "forwarding" calls within OO structures.
                      +
                      DEPRECATED: Tokens types used for "forwarding" calls within OO structures.
                      - $OONameTokens + $OONameTokens -  : array +  : array<string|int, mixed>
                      -
                      Tokens types which can be encountered in the fully/partially qualified name of an OO structure.
                      +
                      DEPRECATED: Tokens types which can be encountered in the fully/partially qualified name of an OO structure.
                      - $OOPropertyScopes + $OOPropertyScopes -  : array +  : array<string|int, mixed>
                      -
                      OO scopes in which properties can be declared.
                      +
                      DEPRECATED: OO scopes in which properties can be declared.
                      - $parameterTypeTokens + $parameterTypeTokens -  : array +  : array<string|int, mixed>
                      -
                      Token types which can be encountered in a parameter type declaration.
                      +
                      DEPRECATED: Token types which can be encountered in a parameter type declaration.
                      - $propertyModifierKeywords + $propertyModifierKeywords -  : array +  : array<string|int, mixed>
                      -
                      Modifier keywords which can be used for a property declaration.
                      +
                      DEPRECATED: Modifier keywords which can be used for a property declaration.
                      - $propertyTypeTokens + $propertyTypeTokens -  : array +  : array<string|int, mixed>
                      -
                      Token types which can be encountered in a property type declaration.
                      +
                      DEPRECATED: Token types which can be encountered in a property type declaration.
                      - $returnTypeTokens + $returnTypeTokens -  : array +  : array<string|int, mixed>
                      -
                      Token types which can be encountered in a return type declaration.
                      +
                      DEPRECATED: Token types which can be encountered in a return type declaration.
                      - $shortArrayTokens + $shortArrayTokens -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used for short arrays.
                      +
                      DEPRECATED: Tokens which are used for short arrays.
                      - $shortArrayTokensBC + $shortArrayTokensBC -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used for short arrays.
                      +
                      DEPRECATED: Tokens which are used for short arrays (PHPCS cross-version compatible).
                      - $shortListTokens + $shortListTokens -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used for short lists.
                      +
                      DEPRECATED: Tokens which are used for short lists.
                      - $shortListTokensBC + $shortListTokensBC -  : array +  : array<string|int, mixed>
                      -
                      Tokens which are used for short lists.
                      +
                      DEPRECATED: Tokens which are used for short lists (PHPCS cross-version compatible).
                      - $textStingStartTokens + $textStingStartTokens -  : array +  : array<string|int, mixed>
                      -
                      Tokens which can start a - potentially multi-line - text string.
                      +
                      DEPRECATED: Tokens which can start a - potentially multi-line - text string.
                      - arrowFunctionTokensBC() + __callStatic() + +  : array<string|int, mixed> +
                      +
                      Handle calls to (undeclared) methods for token arrays which don't need special handling.
                      + +
                      + alternativeControlStructureSyntaxClosers() + +  : array<string|int, mixed> +
                      +
                      Tokens representing alternative control structure syntax closer keywords.
                      + +
                      + alternativeControlStructureSyntaxes() + +  : array<string|int, mixed> +
                      +
                      Tokens for control structures which can use the alternative control structure syntax.
                      + +
                      + arrayOpenTokensBC() + +  : array<string|int, mixed> +
                      +
                      + +
                      + arrayTokens() + +  : array<string|int, mixed> +
                      +
                      + +
                      + arrayTokensBC() + +  : array<string|int, mixed> +
                      +
                      + +
                      + arrowFunctionTokensBC() + +  : array<string|int, mixed> +
                      +
                      DEPRECATED: Tokens which can represent the arrow function keyword.
                      + +
                      + classModifierKeywords() + +  : array<string|int, mixed> +
                      +
                      + +
                      + closedScopes() + +  : array<string|int, mixed> +
                      +
                      + +
                      + controlStructureTokens() + +  : array<string|int, mixed> +
                      +
                      + +
                      + functionCallTokens() + +  : array<string|int, mixed> +
                      +
                      Tokens which can represent function calls and function-call-like language constructs.
                      + +
                      + functionDeclarationTokens() + +  : array<string|int, mixed> +
                      +
                      + +
                      + functionDeclarationTokensBC() + +  : array<string|int, mixed> +
                      +
                      DEPRECATED: Tokens which represent a keyword which starts a function declaration.
                      + +
                      + incrementDecrementOperators() + +  : array<string|int, mixed> +
                      +
                      + +
                      + listTokens() + +  : array<string|int, mixed> +
                      +
                      + +
                      + listTokensBC() + +  : array<string|int, mixed> +
                      +
                      + +
                      + namespaceDeclarationClosers() + +  : array<string|int, mixed> +
                      +
                      + +
                      + namespacedNameTokens() + +  : array<string|int, mixed> +
                      +
                      Tokens types which can be encountered in a fully, partially or unqualified name.
                      + +
                      + nameTokens() + +  : array<string|int, mixed> +
                      +
                      + +
                      + objectOperators() + +  : array<string|int, mixed> +
                      +
                      + +
                      + ooCanExtend() + +  : array<string|int, mixed> +
                      +
                      OO structures which can use the "extends" keyword.
                      + +
                      + ooCanImplement() -  : array +  : array<string|int, mixed>
                      -
                      Tokens which can represent the arrow function keyword.
                      +
                      OO structures which can use the "implements" keyword.
                      + +
                      + ooConstantScopes() + +  : array<string|int, mixed> +
                      +
                      OO scopes in which constants can be declared.
                      + +
                      + ooHierarchyKeywords() + +  : array<string|int, mixed> +
                      +
                      Tokens types used for "forwarding" calls within OO structures.
                      + +
                      + ooPropertyScopes() + +  : array<string|int, mixed> +
                      +
                      OO scopes in which properties can be declared.
                      + +
                      + parameterPassingTokens() + +  : array<string|int, mixed> +
                      +
                      Tokens which can be passed to the methods in the PassedParameter class.
                      + +
                      + parameterTypeTokens() + +  : array<string|int, mixed> +
                      +
                      Token types which can be encountered in a parameter type declaration.
                      + +
                      + parameterTypeTokensBC() + +  : array<string|int, mixed> +
                      +
                      DEPRECATED: Token types which can be encountered in a parameter type declaration (cross-version).
                      + +
                      + phpOpenTags() + +  : array<string|int, mixed> +
                      +
                      + +
                      + propertyModifierKeywords() + +  : array<string|int, mixed> +
                      +
                      + +
                      + propertyTypeTokens() + +  : array<string|int, mixed> +
                      +
                      Token types which can be encountered in a property type declaration.
                      + +
                      + propertyTypeTokensBC() + +  : array<string|int, mixed> +
                      +
                      DEPRECATED: Token types which can be encountered in a property type declaration (cross-version).
                      + +
                      + returnTypeTokens() + +  : array<string|int, mixed> +
                      +
                      Token types which can be encountered in a return type declaration.
                      + +
                      + returnTypeTokensBC() + +  : array<string|int, mixed> +
                      +
                      DEPRECATED: Token types which can be encountered in a return type declaration (cross-version).
                      + +
                      + shortArrayListOpenTokensBC() + +  : array<string|int, mixed> +
                      +
                      - functionDeclarationTokens() + shortArrayTokens() -  : array +  : array<string|int, mixed>
                      -
                      Tokens which can represent a keyword which starts a function declaration.
                      +
                      - functionDeclarationTokensBC() + shortArrayTokensBC() -  : array +  : array<string|int, mixed>
                      -
                      Tokens which can represent a keyword which starts a function declaration.
                      +
                      - parameterTypeTokensBC() + shortListTokens() -  : array +  : array<string|int, mixed>
                      -
                      Token types which can be encountered in a parameter type declaration (cross-version).
                      +
                      - propertyTypeTokensBC() + shortListTokensBC() -  : array +  : array<string|int, mixed>
                      -
                      Token types which can be encountered in a property type declaration (cross-version).
                      +
                      - returnTypeTokensBC() + textStringStartTokens() -  : array +  : array<string|int, mixed>
                      -
                      Token types which can be encountered in a return type declaration (cross-version).
                      +
                      Tokens which can start a - potentially multi-line - text string.
                      @@ -379,36 +699,40 @@

                      Properties - +

                      $alternativeControlStructureSyntaxCloserTokens - +

                      + 91 -

                      Alternative control structure syntax closer keyword tokens.

                      + - +

                      DEPRECATED: Tokens representing alternative control structure syntax closer keywords.

                      + + public - static array + static array<string|int, mixed> $alternativeControlStructureSyntaxCloserTokens - = [T_ENDIF => T_ENDIF, T_ENDFOR => T_ENDFOR, T_ENDFOREACH => T_ENDFOREACH, T_ENDWHILE => T_ENDWHILE, T_ENDSWITCH => T_ENDSWITCH, T_ENDDECLARE => T_ENDDECLARE] + = [\T_ENDIF => \T_ENDIF, \T_ENDFOR => \T_ENDFOR, \T_ENDFOREACH => \T_ENDFOREACH, \T_ENDWHILE => \T_ENDWHILE, \T_ENDSWITCH => \T_ENDSWITCH, \T_ENDDECLARE => \T_ENDDECLARE]
                      +

                      =>

                      +
                      +
                      Tags @@ -420,8 +744,20 @@
                      1.0.0-alpha2 - -
                      + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::alternativeControlStructureSyntaxClosers() +method instead.

                      +
                      + +
                      @@ -430,29 +766,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $alternativeControlStructureSyntaxTokens - +

                      + 70 -

                      Control structures which can use the alternative control structure syntax.

                      + - +

                      DEPRECATED: Tokens for control structures which can use the alternative control structure syntax.

                      + + public - static array + static array<string|int, mixed> $alternativeControlStructureSyntaxTokens - = [T_IF => T_IF, T_ELSEIF => T_ELSEIF, T_ELSE => T_ELSE, T_FOR => T_FOR, T_FOREACH => T_FOREACH, T_SWITCH => T_SWITCH, T_WHILE => T_WHILE, T_DECLARE => T_DECLARE] + = [\T_IF => \T_IF, \T_ELSEIF => \T_ELSEIF, \T_ELSE => \T_ELSE, \T_FOR => \T_FOR, \T_FOREACH => \T_FOREACH, \T_SWITCH => \T_SWITCH, \T_WHILE => \T_WHILE, \T_DECLARE => \T_DECLARE]
                      +

                      =>

                      +
                      +
                      Tags @@ -464,8 +804,20 @@
                      1.0.0-alpha2 - -
                      + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::alternativeControlStructureSyntaxes() +method instead.

                      +
                      + +
                      @@ -474,29 +826,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $arrayTokens - +

                      + 138 -

                      Tokens which are used to create arrays.

                      + - +

                      DEPRECATED: Tokens which are used to create arrays.

                      + + public - static array + static array<string|int, mixed> $arrayTokens - = [T_ARRAY => T_ARRAY, T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY] + = [\T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -507,18 +863,53 @@
                      see
                      - Collections::$shortArrayTokens -

                      Related property containing only tokens used -for short arrays.

                      + Collections::arrayOpenTokensBC() + +

                      Related method to retrieve only the "open" tokens +used for arrays (PHPCS cross-version compatible).

                      +
                      + +
                      +
                      + see +
                      +
                      + Collections::arrayTokensBC() + +

                      Related method to retrieve tokens used +for arrays (PHPCS cross-version compatible).

                      +
                      + +
                      +
                      + see +
                      +
                      + Collections::shortArrayTokens() + +

                      Related method to retrieve only tokens used +for short arrays.

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::arrayTokens() method instead.

                      +
                      + +
                      @@ -527,30 +918,36 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $arrayTokensBC - +

                      + 162 -

                      Tokens which are used to create arrays.

                      + - +

                      DEPRECATED: Tokens which are used to create arrays (PHPCS cross-version compatible).

                      + + public - static array + static array<string|int, mixed> $arrayTokensBC - = [T_ARRAY => T_ARRAY, T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET => T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET] + = [\T_ARRAY => \T_ARRAY, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET]
                      + +

                      Includes T_OPEN_SQUARE_BRACKET and T_CLOSE_SQUARE_BRACKET to allow for handling +intermittent tokenizer issues related to the retokenization to T_OPEN_SHORT_ARRAY. +Should only be used selectively.

                      +
                      -

                      List which is backward-compatible with PHPCS < 3.3.0. -Should only be used selectively.

                      +

                      <int|string> => <int|string>

                      +
                      @@ -562,18 +959,42 @@
                      see
                      - Collections::$shortArrayTokensBC -

                      Related property containing only tokens used -for short arrays (cross-version).

                      + Collections::arrayOpenTokensBC() + +

                      Related method to retrieve only the "open" tokens +used for arrays (PHPCS cross-version compatible).

                      +
                      + +
                      +
                      + see +
                      +
                      + Collections::shortArrayTokensBC() + +

                      Related method to retrieve only tokens used +for short arrays (PHPCS cross-version compatible).

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::arrayTokensBC() method instead.

                      +
                      + +
                      @@ -582,29 +1003,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $classModifierKeywords - +

                      + 180 -

                      Modifier keywords which can be used for a class declaration.

                      + - +

                      DEPRECATED: Modifier keywords which can be used for a class declaration.

                      + + public - static array + static array<string|int, mixed> $classModifierKeywords - = [T_FINAL => T_FINAL, T_ABSTRACT => T_ABSTRACT] + = [\T_FINAL => \T_FINAL, \T_ABSTRACT => \T_ABSTRACT, \T_READONLY => \T_READONLY]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -615,9 +1040,30 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_READONLY token for PHP 8.2 readonly classes.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::classModifierKeywords() method instead.

                      +
                      + +
                      @@ -626,32 +1072,37 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $closedScopes - +

                      + 202 -

                      List of tokens which represent "closed" scopes.

                      + - +

                      DEPRECATED: List of tokens which represent "closed" scopes.

                      + + public - static array + static array<string|int, mixed> $closedScopes - = [T_CLASS => T_CLASS, T_ANON_CLASS => T_ANON_CLASS, T_INTERFACE => T_INTERFACE, T_TRAIT => T_TRAIT, T_FUNCTION => T_FUNCTION, T_CLOSURE => T_CLOSURE] + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, \T_TRAIT => \T_TRAIT, \T_ENUM => \T_ENUM, \T_FUNCTION => \T_FUNCTION, \T_CLOSURE => \T_CLOSURE]

                      I.e. anything declared within that scope - except for other closed scopes - is outside of the global namespace.

                      This list doesn't contain the T_NAMESPACE token on purpose as variables declared -within a namespace scope are still global and not limited to that namespace.

                      +within a namespace scope are still global and not limited to that namespace.

                      +
                      + +

                      <int|string> => <int|string>

                      +

                      @@ -663,9 +1114,30 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the PHP 8.1 T_ENUM token.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::closedScopes() method instead.

                      +
                      + +
                      @@ -674,29 +1146,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $controlStructureTokens - +

                      + 222 -

                      Control structure tokens.

                      + - +

                      DEPRECATED: Control structure tokens.

                      + + public - static array + static array<string|int, mixed> $controlStructureTokens - = [T_IF => T_IF, T_ELSEIF => T_ELSEIF, T_ELSE => T_ELSE, T_FOR => T_FOR, T_FOREACH => T_FOREACH, T_SWITCH => T_SWITCH, T_DO => T_DO, T_WHILE => T_WHILE, T_DECLARE => T_DECLARE] + = [\T_IF => \T_IF, \T_ELSEIF => \T_ELSEIF, \T_ELSE => \T_ELSE, \T_FOR => \T_FOR, \T_FOREACH => \T_FOREACH, \T_SWITCH => \T_SWITCH, \T_DO => \T_DO, \T_WHILE => \T_WHILE, \T_DECLARE => \T_DECLARE, \T_MATCH => \T_MATCH]
                      +

                      =>

                      +
                      +
                      Tags @@ -708,8 +1184,29 @@
                      1.0.0-alpha2 - -
                      + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_MATCH token for PHP 8.0 match expressions.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::controlStructureTokens() method instead.

                      +
                      + +
                      @@ -718,29 +1215,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $incrementDecrementOperators - +

                      + 257 -

                      Increment/decrement operator tokens.

                      + - +

                      DEPRECATED: Increment/decrement operator tokens.

                      + + public - static array + static array<string|int, mixed> $incrementDecrementOperators - = [T_DEC => T_DEC, T_INC => T_INC] + = [\T_DEC => \T_DEC, \T_INC => \T_INC]
                      +

                      =>

                      +
                      +
                      Tags @@ -752,8 +1253,19 @@
                      1.0.0-alpha3 - -
                      + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::incrementDecrementOperators() method instead.

                      +
                      + +
                      @@ -762,29 +1274,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $listTokens - +

                      + 276 -

                      Tokens which are used to create lists.

                      + - +

                      DEPRECATED: Tokens which are used to create lists.

                      + + public - static array + static array<string|int, mixed> $listTokens - = [T_LIST => T_LIST, T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY] + = [\T_LIST => \T_LIST, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -795,18 +1311,42 @@
                      see
                      - Collections::$shortListTokens -

                      Related property containing only tokens used -for short lists.

                      + Collections::listTokensBC() + +

                      Related method to retrieve tokens used +for lists (PHPCS cross-version).

                      +
                      + +
                      +
                      + see +
                      +
                      + Collections::shortListTokens() + +

                      Related method to retrieve only tokens used +for short lists.

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::listTokens() method instead.

                      +
                      + +
                      @@ -815,30 +1355,36 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $listTokensBC - +

                      + 298 -

                      Tokens which are used to create lists.

                      + - +

                      DEPRECATED: Tokens which are used to create lists (PHPCS cross-version compatible).

                      + + public - static array + static array<string|int, mixed> $listTokensBC - = [T_LIST => T_LIST, T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET => T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET] + = [\T_LIST => \T_LIST, \T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET]
                      + +

                      Includes T_OPEN_SQUARE_BRACKET and T_CLOSE_SQUARE_BRACKET to allow for handling +intermittent tokenizer issues related to the retokenization to T_OPEN_SHORT_ARRAY. +Should only be used selectively.

                      +
                      -

                      List which is backward-compatible with PHPCS < 3.3.0. -Should only be used selectively.

                      +

                      <int|string> => <int|string>

                      +
                      @@ -850,18 +1396,31 @@
                      see
                      - Collections::$shortListTokensBC -

                      Related property containing only tokens used -for short lists (cross-version).

                      + Collections::shortListTokensBC() + +

                      Related method to retrieve only tokens used +for short lists (cross-version).

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::listTokensBC() method instead.

                      +
                      + +
                      @@ -870,29 +1429,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $magicConstants - +

                      + 316 -

                      Tokens for the PHP magic constants.

                      + - +

                      DEPRECATED: Tokens for the PHP magic constants.

                      + + public - static array + static array<string|int, mixed> $magicConstants - = [T_CLASS_C => T_CLASS_C, T_DIR => T_DIR, T_FILE => T_FILE, T_FUNC_C => T_FUNC_C, T_LINE => T_LINE, T_METHOD_C => T_METHOD_C, T_NS_C => T_NS_C, T_TRAIT_C => T_TRAIT_C] + = [\T_CLASS_C => \T_CLASS_C, \T_DIR => \T_DIR, \T_FILE => \T_FILE, \T_FUNC_C => \T_FUNC_C, \T_LINE => \T_LINE, \T_METHOD_C => \T_METHOD_C, \T_NS_C => \T_NS_C, \T_TRAIT_C => \T_TRAIT_C]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -900,20 +1463,24 @@
                      - link + since
                      - https://www.php.net/language.constants.predefined -

                      PHP Manual on magic constants

                      - -
                      + 1.0.0-alpha3 + + +
                      - since + deprecated
                      - 1.0.0-alpha3 - -
                      + 1.0.0-alpha4 + +

                      Use the Tokens::$magicConstants property +or the BCTokens::magicConstants() method instead.

                      +
                      + +
                      @@ -922,29 +1489,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $namespaceDeclarationClosers - +

                      + 336 -

                      List of tokens which can end a namespace declaration statement.

                      + - +

                      DEPRECATED: List of tokens which can end a namespace declaration statement.

                      + + public - static array + static array<string|int, mixed> $namespaceDeclarationClosers - = [T_SEMICOLON => T_SEMICOLON, T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET, T_CLOSE_TAG => T_CLOSE_TAG] + = [\T_SEMICOLON => \T_SEMICOLON, \T_OPEN_CURLY_BRACKET => \T_OPEN_CURLY_BRACKET, \T_CLOSE_TAG => \T_CLOSE_TAG]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -955,9 +1526,20 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::namespaceDeclarationClosers() method instead.

                      +
                      + +
                      @@ -966,29 +1548,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $objectOperators - +

                      + 374 -

                      Object operators.

                      + - +

                      DEPRECATED: Object operator tokens.

                      + + public - static array + static array<string|int, mixed> $objectOperators - = [T_OBJECT_OPERATOR => T_OBJECT_OPERATOR, T_DOUBLE_COLON => T_DOUBLE_COLON] + = [\T_DOUBLE_COLON => \T_DOUBLE_COLON, \T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR, \T_NULLSAFE_OBJECT_OPERATOR => \T_NULLSAFE_OBJECT_OPERATOR]
                      +

                      =>

                      +
                      +
                      Tags @@ -1000,8 +1586,29 @@
                      1.0.0-alpha3 - -
                      + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the PHP 8.0 T_NULLSAFE_OBJECT_OPERATOR token.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::objectOperators() method instead.

                      +
                      + +
                      @@ -1010,29 +1617,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $OOCanExtend - +

                      + 389 -

                      OO structures which can use the "extends" keyword.

                      + - +

                      DEPRECATED: OO structures which can use the "extends" keyword.

                      + + public - static array + static array<string|int, mixed> $OOCanExtend - = [T_CLASS => T_CLASS, T_ANON_CLASS => T_ANON_CLASS, T_INTERFACE => T_INTERFACE] + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1043,9 +1654,20 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::ooCanExtend() method instead.

                      +
                      + +
                      @@ -1054,29 +1676,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $OOCanImplement - +

                      + 405 -

                      OO structures which can use the "implements" keyword.

                      + - +

                      DEPRECATED: OO structures which can use the "implements" keyword.

                      + + public - static array + static array<string|int, mixed> $OOCanImplement - = [T_CLASS => T_CLASS, T_ANON_CLASS => T_ANON_CLASS] + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_ENUM => \T_ENUM]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1087,9 +1713,30 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the PHP 8.1 T_ENUM token.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::ooCanImplement() method instead.

                      +
                      + +
                      @@ -1098,29 +1745,34 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $OOConstantScopes - +

                      + 424 -

                      OO scopes in which constants can be declared.

                      + - +

                      DEPRECATED: OO scopes in which constants can be declared.

                      + + public - static array + static array<string|int, mixed> $OOConstantScopes - = [T_CLASS => T_CLASS, T_ANON_CLASS => T_ANON_CLASS, T_INTERFACE => T_INTERFACE] + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_INTERFACE => \T_INTERFACE, \T_ENUM => \T_ENUM, \T_TRAIT => \T_TRAIT]
                      + +

                      Note: traits can only declare constants since PHP 8.2.

                      +
                      -

                      Note: traits can not declare constants.

                      +

                      <int|string> => <int|string>

                      +
                      @@ -1132,9 +1784,40 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the PHP 8.1 T_ENUM token.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRAIT token for PHP 8.2 constants in traits.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::ooConstantScopes() method instead.

                      +
                      + +
                      @@ -1143,29 +1826,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $OOHierarchyKeywords - +

                      + 443 -

                      Tokens types used for "forwarding" calls within OO structures.

                      + - +

                      DEPRECATED: Tokens types used for "forwarding" calls within OO structures.

                      + + public - static array + static array<string|int, mixed> $OOHierarchyKeywords - = [T_PARENT => T_PARENT, T_SELF => T_SELF, T_STATIC => T_STATIC] + = [\T_PARENT => \T_PARENT, \T_SELF => \T_SELF, \T_STATIC => \T_STATIC]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1176,17 +1863,28 @@
                      link
                      - https://www.php.net/language.oop5.paamayim-nekudotayim -

                      PHP Manual on OO forwarding calls

                      - -
                      +

                      PHP Manual on OO forwarding calls

                      +
                      + +
                      since
                      1.0.0-alpha3 - -
                      + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::ooHierarchyKeywords() method instead.

                      +
                      + +
                      @@ -1195,30 +1893,32 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $OONameTokens - +

                      + 458 -

                      Tokens types which can be encountered in the fully/partially qualified name of an OO structure.

                      + - +

                      DEPRECATED: Tokens types which can be encountered in the fully/partially qualified name of an OO structure.

                      + + public - static array + static array<string|int, mixed> $OONameTokens - = [T_NS_SEPARATOR => T_NS_SEPARATOR, T_STRING => T_STRING, T_NAMESPACE => T_NAMESPACE] + = [\T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_STRING => \T_STRING, \T_NAMESPACE => \T_NAMESPACE]
                      -

                      Example:

                      -
                      echo namespace\Sub\ClassName::method();
                      + +

                      <int|string> => <int|string>

                      +
                      @@ -1231,8 +1931,19 @@
                      1.0.0-alpha3 - -
                      + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::namespacedNameTokens() method instead.

                      +
                      + +
                      @@ -1241,29 +1952,34 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $OOPropertyScopes - +

                      + 475 -

                      OO scopes in which properties can be declared.

                      + - +

                      DEPRECATED: OO scopes in which properties can be declared.

                      + + public - static array + static array<string|int, mixed> $OOPropertyScopes - = [T_CLASS => T_CLASS, T_ANON_CLASS => T_ANON_CLASS, T_TRAIT => T_TRAIT] + = [\T_CLASS => \T_CLASS, \T_ANON_CLASS => \T_ANON_CLASS, \T_TRAIT => \T_TRAIT]
                      + +

                      Note: interfaces can not declare properties.

                      +
                      -

                      Note: interfaces can not declare properties.

                      +

                      <int|string> => <int|string>

                      +
                      @@ -1275,9 +1991,20 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::ooPropertyScopes() method instead.

                      +
                      + +
                      @@ -1286,38 +2013,32 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $parameterTypeTokens - +

                      + 493 -

                      Token types which can be encountered in a parameter type declaration.

                      + - +

                      DEPRECATED: Token types which can be encountered in a parameter type declaration.

                      + + public - static array + static array<string|int, mixed> $parameterTypeTokens - = [T_CALLABLE => T_CALLABLE, T_SELF => T_SELF, T_PARENT => T_PARENT, T_STRING => T_STRING, T_NS_SEPARATOR => T_NS_SEPARATOR] + = [\T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, \T_FALSE => \T_FALSE, \T_TRUE => \T_TRUE, \T_NULL => \T_NULL, \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_TYPE_UNION => \T_TYPE_UNION, \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION]
                      -

                      Sister-property to the \PHPCSUtils\Tokens\Collections::parameterTypeTokensBC() method. -The property supports PHPCS 3.3.0 and up. -The method supports PHPCS 2.6.0 and up.

                      -

                      Notable difference:

                      -
                        -
                      • The method will include the T_ARRAY_HINT token when used with PHPCS 2.x and 3.x. -This token constant will no longer exist in PHPCS 4.x.
                      • -
                      -

                      It is recommended to use the property instead of the method if a standard supports does -not need to support PHPCS < 3.3.0.

                      + +

                      <int|string> => <int|string>

                      +
                      @@ -1326,20 +2047,53 @@
                      - see + since +
                      +
                      + 1.0.0-alpha1 + + +
                      +
                      + since
                      - Collections::parameterTypeTokensBC() -

                      Related method (cross-version).

                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support.

                      +
                      -
                      -
                      + +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support.

                      +
                      + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRUE token for PHP 8.2 true type support.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::parameterTypeTokens() method instead.

                      +
                      + +
                      @@ -1348,29 +2102,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $propertyModifierKeywords - +

                      + 528 -

                      Modifier keywords which can be used for a property declaration.

                      + - +

                      DEPRECATED: Modifier keywords which can be used for a property declaration.

                      + + public - static array + static array<string|int, mixed> $propertyModifierKeywords - = [T_PUBLIC => T_PUBLIC, T_PRIVATE => T_PRIVATE, T_PROTECTED => T_PROTECTED, T_STATIC => T_STATIC, T_VAR => T_VAR] + = [\T_PUBLIC => \T_PUBLIC, \T_PRIVATE => \T_PRIVATE, \T_PROTECTED => \T_PROTECTED, \T_STATIC => \T_STATIC, \T_VAR => \T_VAR, \T_READONLY => \T_READONLY]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1381,49 +2139,64 @@
                      since
                      - 1.0.0 - -
                      - - - + 1.0.0-alpha1 + + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_READONLY token for PHP 8.1 readonly properties.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::propertyModifierKeywords() method instead.

                      +
                      + +
                      + + +

                      $propertyTypeTokens - +

                      + 549 -

                      Token types which can be encountered in a property type declaration.

                      + - +

                      DEPRECATED: Token types which can be encountered in a property type declaration.

                      + + public - static array + static array<string|int, mixed> $propertyTypeTokens - = [T_CALLABLE => T_CALLABLE, T_SELF => T_SELF, T_PARENT => T_PARENT, T_STRING => T_STRING, T_NS_SEPARATOR => T_NS_SEPARATOR] + = [\T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, \T_FALSE => \T_FALSE, \T_TRUE => \T_TRUE, \T_NULL => \T_NULL, \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_TYPE_UNION => \T_TYPE_UNION, \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION]
                      -

                      Sister-property to the \PHPCSUtils\Tokens\Collections::propertyTypeTokensBC() method. -The property supports PHPCS 3.3.0 and up. -The method supports PHPCS 2.6.0 and up.

                      -

                      Notable difference:

                      -
                        -
                      • The method will include the T_ARRAY_HINT token when used with PHPCS 2.x and 3.x. -This token constant will no longer exist in PHPCS 4.x.
                      • -
                      -

                      It is recommended to use the property instead of the method if a standard supports does -not need to support PHPCS < 3.3.0.

                      + +

                      <int|string> => <int|string>

                      +
                      @@ -1432,20 +2205,53 @@
                      - see + since +
                      +
                      + 1.0.0-alpha1 + + +
                      +
                      + since
                      - Collections::propertyTypeTokensBC() -

                      Related method (cross-version).

                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support.

                      +
                      -
                      -
                      + +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support.

                      +
                      + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRUE token for PHP 8.2 true type support.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::propertyTypeTokens() method instead.

                      +
                      + +
                      @@ -1454,39 +2260,32 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $returnTypeTokens - +

                      + 574 -

                      Token types which can be encountered in a return type declaration.

                      + - +

                      DEPRECATED: Token types which can be encountered in a return type declaration.

                      + + public - static array + static array<string|int, mixed> $returnTypeTokens - = [T_STRING => T_STRING, T_CALLABLE => T_CALLABLE, T_SELF => T_SELF, T_PARENT => T_PARENT, T_STATIC => T_STATIC, T_NS_SEPARATOR => T_NS_SEPARATOR] + = [\T_CALLABLE => \T_CALLABLE, \T_SELF => \T_SELF, \T_PARENT => \T_PARENT, \T_STATIC => \T_STATIC, \T_FALSE => \T_FALSE, \T_TRUE => \T_TRUE, \T_NULL => \T_NULL, \T_STRING => \T_STRING, \T_NS_SEPARATOR => \T_NS_SEPARATOR, \T_TYPE_UNION => \T_TYPE_UNION, \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION]
                      -

                      Sister-property to the \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() method. -The property supports PHPCS 3.5.4 and up. -The method supports PHPCS 2.6.0 and up.

                      -

                      Notable differences:

                      -
                        -
                      • The method will include the T_ARRAY_HINT and the T_RETURN_TYPE tokens when used with PHPCS 2.x and 3.x. -These token constants will no longer exist in PHPCS 4.x.
                      • -
                      • The method will include the T_ARRAY token which is needed for select arrow functions in PHPCS < 3.5.4.
                      • -
                      -

                      It is recommended to use the property instead of the method if a standard supports does -not need to support PHPCS < 3.5.4.

                      + +

                      <int|string> => <int|string>

                      +
                      @@ -1495,20 +2294,53 @@
                      - see + since +
                      +
                      + 1.0.0-alpha1 + + +
                      +
                      + since
                      - Collections::returnTypeTokensBC() -

                      Related method (cross-version).

                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support.

                      +
                      -
                      -
                      + +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support.

                      +
                      + + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRUE token for PHP 8.2 true type support.

                      +
                      + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::returnTypeTokens() method instead.

                      +
                      + +
                      @@ -1517,29 +2349,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $shortArrayTokens - +

                      + 615 -

                      Tokens which are used for short arrays.

                      + - +

                      DEPRECATED: Tokens which are used for short arrays.

                      + + public - static array + static array<string|int, mixed> $shortArrayTokens - = [T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY] + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1550,17 +2386,30 @@
                      see
                      - Collections::$arrayTokens -

                      Related property containing all tokens used for arrays.

                      + Collections::arrayTokens() + +

                      Related method to retrieve all tokens used for arrays.

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::shortArrayTokens() method instead.

                      +
                      + +
                      @@ -1569,30 +2418,36 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $shortArrayTokensBC - +

                      + 636 -

                      Tokens which are used for short arrays.

                      + - +

                      DEPRECATED: Tokens which are used for short arrays (PHPCS cross-version compatible).

                      + + public - static array + static array<string|int, mixed> $shortArrayTokensBC - = [T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET => T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET] + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET]
                      + +

                      Includes T_OPEN_SQUARE_BRACKET and T_CLOSE_SQUARE_BRACKET to allow for handling +intermittent tokenizer issues related to the retokenization to T_OPEN_SHORT_ARRAY. +Should only be used selectively.

                      +
                      -

                      List which is backward-compatible with PHPCS < 3.3.0. -Should only be used selectively.

                      +

                      <int|string> => <int|string>

                      +
                      @@ -1604,18 +2459,31 @@
                      see
                      - Collections::$arrayTokensBC -

                      Related property containing all tokens used for arrays -(cross-version).

                      + Collections::arrayTokensBC() + +

                      Related method to retrieve all tokens used for arrays +(cross-version).

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::shortArrayTokensBC() method instead.

                      +
                      + +
                      @@ -1624,29 +2492,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $shortListTokens - +

                      + 654 -

                      Tokens which are used for short lists.

                      + - +

                      DEPRECATED: Tokens which are used for short lists.

                      + + public - static array + static array<string|int, mixed> $shortListTokens - = [T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY] + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1657,17 +2529,30 @@
                      see
                      - Collections::$listTokens -

                      Related property containing all tokens used for lists.

                      + Collections::listTokens() + +

                      Related method to retrieve all tokens used for lists.

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::shortListTokens() method instead.

                      +
                      + +
                      @@ -1676,30 +2561,36 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $shortListTokensBC - +

                      + 675 -

                      Tokens which are used for short lists.

                      + - +

                      DEPRECATED: Tokens which are used for short lists (PHPCS cross-version compatible).

                      + + public - static array + static array<string|int, mixed> $shortListTokensBC - = [T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY => T_CLOSE_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET => T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET] + = [\T_OPEN_SHORT_ARRAY => \T_OPEN_SHORT_ARRAY, \T_CLOSE_SHORT_ARRAY => \T_CLOSE_SHORT_ARRAY, \T_OPEN_SQUARE_BRACKET => \T_OPEN_SQUARE_BRACKET, \T_CLOSE_SQUARE_BRACKET => \T_CLOSE_SQUARE_BRACKET]
                      -

                      List which is backward-compatible with PHPCS < 3.3.0. -Should only be used selectively.

                      +

                      Includes T_OPEN_SQUARE_BRACKET and T_CLOSE_SQUARE_BRACKET to allow for handling +intermittent tokenizer issues related to the retokenization to T_OPEN_SHORT_ARRAY. +Should only be used selectively.

                      +
                      + +

                      <int|string> => <int|string>

                      +
                      @@ -1711,18 +2602,31 @@
                      see
                      - Collections::$listTokensBC -

                      Related property containing all tokens used for lists -(cross-version).

                      + Collections::listTokensBC() + +

                      Related method to retrieve all tokens used for lists +(cross-version).

                      +
                      -
                      +
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::shortListTokensBC() method instead.

                      +
                      + +
                      @@ -1731,29 +2635,33 @@
                      phpdocumentor-element -property -public - -static " + -static -deprecated " >

                      $textStingStartTokens - +

                      + 691 -

                      Tokens which can start a - potentially multi-line - text string.

                      + - +

                      DEPRECATED: Tokens which can start a - potentially multi-line - text string.

                      + + public - static array + static array<string|int, mixed> $textStingStartTokens - = [T_START_HEREDOC => T_START_HEREDOC, T_START_NOWDOC => T_START_NOWDOC, T_CONSTANT_ENCAPSED_STRING => T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTED_STRING => T_DOUBLE_QUOTED_STRING] + = [\T_START_HEREDOC => \T_START_HEREDOC, \T_START_NOWDOC => \T_START_NOWDOC, \T_CONSTANT_ENCAPSED_STRING => \T_CONSTANT_ENCAPSED_STRING, \T_DOUBLE_QUOTED_STRING => \T_DOUBLE_QUOTED_STRING]
                      +

                      <int|string> => <int|string>

                      +
                      +
                      Tags @@ -1764,9 +2672,20 @@
                      since
                      - 1.0.0 - -
                      + 1.0.0-alpha1 + + + +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::textStringStartTokens() method instead.

                      +
                      + +
                      @@ -1775,7 +2694,7 @@

                      Methods - +

                      -public -static " > -

                      - arrowFunctionTokensBC() - +

                      + __callStatic() +

                      + 711 + + -

                      Tokens which can represent the arrow function keyword.

                      +

                      Handle calls to (undeclared) methods for token arrays which don't need special handling.

                      public - static arrowFunctionTokensBC() : array - -

                      Note: this is a method, not a property as the T_FN token for arrow functions may not exist.

                      + static __callStatic(string $name, array<string|int, mixed> $args) : array<string|int, mixed> +
                      Parameters
                      +
                      +
                      + $name + : string +
                      +
                      +

                      The name of the method which has been called.

                      +
                      + +
                      +
                      + $args + : array<string|int, mixed> +
                      +
                      +

                      Any arguments passed to the method. +Unused as none of the methods take arguments.

                      +
                      + +
                      +
                      +
                      Tags @@ -1812,15 +2753,27 @@
                      since
                      - 1.0.0-alpha2 - -
                      + 1.0.0-alpha4 + + + +
                      + throws +
                      +
                      + InvalidTokenArray + +

                      When an invalid token array is requested.

                      +
                      + +
                      Return values
                      - array + array<string|int, mixed> — -

                      <int|string> => <int|string>

                      +

                      <int|string> => <int|string> Token array

                      +
                      @@ -1830,55 +2783,49 @@
                      Return values
                      -public -static " > -

                      - functionDeclarationTokens() - +

                      + alternativeControlStructureSyntaxClosers() +

                      + 768 -

                      Tokens which can represent a keyword which starts a function declaration.

                      + + +

                      Tokens representing alternative control structure syntax closer keywords.

                      public - static functionDeclarationTokens() : array - -

                      Note: this is a method, not a property as the T_FN token for arrow functions may not exist.

                      -

                      Sister-method to the \PHPCSUtils\Tokens\Collections::functionDeclarationTokensBC() method. -This method supports PHPCS 3.5.3 and up. -The \PHPCSUtils\Tokens\Collections::functionDeclarationTokensBC() method supports PHPCS 2.6.0 and up.

                      + static alternativeControlStructureSyntaxClosers() : array<string|int, mixed> +
                      Tags
                      - see -
                      -
                      - Collections::functionDeclarationTokensBC() -

                      Related method (PHPCS 2.6.0+).

                      - -
                      -
                      since
                      - 1.0.0-alpha3 - -
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$alternativeControlStructureSyntaxCloserTokens +property.

                      +
                      + +
                      Return values
                      - array + array<string|int, mixed> — -

                      <int|string> => <int|string>

                      +

                      =>

                      +
                      @@ -1888,72 +2835,49 @@
                      Return values
                      -public -static " > -

                      - functionDeclarationTokensBC() - +

                      + alternativeControlStructureSyntaxes() +

                      + 755 + + -

                      Tokens which can represent a keyword which starts a function declaration.

                      +

                      Tokens for control structures which can use the alternative control structure syntax.

                      public - static functionDeclarationTokensBC() : array - -

                      Note: this is a method, not a property as the T_FN token for arrow functions may not exist.

                      -

                      Sister-method to the \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() method. -The \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() method supports PHPCS 3.5.3 and up. -This method supports PHPCS 2.6.0 and up.

                      -

                      Notable difference:

                      -
                        -
                      • This method accounts for when the T_FN token doesn't exist.
                      • -
                      -

                      Note: if this method is used, the \PHPCSUtils\Utils\FunctionDeclarations::isArrowFunction() -method needs to be used on arrow function tokens to verify whether it really is an arrow function -declaration or not.

                      -

                      It is recommended to use the \PHPCSUtils\Tokens\Collections::functionDeclarationTokens() method instead of -this method if a standard supports does not need to support PHPCS < 3.5.3.

                      + static alternativeControlStructureSyntaxes() : array<string|int, mixed> +
                      Tags
                      - see -
                      -
                      - Collections::functionDeclarationTokens() -

                      Related method (PHPCS 3.5.3+).

                      - -
                      -
                      - see -
                      -
                      - FunctionDeclarations::isArrowFunction() -

                      Arrow function verification.

                      - -
                      -
                      since
                      - 1.0.0-alpha3 - -
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$alternativeControlStructureSyntaxTokens +property.

                      +
                      + +
                      Return values
                      - array + array<string|int, mixed> — -

                      <int|string> => <int|string>

                      +

                      =>

                      +
                      @@ -1963,62 +2887,32 @@
                      Return values
                      -public -static " > -

                      - parameterTypeTokensBC() - +

                      + arrayOpenTokensBC() +

                      + 0 -

                      Token types which can be encountered in a parameter type declaration (cross-version).

                      + + public - static parameterTypeTokensBC() : array + static arrayOpenTokensBC() : array<string|int, mixed> -

                      Sister-method to the \PHPCSUtils\Tokens\Collections::$parameterTypeTokens property. -The property supports PHPCS 3.3.0 and up. -The method supports PHPCS 2.6.0 and up.

                      -

                      Notable difference:

                      -
                        -
                      • The method will include the T_ARRAY_HINT token when used with PHPCS 2.x and 3.x. -This token constant will no longer exist in PHPCS 4.x.
                      • -
                      -

                      It is recommended to use the property instead of the method if a standard supports does -not need to support PHPCS < 3.3.0.

                      +

                      Tokens which can open an array (PHPCS cross-version compatible).

                      +
                      -
                      - Tags - -
                      -
                      -
                      - see -
                      -
                      - Collections::$parameterTypeTokens -

                      Related property (PHPCS 3.3.0+).

                      - -
                      -
                      - since -
                      -
                      - 1.0.0-alpha3 - -
                      -
                      Return values
                      - array + array<string|int, mixed> — -

                      <int|string> => <int|string>

                      - +
                      Return values
                      -public -static " > -

                      - propertyTypeTokensBC() - +

                      + arrayTokens() +

                      + 0 -

                      Token types which can be encountered in a property type declaration (cross-version).

                      + + public - static propertyTypeTokensBC() : array + static arrayTokens() : array<string|int, mixed> -

                      Sister-method to the \PHPCSUtils\Tokens\Collections::$propertyTypeTokens property. -The property supports PHPCS 3.3.0 and up. -The method supports PHPCS 2.6.0 and up.

                      -

                      Notable difference:

                      -
                        -
                      • The method will include the T_ARRAY_HINT token when used with PHPCS 2.x and 3.x. -This token constant will no longer exist in PHPCS 4.x.
                      • -
                      -

                      It is recommended to use the property instead of the method if a standard supports does -not need to support PHPCS < 3.3.0.

                      +

                      Tokens which are used to create arrays.

                      +
                      -
                      - Tags - -
                      -
                      -
                      - see -
                      -
                      - Collections::$propertyTypeTokens -

                      Related property (PHPCS 3.3.0+).

                      - -
                      -
                      - since -
                      -
                      - 1.0.0-alpha3 - -
                      -
                      Return values
                      - array + array<string|int, mixed> — -

                      <int|string> => <int|string>

                      - +
                      Return values -public -static " > -

                      - returnTypeTokensBC() - +

                      + arrayTokensBC() +

                      + 0 -

                      Token types which can be encountered in a return type declaration (cross-version).

                      + + public - static returnTypeTokensBC() : array + static arrayTokensBC() : array<string|int, mixed> -

                      Sister-property to the \PHPCSUtils\Tokens\Collections::returnTypeTokensBC() method. -The property supports PHPCS 3.5.4 and up. -The method supports PHPCS 2.6.0 and up.

                      -

                      Notable differences:

                      -
                        -
                      • The method will include the T_ARRAY_HINT and the T_RETURN_TYPE tokens when used with PHPCS 2.x and 3.x. -These token constants will no longer exist in PHPCS 4.x.
                      • -
                      • The method will include the T_ARRAY token which is needed for select arrow functions in PHPCS < 3.5.4.
                      • -
                      -

                      It is recommended to use the property instead of the method if a standard supports does -not need to support PHPCS < 3.5.4.

                      +

                      Tokens which are used to create arrays +(PHPCS cross-version compatible).

                      +
                      -
                      - Tags - -
                      -
                      -
                      - see -
                      -
                      - Collections::$returnTypeTokens -

                      Related property (PHPCS 3.5.4+).

                      - -
                      -
                      - since -
                      -
                      - 1.0.0-alpha3 - -
                      -
                      Return values
                      - array + array<string|int, mixed> — -

                      <int|string> => <int|string>

                      - +
                      - +
                      +

                      + arrowFunctionTokensBC() + +

                      + + +

                      DEPRECATED: Tokens which can represent the arrow function keyword.

                      + + + public + static arrowFunctionTokensBC() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha2 + + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the T_FN token constant instead.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + classModifierKeywords() + +

                      + + + + + public + static classModifierKeywords() : array<string|int, mixed> + +

                      Modifier keywords which can be used for a class declaration.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + closedScopes() + +

                      + + + + + public + static closedScopes() : array<string|int, mixed> + +

                      List of tokens which represent "closed" scopes.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + controlStructureTokens() + +

                      + + + + + public + static controlStructureTokens() : array<string|int, mixed> + +

                      Control structure tokens.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + functionCallTokens() + +

                      + + +

                      Tokens which can represent function calls and function-call-like language constructs.

                      + + + public + static functionCallTokens() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + see +
                      +
                      + Collections::parameterPassingTokens() + +

                      Related method.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + functionDeclarationTokens() + +

                      + + + + + public + static functionDeclarationTokens() : array<string|int, mixed> + +

                      Tokens which represent a keyword which starts +a function declaration.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + functionDeclarationTokensBC() + +

                      + + +

                      DEPRECATED: Tokens which represent a keyword which starts a function declaration.

                      + + + public + static functionDeclarationTokensBC() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha3 + + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::functionDeclarationTokens() method instead.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + incrementDecrementOperators() + +

                      + + + + + public + static incrementDecrementOperators() : array<string|int, mixed> + +

                      Increment/decrement operator tokens.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + listTokens() + +

                      + + + + + public + static listTokens() : array<string|int, mixed> + +

                      Tokens which are used to create lists.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + listTokensBC() + +

                      + + + + + public + static listTokensBC() : array<string|int, mixed> + +

                      Tokens which are used to create lists +(PHPCS cross-version compatible)

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + namespaceDeclarationClosers() + +

                      + + + + + public + static namespaceDeclarationClosers() : array<string|int, mixed> + +

                      List of tokens which can end a namespace declaration statement.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + namespacedNameTokens() + +

                      + + +

                      Tokens types which can be encountered in a fully, partially or unqualified name.

                      + + + public + static namespacedNameTokens() : array<string|int, mixed> + +

                      Example:

                      +
                      echo namespace\Sub\ClassName::method();
                      +
                      +
                      + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + nameTokens() + +

                      + + + + + public + static nameTokens() : array<string|int, mixed> + +

                      Tokens used for "names", be it namespace, OO, function +or constant names.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + objectOperators() + +

                      + + + + + public + static objectOperators() : array<string|int, mixed> + +

                      Object operator tokens.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + ooCanExtend() + +

                      + + +

                      OO structures which can use the "extends" keyword.

                      + + + public + static ooCanExtend() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$OOCanExtend property.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + ooCanImplement() + +

                      + + +

                      OO structures which can use the "implements" keyword.

                      + + + public + static ooCanImplement() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$OOCanImplement property.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the PHP 8.1 T_ENUM token.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + ooConstantScopes() + +

                      + + +

                      OO scopes in which constants can be declared.

                      + + + public + static ooConstantScopes() : array<string|int, mixed> + +

                      Note: traits can only declare constants since PHP 8.2.

                      +
                      + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$OOConstantScopes property.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the PHP 8.1 T_ENUM token.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRAIT token for PHP 8.2 constants in traits.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + ooHierarchyKeywords() + +

                      + + +

                      Tokens types used for "forwarding" calls within OO structures.

                      + + + public + static ooHierarchyKeywords() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + link +
                      +
                      +

                      PHP Manual on OO forwarding calls

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$OOHierarchyKeywords property.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + ooPropertyScopes() + +

                      + + +

                      OO scopes in which properties can be declared.

                      + + + public + static ooPropertyScopes() : array<string|int, mixed> + +

                      Note: interfaces can not declare properties.

                      +
                      + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$OOPropertyScopes property.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + parameterPassingTokens() + +

                      + + +

                      Tokens which can be passed to the methods in the PassedParameter class.

                      + + + public + static parameterPassingTokens() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + see +
                      +
                      + PassedParameters + + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + parameterTypeTokens() + +

                      + + +

                      Token types which can be encountered in a parameter type declaration.

                      + + + public + static parameterTypeTokens() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$parameterTypeTokens property.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added support for PHP 8.0 identifier name tokens.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRUE token for PHP 8.2 true type support.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + parameterTypeTokensBC() + +

                      + + +

                      DEPRECATED: Token types which can be encountered in a parameter type declaration (cross-version).

                      + + + public + static parameterTypeTokensBC() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + see +
                      +
                      + Collections::parameterTypeTokens() + +

                      Related method (PHPCS 3.3.0+).

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha3 + + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::parameterTypeTokens() method instead.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + phpOpenTags() + +

                      + + + + + public + static phpOpenTags() : array<string|int, mixed> + +

                      Tokens which open PHP.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + propertyModifierKeywords() + +

                      + + + + + public + static propertyModifierKeywords() : array<string|int, mixed> + +

                      Modifier keywords which can be used for a property declaration.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + propertyTypeTokens() + +

                      + + +

                      Token types which can be encountered in a property type declaration.

                      + + + public + static propertyTypeTokens() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$propertyTypeTokens property.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added support for PHP 8.0 identifier name tokens.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRUE token for PHP 8.2 true type support.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + propertyTypeTokensBC() + +

                      + + +

                      DEPRECATED: Token types which can be encountered in a property type declaration (cross-version).

                      + + + public + static propertyTypeTokensBC() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + see +
                      +
                      + Collections::propertyTypeTokens() + +

                      Related method (PHPCS 3.3.0+).

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha3 + + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::propertyTypeTokens() method instead.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + returnTypeTokens() + +

                      + + +

                      Token types which can be encountered in a return type declaration.

                      + + + public + static returnTypeTokens() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$returnTypeTokens property.

                      +
                      -
                      -
                      + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_UNION, T_FALSE, T_NULL tokens for PHP 8.0 union type support.

                      +
                      -

                      Search results

                      -
                        -
                      -
                      + +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added support for PHP 8.0 identifier name tokens.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TYPE_INTERSECTION token for PHP 8.1 intersection type support.

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      Added the T_TRUE token for PHP 8.2 true type support.

                      +
                      + +
                      + + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + + +
                      +

                      + returnTypeTokensBC() + +

                      + + +

                      DEPRECATED: Token types which can be encountered in a return type declaration (cross-version).

                      + + + public + static returnTypeTokensBC() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + see +
                      +
                      + Collections::returnTypeTokens() + +

                      Related method (PHPCS 3.3.0+).

                      +
                      + +
                      +
                      + since +
                      +
                      + 1.0.0-alpha3 + + +
                      +
                      + deprecated +
                      +
                      + 1.0.0-alpha4 + +

                      Use the Collections::returnTypeTokens() method instead.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      +
                      +

                      + shortArrayListOpenTokensBC() + +

                      + + + + + public + static shortArrayListOpenTokensBC() : array<string|int, mixed> + +

                      Tokens which can open a short array or short list +(PHPCS cross-version compatible).

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + shortArrayTokens() + +

                      + + + + + public + static shortArrayTokens() : array<string|int, mixed> + +

                      Tokens which are used for short arrays.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + shortArrayTokensBC() + +

                      + + + + + public + static shortArrayTokensBC() : array<string|int, mixed> + +

                      Tokens which are used for short arrays +(PHPCS cross-version compatible).

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + shortListTokens() + +

                      + + + + + public + static shortListTokens() : array<string|int, mixed> + +

                      Tokens which are used for short lists.

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + shortListTokensBC() + +

                      + + + + + public + static shortListTokensBC() : array<string|int, mixed> + +

                      Tokens which are used for short lists +(PHPCS cross-version compatible).

                      +
                      + + + + +
                      Return values
                      + array<string|int, mixed> + — + + +
                      +
                      +

                      + textStringStartTokens() + +

                      + + +

                      Tokens which can start a - potentially multi-line - text string.

                      + + + public + static textStringStartTokens() : array<string|int, mixed> + + + + +
                      + Tags + +
                      +
                      +
                      + since +
                      +
                      + 1.0.0-alpha4 + +

                      This method replaces the Collections::$textStingStartTokens property.

                      +
                      + +
                      +
                      + +
                      Return values
                      + array<string|int, mixed> + — +

                      <int|string> => <int|string>

                      +
                      + + +
                      + + + + + + +
                      +
                      +
                      +

                      Search results

                      + +
                      +
                      +
                        +
                        +
                        +
                        - +
                        + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Tokens-TokenHelper.html b/docs/phpdoc/classes/PHPCSUtils-Tokens-TokenHelper.html new file mode 100644 index 00000000..87f241cc --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Tokens-TokenHelper.html @@ -0,0 +1,369 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                        +

                        PHPCSUtils

                        + + + + + +
                        + +
                        +
                        + + + + +
                        + + +
                        +

                        + TokenHelper + + +
                        + in package + +
                        + + +

                        + + + +

                        Helpers for working with tokens.

                        + + + +
                        + Tags + +
                        +
                        +
                        + since +
                        +
                        + 1.0.0 + + +
                        +
                        + + + + + + +

                        + Table of Contents + +

                        + +
                        +
                        + tokenExists() + +  : bool +
                        +
                        Check whether a PHP native token exists (for real).
                        + +
                        + + + + + + + +
                        +

                        + Methods + +

                        +
                        +

                        + tokenExists() + +

                        + + +

                        Check whether a PHP native token exists (for real).

                        + + + public + static tokenExists(string $name) : bool + +

                        Under normal circumstances, checking whether a token exists (either defined by PHP or by PHPCS) +is as straight-forward as running defined('T_TOKEN_NAME').

                        +

                        Unfortunately, this doesn't work in all circumstances, most notably, if an external standard +also uses PHP-Parser or when code coverage is run on a standard using PHPUnit >= 9.3 (which uses PHP-Parser), +this logic breaks because PHP-Parser also polyfills tokens. +This method takes potentially polyfilled tokens from PHP-Parser into account and will regard the token +as undefined if it was declared by PHP-Parser.

                        +

                        Note: this method only needs to be used for PHP native tokens, not for PHPCS specific tokens. +Also, realistically, it only needs to be used for tokens introduced in PHP in recent versions (PHP 7.4 and up). +Having said that, the method will also work correctly when a name of a PHPCS native token is passed or +of an older PHP native token.

                        +
                        + +
                        Parameters
                        +
                        +
                        + $name + : string +
                        +
                        +

                        The token name.

                        +
                        + +
                        +
                        + + +
                        + Tags + +
                        +
                        +
                        + link +
                        +
                        +

                        PHP-Code-Coverage#798

                        +
                        + +
                        +
                        + link +
                        +
                        +

                        PHP-Parser Lexer code

                        +
                        + +
                        +
                        + since +
                        +
                        + 1.0.0-alpha4 + + +
                        +
                        + +
                        Return values
                        + bool + — + + +
                        +
                        + + + + +
                        +
                        +
                        +
                        +

                        Search results

                        + +
                        +
                        +
                          +
                          +
                          +
                          +
                          +
                          + + +
                          + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html index 9625c6e8..e23f7eca 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Arrays.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                          -

                          PHPCSUtils

                          - -
                          - -
                          -
                          -

                          Utility functions for use when examining arrays.

                          @@ -98,8 +153,19 @@
                          1.0.0 - -
                          + + + +
                          + since +
                          +
                          + 1.0.0-alpha4 + +

                          Dropped support for PHPCS < 3.7.1.

                          +
                          + +
                          @@ -113,24 +179,24 @@

                          -
                          - getDoubleArrowPtr() +
                          + getDoubleArrowPtr() -  : int|false +  : int|false
                          Get the stack pointer position of the double arrow within an array item.
                          - getOpenClose() + getOpenClose() -  : array|false +  : array<string|int, mixed>|false
                          Find the array opener and closer based on a T_ARRAY or T_OPEN_SHORT_ARRAY token.
                          - isShortArray() + isShortArray() -  : bool +  : bool
                          Determine whether a T_OPEN/CLOSE_SHORT_ARRAY token is a short array construct and not a short list.
                          @@ -146,7 +212,7 @@

                          Methods - +

                          Parameters
                          @@ -180,7 +248,8 @@
                          Parameters
                          : File
                          -

                          The file being examined.

                          +

                          The file being examined.

                          +
                          @@ -188,7 +257,8 @@
                          Parameters
                          : int
                          -

                          Stack pointer to the start of the array item.

                          +

                          Stack pointer to the start of the array item.

                          +
                          @@ -196,7 +266,8 @@
                          Parameters
                          : int
                          -

                          Stack pointer to the last token in the array item.

                          +

                          Stack pointer to the last token in the array item.

                          +
                          @@ -212,30 +283,56 @@
                          1.0.0 - -
                          + + +
                          since
                          1.0.0-alpha2 -

                          Now allows for arrow functions in arrays.

                          + +

                          Now allows for arrow functions in arrays.

                          +
                          + +
                          +
                          + since +
                          +
                          + 1.0.0-alpha4 + +

                          Now allows for match expressions in arrays.

                          +
                          -
                          + +
                          + since +
                          +
                          + 1.0.0-alpha4 + +

                          Now allows for attributes in arrays.

                          +
                          + +
                          throws
                          RuntimeException -

                          If the start or end positions are invalid.

                          + +

                          If the start or end positions are invalid.

                          +
                          -
                          +
                          Return values
                          int|false — -

                          Stack pointer to the double arrow if this array item has a key; or FALSE otherwise.

                          +

                          Stack pointer to the double arrow if this array item has a key; or FALSE otherwise.

                          +
                          @@ -247,23 +344,25 @@
                          Return values
                          >

                          getOpenClose() - +

                          + 99 + +

                          Find the array opener and closer based on a T_ARRAY or T_OPEN_SHORT_ARRAY token.

                          public - static getOpenClose(File $phpcsFile, int $stackPtr[, true|null $isShortArray = null ]) : array|false + static getOpenClose(File $phpcsFile, int $stackPtr[, true|null $isShortArray = null ]) : array<string|int, mixed>|false

                          This method also accepts T_OPEN_SQUARE_BRACKET tokens to allow it to be PHPCS cross-version compatible as the short array tokenizing has been plagued by -a number of bugs over time, which affects the short array determination.

                          +a number of bugs over time, which affects the short array determination.

                          +
                          Parameters
                          @@ -272,7 +371,8 @@
                          Parameters
                          : File
                          -

                          The file being scanned.

                          +

                          The file being scanned.

                          +
                          @@ -281,7 +381,8 @@
                          Parameters

                          The position of the T_ARRAY or T_OPEN_SHORT_ARRAY -token in the stack.

                          +token in the stack.

                          +
                          @@ -294,7 +395,8 @@
                          Parameters
                          Efficiency tweak for when this has already been established, i.e. when encountering a nested array while walking the tokens in an array. -Use with care.

                          +Use with care.

                          +
                          @@ -310,12 +412,13 @@
                          1.0.0 - -
                          + + +
                          Return values
                          - array|false + array<string|int, mixed>|false

                          An array with the token pointers; or FALSE if this is not a (short) array token or if the opener/closer could not be determined. @@ -323,7 +426,9 @@

                          Return values
                          array(
                             'opener' => integer, // Stack pointer to the array open bracket.
                             'closer' => integer, // Stack pointer to the array close bracket.
                          -)
                          +) + + @@ -335,24 +440,26 @@
                          Return values
                          >

                          isShortArray() - +

                          + 65 + +

                          Determine whether a T_OPEN/CLOSE_SHORT_ARRAY token is a short array construct and not a short list.

                          public - static isShortArray(File $phpcsFile, int $stackPtr) : bool + static isShortArray(File $phpcsFile, int $stackPtr) : bool

                          This method also accepts T_OPEN/CLOSE_SQUARE_BRACKET tokens to allow it to be PHPCS cross-version compatible as the short array tokenizing has been plagued by -a number of bugs over time.

                          +a number of bugs over time.

                          +
                          Parameters
                          @@ -361,7 +468,8 @@
                          Parameters
                          : File
                          -

                          The file being scanned.

                          +

                          The file being scanned.

                          +
                          @@ -369,7 +477,8 @@
                          Parameters
                          : int
                          -

                          The position of the short array bracket token.

                          +

                          The position of the short array bracket token.

                          +
                          @@ -385,8 +494,9 @@
                          1.0.0 - -
                          + + +
                          Return values
                          @@ -394,27 +504,99 @@
                          Return values

                          TRUE if the token passed is the open/close bracket of a short array. FALSE if the token is a short list bracket, a plain square bracket -or not one of the accepted tokens.

                          +or not one of the accepted tokens.

                          + - -
                          + + -

                          Search results

                          -
                            -
                          -
                          + +
                          +
                          +
                          +

                          Search results

                          + +
                          +
                          +
                            +
                            +
                            +
                            - +
                            + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html index fd98e67a..3d06ec19 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Conditions.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                            -

                            PHPCSUtils

                            - -
                            - -
                            -
                            -

                            Utility functions for use when examining token conditions.

                            @@ -98,12 +153,14 @@
                            1.0.0 -

                            The Conditions::getCondition() and Conditions::hasCondition() + +

                            The Conditions::getCondition() and Conditions::hasCondition() methods are based on and inspired by the methods of the same name in the PHPCS native PHP_CodeSniffer\Files\File class. -Also see {@see \PHPCSUtils\BackCompat\BCFile}.

                            +Also see BCFile.

                            +
                            -
                            + @@ -117,31 +174,31 @@

                            -
                            - getCondition() +
                            + getCondition() -  : int|false +  : int|false
                            Retrieve the position of a condition for the passed token.
                            - getFirstCondition() + getFirstCondition() -  : int|false +  : int|false
                            Return the position of the first (outermost) condition of a certain type for the passed token.
                            - getLastCondition() + getLastCondition() -  : int|false +  : int|false
                            Return the position of the last (innermost) condition of a certain type for the passed token.
                            - hasCondition() + hasCondition() -  : bool +  : bool
                            Determine if the passed token has a condition of one of the passed types.
                            @@ -156,7 +213,7 @@

                            Methods - +

                            >

                            getCondition() - +

                            + +

                            Retrieve the position of a condition for the passed token.

                            public - static getCondition(File $phpcsFile, int $stackPtr[, int|string|array $types = [] ][, bool $first = true ]) : int|false + static getCondition(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $types = [] ][, bool $first = true ]) : int|false

                            If no types are specified, the first condition for the token - or if $first=false, the last condition - will be returned.

                            @@ -187,7 +245,8 @@

                          • The singular $type parameter has become the more flexible $types parameter allowing to search for several types of conditions in one go.
                          • The $types parameter is now optional.
                          • -

                            + +

                            Parameters
                            @@ -196,7 +255,8 @@
                            Parameters
                            : File
                            -

                            The file being scanned.

                            +

                            The file being scanned.

                            +
                            @@ -204,15 +264,17 @@
                            Parameters
                            : int
                            -

                            The position of the token we are checking.

                            +

                            The position of the token we are checking.

                            +
                            $types - : int|string|array + : int|string|array<string|int, mixed> = []
                            -

                            Optional. The type(s) of tokens to search for.

                            +

                            Optional. The type(s) of tokens to search for.

                            +
                            @@ -222,7 +284,8 @@
                            Parameters

                            Optional. Whether to search for the first (outermost) (true) or the last (innermost) condition (false) of -the specified type(s).

                            +the specified type(s).

                            +
                            @@ -238,42 +301,50 @@
                            File::getCondition() -

                            Original source.

                            + +

                            Original source.

                            +
                            -
                            +
                            see
                            - BCFile::getCondition() -

                            Cross-version compatible version of the original.

                            + BCFile::getCondition() + +

                            Cross-version compatible version of the original.

                            +
                            -
                            +
                            since
                            1.0.0 - -
                            + + +
                            since
                            1.0.0-alpha2 -

                            The $reverse parameter has been renamed to $first and the meaning of the + +

                            The $reverse parameter has been renamed to $first and the meaning of the boolean reversed (true = first, false = last, was: true = last, false = first) to be in line with PHPCS itself which added the $first parameter in v 3.5.4 -to allow for the same/similar functionality as $reverse already offered.

                            +to allow for the same/similar functionality as $reverse already offered.

                            +
                            -
                            +
                            Return values
                            int|false

                            Integer stack pointer to the condition; or FALSE if the token -does not have the condition or has no conditions at all.

                            +does not have the condition or has no conditions at all.

                            + @@ -285,22 +356,24 @@
                            Return values
                            >

                            getFirstCondition() - +

                            + +

                            Return the position of the first (outermost) condition of a certain type for the passed token.

                            public - static getFirstCondition(File $phpcsFile, int $stackPtr[, int|string|array $types = [] ]) : int|false + static getFirstCondition(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $types = [] ]) : int|false

                            If no types are specified, the first condition for the token, independently of type, -will be returned.

                            +will be returned.

                            +
                            Parameters
                            @@ -309,7 +382,8 @@
                            Parameters
                            : File
                            -

                            The file where this token was found.

                            +

                            The file where this token was found.

                            +
                            @@ -317,15 +391,17 @@
                            Parameters
                            : int
                            -

                            The position of the token we are checking.

                            +

                            The position of the token we are checking.

                            +
                            $types - : int|string|array + : int|string|array<string|int, mixed> = []
                            -

                            Optional. The type(s) of tokens to search for.

                            +

                            Optional. The type(s) of tokens to search for.

                            +
                            @@ -341,15 +417,17 @@
                            1.0.0 - -
                            + + +
                            Return values
                            int|false

                            Integer stack pointer to the condition; or FALSE if the token -does not have the condition or has no conditions at all.

                            +does not have the condition or has no conditions at all.

                            + @@ -361,22 +439,24 @@
                            Return values
                            >

                            getLastCondition() - +

                            + +

                            Return the position of the last (innermost) condition of a certain type for the passed token.

                            public - static getLastCondition(File $phpcsFile, int $stackPtr[, int|string|array $types = [] ]) : int|false + static getLastCondition(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $types = [] ]) : int|false

                            If no types are specified, the last condition for the token, independently of type, -will be returned.

                            +will be returned.

                            +
                            Parameters
                            @@ -385,7 +465,8 @@
                            Parameters
                            : File
                            -

                            The file where this token was found.

                            +

                            The file where this token was found.

                            +
                            @@ -393,15 +474,17 @@
                            Parameters
                            : int
                            -

                            The position of the token we are checking.

                            +

                            The position of the token we are checking.

                            +
                            $types - : int|string|array + : int|string|array<string|int, mixed> = []
                            -

                            Optional. The type(s) of tokens to search for.

                            +

                            Optional. The type(s) of tokens to search for.

                            +
                            @@ -417,15 +500,17 @@
                            1.0.0 - -
                            + + +
                            Return values
                            int|false

                            Integer stack pointer to the condition; or FALSE if the token -does not have the condition or has no conditions at all.

                            +does not have the condition or has no conditions at all.

                            + @@ -437,21 +522,23 @@
                            Return values
                            >

                            hasCondition() - +

                            + +

                            Determine if the passed token has a condition of one of the passed types.

                            public - static hasCondition(File $phpcsFile, int $stackPtr, int|string|array $types) : bool + static hasCondition(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $types) : bool -

                            This method is not significantly different from the PHPCS native version.

                            +

                            This method is not significantly different from the PHPCS native version.

                            +
                            Parameters
                            @@ -460,7 +547,8 @@
                            Parameters
                            : File
                            -

                            The file being scanned.

                            +

                            The file being scanned.

                            +
                            @@ -468,15 +556,17 @@
                            Parameters
                            : int
                            -

                            The position of the token we are checking.

                            +

                            The position of the token we are checking.

                            +
                            $types - : int|string|array + : int|string|array<string|int, mixed>
                            -

                            The type(s) of tokens to search for.

                            +

                            The type(s) of tokens to search for.

                            +
                            @@ -492,24 +582,29 @@
                            File::hasCondition() -

                            Original source.

                            + +

                            Original source.

                            +
                            -
                            +
                            see
                            - BCFile::hasCondition() -

                            Cross-version compatible version of the original.

                            + BCFile::hasCondition() + +

                            Cross-version compatible version of the original.

                            +
                            -
                            +
                            since
                            1.0.0 - -
                            + + +
                            Return values
                            @@ -520,21 +615,92 @@
                            Return values
                            - -
                            + + -

                            Search results

                            -
                              -
                            -
                            + +
                            +
                            +
                            +

                            Search results

                            + +
                            +
                            +
                              +
                              +
                              +
                              - +
                              + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Context.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Context.html new file mode 100644 index 00000000..f91437c5 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Context.html @@ -0,0 +1,760 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                              +

                              PHPCSUtils

                              + + + + + +
                              + +
                              +
                              + + + + +
                              + + +
                              +

                              + Context + + +
                              + in package + +
                              + + +

                              + + + +

                              Utility functions for examining in which context a certain token is used.

                              + +

                              Example use-cases:

                              +
                                +
                              • A sniff looking for the use of certain variables may want to disregard the "use" +of these variables within a call to isset() or empty().
                              • +
                              • A sniff looking for incrementor/decrementors may want to disregard these when used +as the third expression in a for() condition.
                              • +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + + + + + + +

                              + Table of Contents + +

                              + +
                              +
                              + inAttribute() + +  : bool +
                              +
                              Check whether an arbitrary token is within an attribute.
                              + +
                              + inEmpty() + +  : bool +
                              +
                              Check whether an arbitrary token is within a call to empty().
                              + +
                              + inForCondition() + +  : string|false +
                              +
                              Check whether an arbitrary token is in a for condition and if so, in which part: +the first, second or third expression.
                              + +
                              + inForeachCondition() + +  : string|false +
                              +
                              Check whether an arbitrary token is in a foreach condition and if so, in which part: +before or after the "as".
                              + +
                              + inIsset() + +  : bool +
                              +
                              Check whether an arbitrary token is within a call to isset().
                              + +
                              + inUnset() + +  : bool +
                              +
                              Check whether an arbitrary token is within a call to unset().
                              + +
                              + + + + + + + +
                              +

                              + Methods + +

                              +
                              +

                              + inAttribute() + +

                              + + +

                              Check whether an arbitrary token is within an attribute.

                              + + + public + static inAttribute(File $phpcsFile, int $stackPtr) : bool + + +
                              Parameters
                              +
                              +
                              + $phpcsFile + : File +
                              +
                              +

                              The file being scanned.

                              +
                              + +
                              +
                              + $stackPtr + : int +
                              +
                              +

                              The position of the token we are checking.

                              +
                              + +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + +
                              Return values
                              + bool + — + + +
                              +
                              +

                              + inEmpty() + +

                              + + +

                              Check whether an arbitrary token is within a call to empty().

                              + + + public + static inEmpty(File $phpcsFile, int $stackPtr) : bool + +

                              This method is a thin, descriptive wrapper around the Parentheses::getLastOwner() method. +For more complex/combined queries, it is recommended to call the Parentheses::getLastOwner() +method directly.

                              +
                              + +
                              Parameters
                              +
                              +
                              + $phpcsFile + : File +
                              +
                              +

                              The file being scanned.

                              +
                              + +
                              +
                              + $stackPtr + : int +
                              +
                              +

                              The position of the token we are checking.

                              +
                              + +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + +
                              Return values
                              + bool + — + + +
                              +
                              +

                              + inForCondition() + +

                              + + +

                              Check whether an arbitrary token is in a for condition and if so, in which part: +the first, second or third expression.

                              + + + public + static inForCondition(File $phpcsFile, int $stackPtr) : string|false + +

                              Note: the semicolons separating the conditions are regarded as belonging with the +expression before it.

                              +
                              + +
                              Parameters
                              +
                              +
                              + $phpcsFile + : File +
                              +
                              +

                              The file being scanned.

                              +
                              + +
                              +
                              + $stackPtr + : int +
                              +
                              +

                              The position of the token we are checking.

                              +
                              + +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + +
                              Return values
                              + string|false + — +

                              String 'expr1', 'expr2' or 'expr3' when the token is within +a for condition. +FALSE in all other cases, including for parse errors.

                              +
                              + + +
                              +
                              +

                              + inForeachCondition() + +

                              + + +

                              Check whether an arbitrary token is in a foreach condition and if so, in which part: +before or after the "as".

                              + + + public + static inForeachCondition(File $phpcsFile, int $stackPtr) : string|false + + +
                              Parameters
                              +
                              +
                              + $phpcsFile + : File +
                              +
                              +

                              The file being scanned.

                              +
                              + +
                              +
                              + $stackPtr + : int +
                              +
                              +

                              The position of the token we are checking.

                              +
                              + +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + +
                              Return values
                              + string|false + — +

                              String 'beforeAs', 'as' or 'afterAs' when the token is within +a foreach condition. +FALSE in all other cases, including for parse errors.

                              +
                              + + +
                              +
                              +

                              + inIsset() + +

                              + + +

                              Check whether an arbitrary token is within a call to isset().

                              + + + public + static inIsset(File $phpcsFile, int $stackPtr) : bool + +

                              This method is a thin, descriptive wrapper around the Parentheses::getLastOwner() method. +For more complex/combined queries, it is recommended to call the Parentheses::getLastOwner() +method directly.

                              +
                              + +
                              Parameters
                              +
                              +
                              + $phpcsFile + : File +
                              +
                              +

                              The file being scanned.

                              +
                              + +
                              +
                              + $stackPtr + : int +
                              +
                              +

                              The position of the token we are checking.

                              +
                              + +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + +
                              Return values
                              + bool + — + + +
                              +
                              +

                              + inUnset() + +

                              + + +

                              Check whether an arbitrary token is within a call to unset().

                              + + + public + static inUnset(File $phpcsFile, int $stackPtr) : bool + +

                              This method is a thin, descriptive wrapper around the Parentheses::getLastOwner() method. +For more complex/combined queries, it is recommended to call the Parentheses::getLastOwner() +method directly.

                              +
                              + +
                              Parameters
                              +
                              +
                              + $phpcsFile + : File +
                              +
                              +

                              The file being scanned.

                              +
                              + +
                              +
                              + $stackPtr + : int +
                              +
                              +

                              The position of the token we are checking.

                              +
                              + +
                              +
                              + + +
                              + Tags + +
                              +
                              +
                              + since +
                              +
                              + 1.0.0-alpha4 + + +
                              +
                              + +
                              Return values
                              + bool + — + + +
                              +
                              + + + + +
                              +
                              +
                              +
                              +

                              Search results

                              + +
                              +
                              +
                                +
                                +
                                +
                                +
                                +
                                + + +
                                + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html b/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html index f51aaa5c..6aae9536 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-ControlStructures.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                -

                                PHPCSUtils

                                - -
                                - -
                                -
                                -

                                Utility functions for use when examining control structures.

                                @@ -98,8 +153,19 @@
                                1.0.0 - -
                                + + + +
                                + since +
                                +
                                + 1.0.0-alpha4 + +

                                Dropped support for PHPCS < 3.7.1.

                                +
                                + +
                                @@ -113,31 +179,31 @@

                                -
                                - getCaughtExceptions() +
                                + getCaughtExceptions() -  : array +  : array<string|int, mixed>
                                Retrieve the exception(s) being caught in a CATCH condition.
                                - getDeclareScopeOpenClose() + getDeclareScopeOpenClose() -  : array|false +  : array<string|int, mixed>|false
                                Get the scope opener and closer for a DECLARE statement.
                                - hasBody() + hasBody() -  : bool +  : bool
                                Check whether a control structure has a body.
                                - isElseIf() + isElseIf() -  : bool +  : bool
                                Check whether an IF or ELSE token is part of an "else if".
                                @@ -152,7 +218,7 @@

                                Methods - +

                                >

                                getCaughtExceptions() - +

                                + 278 + +

                                Retrieve the exception(s) being caught in a CATCH condition.

                                public - static getCaughtExceptions(File $phpcsFile, int $stackPtr) : array + static getCaughtExceptions(File $phpcsFile, int $stackPtr) : array<string|int, mixed>
                                Parameters
                                @@ -184,7 +251,8 @@
                                Parameters
                                : File
                                -

                                The file being scanned.

                                +

                                The file being scanned.

                                +
                                @@ -192,7 +260,8 @@
                                Parameters
                                : int
                                -

                                The position of the token we are checking.

                                +

                                The position of the token we are checking.

                                +

                                @@ -208,30 +277,45 @@
                                1.0.0-alpha3 - -
                                + + + +
                                + since +
                                +
                                + 1.0.0-alpha4 + +

                                Added support for PHP 8.0 identifier name tokenization.

                                +
                                + +
                                throws
                                RuntimeException -

                                If the specified $stackPtr is not of -type T_CATCH or doesn't exist.

                                + +

                                If the specified $stackPtr is not of +type T_CATCH or doesn't exist.

                                +
                                -
                                +
                                throws
                                RuntimeException -

                                If no parenthesis opener or closer can be -determined (parse error).

                                + +

                                If no parenthesis opener or closer can be +determined (parse error).

                                +
                                -
                                +
                                Return values
                                - array + array<string|int, mixed>

                                Array with information about the caught Exception(s). The returned array will contain the following information for @@ -240,7 +324,9 @@

                                Return values
                                'type' => string, // The type declaration for the exception being caught. 'type_token' => integer, // The stack pointer to the start of the type declaration. 'type_end_token' => integer, // The stack pointer to the end of the type declaration. -)
                                +) + + @@ -248,37 +334,37 @@
                                Return values
                                class="phpdocumentor-element -method -public - -static " + -deprecated -static " >

                                getDeclareScopeOpenClose() - +

                                + 224 + +

                                Get the scope opener and closer for a DECLARE statement.

                                - + public - static getDeclareScopeOpenClose(File $phpcsFile, int $stackPtr) : array|false + static getDeclareScopeOpenClose(File $phpcsFile, int $stackPtr) : array<string|int, mixed>|false

                                A declare statement can be:

                                  -
                                • applied to the rest of the file, like declare(ticks=1);
                                • +
                                • applied to the rest of the file, like declare(ticks=1); +
                                • applied to a limited scope using curly braces;
                                • applied to a limited scope using the alternative control structure syntax.

                                In the first case, the statement - correctly - won't have a scope opener/closer. In the second case, the statement will have the scope opener/closer indexes. In the last case, due to a bug in the PHPCS Tokenizer, it won't have the scope opener/closer indexes, -while it really should. This bug is fixed in PHPCS 3.5.4.

                                -

                                In other words, if a sniff needs to support PHPCS < 3.5.4 and needs to take the alternative -control structure syntax into account, this method can be used to retrieve the -scope opener/closer for the declare statement.

                                +while it really should. This bug was fixed in PHPCS 3.5.4.

                                +
                                Parameters
                                @@ -287,7 +373,8 @@
                                Parameters
                                : File
                                -

                                The file being scanned.

                                +

                                The file being scanned.

                                +
                                @@ -295,7 +382,8 @@
                                Parameters
                                : int
                                -

                                The position of the token we are checking.

                                +

                                The position of the token we are checking.

                                +
                                @@ -310,21 +398,32 @@
                                link
                                - https://github.com/squizlabs/PHP_CodeSniffer/pull/2843 -

                                PHPCS PR #2843

                                - -
                                +

                                PHPCS PR #2843

                                +
                                + +
                                since
                                1.0.0 - -
                                + + + +
                                + deprecated +
                                +
                                + 1.0.0-alpha4 + +

                                Check the scope_opener/scope_closer instead.

                                +
                                + +
                                Return values
                                - array|false + array<string|int, mixed>|false

                                An array with the token pointers; or FALSE if not a DECLARE token or if the opener/closer could not be determined. @@ -332,7 +431,9 @@

                                Return values
                                array(
                                   'opener' => integer, // Stack pointer to the scope opener.
                                   'closer' => integer, // Stack pointer to the scope closer.
                                -)
                                +) + + @@ -344,25 +445,28 @@
                                Return values
                                >

                                hasBody() - +

                                + 52 + +

                                Check whether a control structure has a body.

                                public - static hasBody(File $phpcsFile, int $stackPtr[, bool $allowEmpty = true ]) : bool + static hasBody(File $phpcsFile, int $stackPtr[, bool $allowEmpty = true ]) : bool

                                Some control structures - while, for and declare - can be declared without a body, like:

                                -
                                while (++$i < 10);
                                +
                                while (++$i < 10);
                                +

                                All other control structures will always have a body, though the body may be empty, where "empty" means: no code is found in the body. If a control structure body only contains a comment, it will be -regarded as empty.

                                +regarded as empty.

                                +
                                Parameters
                                @@ -371,7 +475,8 @@
                                Parameters
                                : File
                                -

                                The file being scanned.

                                +

                                The file being scanned.

                                +
                                @@ -379,7 +484,8 @@
                                Parameters
                                : int
                                -

                                The position of the token we are checking.

                                +

                                The position of the token we are checking.

                                +
                                @@ -389,7 +495,8 @@
                                Parameters

                                Whether a control structure with an empty body should still be considered as having a body. -Defaults to true.

                                +Defaults to true.

                                +
                                @@ -405,8 +512,19 @@
                                1.0.0 - -
                                + + + +
                                + since +
                                +
                                + 1.0.0-alpha4 + +

                                Added support for PHP 8.0 match control structures.

                                +
                                + +
                                Return values
                                @@ -414,7 +532,8 @@
                                Return values

                                TRUE when the control structure has a body, or in case $allowEmpty is set to FALSE: when it has a non-empty body. -FALSE in all other cases, including when a non-control structure token has been passed.

                                +FALSE in all other cases, including when a non-control structure token has been passed.

                                + @@ -426,19 +545,20 @@
                                Return values
                                >

                                isElseIf() - +

                                + 153 + +

                                Check whether an IF or ELSE token is part of an "else if".

                                public - static isElseIf(File $phpcsFile, int $stackPtr) : bool + static isElseIf(File $phpcsFile, int $stackPtr) : bool
                                Parameters
                                @@ -448,7 +568,8 @@
                                Parameters
                                : File
                                -

                                The file being scanned.

                                +

                                The file being scanned.

                                +
                                @@ -456,7 +577,8 @@
                                Parameters
                                : int
                                -

                                The position of the token we are checking.

                                +

                                The position of the token we are checking.

                                +
                                @@ -472,8 +594,9 @@
                                1.0.0 - -
                                + + +
                                Return values
                                @@ -484,21 +607,92 @@
                                Return values
                                - -
                                + + -

                                Search results

                                -
                                  -
                                -
                                + +
                                +
                                +
                                +

                                Search results

                                + +
                                +
                                +
                                  +
                                  +
                                  +
                                  - +
                                  + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html b/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html index ec549ccc..5bfe7eb8 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-FunctionDeclarations.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                  -

                                  PHPCSUtils

                                  - -
                                  - -
                                  -
                                  -

                                  Utility functions for use when examining function declaration statements.

                                  @@ -98,14 +153,26 @@
                                  1.0.0 -

                                  The FunctionDeclarations::getProperties() and the + +

                                  The FunctionDeclarations::getProperties() and the FunctionDeclarations::getParameters() methods are based on and inspired by respectively the getMethodProperties() and getMethodParameters() methods in the PHPCS native PHP_CodeSniffer\Files\File class. -Also see {@see \PHPCSUtils\BackCompat\BCFile}.

                                  +Also see BCFile.

                                  +
                                  -
                                  + +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Dropped support for PHPCS < 3.7.1.

                                  +
                                  + +
                                  @@ -119,116 +186,116 @@

                                  -
                                  - $magicFunctions +
                                  + $magicFunctions -  : array +  : array<string|int, mixed>
                                  A list of all PHP magic functions.
                                  - $magicMethods + $magicMethods -  : array +  : array<string|int, mixed>
                                  A list of all PHP magic methods.
                                  - $methodsDoubleUnderscore + $methodsDoubleUnderscore -  : array +  : array<string|int, mixed>
                                  A list of all PHP native non-magic methods starting with a double underscore.
                                  - getArrowFunctionOpenClose() + getArrowFunctionOpenClose() -  : array|false +  : array<string|int, mixed>|false
                                  Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer for an arrow function.
                                  - getName() + getName() -  : string|null +  : string|null
                                  Returns the declaration name for a function.
                                  - getParameters() + getParameters() -  : array +  : array<string|int, mixed>
                                  Retrieves the method parameters for the specified function token.
                                  - getProperties() + getProperties() -  : array +  : array<string|int, mixed>
                                  Retrieves the visibility and implementation properties of a method.
                                  - isArrowFunction() + isArrowFunction() -  : bool +  : bool
                                  Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function.
                                  - isMagicFunction() + isMagicFunction() -  : bool +  : bool
                                  Checks if a given function is a PHP magic function.
                                  - isMagicFunctionName() + isMagicFunctionName() -  : bool +  : bool
                                  Verify if a given function name is the name of a PHP magic function.
                                  - isMagicMethod() + isMagicMethod() -  : bool +  : bool
                                  Checks if a given function is a PHP magic method.
                                  - isMagicMethodName() + isMagicMethodName() -  : bool +  : bool
                                  Verify if a given function name is the name of a PHP magic method.
                                  - isPHPDoubleUnderscoreMethod() + isPHPDoubleUnderscoreMethod() -  : bool +  : bool
                                  Checks if a given function is a non-magic PHP native double underscore method.
                                  - isPHPDoubleUnderscoreMethodName() + isPHPDoubleUnderscoreMethodName() -  : bool +  : bool
                                  Verify if a given function name is the name of a non-magic PHP native double underscore method.
                                  - isSpecialMethod() + isSpecialMethod() -  : bool +  : bool
                                  Checks if a given function is a magic method or a PHP native double underscore method.
                                  - isSpecialMethodName() + isSpecialMethodName() -  : bool +  : bool
                                  Verify if a given function name is the name of a magic method or a PHP native double underscore method.
                                  @@ -242,7 +309,7 @@

                                  Properties - +

                                  >

                                  $magicFunctions - +

                                  + +

                                  A list of all PHP magic functions.

                                  public - static array + static array<string|int, mixed> $magicFunctions = ['__autoload' => 'autoload']

                                  The array keys contain the function names. The values contain the name without the double underscore.

                                  The function names are listed in lowercase as these function names in PHP are case-insensitive -and comparisons against this list should therefore always be done in a case-insensitive manner.

                                  +and comparisons against this list should therefore always be done in a case-insensitive manner.

                                  +
                                  + +

                                  =>

                                  +

                                  @@ -286,8 +358,9 @@
                                  1.0.0 - -
                                  + + +
                                  @@ -300,21 +373,22 @@
                                  >

                                  $magicMethods - +

                                  + +

                                  A list of all PHP magic methods.

                                  public - static array + static array<string|int, mixed> $magicMethods = [ '__construct' => 'construct', @@ -340,7 +414,11 @@

                                  The array keys contain the method names. The values contain the name without the double underscore.

                                  The method names are listed in lowercase as these method names in PHP are case-insensitive -and comparisons against this list should therefore always be done in a case-insensitive manner.

                                  +and comparisons against this list should therefore always be done in a case-insensitive manner.

                                  + + +

                                  =>

                                  +

                                  @@ -353,8 +431,9 @@
                                  1.0.0 - -
                                  + + + @@ -367,21 +446,22 @@
                                  >

                                  $methodsDoubleUnderscore - +

                                  + +

                                  A list of all PHP native non-magic methods starting with a double underscore.

                                  public - static array + static array<string|int, mixed> $methodsDoubleUnderscore = ['__dorequest' => 'SOAPClient', '__getcookies' => 'SOAPClient', '__getfunctions' => 'SOAPClient', '__getlastrequest' => 'SOAPClient', '__getlastrequestheaders' => 'SOAPClient', '__getlastresponse' => 'SOAPClient', '__getlastresponseheaders' => 'SOAPClient', '__gettypes' => 'SOAPClient', '__setcookie' => 'SOAPClient', '__setlocation' => 'SOAPClient', '__setsoapheaders' => 'SOAPClient', '__soapcall' => 'SOAPClient'] @@ -389,7 +469,11 @@

                                  The array keys are the method names, the values the name of the PHP class containing the function.

                                  The method names are listed in lowercase as function names in PHP are case-insensitive -and comparisons against this list should therefore always be done in a case-insensitive manner.

                                  +and comparisons against this list should therefore always be done in a case-insensitive manner.

                                  + + +

                                  =>

                                  +

                                  @@ -402,8 +486,9 @@
                                  1.0.0 - -
                                  + + + @@ -412,35 +497,35 @@

                                  Methods - +

                                  getArrowFunctionOpenClose() - +

                                  + 695 + +

                                  Retrieve the parenthesis opener, parenthesis closer, the scope opener and the scope closer for an arrow function.

                                  - + public - static getArrowFunctionOpenClose(File $phpcsFile, int $stackPtr) : array|false + static getArrowFunctionOpenClose(File $phpcsFile, int $stackPtr) : array<string|int, mixed>|false

                                  Helper function for cross-version compatibility with both PHP as well as PHPCS. -In PHPCS versions prior to PHPCS 3.5.3/3.5.4, the T_FN token is not yet backfilled -and does not have parenthesis opener/closer nor scope opener/closer indexes assigned -in the $tokens array.

                                  +As of PHPCS 3.5.6, this function is no longer be needed.

                                  +
                                  Parameters
                                  @@ -449,7 +534,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file where this token was found.

                                  +

                                  The file where this token was found.

                                  +
                                  @@ -459,7 +545,8 @@
                                  Parameters

                                  The token to retrieve the openers/closers for. Typically a T_FN or T_STRING token as those are the -only two tokens which can be the arrow function keyword.

                                  +only two tokens which can be the arrow function keyword.

                                  +
                                  @@ -474,21 +561,34 @@
                                  see
                                  - FunctionDeclarations::isArrowFunction() -

                                  Related function.

                                  + FunctionDeclarations::isArrowFunction() + +

                                  Related function.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + + +
                                  + deprecated +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Use the T_FN token constant instead.

                                  +
                                  + +
                                  Return values
                                  - array|false + array<string|int, mixed>|false

                                  An array with the token pointers or FALSE if this is not an arrow function. The format of the return value is:

                                  @@ -497,7 +597,9 @@
                                  Return values
                                  'parenthesis_closer' => integer, // Stack pointer to the parenthesis closer. 'scope_opener' => integer, // Stack pointer to the scope opener (arrow). 'scope_closer' => integer, // Stack pointer to the scope closer. -)
                                  +) + + @@ -509,21 +611,23 @@
                                  Return values
                                  >

                                  getName() - +

                                  + 136 + +

                                  Returns the declaration name for a function.

                                  public - static getName(File $phpcsFile, int $stackPtr) : string|null + static getName(File $phpcsFile, int $stackPtr) : string|null -

                                  Alias for the \PHPCSUtils\Utils\ObjectDeclarations::getName() method.

                                  +

                                  Alias for the ObjectDeclarations::getName() method.

                                  +
                                  Parameters
                                  @@ -532,7 +636,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file being scanned.

                                  +

                                  The file being scanned.

                                  +
                                  @@ -540,7 +645,8 @@
                                  Parameters
                                  : int
                                  -

                                  The position of the function keyword token.

                                  +

                                  The position of the function keyword token.

                                  +
                                  @@ -555,47 +661,49 @@
                                  see
                                  - BCFile::getDeclarationName() -

                                  Original function.

                                  + BCFile::getDeclarationName() + +

                                  Original function.

                                  +
                                  -
                                  +
                                  see
                                  - ObjectDeclarations::getName() -

                                  PHPCSUtils native improved version.

                                  + ObjectDeclarations::getName() + +

                                  PHPCSUtils native improved version.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  -
                                  - codeCoverageIgnore -
                                  -
                                  - -
                                  + + +
                                  throws
                                  RuntimeException -

                                  If the specified token is not of type -T_FUNCTION.

                                  + +

                                  If the specified token is not of type +T_FUNCTION.

                                  +
                                  -
                                  +
                                  Return values
                                  string|null

                                  The name of the function; or NULL if the passed token doesn't exist, -the function is anonymous or in case of a parse error/live coding.

                                  +the function is anonymous or in case of a parse error/live coding.

                                  + @@ -607,19 +715,20 @@
                                  Return values
                                  >

                                  getParameters() - +

                                  + 394 + +

                                  Retrieves the method parameters for the specified function token.

                                  public - static getParameters(File $phpcsFile, int $stackPtr) : array + static getParameters(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

                                  Also supports passing in a T_USE token for a closure use group.

                                  The returned array will contain the following information for each parameter:

                                  @@ -627,6 +736,7 @@

                                  'name' => '$var', // The variable name. 'token' => integer, // The stack pointer to the variable name. 'content' => string, // The full content of the variable definition. + 'has_attributes' => boolean, // Does the parameter have one or more attributes attached ? 'pass_by_reference' => boolean, // Is the variable passed by reference? 'reference_token' => integer, // The stack pointer to the reference operator // or FALSE if the param is not passed by reference. @@ -638,23 +748,34 @@

                                  // or FALSE if there is no type hint. 'type_hint_end_token' => integer, // The stack pointer to the end of the type hint // or FALSE if there is no type hint. - 'nullable_type' => boolean, // TRUE if the var type is nullable. + 'nullable_type' => boolean, // TRUE if the var type is preceded by the nullability + // operator. 'comma_token' => integer, // The stack pointer to the comma after the param // or FALSE if this is the last param. -) +) +

                                  Parameters with default values have the following additional array indexes:

                                    'default'             => string,  // The full content of the default value.
                                     'default_token'       => integer, // The stack pointer to the start of the default value.
                                  -  'default_equal_token' => integer, // The stack pointer to the equals sign.
                                  + 'default_equal_token' => integer, // The stack pointer to the equals sign. + +

                                  Parameters declared using PHP 8 constructor property promotion, have these additional array indexes:

                                  +
                                    'property_visibility' => string,  // The property visibility as declared.
                                  +  'visibility_token'    => integer, // The stack pointer to the visibility modifier token.
                                  +  'property_readonly'   => bool,    // TRUE if the readonly keyword was found.
                                  +  'readonly_token'      => integer, // The stack pointer to the readonly modifier token.
                                  +

                                  Main differences with the PHPCS version:

                                  • Defensive coding against incorrect calls to this method.
                                  • More efficient and more stable checking whether a T_USE token is a closure use.
                                  • More efficient and more stable looping of the default value.
                                  • Clearer exception message when a non-closure use token was passed to the function.
                                  • -
                                  • To allow for backward compatible handling of arrow functions, this method will also accept -T_STRING tokens and examine them to check if these are arrow functions.
                                  • -

                                  +
                                • Support for PHP 8.0 identifier name tokens in parameter types, cross-version PHP & PHPCS.
                                • +
                                • Support for the PHP 8.2 true type.
                                • +
                                • The results of this function call are cached during a PHPCS run for faster response times.
                                • + +
                                  Parameters
                                  @@ -663,7 +784,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file being scanned.

                                  +

                                  The file being scanned.

                                  +
                                  @@ -672,7 +794,8 @@
                                  Parameters

                                  The position in the stack of the function token -to acquire the parameters for.

                                  +to acquire the parameters for.

                                  +
                                  @@ -688,55 +811,136 @@
                                  File::getMethodParameters() -

                                  Original source.

                                  + +

                                  Original source.

                                  +
                                  -
                                  +
                                  see
                                  - BCFile::getMethodParameters() -

                                  Cross-version compatible version of the original.

                                  + BCFile::getMethodParameters() + +

                                  Cross-version compatible version of the original.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  since
                                  1.0.0-alpha2 -

                                  Added BC support for PHP 7.4 arrow functions.

                                  + +

                                  Added support for PHP 7.4 arrow functions.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.0 union types.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.0 constructor property promotion.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.0 identifier name tokenization.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.0 parameter attributes.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.1 readonly keyword for constructor property promotion.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.1 intersection types.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.2 true type.

                                  +
                                  -
                                  +
                                  throws
                                  RuntimeException -

                                  If the specified $stackPtr is not of + +

                                  If the specified $stackPtr is not of type T_FUNCTION, T_CLOSURE or T_USE, -nor an arrow function.

                                  +nor an arrow function.

                                  +
                                  -
                                  +
                                  throws
                                  RuntimeException -

                                  If a passed T_USE token is not a closure -use token.

                                  + +

                                  If a passed T_USE token is not a closure +use token.

                                  +
                                  -
                                  +
                                  Return values
                                  - array + array<string|int, mixed> — @@ -749,34 +953,37 @@
                                  Return values
                                  >

                                  getProperties() - +

                                  + 191 + +

                                  Retrieves the visibility and implementation properties of a method.

                                  public - static getProperties(File $phpcsFile, int $stackPtr) : array + static getProperties(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

                                  Main differences with the PHPCS version:

                                  • Bugs fixed:
                                    • Handling of PHPCS annotations.
                                    • -
                                    • "has_body" index could be set to true for functions without body in the case of +
                                    • +"has_body" index could be set to true for functions without body in the case of parse errors or live coding.
                                    • -
                                  • +
                                  +
                                • Defensive coding against incorrect calls to this method.
                                • More efficient checking whether a function has a body.
                                • -
                                • New "return_type_end_token" (int|false) array index.
                                • -
                                • To allow for backward compatible handling of arrow functions, this method will also accept -T_STRING tokens and examine them to check if these are arrow functions.
                                • -
                                  +
                                • Support for PHP 8.0 identifier name tokens in return types, cross-version PHP & PHPCS.
                                • +
                                • Support for the PHP 8.2 true type.
                                • + +
                                  Parameters
                                  @@ -785,7 +992,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file being scanned.

                                  +

                                  The file being scanned.

                                  +
                                  @@ -794,7 +1002,8 @@
                                  Parameters

                                  The position in the stack of the function token to -acquire the properties for.

                                  +acquire the properties for.

                                  +
                                  @@ -810,53 +1019,94 @@
                                  File::getMethodProperties() -

                                  Original source.

                                  + +

                                  Original source.

                                  +
                                  -
                                  +
                                  see
                                  - BCFile::getMethodProperties() -

                                  Cross-version compatible version of the original.

                                  + BCFile::getMethodProperties() + +

                                  Cross-version compatible version of the original.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  since
                                  1.0.0-alpha2 -

                                  Added BC support for PHP 7.4 arrow functions.

                                  + +

                                  Added support for PHP 7.4 arrow functions.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0-alpha3 -

                                  Added support for PHP 8.0 static return type.

                                  + +

                                  Added support for PHP 8.0 static return type.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.0 union types.

                                  +
                                  + +
                                  +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.1 intersection types.

                                  +
                                  -
                                  + +
                                  + since +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Added support for PHP 8.2 true type.

                                  +
                                  + +
                                  throws
                                  RuntimeException -

                                  If the specified position is not a T_FUNCTION -or T_CLOSURE token, nor an arrow function.

                                  + +

                                  If the specified position is not a T_FUNCTION +or T_CLOSURE token, nor an arrow function.

                                  +
                                  -
                                  +
                                  Return values
                                  - array + array<string|int, mixed>

                                  Array with information about a function declaration. The format of the return value is:

                                  @@ -868,12 +1118,15 @@
                                  Return values
                                  // or FALSE if there is no return type. 'return_type_end_token' => integer, // The stack pointer to the end of the return type // or FALSE if there is no return type. - 'nullable_return_type' => false, // TRUE if the return type is nullable. + 'nullable_return_type' => false, // TRUE if the return type is preceded + // by the nullability operator. 'is_abstract' => false, // TRUE if the abstract keyword was found. 'is_final' => false, // TRUE if the final keyword was found. 'is_static' => false, // TRUE if the static keyword was found. 'has_body' => false, // TRUE if the method has a body -);
                                  +); + + @@ -881,45 +1134,28 @@
                                  Return values
                                  class="phpdocumentor-element -method -public - -static " + -deprecated -static " >

                                  isArrowFunction() - +

                                  + 643 + +

                                  Check if an arbitrary token is the "fn" keyword for a PHP 7.4 arrow function.

                                  - + public - static isArrowFunction(File $phpcsFile, int $stackPtr) : bool + static isArrowFunction(File $phpcsFile, int $stackPtr) : bool -

                                  Helper function for cross-version compatibility with both PHP as well as PHPCS.

                                  -
                                    -
                                  • PHP 7.4+ will tokenize most tokens with the content "fn" as T_FN, even when it isn't an arrow function.
                                  • -
                                  • PHPCS < 3.5.3 will tokenize arrow functions keywords as T_STRING.
                                  • -
                                  • PHPCS 3.5.3/3.5.4 will tokenize the keyword differently depending on which PHP version is used -and similar to PHP will tokenize most tokens with the content "fn" as T_FN, even when it's not an -arrow function. -
                                    -

                                    Note: the tokens tokenized by PHPCS 3.5.3 - 3.5.4 as T_FN are not 100% the same as those tokenized -by PHP 7.4+ as T_FN.

                                    -
                                  • -
                                  -

                                  Either way, the T_FN token is not a reliable search vector for finding or examining -arrow functions, at least not until PHPCS 3.5.5. -This function solves that and will give reliable results in the same way as this is now -solved in PHPCS 3.5.5.

                                  -
                                  -

                                  Note: Bugs are still being found and reported about how PHPCS tokenizes the arrow functions. -This method will keep up with upstream changes and backport them, in as far possible, to allow -for sniffing arrow functions in PHPCS < current.

                                  -
                                  +

                                  Helper function for cross-version compatibility with both PHP as well as PHPCS. +As of PHPCS 3.5.6, this function is no longer be needed.

                                  +
                                  Parameters
                                  @@ -928,7 +1164,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file where this token was found.

                                  +

                                  The file where this token was found.

                                  +
                                  @@ -938,7 +1175,8 @@
                                  Parameters

                                  The token to check. Typically a T_FN or T_STRING token as those are the only two -tokens which can be the arrow function keyword.

                                  +tokens which can be the arrow function keyword.

                                  +
                                  @@ -953,24 +1191,38 @@
                                  see
                                  - FunctionDeclarations::getArrowFunctionOpenClose() -

                                  Related function.

                                  + FunctionDeclarations::getArrowFunctionOpenClose() + +

                                  Related function.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + + +
                                  + deprecated +
                                  +
                                  + 1.0.0-alpha4 + +

                                  Use the T_FN token constant instead.

                                  +
                                  + +
                                  Return values
                                  bool

                                  TRUE if the token is the "fn" keyword for an arrow function. FALSE when it's not -or in case of live coding/parse error.

                                  +or in case of live coding/parse error.

                                  + @@ -982,19 +1234,20 @@
                                  Return values
                                  >

                                  isMagicFunction() - +

                                  + 743 + +

                                  Checks if a given function is a PHP magic function.

                                  public - static isMagicFunction(File $phpcsFile, int $stackPtr) : bool + static isMagicFunction(File $phpcsFile, int $stackPtr) : bool
                                  Parameters
                                  @@ -1004,7 +1257,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file where this token was found.

                                  +

                                  The file where this token was found.

                                  +
                                  @@ -1012,7 +1266,8 @@
                                  Parameters
                                  : int
                                  -

                                  The T_FUNCTION token to check.

                                  +

                                  The T_FUNCTION token to check.

                                  +
                                  @@ -1027,34 +1282,41 @@
                                  todo
                                  -

                                  Add check for the function declaration being namespaced!

                                  + +

                                  Add check for the function declaration being namespaced!

                                  +
                                  -
                                  +
                                  see
                                  FunctionDeclaration::$magicFunctions -

                                  List of names of magic functions.

                                  + +

                                  List of names of magic functions.

                                  +
                                  -
                                  +
                                  see
                                  FunctionDeclaration::isMagicFunctionName() -

                                  For when you already know the name of the + +

                                  For when you already know the name of the function and scope checking is done in the -sniff.

                                  +sniff.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1071,19 +1333,20 @@
                                  Return values
                                  >

                                  isMagicFunctionName() - +

                                  + 769 + +

                                  Verify if a given function name is the name of a PHP magic function.

                                  public - static isMagicFunctionName(string $name) : bool + static isMagicFunctionName(string $name) : bool
                                  Parameters
                                  @@ -1093,7 +1356,8 @@
                                  Parameters
                                  : string
                                  -

                                  The full function name.

                                  +

                                  The full function name.

                                  +
                                  @@ -1109,16 +1373,19 @@
                                  FunctionDeclaration::$magicFunctions -

                                  List of names of magic functions.

                                  + +

                                  List of names of magic functions.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1135,19 +1402,20 @@
                                  Return values
                                  >

                                  isMagicMethod() - +

                                  + 790 + +

                                  Checks if a given function is a PHP magic method.

                                  public - static isMagicMethod(File $phpcsFile, int $stackPtr) : bool + static isMagicMethod(File $phpcsFile, int $stackPtr) : bool
                                  Parameters
                                  @@ -1157,7 +1425,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file where this token was found.

                                  +

                                  The file where this token was found.

                                  +
                                  @@ -1165,7 +1434,8 @@
                                  Parameters
                                  : int
                                  -

                                  The T_FUNCTION token to check.

                                  +

                                  The T_FUNCTION token to check.

                                  +
                                  @@ -1181,26 +1451,31 @@
                                  FunctionDeclaration::$magicMethods -

                                  List of names of magic methods.

                                  + +

                                  List of names of magic methods.

                                  +
                                  -
                                  +
                                  see
                                  FunctionDeclaration::isMagicMethodName() -

                                  For when you already know the name of the + +

                                  For when you already know the name of the method and scope checking is done in the -sniff.

                                  +sniff.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1217,19 +1492,20 @@
                                  Return values
                                  >

                                  isMagicMethodName() - +

                                  + 811 + +

                                  Verify if a given function name is the name of a PHP magic method.

                                  public - static isMagicMethodName(string $name) : bool + static isMagicMethodName(string $name) : bool
                                  Parameters
                                  @@ -1239,7 +1515,8 @@
                                  Parameters
                                  : string
                                  -

                                  The full function name.

                                  +

                                  The full function name.

                                  +
                                  @@ -1255,16 +1532,19 @@
                                  FunctionDeclaration::$magicMethods -

                                  List of names of magic methods.

                                  + +

                                  List of names of magic methods.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1281,19 +1561,20 @@
                                  Return values
                                  >

                                  isPHPDoubleUnderscoreMethod() - +

                                  + 833 + +

                                  Checks if a given function is a non-magic PHP native double underscore method.

                                  public - static isPHPDoubleUnderscoreMethod(File $phpcsFile, int $stackPtr) : bool + static isPHPDoubleUnderscoreMethod(File $phpcsFile, int $stackPtr) : bool
                                  Parameters
                                  @@ -1303,7 +1584,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file where this token was found.

                                  +

                                  The file where this token was found.

                                  +
                                  @@ -1311,7 +1593,8 @@
                                  Parameters
                                  : int
                                  -

                                  The T_FUNCTION token to check.

                                  +

                                  The T_FUNCTION token to check.

                                  +
                                  @@ -1327,27 +1610,32 @@
                                  FunctionDeclaration::$methodsDoubleUnderscore -

                                  List of the PHP native non-magic -double underscore method names.

                                  + +

                                  List of the PHP native non-magic +double underscore method names.

                                  +
                                  -
                                  +
                                  see
                                  FunctionDeclaration::isPHPDoubleUnderscoreMethodName() -

                                  For when you already know the + +

                                  For when you already know the name of the method and scope -checking is done in the sniff.

                                  +checking is done in the sniff.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1364,19 +1652,20 @@
                                  Return values
                                  >

                                  isPHPDoubleUnderscoreMethodName() - +

                                  + 874 + +

                                  Verify if a given function name is the name of a non-magic PHP native double underscore method.

                                  public - static isPHPDoubleUnderscoreMethodName(string $name) : bool + static isPHPDoubleUnderscoreMethodName(string $name) : bool
                                  Parameters
                                  @@ -1386,7 +1675,8 @@
                                  Parameters
                                  : string
                                  -

                                  The full function name.

                                  +

                                  The full function name.

                                  +
                                  @@ -1402,17 +1692,20 @@
                                  FunctionDeclaration::$methodsDoubleUnderscore -

                                  List of the PHP native non-magic -double underscore method names.

                                  + +

                                  List of the PHP native non-magic +double underscore method names.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1429,22 +1722,22 @@
                                  Return values
                                  >

                                  isSpecialMethod() - +

                                  + 897 + +

                                  Checks if a given function is a magic method or a PHP native double underscore method.

                                  public - static isSpecialMethod(File $phpcsFile, int $stackPtr) : bool + static isSpecialMethod(File $phpcsFile, int $stackPtr) : bool -

                                  {@internal Not the most efficient way of checking this, but less efficient ways will get -less reliable results or introduce a lot of code duplication.}

                                  +
                                  Parameters
                                  @@ -1453,7 +1746,8 @@
                                  Parameters
                                  : File
                                  -

                                  The file where this token was found.

                                  +

                                  The file where this token was found.

                                  +
                                  @@ -1461,7 +1755,8 @@
                                  Parameters
                                  : int
                                  -

                                  The T_FUNCTION token to check.

                                  +

                                  The T_FUNCTION token to check.

                                  +
                                  @@ -1477,18 +1772,21 @@
                                  FunctionDeclaration::isSpecialMethodName() -

                                  For when you already know the name of the + +

                                  For when you already know the name of the method and scope checking is done in the -sniff.

                                  +sniff.

                                  +
                                  -
                                  +
                                  since
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1505,19 +1803,20 @@
                                  Return values
                                  >

                                  isSpecialMethodName() - +

                                  + 919 + +

                                  Verify if a given function name is the name of a magic method or a PHP native double underscore method.

                                  public - static isSpecialMethodName(string $name) : bool + static isSpecialMethodName(string $name) : bool
                                  Parameters
                                  @@ -1527,7 +1826,8 @@
                                  Parameters
                                  : string
                                  -

                                  The full function name.

                                  +

                                  The full function name.

                                  +
                                  @@ -1543,8 +1843,9 @@
                                  1.0.0 - -
                                  + + +
                                  Return values
                                  @@ -1555,21 +1856,92 @@
                                  Return values
                                  - -
                                  + + -

                                  Search results

                                  -
                                    -
                                  -
                                  + +
                                  +
                                  +
                                  +

                                  Search results

                                  + +
                                  +
                                  +
                                    +
                                    +
                                    +
                                    - +
                                    + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html b/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html index 567ce6f3..3aad22cc 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-GetTokensAsString.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                    -

                                    PHPCSUtils

                                    - -
                                    - -
                                    -
                                    -

                                    Utility functions to retrieve the content of a set of tokens as a string.

                                    -

                                    In contrast to the PHPCS native \PHP_CodeSniffer\Files\File::getTokensAsString() method, +

                                    In contrast to the PHPCS native File::getTokensAsString() method, which has $length as the third parameter, all methods in this class expect a stack pointer to -an $end token (inclusive) as the third parameter.

                                    +an $end token (inclusive) as the third parameter.

                                    +
                                    @@ -101,12 +157,14 @@
                                    1.0.0 -

                                    The principle of this class is loosely based on and inspired by the -{@see \PHP_CodeSniffer\Files\File::getTokensAsString()} method in the + +

                                    The principle of this class is loosely based on and inspired by the +File::getTokensAsString() method in the PHPCS native File class. -Also see {@see \PHPCSUtils\BackCompat\BCFile::getTokensAsString()}.

                                    +Also see BCFile::getTokensAsString().

                                    +
                                    -
                                    + @@ -120,59 +178,59 @@

                                    -
                                    - compact() +
                                    + compact() -  : string +  : string
                                    Retrieve the content of the tokens from the specified start position in the token stack to the specified end position (inclusive) with all consecutive whitespace tokens - tabs, new lines, multiple spaces - replaced by a single space and optionally without comments.
                                    - noComments() + noComments() -  : string +  : string
                                    Retrieve the content of the tokens from the specified start position in the token stack to the specified end position (inclusive) without comments.
                                    - noEmpties() + noEmpties() -  : string +  : string
                                    Retrieve the code-tokens only content of the tokens from the specified start position in the token stack to the specified end position (inclusive) without whitespace or comments.
                                    - normal() + normal() -  : string +  : string
                                    Retrieve the tab-replaced content of the tokens from the specified start position in the token stack to the specified end position (inclusive).
                                    - origContent() + origContent() -  : string +  : string
                                    Retrieve the original content of the tokens from the specified start position in the token stack to the specified end position (inclusive).
                                    - tabReplaced() + tabReplaced() -  : string +  : string
                                    Retrieve the tab-replaced content of the tokens from the specified start position in the token stack to the specified end position (inclusive).
                                    - getString() + getString() -  : string +  : string
                                    Retrieve the content of the tokens from the specified start position in the token stack to the specified end position (inclusive).
                                    @@ -188,7 +246,7 @@

                                    Methods - +

                                    >

                                    compact() - +

                                    + +

                                    Retrieve the content of the tokens from the specified start position in the token stack to the specified end position (inclusive) with all consecutive whitespace tokens - tabs, @@ -212,7 +271,7 @@

                                    public - static compact(File $phpcsFile, int $start, int $end[, bool $stripComments = false ]) : string + static compact(File $phpcsFile, int $start, int $end[, bool $stripComments = false ]) : string

                                    Parameters
                                    @@ -222,7 +281,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -230,7 +290,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -238,7 +299,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -247,7 +309,8 @@
                                    Parameters
                                    = false

                                    Whether comments should be stripped from the contents. -Defaults to false.

                                    +Defaults to false.

                                    +

                                    @@ -263,30 +326,36 @@
                                    File::getTokensAsString() -

                                    Loosely related function.

                                    + +

                                    Loosely related function.

                                    +
                                    -
                                    +
                                    since
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents with compacted whitespace and optionally stripped off comments.

                                    +

                                    The token contents with compacted whitespace and optionally stripped off comments.

                                    +
                                    @@ -298,20 +367,21 @@
                                    Return values
                                    >

                                    noComments() - +

                                    + +

                                    Retrieve the content of the tokens from the specified start position in the token stack to the specified end position (inclusive) without comments.

                                    public - static noComments(File $phpcsFile, int $start, int $end) : string + static noComments(File $phpcsFile, int $start, int $end) : string
                                    Parameters
                                    @@ -321,7 +391,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -329,7 +400,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -337,7 +409,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -353,30 +426,36 @@
                                    File::getTokensAsString() -

                                    Loosely related function.

                                    + +

                                    Loosely related function.

                                    +
                                    -
                                    +
                                    since
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents stripped off comments.

                                    +

                                    The token contents stripped off comments.

                                    +
                                    @@ -388,23 +467,25 @@
                                    Return values
                                    >

                                    noEmpties() - +

                                    + +

                                    Retrieve the code-tokens only content of the tokens from the specified start position in the token stack to the specified end position (inclusive) without whitespace or comments.

                                    public - static noEmpties(File $phpcsFile, int $start, int $end) : string + static noEmpties(File $phpcsFile, int $start, int $end) : string -

                                    This is, for instance, useful to retrieve a namespace name without stray whitespace or comments. -Use this function selectively and with care!

                                    +

                                    This is useful, for instance, to retrieve a namespace name without stray whitespace or comments. +Use this function selectively and with care!

                                    +
                                    Parameters
                                    @@ -413,7 +494,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -421,7 +503,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -429,7 +512,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -445,30 +529,36 @@
                                    File::getTokensAsString() -

                                    Loosely related function.

                                    + +

                                    Loosely related function.

                                    +
                                    -
                                    +
                                    since
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents stripped off comments and whitespace.

                                    +

                                    The token contents stripped off comments and whitespace.

                                    +
                                    @@ -480,26 +570,24 @@
                                    Return values
                                    >

                                    normal() - +

                                    + 48 + +

                                    Retrieve the tab-replaced content of the tokens from the specified start position in the token stack to the specified end position (inclusive).

                                    public - static normal(File $phpcsFile, int $start, int $end) : string + static normal(File $phpcsFile, int $start, int $end) : string -

                                    This is the default behaviour for PHPCS.

                                    -

                                    If the tabWidth is set, either via a (custom) ruleset, the config file or by passing it -on the command-line, PHPCS will automatically replace tabs with spaces. -The 'content' index key in the $tokens array will contain the tab-replaced content. -The 'orig_content' index key in the $tokens array will contain the original content.

                                    +

                                    Alias for the GetTokensAsString::tabReplaced() method.

                                    +
                                    Parameters
                                    @@ -508,7 +596,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -516,7 +605,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -524,7 +614,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -536,42 +627,30 @@
                                    - see -
                                    -
                                    - File::getTokensAsString() -

                                    Similar length-based function.

                                    - -
                                    -
                                    - see -
                                    -
                                    - BCFile::getTokensAsString() -

                                    Cross-version compatible version of the original.

                                    - -
                                    -
                                    since
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents.

                                    +

                                    The token contents.

                                    +
                                    @@ -583,28 +662,30 @@
                                    Return values
                                    >

                                    origContent() - +

                                    + +

                                    Retrieve the original content of the tokens from the specified start position in the token stack to the specified end position (inclusive).

                                    public - static origContent(File $phpcsFile, int $start, int $end) : string + static origContent(File $phpcsFile, int $start, int $end) : string -

                                    In contrast to the \PHPCSUtils\Utils\GetTokensAsString::normal() method, this method will return +

                                    In contrast to the GetTokensAsString::tabReplaced() method, this method will return the original token content for the specified tokens. That means that if the original content contained tabs, the return value of this function will also contain tabs.

                                    The same can be achieved in PHPCS since version 3.3.0, by calling the -\PHP_CodeSniffer\Files\File::getTokensAsString() method and passing true as the -value for the $origContent parameter.

                                    +File::getTokensAsString() method and passing true as the +value for the $origContent parameter.

                                    +
                                    Parameters
                                    @@ -613,7 +694,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -621,7 +703,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -629,7 +712,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -645,38 +729,46 @@
                                    File::getTokensAsString() -

                                    Similar length-based function.

                                    + +

                                    Similar length-based function.

                                    +
                                    -
                                    +
                                    see
                                    - BCFile::getTokensAsString() -

                                    Cross-version compatible version of the original.

                                    + BCFile::getTokensAsString() + +

                                    Cross-version compatible version of the original.

                                    +
                                    -
                                    +
                                    since
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents.

                                    +

                                    The token contents.

                                    +
                                    @@ -688,22 +780,28 @@
                                    Return values
                                    >

                                    tabReplaced() - +

                                    + +

                                    Retrieve the tab-replaced content of the tokens from the specified start position in the token stack to the specified end position (inclusive).

                                    public - static tabReplaced(File $phpcsFile, int $start, int $end) : string + static tabReplaced(File $phpcsFile, int $start, int $end) : string -

                                    Alias for the \PHPCSUtils\Utils\GetTokensAsString::normal() method.

                                    +

                                    This is the default behaviour for PHPCS.

                                    +

                                    If the tabWidth is set, either via a (custom) ruleset, the config file or by passing it +on the command-line, PHPCS will automatically replace tabs with spaces. +The 'content' index key in the $tokens array will contain the tab-replaced content. +The 'orig_content' index key in the $tokens array will contain the original content.

                                    +
                                    Parameters
                                    @@ -712,7 +810,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -720,7 +819,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -728,7 +828,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -740,26 +841,50 @@
                                    + see +
                                    +
                                    + File::getTokensAsString() + +

                                    Similar length-based function.

                                    +
                                    + +
                                    +
                                    + see +
                                    +
                                    + BCFile::getTokensAsString() + +

                                    Cross-version compatible version of the original.

                                    +
                                    + +
                                    +
                                    since
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents.

                                    +

                                    The token contents.

                                    +
                                    @@ -771,20 +896,21 @@
                                    Return values
                                    >

                                    getString() - +

                                    + +

                                    Retrieve the content of the tokens from the specified start position in the token stack to the specified end position (inclusive).

                                    protected - static getString(File $phpcsFile, int $start, int $end[, bool $origContent = false ][, bool $stripComments = false ][, bool $stripWhitespace = false ][, bool $compact = false ]) : string + static getString(File $phpcsFile, int $start, int $end[, bool $origContent = false ][, bool $stripComments = false ][, bool $stripWhitespace = false ][, bool $compact = false ]) : string
                                    Parameters
                                    @@ -794,7 +920,8 @@
                                    Parameters
                                    : File
                                    -

                                    The file being scanned.

                                    +

                                    The file being scanned.

                                    +
                                    @@ -802,7 +929,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to start from in the token stack.

                                    +

                                    The position to start from in the token stack.

                                    +
                                    @@ -810,7 +938,8 @@
                                    Parameters
                                    : int
                                    -

                                    The position to end at in the token stack (inclusive).

                                    +

                                    The position to end at in the token stack (inclusive).

                                    +
                                    @@ -820,7 +949,8 @@
                                    Parameters

                                    Whether the original content or the tab replaced content should be used. -Defaults to false (= tabs replaced with spaces).

                                    +Defaults to false (= tabs replaced with spaces).

                                    +
                                    @@ -829,7 +959,8 @@
                                    Parameters
                                    = false

                                    Whether comments should be stripped from the contents. -Defaults to false.

                                    +Defaults to false.

                                    +
                                    @@ -838,7 +969,8 @@
                                    Parameters
                                    = false

                                    Whether whitespace should be stripped from the contents. -Defaults to false.

                                    +Defaults to false.

                                    +
                                    @@ -847,7 +979,8 @@
                                    Parameters
                                    = false

                                    Whether all consecutive whitespace tokens should be -replaced with a single space. Defaults to false.

                                    +replaced with a single space. Defaults to false.

                                    +
                                    @@ -863,42 +996,117 @@
                                    1.0.0 - -
                                    + + +
                                    throws
                                    RuntimeException -

                                    If the specified start position does not exist.

                                    + +

                                    If the specified start position does not exist.

                                    +
                                    -
                                    +
                                    Return values
                                    string — -

                                    The token contents.

                                    +

                                    The token contents.

                                    +
                                    - -
                                    + + -

                                    Search results

                                    -
                                      -
                                    -
                                    + +
                                    +
                                    +
                                    +

                                    Search results

                                    + +
                                    +
                                    +
                                      +
                                      +
                                      +
                                      - +
                                      + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html index 412f7a62..b29767a6 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Lists.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                      -

                                      PHPCSUtils

                                      - -
                                      - -
                                      -
                                      -

                                      Utility functions to retrieve information when working with lists.

                                      @@ -98,8 +153,19 @@
                                      1.0.0 - -
                                      + + + +
                                      + since +
                                      +
                                      + 1.0.0-alpha4 + +

                                      Dropped support for PHPCS < 3.7.1.

                                      +
                                      + +
                                      @@ -113,24 +179,24 @@

                                      -
                                      - getAssignments() +
                                      + getAssignments() -  : array +  : array<string|int, mixed>
                                      Retrieves information on the assignments made in the specified (long/short) list.
                                      - getOpenClose() + getOpenClose() -  : array|false +  : array<string|int, mixed>|false
                                      Find the list opener and closer based on a T_LIST or T_OPEN_SHORT_ARRAY token.
                                      - isShortList() + isShortList() -  : bool +  : bool
                                      Determine whether a T_OPEN/CLOSE_SHORT_ARRAY token is a short list() construct.
                                      @@ -145,7 +211,7 @@

                                      Methods - +

                                      >

                                      getAssignments() - +

                                      + 203 + +

                                      Retrieves information on the assignments made in the specified (long/short) list.

                                      public - static getAssignments(File $phpcsFile, int $stackPtr) : array + static getAssignments(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

                                      This method also accepts T_OPEN_SQUARE_BRACKET tokens to allow it to be PHPCS cross-version compatible as the short array tokenizing has been plagued by @@ -198,12 +265,15 @@

                                      'assign_by_reference' => bool, // Is the variable assigned by reference? 'reference_token' => int|false, // The stack pointer to the reference operator; // or FALSE when not a reference assignment. -) +) +

                                      Assignments with keys will have the following additional array indexes set:

                                        'key'                 => string, // The content of the key, cleaned of comments.
                                         'key_token'           => int,    // The stack pointer to the start of the key.
                                         'key_end_token'       => int,    // The stack pointer to the end of the key.
                                      -  'double_arrow_token'  => int,    // The stack pointer to the double arrow.

                                      + 'double_arrow_token' => int, // The stack pointer to the double arrow. + +

                                      Parameters
                                      @@ -212,7 +282,8 @@
                                      Parameters
                                      : File
                                      -

                                      The file being scanned.

                                      +

                                      The file being scanned.

                                      +
                                      @@ -221,7 +292,8 @@
                                      Parameters

                                      The position in the stack of the function token -to acquire the parameters for.

                                      +to acquire the parameters for.

                                      +
                                      @@ -237,34 +309,40 @@
                                      1.0.0 - -
                                      + + +
                                      since
                                      1.0.0-alpha3 -

                                      The returned value has been simplified with sensible defaults and always -available keys.

                                      + +

                                      The returned value has been simplified with sensible defaults and always +available keys.

                                      +
                                      -
                                      +
                                      throws
                                      RuntimeException -

                                      If the specified $stackPtr is not of + +

                                      If the specified $stackPtr is not of type T_LIST, T_OPEN_SHORT_ARRAY or -T_OPEN_SQUARE_BRACKET.

                                      +T_OPEN_SQUARE_BRACKET.

                                      +
                                      -
                                      +
                                      Return values
                                      - array + array<string|int, mixed>

                                      An array with information on each assignment made, including skipped assignments (empty), -or an empty array if no assignments are made at all (fatal error in PHP >= 7.0).

                                      +or an empty array if no assignments are made at all (fatal error in PHP >= 7.0).

                                      + @@ -276,23 +354,25 @@
                                      Return values
                                      >

                                      getOpenClose() - +

                                      + 101 + +

                                      Find the list opener and closer based on a T_LIST or T_OPEN_SHORT_ARRAY token.

                                      public - static getOpenClose(File $phpcsFile, int $stackPtr[, true|null $isShortList = null ]) : array|false + static getOpenClose(File $phpcsFile, int $stackPtr[, true|null $isShortList = null ]) : array<string|int, mixed>|false

                                      This method also accepts T_OPEN_SQUARE_BRACKET tokens to allow it to be PHPCS cross-version compatible as the short array tokenizing has been plagued by -a number of bugs over time, which affects the short list determination.

                                      +a number of bugs over time, which affects the short list determination.

                                      +
                                      Parameters
                                      @@ -301,7 +381,8 @@
                                      Parameters
                                      : File
                                      -

                                      The file being scanned.

                                      +

                                      The file being scanned.

                                      +
                                      @@ -310,7 +391,8 @@
                                      Parameters

                                      The position of the T_LIST or T_OPEN_SHORT_ARRAY -token in the stack.

                                      +token in the stack.

                                      +
                                      @@ -323,7 +405,8 @@
                                      Parameters
                                      Efficiency tweak for when this has already been established, i.e. when encountering a nested list while walking the tokens in a list. -Use with care.

                                      +Use with care.

                                      +
                                      @@ -339,12 +422,13 @@
                                      1.0.0 - -
                                      + + +
                                      Return values
                                      - array|false + array<string|int, mixed>|false

                                      An array with the token pointers; or FALSE if this is not a (short) list token or if the opener/closer could not be determined. @@ -352,7 +436,9 @@

                                      Return values
                                      array(
                                         'opener' => integer, // Stack pointer to the list open bracket.
                                         'closer' => integer, // Stack pointer to the list close bracket.
                                      -)
                                      +) + + @@ -364,23 +450,25 @@
                                      Return values
                                      >

                                      isShortList() - +

                                      + 67 + +

                                      Determine whether a T_OPEN/CLOSE_SHORT_ARRAY token is a short list() construct.

                                      public - static isShortList(File $phpcsFile, int $stackPtr) : bool + static isShortList(File $phpcsFile, int $stackPtr) : bool

                                      This method also accepts T_OPEN/CLOSE_SQUARE_BRACKET tokens to allow it to be PHPCS cross-version compatible as the short array tokenizing has been plagued by -a number of bugs over time, which affects the short list determination.

                                      +a number of bugs over time, which affects the short list determination.

                                      +
                                      Parameters
                                      @@ -389,7 +477,8 @@
                                      Parameters
                                      : File
                                      -

                                      The file being scanned.

                                      +

                                      The file being scanned.

                                      +
                                      @@ -397,7 +486,8 @@
                                      Parameters
                                      : int
                                      -

                                      The position of the short array bracket token.

                                      +

                                      The position of the short array bracket token.

                                      +
                                      @@ -413,8 +503,9 @@
                                      1.0.0 - -
                                      + + +
                                      Return values
                                      @@ -422,27 +513,99 @@
                                      Return values

                                      TRUE if the token passed is the open/close bracket of a short list. FALSE if the token is a short array bracket or plain square bracket -or not one of the accepted tokens.

                                      +or not one of the accepted tokens.

                                      + - -
                                      + + -

                                      Search results

                                      -
                                        -
                                      -
                                      + +
                                      +
                                      +
                                      +

                                      Search results

                                      + +
                                      +
                                      +
                                        +
                                        +
                                        +
                                        - +
                                        + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-MessageHelper.html b/docs/phpdoc/classes/PHPCSUtils-Utils-MessageHelper.html new file mode 100644 index 00000000..229fb391 --- /dev/null +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-MessageHelper.html @@ -0,0 +1,695 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                        +

                                        PHPCSUtils

                                        + + + + + +
                                        + +
                                        +
                                        + + + + +
                                        + + +
                                        +

                                        + MessageHelper + + +
                                        + in package + +
                                        + + +

                                        + + + +

                                        Helper functions for creating PHPCS error/warning messages.

                                        + + + +
                                        + Tags + +
                                        +
                                        +
                                        + since +
                                        +
                                        + 1.0.0 + + +
                                        +
                                        + + + + + + +

                                        + Table of Contents + +

                                        + +
                                        +
                                        + addFixableMessage() + +  : bool +
                                        +
                                        Add a PHPCS message to the output stack as either a fixable warning or a fixable error.
                                        + +
                                        + addMessage() + +  : bool +
                                        +
                                        Add a PHPCS message to the output stack as either a warning or an error.
                                        + +
                                        + showEscapeChars() + +  : string +
                                        +
                                        Make the whitespace escape codes used in an arbitrary text string visible.
                                        + +
                                        + stringToErrorcode() + +  : string +
                                        +
                                        Convert an arbitrary text string to an alphanumeric string with underscores.
                                        + +
                                        + + + + + + + +
                                        +

                                        + Methods + +

                                        +
                                        +

                                        + addFixableMessage() + +

                                        + + +

                                        Add a PHPCS message to the output stack as either a fixable warning or a fixable error.

                                        + + + public + static addFixableMessage(File $phpcsFile, string $message, int $stackPtr[, bool $isError = true ][, string $code = 'Found' ][, array<string|int, mixed> $data = [] ], int $severity) : bool + + +
                                        Parameters
                                        +
                                        +
                                        + $phpcsFile + : File +
                                        +
                                        +

                                        The file where this token was found.

                                        +
                                        + +
                                        +
                                        + $message + : string +
                                        +
                                        +

                                        The message.

                                        +
                                        + +
                                        +
                                        + $stackPtr + : int +
                                        +
                                        +

                                        The position of the token +the message relates to.

                                        +
                                        + +
                                        +
                                        + $isError + : bool + = true
                                        +
                                        +

                                        Whether to report the message as an +'error' or 'warning'. +Defaults to true (error).

                                        +
                                        + +
                                        +
                                        + $code + : string + = 'Found'
                                        +
                                        +

                                        The error code for the message. +Defaults to 'Found'.

                                        +
                                        + +
                                        +
                                        + $data + : array<string|int, mixed> + = []
                                        +
                                        +

                                        Optional input for the data replacements.

                                        +
                                        + +
                                        +
                                        + $severity + : int +
                                        +
                                        +

                                        Optional. Severity level. Defaults to 0 which will +translate to the PHPCS default severity level.

                                        +
                                        + +
                                        +
                                        + + +
                                        + Tags + +
                                        +
                                        +
                                        + since +
                                        +
                                        + 1.0.0-alpha4 + + +
                                        +
                                        + +
                                        Return values
                                        + bool + — + + +
                                        +
                                        +

                                        + addMessage() + +

                                        + + +

                                        Add a PHPCS message to the output stack as either a warning or an error.

                                        + + + public + static addMessage(File $phpcsFile, string $message, int $stackPtr[, bool $isError = true ][, string $code = 'Found' ][, array<string|int, mixed> $data = [] ], int $severity) : bool + + +
                                        Parameters
                                        +
                                        +
                                        + $phpcsFile + : File +
                                        +
                                        +

                                        The file where this token was found.

                                        +
                                        + +
                                        +
                                        + $message + : string +
                                        +
                                        +

                                        The message.

                                        +
                                        + +
                                        +
                                        + $stackPtr + : int +
                                        +
                                        +

                                        The position of the token +the message relates to.

                                        +
                                        + +
                                        +
                                        + $isError + : bool + = true
                                        +
                                        +

                                        Whether to report the message as an +'error' or 'warning'. +Defaults to true (error).

                                        +
                                        + +
                                        +
                                        + $code + : string + = 'Found'
                                        +
                                        +

                                        The error code for the message. +Defaults to 'Found'.

                                        +
                                        + +
                                        +
                                        + $data + : array<string|int, mixed> + = []
                                        +
                                        +

                                        Optional input for the data replacements.

                                        +
                                        + +
                                        +
                                        + $severity + : int +
                                        +
                                        +

                                        Optional. Severity level. Defaults to 0 which will +translate to the PHPCS default severity level.

                                        +
                                        + +
                                        +
                                        + + +
                                        + Tags + +
                                        +
                                        +
                                        + since +
                                        +
                                        + 1.0.0-alpha4 + + +
                                        +
                                        + +
                                        Return values
                                        + bool + — + + +
                                        +
                                        +

                                        + showEscapeChars() + +

                                        + + +

                                        Make the whitespace escape codes used in an arbitrary text string visible.

                                        + + + public + static showEscapeChars(string $text) : string + +

                                        At times, it is useful to show a code snippet in an error message. +If such a code snippet contains new lines and/or tab or space characters, those would be +displayed as-is in the command-line report, often breaking the layout of the report +or making the report harder to read.

                                        +

                                        This method will convert these characters to their escape codes, making them visible in the +display string without impacting the report layout.

                                        +
                                        + +
                                        Parameters
                                        +
                                        +
                                        + $text + : string +
                                        +
                                        +

                                        Arbitrary text string.

                                        +
                                        + +
                                        +
                                        + + +
                                        + Tags + +
                                        +
                                        +
                                        + see +
                                        +
                                        + GetTokensToString + +

                                        Methods to retrieve a multi-token code snippet.

                                        +
                                        + +
                                        +
                                        + see +
                                        +
                                        + prepareForOutput() + +

                                        Similar PHPCS native method.

                                        +
                                        + +
                                        +
                                        + since +
                                        +
                                        + 1.0.0-alpha4 + + +
                                        +
                                        + +
                                        Return values
                                        + string + — + + +
                                        +
                                        +

                                        + stringToErrorcode() + +

                                        + + +

                                        Convert an arbitrary text string to an alphanumeric string with underscores.

                                        + + + public + static stringToErrorcode(string $text[, bool $strtolower = false ]) : string + +

                                        Pre-empt issues in XML and PHP when arbitrary strings are being used as error codes.

                                        +
                                        + +
                                        Parameters
                                        +
                                        +
                                        + $text + : string +
                                        +
                                        +

                                        Arbitrary text string intended to be used in an error code.

                                        +
                                        + +
                                        +
                                        + $strtolower + : bool + = false
                                        +
                                        +

                                        Whether or not to convert the text string to lowercase.

                                        +
                                        + +
                                        +
                                        + + +
                                        + Tags + +
                                        +
                                        +
                                        + since +
                                        +
                                        + 1.0.0-alpha4 + + +
                                        +
                                        + +
                                        Return values
                                        + string + — + + +
                                        +
                                        + + + + +
                                        +
                                        +
                                        +
                                        +

                                        Search results

                                        + +
                                        +
                                        +
                                          +
                                          +
                                          +
                                          +
                                          +
                                          + + +
                                          + + + + + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html index 83545f43..dda276fe 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Namespaces.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                          -

                                          PHPCSUtils

                                          - -
                                          - -
                                          -
                                          -

                                          Utility functions for use when examining T_NAMESPACE tokens and to determine the namespace of arbitrary tokens.

                                          @@ -98,17 +153,28 @@
                                          link
                                          - https://www.php.net/language.namespaces -

                                          PHP Manual on namespaces.

                                          - -
                                          +

                                          PHP Manual on namespaces.

                                          +
                                          + +
                                          since
                                          1.0.0 - -
                                          + + + +
                                          + since +
                                          +
                                          + 1.0.0-alpha4 + +

                                          Dropped support for PHPCS < 3.7.1.

                                          +
                                          + +
                                          @@ -122,45 +188,45 @@

                                          -
                                          - determineNamespace() +
                                          + determineNamespace() -  : string +  : string
                                          Determine the namespace name an arbitrary token lives in.
                                          - findNamespacePtr() + findNamespacePtr() -  : int|false +  : int|false
                                          Determine the namespace an arbitrary token lives in.
                                          - getDeclaredName() + getDeclaredName() -  : string|false +  : string|false
                                          Get the complete namespace name as declared.
                                          - getType() + getType() -  : string +  : string
                                          Determine what a T_NAMESPACE token is used for.
                                          - isDeclaration() + isDeclaration() -  : bool +  : bool
                                          Determine whether a T_NAMESPACE token is the keyword for a namespace declaration.
                                          - isOperator() + isOperator() -  : bool +  : bool
                                          Determine whether a T_NAMESPACE token is used as an operator.
                                          @@ -175,7 +241,7 @@

                                          Methods - +

                                          >

                                          determineNamespace() - +

                                          + 377 + +

                                          Determine the namespace name an arbitrary token lives in.

                                          public - static determineNamespace(File $phpcsFile, int $stackPtr) : string + static determineNamespace(File $phpcsFile, int $stackPtr) : string

                                          Note: this method has no opinion on whether the token passed is actually subject -to namespacing.

                                          +to namespacing.

                                          +

                                          Parameters
                                          @@ -209,7 +277,8 @@
                                          Parameters
                                          : File
                                          -

                                          The file being scanned.

                                          +

                                          The file being scanned.

                                          +
                                          @@ -218,7 +287,8 @@
                                          Parameters

                                          The token for which to determine -the namespace.

                                          +the namespace.

                                          +
                                          @@ -234,15 +304,17 @@
                                          1.0.0 - -
                                          + + +
                                          Return values
                                          string

                                          Namespace name; or an empty string if the namespace couldn't be -determined or when no namespace applies.

                                          +determined or when no namespace applies.

                                          + @@ -254,19 +326,20 @@
                                          Return values
                                          >

                                          findNamespacePtr() - +

                                          + 232 + +

                                          Determine the namespace an arbitrary token lives in.

                                          public - static findNamespacePtr(File $phpcsFile, int $stackPtr) : int|false + static findNamespacePtr(File $phpcsFile, int $stackPtr) : int|false

                                          Take note:

                                            @@ -275,7 +348,8 @@

                                            are not within a namespace.
                                          1. This method has no opinion on whether the token passed is actually subject to namespacing.
                                          2. -

                                          + +
                                          Parameters
                                          @@ -284,7 +358,8 @@
                                          Parameters
                                          : File
                                          -

                                          The file being scanned.

                                          +

                                          The file being scanned.

                                          +
                                          @@ -293,7 +368,8 @@
                                          Parameters

                                          The token for which to determine -the namespace.

                                          +the namespace.

                                          +
                                          @@ -309,8 +385,9 @@
                                          1.0.0 - -
                                          + + +
                                          Return values
                                          @@ -318,7 +395,8 @@
                                          Return values

                                          Token pointer to the namespace keyword for the applicable namespace declaration; or FALSE if it couldn't be determined or -if no namespace applies.

                                          +if no namespace applies.

                                          + @@ -330,22 +408,24 @@
                                          Return values
                                          >

                                          getDeclaredName() - +

                                          + 179 + +

                                          Get the complete namespace name as declared.

                                          public - static getDeclaredName(File $phpcsFile, int $stackPtr[, bool $clean = true ]) : string|false + static getDeclaredName(File $phpcsFile, int $stackPtr[, bool $clean = true ]) : string|false

                                          For hierarchical namespaces, the namespace name will be composed of several tokens, -i.e. "MyProject\Sub\Level", which will be returned together as one string.

                                          +i.e. "MyProject\Sub\Level", which will be returned together as one string.

                                          +
                                          Parameters
                                          @@ -354,7 +434,8 @@
                                          Parameters
                                          : File
                                          -

                                          The file being scanned.

                                          +

                                          The file being scanned.

                                          +
                                          @@ -362,7 +443,8 @@
                                          Parameters
                                          : int
                                          -

                                          The position of a T_NAMESPACE token.

                                          +

                                          The position of a T_NAMESPACE token.

                                          +
                                          @@ -372,7 +454,8 @@
                                          Parameters

                                          Optional. Whether to get the name stripped of potentially interlaced whitespace and/or -comments. Defaults to true.

                                          +comments. Defaults to true.

                                          +
                                          @@ -388,8 +471,9 @@
                                          1.0.0 - -
                                          + + +
                                          Return values
                                          @@ -401,7 +485,8 @@
                                          Return values

                                          Note: The name can be an empty string for a valid global namespace declaration.

                                          -
                                          + + @@ -413,19 +498,20 @@
                                          Return values
                                          >

                                          getType() - +

                                          + 52 + +

                                          Determine what a T_NAMESPACE token is used for.

                                          public - static getType(File $phpcsFile, int $stackPtr) : string + static getType(File $phpcsFile, int $stackPtr) : string
                                          Parameters
                                          @@ -435,7 +521,8 @@
                                          Parameters
                                          : File
                                          -

                                          The file being scanned.

                                          +

                                          The file being scanned.

                                          +
                                          @@ -443,7 +530,8 @@
                                          Parameters
                                          : int
                                          -

                                          The position of the T_NAMESPACE token.

                                          +

                                          The position of the T_NAMESPACE token.

                                          +
                                          @@ -459,17 +547,30 @@
                                          1.0.0 - -
                                          + + + +
                                          + since +
                                          +
                                          + 1.0.0-alpha4 + +

                                          Added support for PHP 8.0 identifier name tokenization.

                                          +
                                          + +
                                          throws
                                          RuntimeException -

                                          If the specified position is -not a T_NAMESPACE token.

                                          + +

                                          If the specified position is +not a T_NAMESPACE token.

                                          +
                                          -
                                          +
                                          Return values
                                          @@ -478,7 +579,8 @@
                                          Return values

                                          Either 'declaration', 'operator' or an empty string. An empty string will be returned if it couldn't be reliably determined what the T_NAMESPACE token is used for, -which, in most cases, will mean the code contains a parse/fatal error.

                                          +which, in most cases, will mean the code contains a parse/fatal error.

                                          + @@ -490,19 +592,20 @@
                                          Return values
                                          >

                                          isDeclaration() - +

                                          + 133 + +

                                          Determine whether a T_NAMESPACE token is the keyword for a namespace declaration.

                                          public - static isDeclaration(File $phpcsFile, int $stackPtr) : bool + static isDeclaration(File $phpcsFile, int $stackPtr) : bool
                                          Parameters
                                          @@ -512,7 +615,8 @@
                                          Parameters
                                          : File
                                          -

                                          The file being scanned.

                                          +

                                          The file being scanned.

                                          +
                                          @@ -520,7 +624,8 @@
                                          Parameters
                                          : int
                                          -

                                          The position of a T_NAMESPACE token.

                                          +

                                          The position of a T_NAMESPACE token.

                                          +
                                          @@ -536,24 +641,28 @@
                                          1.0.0 - -
                                          + + +
                                          throws
                                          RuntimeException -

                                          If the specified position is -not a T_NAMESPACE token.

                                          + +

                                          If the specified position is +not a T_NAMESPACE token.

                                          +
                                          -
                                          +
                                          Return values
                                          bool

                                          TRUE if the token passed is the keyword for a namespace declaration. -FALSE if not.

                                          +FALSE if not.

                                          + @@ -565,19 +674,20 @@
                                          Return values
                                          >

                                          isOperator() - +

                                          + 154 + +

                                          Determine whether a T_NAMESPACE token is used as an operator.

                                          public - static isOperator(File $phpcsFile, int $stackPtr) : bool + static isOperator(File $phpcsFile, int $stackPtr) : bool
                                          Parameters
                                          @@ -587,7 +697,8 @@
                                          Parameters
                                          : File
                                          -

                                          The file being scanned.

                                          +

                                          The file being scanned.

                                          +
                                          @@ -595,7 +706,8 @@
                                          Parameters
                                          : int
                                          -

                                          The position of a T_NAMESPACE token.

                                          +

                                          The position of a T_NAMESPACE token.

                                          +
                                          @@ -610,53 +722,128 @@
                                          link
                                          - https://www.php.net/language.namespaces.nsconstants -

                                          PHP Manual about the use of the -namespace keyword as an operator.

                                          - -
                                          +

                                          PHP Manual about the use of the +namespace keyword as an operator.

                                          +
                                          + +
                                          since
                                          1.0.0 - -
                                          + + +
                                          throws
                                          RuntimeException -

                                          If the specified position is -not a T_NAMESPACE token.

                                          + +

                                          If the specified position is +not a T_NAMESPACE token.

                                          +
                                          -
                                          +
                                          Return values
                                          bool — -

                                          TRUE if the namespace token passed is used as an operator. FALSE if not.

                                          +

                                          TRUE if the namespace token passed is used as an operator. FALSE if not.

                                          +
                                          - -
                                          + + -

                                          Search results

                                          -
                                            -
                                          -
                                          + +
                                          +
                                          +
                                          +

                                          Search results

                                          + +
                                          +
                                          +
                                            +
                                            +
                                            +
                                            - +
                                            + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-NamingConventions.html b/docs/phpdoc/classes/PHPCSUtils-Utils-NamingConventions.html index 4e5bd947..77a36805 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-NamingConventions.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-NamingConventions.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                            -

                                            PHPCSUtils

                                            - -
                                            - -
                                            -
                                            -

                                            Utility functions for working with identifier names.

                                            Identifier names in PHP are:

                                            +
                                          • +namespace names;
                                          • +
                                          • +class, +trait, +interface and +enum names;
                                          • +
                                          • +function and method names;
                                          • +
                                          • +variable names;
                                          • +
                                          • +constant names.
                                          • + +
                                            @@ -108,8 +170,9 @@
                                            1.0.0-alpha3 - -
                                            + + + @@ -124,37 +187,37 @@

                                            - AZ_LOWER + AZ_LOWER -  = 'abcdefghijklmnopqrstuvwxyz' +  = 'abcdefghijklmnopqrstuvwxyz'
                                            Lowercase a-z.
                                            - AZ_UPPER + AZ_UPPER -  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                                            Uppercase A-Z.
                                            - PHP_LABEL_REGEX + PHP_LABEL_REGEX -  = '`^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$`' +  = '`^[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*$`'
                                            Regular expression to check if a given identifier name is valid for use in PHP.
                                            -
                                            - isEqual() +
                                            + isEqual() -  : bool +  : bool
                                            Check if two arbitrary identifier names will be seen as the same in PHP.
                                            - isValidIdentifierName() + isValidIdentifierName() -  : bool +  : bool
                                            Verify whether an arbitrary text string is valid as an identifier name in PHP.
                                            @@ -166,25 +229,26 @@

                                            Constants - +

                                            AZ_LOWER - +

                                            + 56 + +

                                            Lowercase a-z.

                                            public - string + string AZ_LOWER = 'abcdefghijklmnopqrstuvwxyz' @@ -192,6 +256,7 @@

                                            +

                                            Tags @@ -202,28 +267,30 @@
                                            1.0.0 - -
                                            + + +

                                            AZ_UPPER - +

                                            + 47 + +

                                            Uppercase A-Z.

                                            public - string + string AZ_UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -231,6 +298,7 @@

                                            +

                                            Tags @@ -241,35 +309,38 @@
                                            1.0.0 - -
                                            + + +

                                            PHP_LABEL_REGEX - +

                                            + 38 + +

                                            Regular expression to check if a given identifier name is valid for use in PHP.

                                            public - string + string PHP_LABEL_REGEX - = '`^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$`' + = '`^[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*$`' +
                                            Tags @@ -280,8 +351,9 @@
                                            1.0.0 - -
                                            + + +
                                            @@ -292,7 +364,7 @@

                                            Methods - +

                                            >

                                            isEqual() - +

                                            + 104 + +

                                            Check if two arbitrary identifier names will be seen as the same in PHP.

                                            public - static isEqual(string $nameA, string $nameB) : bool + static isEqual(string $nameA, string $nameB) : bool

                                            This method should not be used for variable or constant names, but should be used when comparing namespace, class/trait/interface and function names.

                                            @@ -325,8 +398,9 @@

                                            Basically ASCII chars used are case-insensitive, but anything from 0x80 up is case-sensitive.

                                            This method takes this case-(in)sensitivity into account when comparing identifier names.

                                            Note: this method does not check whether the passed names would be valid for identifiers! -The \PHPCSUtils\Utils\NamingConventions::isValidIdentifierName() method should be used -to verify that, if necessary.

                                            +The NamingConventions::isValidIdentifierName() method should be used +to verify that, if necessary.

                                            +
                                            Parameters
                                            @@ -335,7 +409,8 @@
                                            Parameters
                                            : string
                                            -

                                            The first identifier name.

                                            +

                                            The first identifier name.

                                            +
                                            @@ -343,7 +418,8 @@
                                            Parameters
                                            : string
                                            -

                                            The second identifier name.

                                            +

                                            The second identifier name.

                                            +
                                            @@ -359,14 +435,16 @@
                                            1.0.0 - -
                                            + + +
                                            Return values
                                            bool — -

                                            TRUE if these names would be considered the same in PHP; FALSE otherwise.

                                            +

                                            TRUE if these names would be considered the same in PHP; FALSE otherwise.

                                            +
                                            @@ -378,19 +456,20 @@
                                            Return values
                                            >

                                            isValidIdentifierName() - +

                                            + 69 + +

                                            Verify whether an arbitrary text string is valid as an identifier name in PHP.

                                            public - static isValidIdentifierName(string $name) : bool + static isValidIdentifierName(string $name) : bool
                                            Parameters
                                            @@ -404,7 +483,8 @@
                                            Parameters

                                            Note: for variable names, the leading dollar sign - $ - needs to be removed prior to passing the name to this method.

                                            -
                                            + + @@ -420,8 +500,9 @@
                                            1.0.0 - -
                                            + + +
                                            Return values
                                            @@ -432,21 +513,92 @@
                                            Return values
                                            - -
                                            + + -

                                            Search results

                                            -
                                              -
                                            -
                                            + +
                                            +
                                            +
                                            +

                                            Search results

                                            + +
                                            +
                                            +
                                              +
                                              +
                                              +
                                              - +
                                              + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html index 4f4f57fb..526d9cfb 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Numbers.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                              -

                                              PHPCSUtils

                                              - -
                                              - -
                                              -
                                              -

                                              Utility functions for working with integer/float tokens.

                                              -

                                              PHP 7.4 introduced numeric literal separators which break number tokenization in older PHP versions. -PHPCS backfills this since PHPCS 3.5.3/4.

                                              -

                                              In other words, if an external standard intends to support PHPCS < 3.5.4 and PHP < 7.4, working -with number tokens has suddenly become a challenge.

                                              -

                                              The functions in this class have been put in place to ease that pain and it is -strongly recommended to always use these functions when sniffing for and examining the -contents of T_LNUMBER or T_DNUMBER tokens.

                                              +

                                              PHP 7.4 introduced numeric literal separators. PHPCS backfills this since PHPCS 3.5.3/4. +PHP 8.1 introduced an explicit octal notation. This is backfilled in PHPCS since PHPCS 3.7.0.

                                              +

                                              While there are currently no unsupported numeric syntaxes, the methods in this class +can still be useful for external standards which need to examine the +contents of T_LNUMBER or T_DNUMBER tokens.

                                              +
                                              @@ -104,17 +158,57 @@
                                              link
                                              - https://www.php.net/migration74.new-features.php#migration74.new-features.core.numeric-literal-separator -

                                              PHP Manual on numeric literal separators.

                                              - -
                                              +

                                              PHP Manual on numeric literal separators.

                                              +
                                              + + +
                                              + link +
                                              +
                                              +

                                              PHP Manual on the introduction of the integer octal literal prefix.

                                              +
                                              + +
                                              since
                                              1.0.0 - -
                                              + + + +
                                              + since +
                                              +
                                              + 1.0.0-alpha4 + +

                                              Dropped support for PHPCS < 3.7.1.

                                              +
                                              + +
                                              +
                                              + since +
                                              +
                                              + 1.0.0-alpha4 + +

                                              Removed the following class constants:

                                              +
                                                +
                                              • +Numbers::REGEX_NUMLIT_STRING +
                                              • +
                                              • +Numbers::REGEX_HEX_NUMLIT_STRING +
                                              • +
                                              • +Numbers::UNSUPPORTED_PHPCS_VERSION +
                                              • +
                                              +
                                              + +
                                              @@ -129,21 +223,21 @@

                                              - REGEX_BINARY_INT + REGEX_BINARY_INT -  = '`^0b[0-1]+$`iD' +  = '`^0b[0-1]+$`iD'
                                              Regex to determine whether the contents of an arbitrary string represents a binary integer.
                                              - REGEX_DECIMAL_INT + REGEX_DECIMAL_INT -  = '`^(?:0|[1-9][0-9]*)$`D' +  = '`^(?:0|[1-9][0-9]*)$`D'
                                              Regex to determine whether the contents of an arbitrary string represents a decimal integer.
                                              - REGEX_FLOAT + REGEX_FLOAT  = '` ^(?: @@ -151,7 +245,7 @@

                                              (?: (?P<LNUM>[0-9]+) | - (?P<DNUM>([0-9]*\.(?P>LNUM)|(?P>LNUM)\.[0-9]*)) + (?P<DNUM>([0-9]*\\.(?P>LNUM)|(?P>LNUM)\\.[0-9]*)) ) [e][+-]?(?P>LNUM) ) @@ -160,91 +254,70 @@

                                              | (?:0|[1-9][0-9]*) )$ - `ixD' + `ixD'

                                              Regex to determine whether the contents of an arbitrary string represents a float.
                                              - REGEX_HEX_INT + REGEX_HEX_INT -  = '`^0x[0-9A-F]+$`iD' +  = '`^0x[0-9A-F]+$`iD'
                                              Regex to determine whether the contents of an arbitrary string represents a hexidecimal integer.
                                              - REGEX_HEX_NUMLIT_STRING - -  = '`^((?<!\.)_[0-9A-F]*)+$`iD' -
                                              -
                                              Regex to determine is a T_STRING following a T_[DL]NUMBER is part of a hexidecimal numeric literal sequence.
                                              - -
                                              - REGEX_NUMLIT_STRING + REGEX_OCTAL_INT -  = '`^((?<![\.e])_[0-9][0-9e\.]*)+$`iD' -
                                              -
                                              Regex to determine if a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence.
                                              - -
                                              - REGEX_OCTAL_INT - -  = '`^0[0-7]+$`D' +  = '`^0[o]?[0-7]+$`iD'
                                              Regex to determine whether the contents of an arbitrary string represents an octal integer.
                                              -
                                              - UNSUPPORTED_PHPCS_VERSION +
                                              + getCompleteNumber() -  = '3.5.3' +  : array<string|int, mixed>
                                              -
                                              PHPCS versions in which the backfill for PHP 7.4 numeric literal separators is broken.
                                              - -
                                              - getCompleteNumber() - -  : array -
                                              -
                                              Retrieve information about a number token in a cross-version compatible manner.
                                              +
                                              Retrieve information about a number token.
                                              - getDecimalValue() + getDecimalValue() -  : string|false +  : string|false
                                              Get the decimal number value of a numeric string.
                                              - isBinaryInt() + isBinaryInt() -  : bool +  : bool
                                              Verify whether the contents of an arbitrary string represents a binary integer.
                                              - isDecimalInt() + isDecimalInt() -  : bool +  : bool
                                              Verify whether the contents of an arbitrary string represents a decimal integer.
                                              - isFloat() + isFloat() -  : bool +  : bool
                                              Verify whether the contents of an arbitrary string represents a floating point number.
                                              - isHexidecimalInt() + isHexidecimalInt() -  : bool +  : bool
                                              Verify whether the contents of an arbitrary string represents a hexidecimal integer.
                                              - isOctalInt() + isOctalInt() -  : bool +  : bool
                                              Verify whether the contents of an arbitrary string represents an octal integer.
                                              @@ -256,25 +329,26 @@

                                              Constants - +

                                              REGEX_BINARY_INT - +

                                              + 66 + +

                                              Regex to determine whether the contents of an arbitrary string represents a binary integer.

                                              public - string + string REGEX_BINARY_INT = '`^0b[0-1]+$`iD' @@ -282,6 +356,7 @@

                                              +

                                              Tags @@ -292,28 +367,30 @@
                                              1.0.0 - -
                                              + + +

                                              REGEX_DECIMAL_INT - +

                                              + 48 + +

                                              Regex to determine whether the contents of an arbitrary string represents a decimal integer.

                                              public - string + string REGEX_DECIMAL_INT = '`^(?:0|[1-9][0-9]*)$`D' @@ -321,6 +398,7 @@

                                              +

                                              Tags @@ -331,28 +409,30 @@
                                              1.0.0 - -
                                              + + +

                                              REGEX_FLOAT - +

                                              + 86 + +

                                              Regex to determine whether the contents of an arbitrary string represents a float.

                                              public - string + string REGEX_FLOAT = '` ^(?: @@ -360,7 +440,7 @@

                                              (?: (?P<LNUM>[0-9]+) | - (?P<DNUM>([0-9]*\.(?P>LNUM)|(?P>LNUM)\.[0-9]*)) + (?P<DNUM>([0-9]*\\.(?P>LNUM)|(?P>LNUM)\\.[0-9]*)) ) [e][+-]?(?P>LNUM) ) @@ -375,6 +455,7 @@

                                              +

                                              Tags @@ -384,37 +465,39 @@
                                              link
                                              - https://www.php.net/language.types.float -

                                              PHP Manual on floats

                                              - -
                                              +

                                              PHP Manual on floats

                                              +
                                              + +
                                              since
                                              1.0.0 - -
                                              + + +

                                              REGEX_HEX_INT - +

                                              + 75 + +

                                              Regex to determine whether the contents of an arbitrary string represents a hexidecimal integer.

                                              public - string + string REGEX_HEX_INT = '`^0x[0-9A-F]+$`iD' @@ -422,45 +505,6 @@

                                              -

                                              - Tags - -
                                              -
                                              -
                                              - since -
                                              -
                                              - 1.0.0 - -
                                              -
                                              - -
                                              -
                                              -

                                              - REGEX_HEX_NUMLIT_STRING - -

                                              - - - -

                                              Regex to determine is a T_STRING following a T_[DL]NUMBER is part of a hexidecimal numeric literal sequence.

                                              - - - public - string - REGEX_HEX_NUMLIT_STRING - = '`^((?<!\.)_[0-9A-F]*)+$`iD' - - - -

                                              Cross-version compatibility helper for PHP 7.4 numeric literals with underscore separators.

                                              -
                                              Tags @@ -472,113 +516,37 @@
                                              1.0.0 - -
                                              - - -
                                              -
                                              -

                                              - REGEX_NUMLIT_STRING - -

                                              - - - -

                                              Regex to determine if a T_STRING following a T_[DL]NUMBER is part of a numeric literal sequence.

                                              - - - public - string - REGEX_NUMLIT_STRING - = '`^((?<![\.e])_[0-9][0-9e\.]*)+$`iD' - - - -

                                              Cross-version compatibility helper for PHP 7.4 numeric literals with underscore separators.

                                              - - -
                                              - Tags - -
                                              -
                                              -
                                              - since -
                                              -
                                              - 1.0.0 - -
                                              + + +

                                              REGEX_OCTAL_INT - +

                                              + 57 + +

                                              Regex to determine whether the contents of an arbitrary string represents an octal integer.

                                              public - string + string REGEX_OCTAL_INT - = '`^0[0-7]+$`D' + = '`^0[o]?[0-7]+$`iD' -
                                              - Tags - -
                                              -
                                              -
                                              - since -
                                              -
                                              - 1.0.0 - -
                                              -
                                              - -
                                              -
                                              -

                                              - UNSUPPORTED_PHPCS_VERSION - -

                                              - - - -

                                              PHPCS versions in which the backfill for PHP 7.4 numeric literal separators is broken.

                                              - - - public - string - UNSUPPORTED_PHPCS_VERSION - = '3.5.3' - - - -
                                              Tags @@ -590,17 +558,9 @@
                                              1.0.0 - -
                                              -
                                              - since -
                                              -
                                              - 1.0.0-alpha2 -

                                              Changed from a property to a class constant. -Changed from an array to a string.

                                              - -
                                              + + +
                                              @@ -611,7 +571,7 @@

                                              Methods - +

                                              >

                                              getCompleteNumber() - +

                                              + 136 -

                                              Retrieve information about a number token in a cross-version compatible manner.

                                              + + +

                                              Retrieve information about a number token.

                                              public - static getCompleteNumber(File $phpcsFile, int $stackPtr) : array + static getCompleteNumber(File $phpcsFile, int $stackPtr) : array<string|int, mixed>
                                              -

                                              Helper function to deal with numeric literals, potentially with underscore separators.

                                              -

                                              PHP < 7.4 does not tokenize numeric literals containing underscores correctly. -As of PHPCS 3.5.3, PHPCS contains a backfill, but this backfill was buggy in the initial -implementation. A fix for this broken backfill is included in PHPCS 3.5.4.

                                              -

                                              Either way, this function can be used with all PHPCS/PHP combinations and will, if necessary, -provide a backfill for PHPCS/PHP combinations where PHP 7.4 numbers with underscore separators -are tokenized incorrectly - with the exception of PHPCS 3.5.3 as the buggyness of the original -backfill implementation makes it impossible to provide reliable results.

                                              +

                                              Helper function to deal with numeric literals, potentially with underscore separators +and/or explicit octal notation.

                                              +
                                              Parameters
                                              @@ -651,7 +607,8 @@
                                              Parameters
                                              : File
                                              -

                                              The file being scanned.

                                              +

                                              The file being scanned.

                                              +
                                              @@ -659,7 +616,8 @@
                                              Parameters
                                              : int
                                              -

                                              The position of a T_LNUMBER or T_DNUMBER token.

                                              +

                                              The position of a T_LNUMBER or T_DNUMBER token.

                                              +
                                              @@ -671,58 +629,34 @@
                                              - link -
                                              -
                                              - https://github.com/squizlabs/PHP_CodeSniffer/issues/2546 -

                                              PHPCS issue #2546

                                              - -
                                              -
                                              - link -
                                              -
                                              - https://github.com/squizlabs/PHP_CodeSniffer/pull/2771 -

                                              PHPCS PR #2771

                                              - -
                                              -
                                              since
                                              1.0.0 - -
                                              + + +
                                              throws
                                              RuntimeException -

                                              If the specified token is not of type -T_LNUMBER or T_DNUMBER.

                                              - -
                                              -
                                              - throws -
                                              -
                                              - RuntimeException -

                                              If this function is called in combination -with an unsupported PHPCS version.

                                              + +

                                              If the specified token is not of type +T_LNUMBER or T_DNUMBER.

                                              +
                                              -
                                              +
                                              Return values
                                              - array + array<string|int, mixed>

                                              An array with information about the number. The format of the array return value is:

                                              array(
                                              -  'orig_content' => string, // The (potentially concatenated) original
                                              -                            // content of the tokens;
                                              -  'content'      => string, // The (potentially concatenated) content,
                                              -                            // underscore(s) removed;
                                              +  'orig_content' => string, // The original content of the token(s);
                                              +  'content'      => string, // The content, underscore(s) removed;
                                                 'code'         => int,    // The token code of the number, either
                                                                           // T_LNUMBER or T_DNUMBER.
                                                 'type'         => string, // The token type, either 'T_LNUMBER'
                                              @@ -730,10 +664,12 @@ 
                                              Return values
                                              'decimal' => string, // The decimal value of the number; 'last_token' => int, // The stackPtr to the last token which was // part of the number. - // This will be the same as the original - // stackPtr if it is not a PHP 7.4 number - // with underscores. -)
                                              + // At this time, this will be always be the original + // stackPtr. This may change in the future if + // new numeric syntaxes would be added to PHP. +) + +
                                              @@ -745,30 +681,35 @@
                                              Return values
                                              >

                                              getDecimalValue() - +

                                              + 175 + +

                                              Get the decimal number value of a numeric string.

                                              public - static getDecimalValue(string $string) : string|false + static getDecimalValue(string $textString) : string|false -

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +

                                              Takes PHP 7.4 numeric literal separators and explicit octal literals in numbers into account.

                                              +
                                              Parameters
                                              - $string + $textString : string
                                              -

                                              Arbitrary token content string.

                                              +

                                              Arbitrary text string. +This text string should be the (combined) token content of +one or more tokens which together represent a number in PHP.

                                              +
                                              @@ -784,8 +725,9 @@
                                              1.0.0 - -
                                              + + +
                                              Return values
                                              @@ -796,7 +738,8 @@
                                              Return values

                                              Note: floating point numbers with exponent will not be expanded, but returned as-is.

                                              -
                                              + + @@ -808,30 +751,33 @@
                                              Return values
                                              >

                                              isBinaryInt() - +

                                              + 270 + +

                                              Verify whether the contents of an arbitrary string represents a binary integer.

                                              public - static isBinaryInt(string $string) : bool + static isBinaryInt(string $textString) : bool -

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +
                                              Parameters
                                              - $string + $textString : string
                                              -

                                              Arbitrary string.

                                              +

                                              Arbitrary string.

                                              +
                                              @@ -847,8 +793,9 @@
                                              1.0.0 - -
                                              + + +
                                              Return values
                                              @@ -865,30 +812,33 @@
                                              Return values
                                              >

                                              isDecimalInt() - +

                                              + 224 + +

                                              Verify whether the contents of an arbitrary string represents a decimal integer.

                                              public - static isDecimalInt(string $string) : bool + static isDecimalInt(string $textString) : bool -

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +
                                              Parameters
                                              - $string + $textString : string
                                              -

                                              Arbitrary string.

                                              +

                                              Arbitrary string.

                                              +
                                              @@ -904,8 +854,9 @@
                                              1.0.0 - -
                                              + + +
                                              Return values
                                              @@ -922,30 +873,33 @@
                                              Return values
                                              >

                                              isFloat() - +

                                              + 316 + +

                                              Verify whether the contents of an arbitrary string represents a floating point number.

                                              public - static isFloat(string $string) : bool + static isFloat(string $textString) : bool -

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +
                                              Parameters
                                              - $string + $textString : string
                                              -

                                              Arbitrary string.

                                              +

                                              Arbitrary string.

                                              +
                                              @@ -961,8 +915,9 @@
                                              1.0.0 - -
                                              + + +
                                              Return values
                                              @@ -979,30 +934,33 @@
                                              Return values
                                              >

                                              isHexidecimalInt() - +

                                              + 247 + +

                                              Verify whether the contents of an arbitrary string represents a hexidecimal integer.

                                              public - static isHexidecimalInt(string $string) : bool + static isHexidecimalInt(string $textString) : bool -

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +
                                              Parameters
                                              - $string + $textString : string
                                              -

                                              Arbitrary string.

                                              +

                                              Arbitrary string.

                                              +
                                              @@ -1018,8 +976,9 @@
                                              1.0.0 - -
                                              + + +
                                              Return values
                                              @@ -1036,30 +995,33 @@
                                              Return values
                                              >

                                              isOctalInt() - +

                                              + 293 + +

                                              Verify whether the contents of an arbitrary string represents an octal integer.

                                              public - static isOctalInt(string $string) : bool + static isOctalInt(string $textString) : bool -

                                              Takes PHP 7.4 numeric literal separators in numbers into account.

                                              +

                                              Takes PHP 7.4 numeric literal separators and explicit octal literals in numbers into account.

                                              +
                                              Parameters
                                              - $string + $textString : string
                                              -

                                              Arbitrary string.

                                              +

                                              Arbitrary string.

                                              +
                                              @@ -1075,8 +1037,9 @@
                                              1.0.0 - -
                                              + + +
                                              Return values
                                              @@ -1087,21 +1050,92 @@
                                              Return values
                                              - -
                                              + + -

                                              Search results

                                              -
                                                -
                                              -
                                              + +
                                              +
                                              +
                                              +

                                              Search results

                                              + +
                                              +
                                              +
                                                +
                                                +
                                                +
                                                - +
                                                + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html b/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html index 15c76302..186dae24 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-ObjectDeclarations.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                -

                                                PHPCSUtils

                                                - -
                                                - -
                                                -
                                                -

                                                Utility functions for use when examining object declaration statements.

                                                @@ -98,14 +153,26 @@
                                                1.0.0 -

                                                The ObjectDeclarations::get(Declaration)Name(), + +

                                                The ObjectDeclarations::get(Declaration)Name(), ObjectDeclarations::getClassProperties(), ObjectDeclarations::findExtendedClassName() and ObjectDeclarations::findImplementedInterfaceNames() methods are based on and inspired by the methods of the same name in the PHPCS native PHP_CodeSniffer\Files\File class. -Also see {@see \PHPCSUtils\BackCompat\BCFile}.

                                                +Also see BCFile.

                                                +
                                                + +
                                                +
                                                + since +
                                                +
                                                + 1.0.0-alpha4 + +

                                                Dropped support for PHPCS < 3.7.1.

                                                +
                                                -
                                                + @@ -119,40 +186,40 @@

                                                -
                                                - findExtendedClassName() +
                                                + findExtendedClassName() -  : string|false +  : string|false
                                                Retrieves the name of the class that the specified class extends.
                                                - findExtendedInterfaceNames() + findExtendedInterfaceNames() -  : array|false +  : array<string|int, mixed>|false
                                                Retrieves the names of the interfaces that the specified interface extends.
                                                - findImplementedInterfaceNames() + findImplementedInterfaceNames() -  : array|false +  : array<string|int, mixed>|false
                                                -
                                                Retrieves the names of the interfaces that the specified class implements.
                                                +
                                                Retrieves the names of the interfaces that the specified class or enum implements.
                                                - getClassProperties() + getClassProperties() -  : array +  : array<string|int, mixed>
                                                Retrieves the implementation properties of a class.
                                                - getName() + getName() -  : string|null +  : string|null
                                                -
                                                Retrieves the declaration name for classes, interfaces, traits, and functions.
                                                +
                                                Retrieves the declaration name for classes, interfaces, traits, enums and functions.
                                                @@ -165,7 +232,7 @@

                                                Methods - +

                                                >

                                                findExtendedClassName() - +

                                                + 234 + +

                                                Retrieves the name of the class that the specified class extends.

                                                public - static findExtendedClassName(File $phpcsFile, int $stackPtr) : string|false + static findExtendedClassName(File $phpcsFile, int $stackPtr) : string|false

                                                Works for classes, anonymous classes and interfaces, though it is strongly recommended -to use the \PHPCSUtils\Utils\ObjectDeclarations::findExtendedInterfaceNames() +to use the ObjectDeclarations::findExtendedInterfaceNames() method to examine interfaces instead. Interfaces can extend multiple parent interfaces, and that use-case is not handled by this method.

                                                Main differences with the PHPCS version:

                                                @@ -199,10 +267,14 @@

                                                • Handling of PHPCS annotations.
                                                • Handling of comments.
                                                • -
                                                +
                                              • Handling of the namespace keyword used as operator.
                                              • + +
                                              • Improved handling of parse errors.
                                              • The returned name will be clean of superfluous whitespace and/or comments.
                                              • -

                                                +
                                              • Support for PHP 8.0 tokenization of identifier/namespaced names, cross-version PHP & PHPCS.
                                              • + +

                                                Parameters
                                                @@ -211,7 +283,8 @@
                                                Parameters
                                                : File
                                                -

                                                The file being scanned.

                                                +

                                                The file being scanned.

                                                +
                                                @@ -219,7 +292,8 @@
                                                Parameters
                                                : int
                                                -

                                                The stack position of the class or interface.

                                                +

                                                The stack position of the class or interface.

                                                +
                                                @@ -235,40 +309,48 @@
                                                File::findExtendedClassName() -

                                                Original source.

                                                + +

                                                Original source.

                                                +
                                                -
                                                +
                                                see
                                                - BCFile::findExtendedClassName() -

                                                Cross-version compatible version of -the original.

                                                + BCFile::findExtendedClassName() + +

                                                Cross-version compatible version of +the original.

                                                +
                                                -
                                                +
                                                see
                                                - ObjectDeclarations::findExtendedInterfaceNames() -

                                                Similar method for extended interfaces.

                                                + ObjectDeclarations::findExtendedInterfaceNames() + +

                                                Similar method for extended interfaces.

                                                +
                                                -
                                                +
                                                since
                                                1.0.0 - -
                                                + + +
                                                Return values
                                                string|false

                                                The extended class name or FALSE on error or if there -is no extended class name.

                                                +is no extended class name.

                                                + @@ -280,19 +362,20 @@
                                                Return values
                                                >

                                                findExtendedInterfaceNames() - +

                                                + 288 + +

                                                Retrieves the names of the interfaces that the specified interface extends.

                                                public - static findExtendedInterfaceNames(File $phpcsFile, int $stackPtr) : array|false + static findExtendedInterfaceNames(File $phpcsFile, int $stackPtr) : array<string|int, mixed>|false
                                                Parameters
                                                @@ -302,7 +385,8 @@
                                                Parameters
                                                : File
                                                -

                                                The file where this token was found.

                                                +

                                                The file where this token was found.

                                                +
                                                @@ -310,7 +394,8 @@
                                                Parameters
                                                : int
                                                -

                                                The stack position of the interface keyword.

                                                +

                                                The stack position of the interface keyword.

                                                +
                                                @@ -325,24 +410,28 @@
                                                see
                                                - ObjectDeclarations::findExtendedClassName() -

                                                Similar method for extended classes.

                                                + ObjectDeclarations::findExtendedClassName() + +

                                                Similar method for extended classes.

                                                +
                                                -
                                                +
                                                since
                                                1.0.0 - -
                                                + + +
                                                Return values
                                                - array|false + array<string|int, mixed>|false

                                                Array with names of the extended interfaces or FALSE on -error or if there are no extended interface names.

                                                +error or if there are no extended interface names.

                                                + @@ -354,19 +443,20 @@
                                                Return values
                                                >

                                                findImplementedInterfaceNames() - +

                                                + 270 -

                                                Retrieves the names of the interfaces that the specified class implements.

                                                + + +

                                                Retrieves the names of the interfaces that the specified class or enum implements.

                                                public - static findImplementedInterfaceNames(File $phpcsFile, int $stackPtr) : array|false + static findImplementedInterfaceNames(File $phpcsFile, int $stackPtr) : array<string|int, mixed>|false

                                                Main differences with the PHPCS version:

                                                  @@ -374,10 +464,14 @@

                                                  Parameters

                                                  @@ -386,7 +480,8 @@
                                                  Parameters
                                                  : File
                                                  -

                                                  The file being scanned.

                                                  +

                                                  The file being scanned.

                                                  +
                                                  @@ -394,7 +489,8 @@
                                                  Parameters
                                                  : int
                                                  -

                                                  The stack position of the class.

                                                  +

                                                  The stack position of the class or enum token.

                                                  +
                                                  @@ -410,32 +506,48 @@
                                                  File::findImplementedInterfaceNames() -

                                                  Original source.

                                                  + +

                                                  Original source.

                                                  +
                                                  -
                                                  +
                                                  see
                                                  - BCFile::findImplementedInterfaceNames() -

                                                  Cross-version compatible version of -the original.

                                                  + BCFile::findImplementedInterfaceNames() + +

                                                  Cross-version compatible version of +the original.

                                                  +
                                                  -
                                                  +
                                                  since
                                                  1.0.0 - -
                                                  + + + +
                                                  + since +
                                                  +
                                                  + 1.0.0-alpha4 + +

                                                  Added support for PHP 8.1 enums.

                                                  +
                                                  + +
                                                  Return values
                                                  - array|false + array<string|int, mixed>|false

                                                  Array with names of the implemented interfaces or FALSE on -error or if there are no implemented interface names.

                                                  +error or if there are no implemented interface names.

                                                  +
                                                @@ -447,19 +559,20 @@
                                                Return values
                                                >

                                                getClassProperties() - +

                                                + 166 + +

                                                Retrieves the implementation properties of a class.

                                                public - static getClassProperties(File $phpcsFile, int $stackPtr) : array + static getClassProperties(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

                                                Main differences with the PHPCS version:

                                                  @@ -467,10 +580,12 @@

                                                  • Handling of PHPCS annotations.
                                                  • Handling of unorthodox docblock placement.
                                                  • -
                                                  • A class cannot both be abstract as well as final, so this utility should not allow for that.
                                                  • -
                                                  +

                                                +
                                              • Defensive coding against incorrect calls to this method.
                                              • -
                                                +
                                              • Support for PHP 8.2 readonly classes.
                                              • + +
                                                Parameters
                                                @@ -479,7 +594,8 @@
                                                Parameters
                                                : File
                                                -

                                                The file being scanned.

                                                +

                                                The file being scanned.

                                                +
                                                @@ -488,7 +604,8 @@
                                                Parameters

                                                The position in the stack of the T_CLASS -token to acquire the properties for.

                                                +token to acquire the properties for.

                                                +
                                                @@ -504,44 +621,64 @@
                                                File::getClassProperties() -

                                                Original source.

                                                + +

                                                Original source.

                                                +
                                                -
                                                +
                                                see
                                                - BCFile::getClassProperties() -

                                                Cross-version compatible version of the original.

                                                + BCFile::getClassProperties() + +

                                                Cross-version compatible version of the original.

                                                +
                                                -
                                                +
                                                since
                                                1.0.0 - -
                                                + + + +
                                                + since +
                                                +
                                                + 1.0.0-alpha4 + +

                                                Added support for the PHP 8.2 readonly keyword.

                                                +
                                                + +
                                                throws
                                                RuntimeException -

                                                If the specified position is not a -T_CLASS token.

                                                + +

                                                If the specified position is not a +T_CLASS token.

                                                +
                                                -
                                                +
                                                Return values
                                                - array + array<string|int, mixed>

                                                Array with implementation properties of a class. The format of the return value is:

                                                array(
                                                   'is_abstract' => false, // TRUE if the abstract keyword was found.
                                                   'is_final'    => false, // TRUE if the final keyword was found.
                                                -);
                                                + 'is_readonly' => false, // TRUE if the readonly keyword was found. +); + + @@ -553,19 +690,20 @@
                                                Return values
                                                >

                                                getName() - +

                                                + 66 + + -

                                                Retrieves the declaration name for classes, interfaces, traits, and functions.

                                                +

                                                Retrieves the declaration name for classes, interfaces, traits, enums and functions.

                                                public - static getName(File $phpcsFile, int $stackPtr) : string|null + static getName(File $phpcsFile, int $stackPtr) : string|null

                                                Main differences with the PHPCS version:

                                                  @@ -579,12 +717,7 @@

                                                  Using this version of the utility method, either the complete name (invalid or not) will be returned or null in case of no name (parse error).

                                                -

                                                Note:

                                                -
                                                  -
                                                • For ES6 classes in combination with PHPCS 2.x, passing a T_STRING token to -this method will be accepted for JS files.
                                                • -
                                                • Support for JS ES6 method syntax has not been back-filled for PHPCS < 3.0.0.
                                                • -
                                                +
                                                Parameters
                                                @@ -593,7 +726,8 @@
                                                Parameters
                                                : File
                                                -

                                                The file being scanned.

                                                +

                                                The file being scanned.

                                                +
                                                @@ -603,7 +737,8 @@
                                                Parameters

                                                The position of the declaration token which declared the class, interface, -trait, or function.

                                                +trait, enum or function.

                                                +
                                                @@ -619,61 +754,151 @@
                                                File::getDeclarationName() -

                                                Original source.

                                                + +

                                                Original source.

                                                +
                                                -
                                                +
                                                see
                                                - BCFile::getDeclarationName() -

                                                Cross-version compatible version of the original.

                                                + BCFile::getDeclarationName() + +

                                                Cross-version compatible version of the original.

                                                +
                                                -
                                                +
                                                since
                                                1.0.0 - -
                                                + + + +
                                                + since +
                                                +
                                                + 1.0.0-alpha4 + +

                                                Added support for PHP 8.1 enums.

                                                +
                                                + +
                                                throws
                                                RuntimeException -

                                                If the specified token is not of type -T_FUNCTION, T_CLASS, T_TRAIT, or T_INTERFACE.

                                                + +

                                                If the specified token is not of type +T_FUNCTION, T_CLASS, T_ANON_CLASS, +T_CLOSURE, T_TRAIT, T_ENUM or T_INTERFACE.

                                                +
                                                -
                                                +
                                                Return values
                                                string|null — -

                                                The name of the class, interface, trait, or function; +

                                                The name of the class, interface, trait, enum, or function; or NULL if the passed token doesn't exist, the function or -class is anonymous or in case of a parse error/live coding.

                                                +class is anonymous or in case of a parse error/live coding.

                                                +
                                                - -
                                                + + -

                                                Search results

                                                -
                                                  -
                                                -
                                                + +
                                                +
                                                +
                                                +

                                                Search results

                                                + +
                                                +
                                                +
                                                  +
                                                  +
                                                  +
                                                  - +
                                                  + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html index 117720ea..5145fbb4 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Operators.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                  -

                                                  PHPCSUtils

                                                  - -
                                                  - -
                                                  -
                                                  -

                                                  Utility functions for use when working with operators.

                                                  @@ -97,22 +152,34 @@
                                                  link
                                                  - https://www.php.net/language.operators -

                                                  PHP manual on operators.

                                                  - -
                                                  +

                                                  PHP manual on operators.

                                                  +
                                                  + +
                                                  since
                                                  1.0.0 -

                                                  The isReference() method is based on and inspired by + +

                                                  The isReference() method is based on and inspired by the method of the same name in the PHPCS native File class. -Also see {@see \PHPCSUtils\BackCompat\BCFile}. +Also see BCFile. The isUnaryPlusMinus() method is, in part, inspired by the -Squiz.WhiteSpace.OperatorSpacing sniff.

                                                  +Squiz.WhiteSpace.OperatorSpacing sniff.

                                                  +
                                                  -
                                                  + +
                                                  + since +
                                                  +
                                                  + 1.0.0-alpha4 + +

                                                  Dropped support for PHPCS < 3.7.1.

                                                  +
                                                  + +
                                                  @@ -126,24 +193,24 @@

                                                  -
                                                  - isReference() +
                                                  + isReference() -  : bool +  : bool
                                                  Determine if the passed token is a reference operator.
                                                  - isShortTernary() + isShortTernary() -  : bool +  : bool
                                                  Determine whether a ternary is a short ternary/elvis operator, i.e. without "middle".
                                                  - isUnaryPlusMinus() + isUnaryPlusMinus() -  : bool +  : bool
                                                  Determine whether a T_MINUS/T_PLUS token is a unary operator.
                                                  @@ -158,7 +225,7 @@

                                                  Methods - +

                                                  >

                                                  isReference() - +

                                                  + 82 + +

                                                  Determine if the passed token is a reference operator.

                                                  public - static isReference(File $phpcsFile, int $stackPtr) : bool + static isReference(File $phpcsFile, int $stackPtr) : bool

                                                  Main differences with the PHPCS version:

                                                  • Defensive coding against incorrect calls to this method.
                                                  • -
                                                  • Improved handling of select tokenizer errors involving short lists/short arrays.
                                                  • -
                                                  + +

                                                  Parameters
                                                  @@ -195,7 +263,8 @@
                                                  Parameters
                                                  : File
                                                  -

                                                  The file being scanned.

                                                  +

                                                  The file being scanned.

                                                  +
                                                  @@ -203,7 +272,8 @@
                                                  Parameters
                                                  : int
                                                  -

                                                  The position of the T_BITWISE_AND token.

                                                  +

                                                  The position of the T_BITWISE_AND token.

                                                  +
                                                  @@ -219,39 +289,57 @@
                                                  File::isReference() -

                                                  Original source.

                                                  + +

                                                  Original source.

                                                  +
                                                  -
                                                  +
                                                  see
                                                  - BCFile::isReference() -

                                                  Cross-version compatible version of the original.

                                                  + BCFile::isReference() + +

                                                  Cross-version compatible version of the original.

                                                  +
                                                  -
                                                  +
                                                  since
                                                  1.0.0 - -
                                                  + + +
                                                  since
                                                  1.0.0-alpha2 -

                                                  Added BC support for PHP 7.4 arrow functions.

                                                  + +

                                                  Added support for PHP 7.4 arrow functions.

                                                  +
                                                  -
                                                  + +
                                                  + since +
                                                  +
                                                  + 1.0.0-alpha4 + +

                                                  Added support for PHP 8.0 identifier name tokenization.

                                                  +
                                                  + +
                                                  Return values
                                                  bool

                                                  TRUE if the specified token position represents a reference. -FALSE if the token represents a bitwise operator.

                                                  +FALSE if the token represents a bitwise operator.

                                                  + @@ -263,19 +351,20 @@
                                                  Return values
                                                  >

                                                  isShortTernary() - +

                                                  + 231 + +

                                                  Determine whether a ternary is a short ternary/elvis operator, i.e. without "middle".

                                                  public - static isShortTernary(File $phpcsFile, int $stackPtr) : bool + static isShortTernary(File $phpcsFile, int $stackPtr) : bool
                                                  Parameters
                                                  @@ -285,7 +374,8 @@
                                                  Parameters
                                                  : File
                                                  -

                                                  The file being scanned.

                                                  +

                                                  The file being scanned.

                                                  +
                                                  @@ -294,7 +384,8 @@
                                                  Parameters

                                                  The position of the ternary then/else -operator in the stack.

                                                  +operator in the stack.

                                                  +
                                                  @@ -310,14 +401,16 @@
                                                  1.0.0 - -
                                                  + + +
                                                  Return values
                                                  bool — -

                                                  TRUE if short ternary; or FALSE otherwise.

                                                  +

                                                  TRUE if short ternary; or FALSE otherwise.

                                                  +
                                                  @@ -329,19 +422,20 @@
                                                  Return values
                                                  >

                                                  isUnaryPlusMinus() - +

                                                  + 180 + +

                                                  Determine whether a T_MINUS/T_PLUS token is a unary operator.

                                                  public - static isUnaryPlusMinus(File $phpcsFile, int $stackPtr) : bool + static isUnaryPlusMinus(File $phpcsFile, int $stackPtr) : bool
                                                  Parameters
                                                  @@ -351,7 +445,8 @@
                                                  Parameters
                                                  : File
                                                  -

                                                  The file being scanned.

                                                  +

                                                  The file being scanned.

                                                  +
                                                  @@ -359,7 +454,8 @@
                                                  Parameters
                                                  : int
                                                  -

                                                  The position of the plus/minus token.

                                                  +

                                                  The position of the plus/minus token.

                                                  +
                                                  @@ -375,8 +471,9 @@
                                                  1.0.0 - -
                                                  + + +
                                                  Return values
                                                  @@ -384,27 +481,99 @@
                                                  Return values

                                                  TRUE if the token passed is a unary operator. FALSE otherwise, i.e. if the token is an arithmetic operator, -or if the token is not a T_PLUS/T_MINUS token.

                                                  +or if the token is not a T_PLUS/T_MINUS token.

                                                  + - -
                                                  + + -

                                                  Search results

                                                  -
                                                    -
                                                  -
                                                  + +
                                                  +
                                                  +
                                                  +

                                                  Search results

                                                  + +
                                                  +
                                                  +
                                                    +
                                                    +
                                                    +
                                                    - +
                                                    + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html index 66bcde0b..75f001df 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Orthography.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                    -

                                                    PHPCSUtils

                                                    - -
                                                    - -
                                                    -
                                                    -

                                                    Utility functions for checking the orthography of arbitrary text strings.

                                                    An orthography is a set of conventions for writing a language. It includes norms of spelling, hyphenation, capitalization, word breaks, emphasis, and punctuation. -Source: https://en.wikipedia.org/wiki/Orthography

                                                    -
                                                    +Source: https://en.wikipedia.org/wiki/Orthography

                                                    + +
                                                    @@ -103,8 +159,9 @@
                                                    1.0.0 - -
                                                    + + + @@ -119,30 +176,30 @@

                                                    - TERMINAL_POINTS + TERMINAL_POINTS -  = '.?!' +  = '.?!'
                                                    Characters which are considered terminal points for a sentence.
                                                    -
                                                    - isFirstCharCapitalized() +
                                                    + isFirstCharCapitalized() -  : bool +  : bool
                                                    Check if the first character of an arbitrary text string is a capital letter.
                                                    - isFirstCharLowercase() + isFirstCharLowercase() -  : bool +  : bool
                                                    Check if the first character of an arbitrary text string is a lowercase letter.
                                                    - isLastCharPunctuation() + isLastCharPunctuation() -  : bool +  : bool
                                                    Check if the last character of an arbitrary text string is a valid punctuation character.
                                                    @@ -154,25 +211,26 @@

                                                    Constants - +

                                                    @@ -210,7 +270,7 @@

                                                    Methods - +

                                                    >

                                                    isFirstCharCapitalized() - +

                                                    + +

                                                    Check if the first character of an arbitrary text string is a capital letter.

                                                    public - static isFirstCharCapitalized(string $string) : bool + static isFirstCharCapitalized(string $textString) : bool

                                                    Letter characters which do not have a concept of lower/uppercase will -be accepted as correctly capitalized.

                                                    +be accepted as correctly capitalized.

                                                    +
                                                    Parameters
                                                    - $string + $textString : string
                                                    @@ -249,7 +311,8 @@
                                                    Parameters
                                                    but also, for instance, a comment text. Potential text delimiter quotes should be stripped off a text string before passing it to this method. -Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}.

                                                    +Also see: TextStrings::stripQuotes().

                                                    +
                                                    @@ -265,8 +328,9 @@
                                                    1.0.0 - -
                                                    + + +
                                                    Return values
                                                    @@ -274,7 +338,8 @@
                                                    Return values

                                                    TRUE when the first character is a capital letter or a letter which doesn't have a concept of capitalization. -FALSE otherwise, including for non-letter characters.

                                                    +FALSE otherwise, including for non-letter characters.

                                                    + @@ -286,25 +351,26 @@
                                                    Return values
                                                    >

                                                    isFirstCharLowercase() - +

                                                    + +

                                                    Check if the first character of an arbitrary text string is a lowercase letter.

                                                    public - static isFirstCharLowercase(string $string) : bool + static isFirstCharLowercase(string $textString) : bool
                                                    Parameters
                                                    - $string + $textString : string
                                                    @@ -313,7 +379,8 @@
                                                    Parameters
                                                    but also, for instance, a comment text. Potential text delimiter quotes should be stripped off a text string before passing it to this method. -Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}.

                                                    +Also see: TextStrings::stripQuotes().

                                                    +
                                                    @@ -329,8 +396,9 @@
                                                    1.0.0 - -
                                                    + + +
                                                    Return values
                                                    @@ -338,7 +406,8 @@
                                                    Return values

                                                    TRUE when the first character is a lowercase letter. FALSE otherwise, including for letters which don't have a concept of -capitalization and for non-letter characters.

                                                    +capitalization and for non-letter characters.

                                                    + @@ -350,25 +419,26 @@
                                                    Return values
                                                    >

                                                    isLastCharPunctuation() - +

                                                    + +

                                                    Check if the last character of an arbitrary text string is a valid punctuation character.

                                                    public - static isLastCharPunctuation(string $string[, string $allowedChars = self::TERMINAL_POINTS ]) : bool + static isLastCharPunctuation(string $textString[, string $allowedChars = self::TERMINAL_POINTS ]) : bool
                                                    Parameters
                                                    - $string + $textString : string
                                                    @@ -377,7 +447,8 @@
                                                    Parameters
                                                    but also, for instance, a comment text. Potential text delimiter quotes should be stripped off a text string before passing it to this method. -Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}.

                                                    +Also see: TextStrings::stripQuotes().

                                                    +
                                                    @@ -388,7 +459,8 @@
                                                    Parameters

                                                    Characters which are considered valid punctuation to end the text string. Defaults to '.?!', i.e. a full stop, question mark -or exclamation mark.

                                                    +or exclamation mark.

                                                    +
                                                    @@ -404,8 +476,9 @@
                                                    1.0.0 - -
                                                    + + +
                                                    Return values
                                                    @@ -416,21 +489,92 @@
                                                    Return values
                                                    - -
                                                    + + -

                                                    Search results

                                                    -
                                                      -
                                                    -
                                                    + +
                                                    +
                                                    +
                                                    +

                                                    Search results

                                                    + +
                                                    +
                                                    +
                                                      +
                                                      +
                                                      +
                                                      - +
                                                      + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html index d92b8dcb..50b6ae1e 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Parentheses.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                      -

                                                      PHPCSUtils

                                                      - -
                                                      - -
                                                      -
                                                      - +

                                                      Utility functions for use when examining parenthesis tokens and arbitrary tokens wrapped +in parentheses.

                                                      + +

                                                      In contrast to PHPCS natively, isset(), unset(), empty(), exit(), die() and eval() +will be considered parentheses owners by the functions in this class.

                                                      +
                                                      @@ -99,8 +157,30 @@
                                                      1.0.0 - -
                                                      + + + +
                                                      + since +
                                                      +
                                                      + 1.0.0-alpha4 + +

                                                      Added support for isset(), unset(), empty(), exit(), die() +and eval() as parentheses owners to all applicable functions.

                                                      +
                                                      + +
                                                      +
                                                      + since +
                                                      +
                                                      + 1.0.0-alpha4 + +

                                                      Dropped support for PHPCS < 3.7.1.

                                                      +
                                                      + +
                                                      @@ -114,90 +194,90 @@

                                                      -
                                                      - firstOwnerIn() +
                                                      + firstOwnerIn() -  : int|false +  : int|false
                                                      -
                                                      Check whether the owner of a outermost wrapping set of parentheses of an arbitrary token +
                                                      Check whether the owner of the outermost wrapping set of parentheses of an arbitrary token is within a limited set of acceptable token types.
                                                      - getFirstCloser() + getFirstCloser() -  : int|false +  : int|false
                                                      -
                                                      Retrieve the position of the closer to the first (outer) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.
                                                      +
                                                      Retrieve the stack pointer to the parentheses closer of the first (outer) set of parentheses +an arbitrary token is wrapped in.
                                                      - getFirstOpener() + getFirstOpener() -  : int|false +  : int|false
                                                      -
                                                      Retrieve the position of the opener to the first (outer) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.
                                                      +
                                                      Retrieve the stack pointer to the parentheses opener of the first (outer) set of parentheses +an arbitrary token is wrapped in.
                                                      - getFirstOwner() + getFirstOwner() -  : int|false +  : int|false
                                                      -
                                                      Retrieve the position of the parentheses owner to the first (outer) set of parentheses an -arbitrary token is wrapped in, where the parentheses owner is within the set of valid owners.
                                                      +
                                                      Retrieve the stack pointer to the parentheses owner of the first (outer) set of parentheses +an arbitrary token is wrapped in.
                                                      - getLastCloser() + getLastCloser() -  : int|false +  : int|false
                                                      -
                                                      Retrieve the position of the closer to the last (inner) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.
                                                      +
                                                      Retrieve the stack pointer to the parentheses closer of the last (inner) set of parentheses +an arbitrary token is wrapped in.
                                                      - getLastOpener() + getLastOpener() -  : int|false +  : int|false
                                                      -
                                                      Retrieve the position of the opener to the last (inner) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.
                                                      +
                                                      Retrieve the stack pointer to the parentheses opener of the last (inner) set of parentheses +an arbitrary token is wrapped in.
                                                      - getLastOwner() + getLastOwner() -  : int|false +  : int|false
                                                      -
                                                      Retrieve the position of the parentheses owner to the last (inner) set of parentheses an -arbitrary token is wrapped in where the parentheses owner is within the set of valid owners.
                                                      +
                                                      Retrieve the stack pointer to the parentheses owner of the last (inner) set of parentheses +an arbitrary token is wrapped in.
                                                      - getOwner() + getOwner() -  : int|false +  : int|false
                                                      -
                                                      Get the pointer to the parentheses owner of an open/close parenthesis.
                                                      +
                                                      Get the stack pointer to the parentheses owner of an open/close parenthesis.
                                                      - hasOwner() + hasOwner() -  : bool +  : bool
                                                      Check whether the passed token is nested within parentheses owned by one of the valid owners.
                                                      - isOwnerIn() + isOwnerIn() -  : bool +  : bool
                                                      Check whether the parenthesis owner of an open/close parenthesis is within a limited set of valid owners.
                                                      - lastOwnerIn() + lastOwnerIn() -  : int|false +  : int|false
                                                      -
                                                      Check whether the owner of a innermost wrapping set of parentheses of an arbitrary token +
                                                      Check whether the owner of the innermost wrapping set of parentheses of an arbitrary token is within a limited set of acceptable token types.
                                                      @@ -211,7 +291,7 @@

                                                      Methods - +

                                                      >

                                                      firstOwnerIn() - +

                                                      + 324 + + -

                                                      Check whether the owner of a outermost wrapping set of parentheses of an arbitrary token +

                                                      Check whether the owner of the outermost wrapping set of parentheses of an arbitrary token is within a limited set of acceptable token types.

                                                      public - static firstOwnerIn(File $phpcsFile, int $stackPtr, int|string|array $validOwners) : int|false + static firstOwnerIn(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $validOwners) : int|false
                                                      Parameters
                                                      @@ -244,7 +325,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -253,16 +335,18 @@
                                                      Parameters

                                                      The position in the stack of the -token to verify.

                                                      +token to verify.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed>

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -278,8 +362,9 @@

                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -288,7 +373,8 @@
                                                      Return values

                                                      Integer stack pointer to the valid parentheses owner; or FALSE if the token was not wrapped in parentheses or if the outermost set of parentheses in which the token is wrapped does not have an owner -within the set of owners considered valid.

                                                      +within the set of owners considered valid.

                                                      + @@ -300,23 +386,26 @@
                                                      Return values
                                                      >

                                                      getFirstCloser() - +

                                                      + 184 -

                                                      Retrieve the position of the closer to the first (outer) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.

                                                      + + +

                                                      Retrieve the stack pointer to the parentheses closer of the first (outer) set of parentheses +an arbitrary token is wrapped in.

                                                      public - static getFirstCloser(File $phpcsFile, int $stackPtr[, int|string|array $validOwners = [] ]) : int|false + static getFirstCloser(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $validOwners = [] ]) : int|false -

                                                      If no $validOwners are specified, the closer to the first set of parentheses surrounding -the token will be returned.

                                                      +

                                                      If the optional $validOwners parameter is passed, the stack pointer to the closer to +the first set of parentheses, which has an owner which is in the list of valid owners, +will be returned. This may be a nested set of parentheses.

                                                      +
                                                      Parameters
                                                      @@ -325,7 +414,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -333,16 +423,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed> = []

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -358,8 +450,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -367,7 +460,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses closer; or FALSE if the token does not have parentheses owned by any of the valid owners or if -the token is not nested in parentheses at all.

                                                      +the token is not nested in parentheses at all.

                                                      + @@ -379,23 +473,26 @@
                                                      Return values
                                                      >

                                                      getFirstOpener() - +

                                                      + 160 -

                                                      Retrieve the position of the opener to the first (outer) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.

                                                      + + +

                                                      Retrieve the stack pointer to the parentheses opener of the first (outer) set of parentheses +an arbitrary token is wrapped in.

                                                      public - static getFirstOpener(File $phpcsFile, int $stackPtr[, int|string|array $validOwners = [] ]) : int|false + static getFirstOpener(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $validOwners = [] ]) : int|false -

                                                      If no $validOwners are specified, the opener to the first set of parentheses surrounding -the token will be returned.

                                                      +

                                                      If the optional $validOwners parameter is passed, the stack pointer to the opener to +the first set of parentheses, which has an owner which is in the list of valid owners, +will be returned. This may be a nested set of parentheses.

                                                      +
                                                      Parameters
                                                      @@ -404,7 +501,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -412,16 +510,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed> = []

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -437,8 +537,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -446,7 +547,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses opener; or FALSE if the token does not have parentheses owned by any of the valid owners or if -the token is not nested in parentheses at all.

                                                      +the token is not nested in parentheses at all.

                                                      + @@ -458,23 +560,26 @@
                                                      Return values
                                                      >

                                                      getFirstOwner() - +

                                                      + 214 -

                                                      Retrieve the position of the parentheses owner to the first (outer) set of parentheses an -arbitrary token is wrapped in, where the parentheses owner is within the set of valid owners.

                                                      + + +

                                                      Retrieve the stack pointer to the parentheses owner of the first (outer) set of parentheses +an arbitrary token is wrapped in.

                                                      public - static getFirstOwner(File $phpcsFile, int $stackPtr[, int|string|array $validOwners = [] ]) : int|false + static getFirstOwner(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $validOwners = [] ]) : int|false -

                                                      If no $validOwners are specified, the owner to the first set of parentheses surrounding -the token will be returned or false if the first set of parentheses does not have an owner.

                                                      +

                                                      If the optional $validOwners parameter is passed, the stack pointer to the owner of +the first set of parentheses, which has an owner which is in the list of valid owners, +will be returned. This may be a nested set of parentheses.

                                                      +
                                                      Parameters
                                                      @@ -483,7 +588,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -491,16 +597,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed> = []

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -516,8 +624,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -525,7 +634,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses owner; or FALSE if the token does not have parentheses owned by any of the valid owners or if -the token is not nested in parentheses at all.

                                                      +the token is not nested in parentheses at all.

                                                      + @@ -537,23 +647,26 @@
                                                      Return values
                                                      >

                                                      getLastCloser() - +

                                                      + 267 -

                                                      Retrieve the position of the closer to the last (inner) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.

                                                      + + +

                                                      Retrieve the stack pointer to the parentheses closer of the last (inner) set of parentheses +an arbitrary token is wrapped in.

                                                      public - static getLastCloser(File $phpcsFile, int $stackPtr[, int|string|array $validOwners = [] ]) : int|false + static getLastCloser(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $validOwners = [] ]) : int|false -

                                                      If no $validOwners are specified, the closer to the last set of parentheses surrounding -the token will be returned.

                                                      +

                                                      If the optional $validOwners parameter is passed, the stack pointer to the closer to +the last set of parentheses, which has an owner which is in the list of valid owners, +will be returned. This may be a set of parentheses higher up.

                                                      +
                                                      Parameters
                                                      @@ -562,7 +675,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -570,16 +684,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed> = []

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -595,8 +711,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -604,7 +721,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses closer; or FALSE if the token does not have parentheses owned by any of the valid owners or if -the token is not nested in parentheses at all.

                                                      +the token is not nested in parentheses at all.

                                                      + @@ -616,23 +734,26 @@
                                                      Return values
                                                      >

                                                      getLastOpener() - +

                                                      + 243 -

                                                      Retrieve the position of the opener to the last (inner) set of parentheses an arbitrary -token is wrapped in, where the parentheses owner is within the set of valid owners.

                                                      + + +

                                                      Retrieve the stack pointer to the parentheses opener of the last (inner) set of parentheses +an arbitrary token is wrapped in.

                                                      public - static getLastOpener(File $phpcsFile, int $stackPtr[, int|string|array $validOwners = [] ]) : int|false + static getLastOpener(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $validOwners = [] ]) : int|false -

                                                      If no $validOwners are specified, the opener to the last set of parentheses surrounding -the token will be returned.

                                                      +

                                                      If the optional $validOwners parameter is passed, the stack pointer to the opener to +the last set of parentheses, which has an owner which is in the list of valid owners, +will be returned. This may be a set of parentheses higher up.

                                                      +
                                                      Parameters
                                                      @@ -641,7 +762,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -649,16 +771,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed> = []

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -674,8 +798,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -683,7 +808,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses opener; or FALSE if the token does not have parentheses owned by any of the valid owners or if -the token is not nested in parentheses at all.

                                                      +the token is not nested in parentheses at all.

                                                      + @@ -695,23 +821,26 @@
                                                      Return values
                                                      >

                                                      getLastOwner() - +

                                                      + 297 -

                                                      Retrieve the position of the parentheses owner to the last (inner) set of parentheses an -arbitrary token is wrapped in where the parentheses owner is within the set of valid owners.

                                                      + + +

                                                      Retrieve the stack pointer to the parentheses owner of the last (inner) set of parentheses +an arbitrary token is wrapped in.

                                                      public - static getLastOwner(File $phpcsFile, int $stackPtr[, int|string|array $validOwners = [] ]) : int|false + static getLastOwner(File $phpcsFile, int $stackPtr[, int|string|array<string|int, mixed> $validOwners = [] ]) : int|false -

                                                      If no $validOwners are specified, the owner to the last set of parentheses surrounding -the token will be returned or false if the last set of parentheses does not have an owner.

                                                      +

                                                      If the optional $validOwners parameter is passed, the stack pointer to the owner of +the last set of parentheses, which has an owner which is in the list of valid owners, +will be returned. This may be a set of parentheses higher up.

                                                      +
                                                      Parameters
                                                      @@ -720,7 +849,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -728,16 +858,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed> = []

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -753,8 +885,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -762,7 +895,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses owner; or FALSE if the token does not have parentheses owned by any of the valid owners or if -the token is not nested in parentheses at all.

                                                      +the token is not nested in parentheses at all.

                                                      + @@ -774,19 +908,20 @@
                                                      Return values
                                                      >

                                                      getOwner() - +

                                                      + 63 -

                                                      Get the pointer to the parentheses owner of an open/close parenthesis.

                                                      + + +

                                                      Get the stack pointer to the parentheses owner of an open/close parenthesis.

                                                      public - static getOwner(File $phpcsFile, int $stackPtr) : int|false + static getOwner(File $phpcsFile, int $stackPtr) : int|false
                                                      Parameters
                                                      @@ -796,7 +931,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -804,7 +940,8 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of T_OPEN/CLOSE_PARENTHESIS token.

                                                      +

                                                      The position of T_OPEN/CLOSE_PARENTHESIS token.

                                                      +
                                                      @@ -820,16 +957,19 @@
                                                      1.0.0 - -
                                                      + + +
                                                      since
                                                      1.0.0-alpha2 -

                                                      Added BC support for PHP 7.4 arrow functions.

                                                      + +

                                                      Added support for PHP 7.4 arrow functions.

                                                      +
                                                      -
                                                      +
                                                      Return values
                                                      @@ -837,7 +977,8 @@
                                                      Return values

                                                      Integer stack pointer to the parentheses owner; or FALSE if the parenthesis does not have a (direct) owner or if the token passed -was not a parenthesis.

                                                      +was not a parenthesis.

                                                      + @@ -849,19 +990,20 @@
                                                      Return values
                                                      >

                                                      hasOwner() - +

                                                      + 136 + +

                                                      Check whether the passed token is nested within parentheses owned by one of the valid owners.

                                                      public - static hasOwner(File $phpcsFile, int $stackPtr, int|string|array $validOwners) : bool + static hasOwner(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $validOwners) : bool
                                                      Parameters
                                                      @@ -871,7 +1013,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -879,16 +1022,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of the token we are checking.

                                                      +

                                                      The position of the token we are checking.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed>

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -904,8 +1049,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -922,20 +1068,21 @@
                                                      Return values
                                                      >

                                                      isOwnerIn() - +

                                                      + 111 + +

                                                      Check whether the parenthesis owner of an open/close parenthesis is within a limited set of valid owners.

                                                      public - static isOwnerIn(File $phpcsFile, int $stackPtr, int|string|array $validOwners) : bool + static isOwnerIn(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $validOwners) : bool
                                                      Parameters
                                                      @@ -945,7 +1092,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -953,16 +1101,18 @@
                                                      Parameters
                                                      : int
                                                      -

                                                      The position of T_OPEN/CLOSE_PARENTHESIS token.

                                                      +

                                                      The position of T_OPEN/CLOSE_PARENTHESIS token.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed>

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -978,23 +1128,27 @@
                                                      1.0.0 - -
                                                      + + +
                                                      since
                                                      1.0.0-alpha2 -

                                                      Added BC support for PHP 7.4 arrow functions.

                                                      + +

                                                      Added support for PHP 7.4 arrow functions.

                                                      +
                                                      -
                                                      +
                                                      Return values
                                                      bool

                                                      TRUE if the owner is within the list of $validOwners; FALSE if not and -if the parenthesis does not have a (direct) owner.

                                                      +if the parenthesis does not have a (direct) owner.

                                                      + @@ -1006,20 +1160,21 @@
                                                      Return values
                                                      >

                                                      lastOwnerIn() - +

                                                      + 352 + + -

                                                      Check whether the owner of a innermost wrapping set of parentheses of an arbitrary token +

                                                      Check whether the owner of the innermost wrapping set of parentheses of an arbitrary token is within a limited set of acceptable token types.

                                                      public - static lastOwnerIn(File $phpcsFile, int $stackPtr, int|string|array $validOwners) : int|false + static lastOwnerIn(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $validOwners) : int|false
                                                      Parameters
                                                      @@ -1029,7 +1184,8 @@
                                                      Parameters
                                                      : File
                                                      -

                                                      The file where this token was found.

                                                      +

                                                      The file where this token was found.

                                                      +
                                                      @@ -1038,16 +1194,18 @@
                                                      Parameters

                                                      The position in the stack of the -token to verify.

                                                      +token to verify.

                                                      +
                                                      $validOwners - : int|string|array + : int|string|array<string|int, mixed>

                                                      Array of token constants for the owners -which should be considered valid.

                                                      +which should be considered valid.

                                                      +
                                                      @@ -1063,8 +1221,9 @@
                                                      1.0.0 - -
                                                      + + +
                                                      Return values
                                                      @@ -1073,27 +1232,99 @@
                                                      Return values

                                                      Integer stack pointer to the valid parentheses owner; or FALSE if the token was not wrapped in parentheses or if the innermost set of parentheses in which the token is wrapped does not have an owner -within the set of owners considered valid.

                                                      +within the set of owners considered valid.

                                                      + - -
                                                      + + -

                                                      Search results

                                                      -
                                                        -
                                                      -
                                                      + +
                                                      +
                                                      +
                                                      +

                                                      Search results

                                                      + +
                                                      +
                                                      +
                                                        +
                                                        +
                                                        +
                                                        - +
                                                        + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html b/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html index 73c09de2..3fc2331f 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-PassedParameters.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                        -

                                                        PHPCSUtils

                                                        - -
                                                        - -
                                                        -
                                                        -

                                                        Utility functions to retrieve information about parameters passed to function calls, -array declarations, isset and unset constructs.

                                                        +class instantiations, array declarations, isset and unset constructs.

                                                        @@ -99,8 +154,19 @@
                                                        1.0.0 - -
                                                        + + + +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Dropped support for PHPCS < 3.7.1.

                                                        +
                                                        + +
                                                        @@ -114,31 +180,38 @@

                                                        -
                                                        - getParameter() +
                                                        + getParameter() -  : array|false +  : array<string|int, mixed>|false
                                                        Get information on a specific parameter passed.
                                                        - getParameterCount() + getParameterCount() -  : int +  : int
                                                        Count the number of parameters which have been passed.
                                                        - getParameters() + getParameterFromStack() -  : array +  : array<string|int, mixed>|false +
                                                        +
                                                        Get information on a specific function call parameter passed.
                                                        + +
                                                        + getParameters() + +  : array<string|int, mixed>
                                                        Get information on all parameters passed.
                                                        - hasParameters() + hasParameters() -  : bool +  : bool
                                                        Checks if any parameters have been passed.
                                                        @@ -153,7 +226,7 @@

                                                        Methods - +

                                                        >

                                                        getParameter() - +

                                                        + 398 + +

                                                        Get information on a specific parameter passed.

                                                        public - static getParameter(File $phpcsFile, int $stackPtr, int $paramOffset) : array|false + static getParameter(File $phpcsFile, int $stackPtr, int $paramOffset[, string|array<string|int, string> $paramNames = [] ]) : array<string|int, mixed>|false -

                                                        See \PHPCSUtils\Utils\PassedParameters::hasParameters() for information on the supported constructs.

                                                        +

                                                        See PassedParameters::hasParameters() for information on the supported constructs.

                                                        +
                                                        Parameters
                                                        @@ -186,7 +261,8 @@
                                                        Parameters
                                                        : File
                                                        -

                                                        The file where this token was found.

                                                        +

                                                        The file where this token was found.

                                                        +
                                                        @@ -194,8 +270,9 @@
                                                        Parameters
                                                        : int
                                                        -

                                                        The position of the T_STRING, T_VARIABLE, T_ARRAY, -T_OPEN_SHORT_ARRAY, T_ISSET or T_UNSET token.

                                                        +

                                                        The position of function call name, +language construct or array open token.

                                                        +
                                                        @@ -203,7 +280,28 @@
                                                        Parameters
                                                        : int
                                                        -

                                                        The 1-based index position of the parameter to retrieve.

                                                        +

                                                        The 1-based index position of the parameter to retrieve.

                                                        +
                                                        + +
                                                        +
                                                        + $paramNames + : string|array<string|int, string> + = []
                                                        +
                                                        +

                                                        Optional. Either the name of the target parameter +to retrieve as a string or an array of names for the +same target parameter. +Only relevant for function calls. +An arrays of names is supported to allow for functions +for which the parameter names have undergone name +changes over time. +When specified, the name will take precedence over the +offset. +For PHP 8 support, it is STRONGLY recommended to +always pass both the offset as well as the parameter +name when examining function calls.

                                                        +
                                                        @@ -215,35 +313,67 @@
                                                        + see +
                                                        +
                                                        + PassedParameters::getParameterFromStack() + +

                                                        For when the parameter stack of a function call is +already retrieved.

                                                        +
                                                        + +
                                                        +
                                                        since
                                                        1.0.0 - -
                                                        + + + +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Added the $paramNames parameter.

                                                        +
                                                        + +
                                                        throws
                                                        RuntimeException -

                                                        If the token passed is not one of the -accepted types or doesn't exist.

                                                        + +

                                                        If the token passed is not one of the +accepted types or doesn't exist.

                                                        +
                                                        + +
                                                        +
                                                        + throws +
                                                        +
                                                        + RuntimeException + +

                                                        If a function call parameter is requested and +the $paramName parameter is not passed.

                                                        +
                                                        -
                                                        +
                                                        Return values
                                                        - array|false + array<string|int, mixed>|false — -

                                                        Array with information on the parameter/array item at the specified offset. +

                                                        Array with information on the parameter/array item at the specified offset, +or with the specified name. Or FALSE if the specified parameter/array item is not found. -The format of the return value is:

                                                        -
                                                        array(
                                                        -  'start' => int,    // The stack pointer to the first token in the parameter/array item.
                                                        -  'end'   => int,    // The stack pointer to the last token in the parameter/array item.
                                                        -  'raw'   => string, // A string with the contents of all tokens between `start` and `end`.
                                                        -  'clean' => string, // Same as `raw`, but all comment tokens have been stripped out.
                                                        -)
                                                        +See PassedParameters::getParameters() for the format of the returned +(single-dimensional) array.

                                                        +
                                                        @@ -255,21 +385,23 @@
                                                        Return values
                                                        >

                                                        getParameterCount() - +

                                                        + 441 + +

                                                        Count the number of parameters which have been passed.

                                                        public - static getParameterCount(File $phpcsFile, int $stackPtr) : int + static getParameterCount(File $phpcsFile, int $stackPtr) : int -

                                                        See \PHPCSUtils\Utils\PassedParameters::hasParameters() for information on the supported constructs.

                                                        +

                                                        See PassedParameters::hasParameters() for information on the supported constructs.

                                                        +
                                                        Parameters
                                                        @@ -278,7 +410,8 @@
                                                        Parameters
                                                        : File
                                                        -

                                                        The file where this token was found.

                                                        +

                                                        The file where this token was found.

                                                        +
                                                        @@ -286,8 +419,9 @@
                                                        Parameters
                                                        : int
                                                        -

                                                        The position of the T_STRING, T_VARIABLE, T_ARRAY, -T_OPEN_SHORT_ARRAY, T_ISSET or T_UNSET token.

                                                        +

                                                        The position of function call name, +language construct or array open token.

                                                        +
                                                        @@ -303,17 +437,20 @@
                                                        1.0.0 - -
                                                        + + +
                                                        throws
                                                        RuntimeException -

                                                        If the token passed is not one of the -accepted types or doesn't exist.

                                                        + +

                                                        If the token passed is not one of the +accepted types or doesn't exist.

                                                        +
                                                        -
                                                        +

                                                        Return values
                                                        @@ -321,6 +458,111 @@
                                                        Return values
                                                        — + +
                                                        +

                                                        + getParameterFromStack() + +

                                                        + + +

                                                        Get information on a specific function call parameter passed.

                                                        + + + public + static getParameterFromStack(array<string|int, mixed> $parameters, int $paramOffset, string|array<string|int, string> $paramNames) : array<string|int, mixed>|false + +

                                                        This is an efficiency method to correctly handle positional versus named parameters +for function calls when multiple parameters need to be examined.

                                                        +

                                                        See PassedParameters::hasParameters() for information on the supported constructs.

                                                        +
                                                        + +
                                                        Parameters
                                                        +
                                                        +
                                                        + $parameters + : array<string|int, mixed> +
                                                        +
                                                        +

                                                        The output of a previous call to PassedParameters::getParameters().

                                                        +
                                                        + +
                                                        +
                                                        + $paramOffset + : int +
                                                        +
                                                        +

                                                        The 1-based index position of the parameter to retrieve.

                                                        +
                                                        + +
                                                        +
                                                        + $paramNames + : string|array<string|int, string> +
                                                        +
                                                        +

                                                        Either the name of the target parameter to retrieve +as a string or an array of names for the same target parameter. +An array of names is supported to allow for functions +for which the parameter names have undergone name +changes over time. +The name will take precedence over the offset.

                                                        +
                                                        + +
                                                        +
                                                        + + +
                                                        + Tags + +
                                                        +
                                                        +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + + +
                                                        +
                                                        + throws +
                                                        +
                                                        + RuntimeException + +

                                                        If the $paramNames parameter is not passed +and the requested parameter was not passed +as a positional parameter in the function call +being examined.

                                                        +
                                                        + +
                                                        +
                                                        + +
                                                        Return values
                                                        + array<string|int, mixed>|false + — +

                                                        Array with information on the parameter at the specified offset, +or with the specified name. +Or FALSE if the specified parameter is not found. +See PassedParameters::getParameters() for the format of the returned +(single-dimensional) array.

                                                        +
                                                        + +
                                                        Return values >

                                                        getParameters() - +

                                                        + 205 + +

                                                        Get information on all parameters passed.

                                                        public - static getParameters(File $phpcsFile, int $stackPtr) : array + static getParameters(File $phpcsFile, int $stackPtr, int $limit[, true|null $isShortArray = null ]) : array<string|int, mixed> -

                                                        See \PHPCSUtils\Utils\PassedParameters::hasParameters() for information on the supported constructs.

                                                        +

                                                        See PassedParameters::hasParameters() for information on the supported constructs.

                                                        +
                                                        Parameters
                                                        @@ -353,7 +597,8 @@
                                                        Parameters
                                                        : File
                                                        -

                                                        The file where this token was found.

                                                        +

                                                        The file where this token was found.

                                                        +
                                                        @@ -361,8 +606,33 @@
                                                        Parameters
                                                        : int
                                                        -

                                                        The position of the T_STRING, T_VARIABLE, T_ARRAY, -T_OPEN_SHORT_ARRAY, T_ISSET, or T_UNSET token.

                                                        +

                                                        The position of function call name, +language construct or array open token.

                                                        +
                                                        + +
                                                        +
                                                        + $limit + : int +
                                                        +
                                                        +

                                                        Optional. Limit the parameter retrieval to the first # +parameters/array entries. +Use with care on function calls, as this can break +support for named parameters!

                                                        +
                                                        + +
                                                        +
                                                        + $isShortArray + : true|null + = null
                                                        +
                                                        +

                                                        Optional. Short-circuit the short array check for +T_OPEN_SHORT_ARRAY tokens if it isn't necessary. +Efficiency tweak for when this has already been established, +Use with EXTREME care.

                                                        +
                                                        @@ -378,32 +648,70 @@
                                                        1.0.0 - -
                                                        + + + +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Added the $limit and $isShortArray parameters.

                                                        +
                                                        + +
                                                        +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Added support for PHP 8.0 function calls with named arguments by introducing +the 'name' and 'name_token' index keys as well as using the name +as the index for the top-level array for named parameters.

                                                        +
                                                        + +
                                                        throws
                                                        RuntimeException -

                                                        If the token passed is not one of the -accepted types or doesn't exist.

                                                        + +

                                                        If the token passed is not one of the +accepted types or doesn't exist.

                                                        +
                                                        -
                                                        +
                                                        Return values
                                                        - array + array<string|int, mixed> — -

                                                        A multi-dimentional array information on each parameter/array item. +

                                                        A multi-dimentional array with information on each parameter/array item. The information gathered about each parameter/array item is in the following format:

                                                        1 => array(
                                                           'start' => int,    // The stack pointer to the first token in the parameter/array item.
                                                           'end'   => int,    // The stack pointer to the last token in the parameter/array item.
                                                           'raw'   => string, // A string with the contents of all tokens between `start` and `end`.
                                                           'clean' => string, // Same as `raw`, but all comment tokens have been stripped out.
                                                        -)
                                                        -

                                                        Note: The array starts at index 1. -If no parameters/array items are found, an empty array will be returned.

                                                        +) + +

                                                        If a named parameter is encountered in a function call, the top-level index will not be +the parameter position, but the parameter name and the array will include two extra keys:

                                                        +
                                                        'parameter_name' => array(
                                                        +  'name'       => string, // The parameter name (without the colon).
                                                        +  'name_token' => int,    // The stack pointer to the parameter name token.
                                                        +  ...
                                                        +)
                                                        +
                                                        +

                                                        The 'start', 'end', 'raw' and 'clean' indexes will always contain just and only +information on the parameter value. +Note: The array starts at index 1 for positional parameters. +The key for named parameters will be the parameter name. +If no parameters/array items are found, an empty array will be returned.

                                                        +
                                                        @@ -415,31 +723,38 @@
                                                        Return values
                                                        >

                                                        hasParameters() - +

                                                        + 85 + +

                                                        Checks if any parameters have been passed.

                                                        public - static hasParameters(File $phpcsFile, int $stackPtr) : bool + static hasParameters(File $phpcsFile, int $stackPtr[, true|null $isShortArray = null ]) : bool
                                                          -
                                                        • If passed a T_STRING or T_VARIABLE stack pointer, it will treat it as a function call. +
                                                        • If passed a T_STRING, T_NAME_FULLY_QUALIFIED, T_NAME_RELATIVE, T_NAME_QUALIFIED +or T_VARIABLE stack pointer, it will treat it as a function call. If a T_STRING or T_VARIABLE which is not a function call is passed, the behaviour is undetermined.
                                                        • -
                                                        • If passed a T_SELF or T_STATIC stack pointer, it will accept it as a -function call when used like new self().
                                                        • +
                                                        • If passed a T_ANON_CLASS stack pointer, it will accept it as a class instantiation.
                                                        • +
                                                        • If passed a T_SELF, T_STATIC or T_PARENT stack pointer, it will accept it as a +class instantiation function call when used like new self().
                                                        • If passed a T_ARRAY or T_OPEN_SHORT_ARRAY stack pointer, it will detect -whether the array has values or is empty.
                                                        • +whether the array has values or is empty. +For purposes of backward-compatibility with older PHPCS versions, T_OPEN_SQUARE_BRACKET +tokens will also be accepted and will be checked whether they are in reality +a short array opener.
                                                        • If passed a T_ISSET or T_UNSET stack pointer, it will detect whether those language constructs have "parameters".
                                                        • -
                                                        + +
                                                        Parameters
                                                        @@ -448,7 +763,8 @@
                                                        Parameters
                                                        : File
                                                        -

                                                        The file where this token was found.

                                                        +

                                                        The file where this token was found.

                                                        +
                                                        @@ -456,8 +772,21 @@
                                                        Parameters
                                                        : int
                                                        -

                                                        The position of the T_STRING, T_VARIABLE, T_ARRAY, -T_OPEN_SHORT_ARRAY, T_ISSET, or T_UNSET token.

                                                        +

                                                        The position of function call name, +language construct or array open token.

                                                        +
                                                        + +
                                                        +
                                                        + $isShortArray + : true|null + = null
                                                        +
                                                        +

                                                        Optional. Short-circuit the short array check for +T_OPEN_SHORT_ARRAY tokens if it isn't necessary. +Efficiency tweak for when this has already been established, +Use with EXTREME care.

                                                        +
                                                        @@ -473,17 +802,51 @@
                                                        1.0.0 - -
                                                        + + + +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Added the $isShortArray parameter.

                                                        +
                                                        + +
                                                        +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Added support for PHP 8.0 identifier name tokenization.

                                                        +
                                                        + +
                                                        +
                                                        + since +
                                                        +
                                                        + 1.0.0-alpha4 + +

                                                        Added defensive coding against PHP 8.1 first class callables +being passed as if they were function calls.

                                                        +
                                                        + +
                                                        throws
                                                        RuntimeException -

                                                        If the token passed is not one of the -accepted types or doesn't exist.

                                                        + +

                                                        If the token passed is not one of the +accepted types or doesn't exist.

                                                        +
                                                        -
                                                        +
                                                        Return values
                                                        @@ -494,21 +857,92 @@
                                                        Return values
                                                        - -
                                                        + + -

                                                        Search results

                                                        -
                                                          -
                                                        -
                                                        + +
                                                        +
                                                        +
                                                        +

                                                        Search results

                                                        + +
                                                        +
                                                        +
                                                          +
                                                          +
                                                          +
                                                          - +
                                                          + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html index 0b0f49bc..3cd86b7c 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Scopes.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                          -

                                                          PHPCSUtils

                                                          - -
                                                          - -
                                                          -
                                                          -

                                                          Utility functions for use when examining token scopes.

                                                          @@ -98,8 +153,9 @@
                                                          1.0.0 - -
                                                          + + + @@ -113,31 +169,31 @@

                                                          -
                                                          - isOOConstant() +
                                                          + isOOConstant() -  : bool +  : bool
                                                          -
                                                          Check whether a T_CONST token is a class/interface constant declaration.
                                                          +
                                                          Check whether a T_CONST token is a class/interface/trait/enum constant declaration.
                                                          - isOOMethod() + isOOMethod() -  : bool +  : bool
                                                          -
                                                          Check whether a T_FUNCTION token is a class/interface/trait method declaration.
                                                          +
                                                          Check whether a T_FUNCTION token is a class/interface/trait/enum method declaration.
                                                          - isOOProperty() + isOOProperty() -  : bool +  : bool
                                                          Check whether a T_VARIABLE token is a class/trait property declaration.
                                                          - validDirectScope() + validDirectScope() -  : int|false +  : int|false
                                                          Check whether the direct wrapping scope of a token is within a limited set of acceptable tokens.
                                                          @@ -153,7 +209,7 @@

                                                          Methods - +

                                                          >

                                                          isOOConstant() - +

                                                          + 71 + + -

                                                          Check whether a T_CONST token is a class/interface constant declaration.

                                                          +

                                                          Check whether a T_CONST token is a class/interface/trait/enum constant declaration.

                                                          public - static isOOConstant(File $phpcsFile, int $stackPtr) : bool + static isOOConstant(File $phpcsFile, int $stackPtr) : bool
                                                          Parameters
                                                          @@ -185,7 +242,8 @@
                                                          Parameters
                                                          : File
                                                          -

                                                          The file where this token was found.

                                                          +

                                                          The file where this token was found.

                                                          +
                                                          @@ -194,7 +252,8 @@
                                                          Parameters

                                                          The position in the stack of the -T_CONST token to verify.

                                                          +T_CONST token to verify.

                                                          +

                                                          @@ -210,8 +269,29 @@
                                                          1.0.0 - -
                                                          + + + +
                                                          + since +
                                                          +
                                                          + 1.0.0-alpha4 + +

                                                          Added support for PHP 8.1 enums.

                                                          +
                                                          + +
                                                          +
                                                          + since +
                                                          +
                                                          + 1.0.0-alpha4 + +

                                                          Added support for PHP 8.2 constants in traits.

                                                          +
                                                          + +
                                                          Return values
                                                          @@ -228,19 +308,20 @@
                                                          Return values
                                                          >

                                                          isOOMethod() - +

                                                          + 132 -

                                                          Check whether a T_FUNCTION token is a class/interface/trait method declaration.

                                                          + + +

                                                          Check whether a T_FUNCTION token is a class/interface/trait/enum method declaration.

                                                          public - static isOOMethod(File $phpcsFile, int $stackPtr) : bool + static isOOMethod(File $phpcsFile, int $stackPtr) : bool
                                                          Parameters
                                                          @@ -250,7 +331,8 @@
                                                          Parameters
                                                          : File
                                                          -

                                                          The file where this token was found.

                                                          +

                                                          The file where this token was found.

                                                          +
                                                          @@ -259,7 +341,8 @@
                                                          Parameters

                                                          The position in the stack of the -T_FUNCTION token to verify.

                                                          +T_FUNCTION token to verify.

                                                          +
                                                          @@ -275,8 +358,19 @@
                                                          1.0.0 - -
                                                          + + + +
                                                          + since +
                                                          +
                                                          + 1.0.0-alpha4 + +

                                                          Added support for PHP 8.1 enums.

                                                          +
                                                          + +
                                                          Return values
                                                          @@ -293,19 +387,20 @@
                                                          Return values
                                                          >

                                                          isOOProperty() - +

                                                          + 97 + +

                                                          Check whether a T_VARIABLE token is a class/trait property declaration.

                                                          public - static isOOProperty(File $phpcsFile, int $stackPtr) : bool + static isOOProperty(File $phpcsFile, int $stackPtr) : bool
                                                          Parameters
                                                          @@ -315,7 +410,8 @@
                                                          Parameters
                                                          : File
                                                          -

                                                          The file where this token was found.

                                                          +

                                                          The file where this token was found.

                                                          +
                                                          @@ -324,7 +420,8 @@
                                                          Parameters

                                                          The position in the stack of the -T_VARIABLE token to verify.

                                                          +T_VARIABLE token to verify.

                                                          +
                                                          @@ -340,8 +437,9 @@
                                                          1.0.0 - -
                                                          + + +
                                                          Return values
                                                          @@ -358,20 +456,21 @@
                                                          Return values
                                                          >

                                                          validDirectScope() - +

                                                          + +

                                                          Check whether the direct wrapping scope of a token is within a limited set of acceptable tokens.

                                                          public - static validDirectScope(File $phpcsFile, int $stackPtr, int|string|array $validScopes) : int|false + static validDirectScope(File $phpcsFile, int $stackPtr, int|string|array<string|int, mixed> $validScopes) : int|false
                                                          Parameters
                                                          @@ -381,7 +480,8 @@
                                                          Parameters
                                                          : File
                                                          -

                                                          The file where this token was found.

                                                          +

                                                          The file where this token was found.

                                                          +
                                                          @@ -390,16 +490,18 @@
                                                          Parameters

                                                          The position in the stack of the -token to verify.

                                                          +token to verify.

                                                          +
                                                          $validScopes - : int|string|array + : int|string|array<string|int, mixed>

                                                          Array of token constants representing -the scopes considered valid.

                                                          +the scopes considered valid.

                                                          +
                                                          @@ -415,35 +517,108 @@
                                                          1.0.0 - -
                                                          + + +
                                                          Return values
                                                          int|false

                                                          Integer stack pointer to the valid direct scope; or FALSE if -no valid direct scope was found.

                                                          +no valid direct scope was found.

                                                          + - -
                                                          + + -

                                                          Search results

                                                          -
                                                            -
                                                          -
                                                          + +
                                                          +
                                                          +
                                                          +

                                                          Search results

                                                          + +
                                                          +
                                                          +
                                                            +
                                                            +
                                                            +
                                                            - +
                                                            + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html b/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html index 4d4223c0..dab53414 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-TextStrings.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                            -

                                                            PHPCSUtils

                                                            - -
                                                            - -
                                                            -
                                                            -

                                                            Utility functions for working with text string tokens.

                                                            @@ -98,8 +153,19 @@
                                                            1.0.0 - -
                                                            + + + +
                                                            + since +
                                                            +
                                                            + 1.0.0-alpha4 + +

                                                            Dropped support for PHPCS < 3.7.1.

                                                            +
                                                            + +
                                                            @@ -113,32 +179,140 @@

                                                            -
                                                            - getCompleteTextString() +
                                                            + START_OF_EMBED + +  = '`(?<!\\\\)(\\\\{2})*(\\{\\$|\\$\\{|\\$(?=[a-zA-Z_\\x7f-\\xff]))`' +
                                                            +
                                                            Regex to match the start of an embedded variable/expression.
                                                            + +
                                                            + TYPE1_EMBED_AFTER_DOLLAR + +  = '`(?P<varname>[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)(?:\\??->(?P>varname)|\\[[^\\]\'"\\s]+\\])?`' +
                                                            +
                                                            Regex to match a "type 1" - directly embedded - variable without the dollar sign.
                                                            + +
                                                            + getCompleteTextString() -  : string +  : string
                                                            Get the complete contents of a - potentially multi-line - text string.
                                                            - stripQuotes() + getEmbeds() + +  : array<int, string> +
                                                            +
                                                            Get the embedded variables/expressions from an arbitrary string.
                                                            + +
                                                            + getEndOfCompleteTextString() + +  : int +
                                                            +
                                                            Get the stack pointer to the end of a - potentially multi-line - text string.
                                                            + +
                                                            + getStripEmbeds() + +  : array<string, mixed> +
                                                            +
                                                            Split an arbitrary text string into embedded variables/expressions and remaining text.
                                                            + +
                                                            + stripEmbeds() + +  : string +
                                                            +
                                                            Strip embedded variables/expressions from an arbitrary string.
                                                            + +
                                                            + stripQuotes() -  : string +  : string
                                                            -
                                                            Strip text delimiter quotes from an arbitrary string.
                                                            +
                                                            Strip text delimiter quotes from an arbitrary text string.
                                                            +
                                                            +

                                                            + Constants + +

                                                            +
                                                            +

                                                            + START_OF_EMBED + +

                                                            + + + +

                                                            Regex to match the start of an embedded variable/expression.

                                                            + + + public + string + START_OF_EMBED + = '`(?<!\\\\)(\\\\{2})*(\\{\\$|\\$\\{|\\$(?=[a-zA-Z_\\x7f-\\xff]))`' + + + +

                                                            Prevents matching escaped variables/expressions.

                                                            +
                                                            + + + + +
                                                            +
                                                            +

                                                            + TYPE1_EMBED_AFTER_DOLLAR + +

                                                            + + + +

                                                            Regex to match a "type 1" - directly embedded - variable without the dollar sign.

                                                            + + + public + string + TYPE1_EMBED_AFTER_DOLLAR + = '`(?P<varname>[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)(?:\\??->(?P>varname)|\\[[^\\]\'"\\s]+\\])?`' + + + +

                                                            Allows for array access and property access in as far as supported (single level).

                                                            +
                                                            + + + + +
                                                            +

                                                            Methods - +

                                                            >

                                                            getCompleteTextString() - +

                                                            + 77 + +

                                                            Get the complete contents of a - potentially multi-line - text string.

                                                            public - static getCompleteTextString(File $phpcsFile, int $stackPtr[, bool $stripQuotes = true ]) : string + static getCompleteTextString(File $phpcsFile, int $stackPtr[, bool $stripQuotes = true ]) : string

                                                            PHPCS tokenizes multi-line text strings with a single token for each line. This method can be used to retrieve the text string as it would be received and processed in PHP itself.

                                                            This method is particularly useful for sniffs which examine the contents of text strings, where the content matching might result in false positives/false negatives if the text -were to be examined line by line.

                                                            +were to be examined line by line.

                                                            +
                                                            Parameters
                                                            @@ -176,7 +352,8 @@
                                                            Parameters
                                                            : File
                                                            -

                                                            The file where this token was found.

                                                            +

                                                            The file where this token was found.

                                                            +
                                                            @@ -186,7 +363,8 @@
                                                            Parameters

                                                            Pointer to the first text string token of a - potentially multi-line - text string -or to a Nowdoc/Heredoc opener.

                                                            +or to a Nowdoc/Heredoc opener.

                                                            +
                                                            @@ -196,7 +374,8 @@
                                                            Parameters

                                                            Optional. Whether to strip text delimiter quotes off the resulting text string. -Defaults to true.

                                                            +Defaults to true.

                                                            +
                                                            @@ -212,32 +391,369 @@
                                                            1.0.0 - -
                                                            + + + +
                                                            + throws +
                                                            +
                                                            + RuntimeException + +

                                                            If the specified position is not a +valid text string token.

                                                            +
                                                            + +
                                                            +
                                                            + throws +
                                                            +
                                                            + RuntimeException + +

                                                            If the specified token is not the first +token in a text string.

                                                            +
                                                            + +
                                                            + + +
                                                            Return values
                                                            + string + — +

                                                            The contents of the complete text string.

                                                            +
                                                            + + + +
                                                            +

                                                            + getEmbeds() + +

                                                            + + +

                                                            Get the embedded variables/expressions from an arbitrary string.

                                                            + + + public + static getEmbeds(string $text) : array<int, string> + +

                                                            Note: this function gets the complete variables/expressions as they are embedded, +i.e. including potential curly brace wrappers, array access, method calls etc.

                                                            +
                                                            + +
                                                            Parameters
                                                            +
                                                            +
                                                            + $text + : string +
                                                            +
                                                            +

                                                            The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token.

                                                            +
                                                            + +
                                                            +
                                                            + + +
                                                            + Tags + +
                                                            +
                                                            +
                                                            + since +
                                                            +
                                                            + 1.0.0-alpha4 + + +
                                                            +
                                                            + +
                                                            Return values
                                                            + array<int, string> + — +

                                                            Array of encountered variable names/expressions with the offset at which +the variable/expression was found in the string, as the key.

                                                            +
                                                            + + +
                                                            +
                                                            +

                                                            + getEndOfCompleteTextString() + +

                                                            + + +

                                                            Get the stack pointer to the end of a - potentially multi-line - text string.

                                                            + + + public + static getEndOfCompleteTextString(File $phpcsFile, int $stackPtr) : int + + +
                                                            Parameters
                                                            +
                                                            +
                                                            + $phpcsFile + : File +
                                                            +
                                                            +

                                                            The file where this token was found.

                                                            +
                                                            + +
                                                            +
                                                            + $stackPtr + : int +
                                                            +
                                                            +

                                                            Pointer to the first text string token +of a - potentially multi-line - text string +or to a Nowdoc/Heredoc opener.

                                                            +
                                                            + +
                                                            +
                                                            + + +
                                                            + Tags + +
                                                            +
                                                            +
                                                            + see +
                                                            +
                                                            + TextStrings::getCompleteTextString() + +

                                                            Retrieve the contents of a complete - potentially +multi-line - text string.

                                                            +
                                                            + +
                                                            +
                                                            + since +
                                                            +
                                                            + 1.0.0-alpha4 + + +
                                                            throws
                                                            RuntimeException -

                                                            If the specified position is not a -valid text string token.

                                                            + +

                                                            If the specified position is not a +valid text string token.

                                                            +
                                                            -
                                                            +
                                                            throws
                                                            RuntimeException -

                                                            If the specified token is not the first -token in a text string.

                                                            + +

                                                            If the specified token is not the first +token in a text string.

                                                            +
                                                            + +
                                                            +
                                                            + +
                                                            Return values
                                                            + int + — +

                                                            Stack pointer to the last token in the text string.

                                                            +
                                                            + + +
                                                            +
                                                            +

                                                            + getStripEmbeds() + +

                                                            + + +

                                                            Split an arbitrary text string into embedded variables/expressions and remaining text.

                                                            + + + public + static getStripEmbeds(string $text) : array<string, mixed> + +

                                                            PHP contains four types of embedding syntaxes:

                                                            +
                                                              +
                                                            1. Directly embedding variables ("$foo");
                                                            2. +
                                                            3. Braces outside the variable ("{$foo}");
                                                            4. +
                                                            5. Braces after the dollar sign ("${foo}");
                                                            6. +
                                                            7. Variable variables ("${expr}", equivalent to (string) ${expr}).
                                                            8. +
                                                            +

                                                            Type 3 and 4 are deprecated as of PHP 8.2 and will be removed in PHP 9.0.

                                                            +

                                                            This method handles all types of embeds, including recognition of whether an embed is escaped or not.

                                                            +
                                                            + +
                                                            Parameters
                                                            +
                                                            +
                                                            + $text + : string +
                                                            +
                                                            +

                                                            The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token.

                                                            +
                                                            + +
                                                            +
                                                            + + +
                                                            + Tags + +
                                                            +
                                                            +
                                                            + link +
                                                            +
                                                            +

                                                            PHP Manual on string parsing

                                                            +
                                                            + +
                                                            +
                                                            + link +
                                                            +
                                                            +

                                                            PHP RFC on deprecating select +string interpolation syntaxes

                                                            +
                                                            + +
                                                            +
                                                            + since +
                                                            +
                                                            + 1.0.0-alpha4 + + +
                                                            +
                                                            + +
                                                            Return values
                                                            + array<string, mixed> + — +

                                                            Array containing two values:

                                                            +
                                                              +
                                                            1. An array containing a string representation of each embed encountered. +The keys in this array are the integer offset within the original string +where the embed was found.
                                                            2. +
                                                            3. The textual contents, embeds stripped out of it. +The format of the array return value is:
                                                            4. +
                                                            +
                                                            array(
                                                            +  'embeds'    => array<int, string>,
                                                            +  'remaining' => string,
                                                            +)
                                                            +
                                                            +
                                                            + + +
                                                            +
                                                            +

                                                            + stripEmbeds() + +

                                                            + + +

                                                            Strip embedded variables/expressions from an arbitrary string.

                                                            + + + public + static stripEmbeds(string $text) : string + + +
                                                            Parameters
                                                            +
                                                            +
                                                            + $text + : string +
                                                            +
                                                            +

                                                            The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token.

                                                            +
                                                            + +
                                                            +
                                                            + + +
                                                            + Tags + +
                                                            +
                                                            +
                                                            + since +
                                                            +
                                                            + 1.0.0-alpha4 + + +
                                                            Return values
                                                            string — -

                                                            The complete text string.

                                                            +

                                                            String without variables/expressions in it.

                                                            +
                                                            @@ -249,34 +765,37 @@
                                                            Return values
                                                            >

                                                            stripQuotes() - +

                                                            + 187 + + -

                                                            Strip text delimiter quotes from an arbitrary string.

                                                            +

                                                            Strip text delimiter quotes from an arbitrary text string.

                                                            public - static stripQuotes(string $string) : string + static stripQuotes(string $textString) : string -

                                                            Intended for use with the "contents" of a T_CONSTANT_ENCAPSED_STRING / T_DOUBLE_QUOTED_STRING.

                                                            +

                                                            Intended for use with the "content" of a T_CONSTANT_ENCAPSED_STRING / T_DOUBLE_QUOTED_STRING.

                                                            • Prevents stripping mis-matched quotes.
                                                            • -
                                                            • Prevents stripping quotes from the textual content of the string.
                                                            • -
                                                            +
                                                          • Prevents stripping quotes from the textual content of the text string.
                                                          • + +
                                                            Parameters
                                                            - $string + $textString : string
                                                            -

                                                            The raw string.

                                                            +

                                                            The raw text string.

                                                            +
                                                            @@ -292,34 +811,107 @@
                                                            1.0.0 - -
                                                            + + +
                                                            Return values
                                                            string — -

                                                            String without quotes around it.

                                                            +

                                                            Text string without quotes around it.

                                                            +
                                                            - -
                                                            + + -

                                                            Search results

                                                            -
                                                              -
                                                            -
                                                            + +
                                                            +
                                                            +
                                                            +

                                                            Search results

                                                            + +
                                                            +
                                                            +
                                                              +
                                                              +
                                                              +
                                                              - +
                                                              + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html b/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html index bfcb2389..bf5ba0c4 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-UseStatements.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                              -

                                                              PHPCSUtils

                                                              - -
                                                              - -
                                                              -
                                                              -

                                                              Utility functions for examining use statements.

                                                              @@ -98,8 +153,19 @@
                                                              1.0.0 - -
                                                              + + + +
                                                              + since +
                                                              +
                                                              + 1.0.0-alpha4 + +

                                                              Dropped support for PHPCS < 3.7.1.

                                                              +
                                                              + +
                                                              @@ -113,46 +179,53 @@

                                                              -
                                                              - getType() +
                                                              + getType() -  : string +  : string
                                                              Determine what a T_USE token is used for.
                                                              - isClosureUse() + isClosureUse() -  : bool +  : bool
                                                              Determine whether a T_USE token represents a closure use statement.
                                                              - isImportUse() + isImportUse() -  : bool +  : bool
                                                              Determine whether a T_USE token represents a class/function/constant import use statement.
                                                              - isTraitUse() + isTraitUse() -  : bool +  : bool
                                                              Determine whether a T_USE token represents a trait use statement.
                                                              - splitAndMergeImportUseStatement() + mergeImportUseStatements() -  : array +  : array<string|int, mixed> +
                                                              +
                                                              Merge two import use statement arrays.
                                                              + +
                                                              + splitAndMergeImportUseStatement() + +  : array<string|int, mixed>
                                                              Split an import use statement into individual imports and merge it with an array of previously seen import use statements.
                                                              - splitImportUseStatement() + splitImportUseStatement() -  : array +  : array<string|int, mixed>
                                                              Split an import use statement into individual imports.
                                                              @@ -167,7 +240,7 @@

                                                              Methods - +

                                                              >

                                                              getType() - +

                                                              + 46 + +

                                                              Determine what a T_USE token is used for.

                                                              public - static getType(File $phpcsFile, int $stackPtr) : string + static getType(File $phpcsFile, int $stackPtr) : string
                                                              Parameters
                                                              @@ -199,7 +273,8 @@
                                                              Parameters
                                                              : File
                                                              -

                                                              The file being scanned.

                                                              +

                                                              The file being scanned.

                                                              +
                                                              @@ -207,7 +282,8 @@
                                                              Parameters
                                                              : int
                                                              -

                                                              The position of the T_USE token.

                                                              +

                                                              The position of the T_USE token.

                                                              +

                                                              @@ -223,17 +299,20 @@
                                                              1.0.0 - -
                                                              + + +
                                                              throws
                                                              RuntimeException -

                                                              If the specified position is not a -T_USE token.

                                                              + +

                                                              If the specified position is not a +T_USE token.

                                                              +
                                                              -
                                                              +
                                                              Return values
                                                              @@ -243,7 +322,8 @@
                                                              Return values
                                                              An empty string will be returned if the token is used in an invalid context or if it couldn't be reliably determined what the T_USE token is used for. An empty string being returned will -normally mean the code being examined contains a parse error.

                                                              +normally mean the code being examined contains a parse error.

                                                              + @@ -255,19 +335,20 @@
                                                              Return values
                                                              >

                                                              isClosureUse() - +

                                                              + 107 + +

                                                              Determine whether a T_USE token represents a closure use statement.

                                                              public - static isClosureUse(File $phpcsFile, int $stackPtr) : bool + static isClosureUse(File $phpcsFile, int $stackPtr) : bool
                                                              Parameters
                                                              @@ -277,7 +358,8 @@
                                                              Parameters
                                                              : File
                                                              -

                                                              The file being scanned.

                                                              +

                                                              The file being scanned.

                                                              +
                                                              @@ -285,7 +367,8 @@
                                                              Parameters
                                                              : int
                                                              -

                                                              The position of the T_USE token.

                                                              +

                                                              The position of the T_USE token.

                                                              +
                                                              @@ -301,24 +384,28 @@
                                                              1.0.0 - -
                                                              + + +
                                                              throws
                                                              RuntimeException -

                                                              If the specified position is not a -T_USE token.

                                                              + +

                                                              If the specified position is not a +T_USE token.

                                                              +
                                                              -
                                                              +
                                                              Return values
                                                              bool

                                                              TRUE if the token passed is a closure use statement. -FALSE if it's not.

                                                              +FALSE if it's not.

                                                              + @@ -330,19 +417,20 @@
                                                              Return values
                                                              >

                                                              isImportUse() - +

                                                              + 126 + +

                                                              Determine whether a T_USE token represents a class/function/constant import use statement.

                                                              public - static isImportUse(File $phpcsFile, int $stackPtr) : bool + static isImportUse(File $phpcsFile, int $stackPtr) : bool
                                                              Parameters
                                                              @@ -352,7 +440,8 @@
                                                              Parameters
                                                              : File
                                                              -

                                                              The file being scanned.

                                                              +

                                                              The file being scanned.

                                                              +
                                                              @@ -360,7 +449,8 @@
                                                              Parameters
                                                              : int
                                                              -

                                                              The position of the T_USE token.

                                                              +

                                                              The position of the T_USE token.

                                                              +
                                                              @@ -376,24 +466,28 @@
                                                              1.0.0 - -
                                                              + + +
                                                              throws
                                                              RuntimeException -

                                                              If the specified position is not a -T_USE token.

                                                              + +

                                                              If the specified position is not a +T_USE token.

                                                              +
                                                              -
                                                              +
                                                              Return values
                                                              bool

                                                              TRUE if the token passed is an import use statement. -FALSE if it's not.

                                                              +FALSE if it's not.

                                                              + @@ -405,19 +499,20 @@
                                                              Return values
                                                              >

                                                              isTraitUse() - +

                                                              + 145 + +

                                                              Determine whether a T_USE token represents a trait use statement.

                                                              public - static isTraitUse(File $phpcsFile, int $stackPtr) : bool + static isTraitUse(File $phpcsFile, int $stackPtr) : bool
                                                              Parameters
                                                              @@ -427,7 +522,8 @@
                                                              Parameters
                                                              : File
                                                              -

                                                              The file being scanned.

                                                              +

                                                              The file being scanned.

                                                              +
                                                              @@ -435,7 +531,8 @@
                                                              Parameters
                                                              : int
                                                              -

                                                              The position of the T_USE token.

                                                              +

                                                              The position of the T_USE token.

                                                              +
                                                              @@ -451,24 +548,120 @@
                                                              1.0.0 - -
                                                              + + +
                                                              throws
                                                              RuntimeException -

                                                              If the specified position is not a -T_USE token.

                                                              + +

                                                              If the specified position is not a +T_USE token.

                                                              +
                                                              -
                                                              +
                                                              Return values
                                                              bool

                                                              TRUE if the token passed is a trait use statement. -FALSE if it's not.

                                                              +FALSE if it's not.

                                                              + + + + +
                                                              +

                                                              + mergeImportUseStatements() + +

                                                              + + +

                                                              Merge two import use statement arrays.

                                                              + + + public + static mergeImportUseStatements(array<string|int, mixed> $previousUseStatements, array<string|int, mixed> $currentUseStatement) : array<string|int, mixed> + +

                                                              Beware: this method should only be used to combine the import use statements found in one file. +Do NOT combine the statements of multiple files as the result will be inaccurate and unreliable.

                                                              +
                                                              + +
                                                              Parameters
                                                              +
                                                              +
                                                              + $previousUseStatements + : array<string|int, mixed> +
                                                              +
                                                              +

                                                              The import use statements collected so far. +This should be either the output of a +previous call to this method or the output of +an earlier call to the +UseStatements::splitImportUseStatement() +method.

                                                              +
                                                              + +
                                                              +
                                                              + $currentUseStatement + : array<string|int, mixed> +
                                                              +
                                                              +

                                                              The parsed import use statements to merge with +the previously collected use statements. +This should be the output of a call to the +UseStatements::splitImportUseStatement() +method.

                                                              +
                                                              + +
                                                              +
                                                              + + +
                                                              + Tags + +
                                                              +
                                                              +
                                                              + see +
                                                              +
                                                              + UseStatements::splitImportUseStatement() + + +
                                                              +
                                                              + since +
                                                              +
                                                              + 1.0.0-alpha4 + + +
                                                              +
                                                              + +
                                                              Return values
                                                              + array<string|int, mixed> + — +

                                                              A multi-level array containing information about the current use statement combined with +the previously collected use statement information. +See UseStatements::splitImportUseStatement() for more details about the array format.

                                                              +
                                                              @@ -480,25 +673,27 @@
                                                              Return values
                                                              >

                                                              splitAndMergeImportUseStatement() - +

                                                              + 375 + +

                                                              Split an import use statement into individual imports and merge it with an array of previously seen import use statements.

                                                              public - static splitAndMergeImportUseStatement(File $phpcsFile, int $stackPtr, array $previousUseStatements) : array + static splitAndMergeImportUseStatement(File $phpcsFile, int $stackPtr, array<string|int, mixed> $previousUseStatements) : array<string|int, mixed>

                                                              Beware: this method should only be used to combine the import use statements found in one file. Do NOT combine the statements of multiple files as the result will be inaccurate and unreliable.

                                                              -

                                                              In most cases when tempted to use this method, the \PHPCSUtils\AbstractSniffs\AbstractFileContextSniff -(upcoming) should be used instead.

                                                              +

                                                              In most cases when tempted to use this method, the AbstractFileContextSniff +(upcoming) should be used instead.

                                                              +
                                                              Parameters
                                                              @@ -507,7 +702,8 @@
                                                              Parameters
                                                              : File
                                                              -

                                                              The file where this token was found.

                                                              +

                                                              The file where this token was found.

                                                              +
                                                              @@ -515,20 +711,22 @@
                                                              Parameters
                                                              : int
                                                              -

                                                              The position in the stack of the T_USE token.

                                                              +

                                                              The position in the stack of the T_USE token.

                                                              +
                                                              $previousUseStatements - : array + : array<string|int, mixed>

                                                              The import use statements collected so far. This should be either the output of a previous call to this method or the output of an earlier call to the -{@see \PHPCSUtils\Utils\UseStatements::splitImportUseStatement()} -method.

                                                              +UseStatements::splitImportUseStatement() +method.

                                                              +
                                                              @@ -544,30 +742,42 @@
                                                              AbstractFileContextSniff - -
                                                              + + +
                                                              see
                                                              - UseStatements::splitImportUseStatement() - -
                                                              + UseStatements::splitImportUseStatement() + + + +
                                                              + see +
                                                              +
                                                              + UseStatements::mergeImportUseStatements() + + +
                                                              since
                                                              1.0.0-alpha3 - -
                                                              + + +
                                                              Return values
                                                              - array + array<string|int, mixed>

                                                              A multi-level array containing information about the current use statement combined with the previously collected use statement information. -See {@see \PHPCSUtils\Utils\UseStatements::splitImportUseStatement()} for more details about the array format.

                                                              +See UseStatements::splitImportUseStatement() for more details about the array format.

                                                              + @@ -579,21 +789,23 @@
                                                              Return values
                                                              >

                                                              splitImportUseStatement() - +

                                                              + 192 + +

                                                              Split an import use statement into individual imports.

                                                              public - static splitImportUseStatement(File $phpcsFile, int $stackPtr) : array + static splitImportUseStatement(File $phpcsFile, int $stackPtr) : array<string|int, mixed> -

                                                              Handles single import, multi-import and group-import use statements.

                                                              +

                                                              Handles single import, multi-import and group-import use statements.

                                                              +
                                                              Parameters
                                                              @@ -602,7 +814,8 @@
                                                              Parameters
                                                              : File
                                                              -

                                                              The file where this token was found.

                                                              +

                                                              The file where this token was found.

                                                              +
                                                              @@ -610,7 +823,8 @@
                                                              Parameters
                                                              : int
                                                              -

                                                              The position in the stack of the T_USE token.

                                                              +

                                                              The position in the stack of the T_USE token.

                                                              +
                                                              @@ -626,30 +840,45 @@
                                                              1.0.0 - -
                                                              + + + +
                                                              + since +
                                                              +
                                                              + 1.0.0-alpha4 + +

                                                              Added support for PHP 8.0 identifier name tokenization.

                                                              +
                                                              + +
                                                              throws
                                                              RuntimeException -

                                                              If the specified position is not a -T_USE token.

                                                              + +

                                                              If the specified position is not a +T_USE token.

                                                              +
                                                              -
                                                              +
                                                              throws
                                                              RuntimeException -

                                                              If the T_USE token is not for an import -use statement.

                                                              + +

                                                              If the T_USE token is not for an import +use statement.

                                                              +
                                                              -
                                                              +
                                                              Return values
                                                              - array + array<string|int, mixed>

                                                              A multi-level array containing information about the use statement. The first level is 'name', 'function' and 'const'. These keys will always exist. @@ -661,7 +890,8 @@

                                                              Return values
                                                              use function Vendor\Package\{
                                                                   LevelA\Name as Alias,
                                                                   LevelB\Another_Name,
                                                              -};
                                                              +}; +

                                                              the return value would look like this:

                                                              array(
                                                                 'name'     => array(),
                                                              @@ -670,27 +900,100 @@ 
                                                              Return values
                                                              'Another_Name' => 'Vendor\Package\LevelB\Another_Name', ), 'const' => array(), -)
                                                              +) + + - -
                                                              + + -

                                                              Search results

                                                              -
                                                                -
                                                              -
                                                              + +
                                                              +
                                                              +
                                                              +

                                                              Search results

                                                              + +
                                                              +
                                                              +
                                                                +
                                                                +
                                                                +
                                                                - +
                                                                + + + + diff --git a/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html b/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html index de1db6fe..07829922 100644 --- a/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html +++ b/docs/phpdoc/classes/PHPCSUtils-Utils-Variables.html @@ -2,71 +2,119 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                -

                                                                PHPCSUtils

                                                                - -
                                                                - -
                                                                -
                                                                -

                                                                Utility functions for use when examining variables.

                                                                @@ -98,11 +153,23 @@
                                                                1.0.0 -

                                                                The Variables::getMemberProperties() method is based on and inspired by + +

                                                                The Variables::getMemberProperties() method is based on and inspired by the method of the same name in the PHPCS native PHP_CodeSniffer\Files\File class. -Also see {@see \PHPCSUtils\BackCompat\BCFile}.

                                                                +Also see BCFile.

                                                                +
                                                                -
                                                                + +
                                                                + since +
                                                                +
                                                                + 1.0.0-alpha4 + +

                                                                Dropped support for PHPCS < 3.7.1.

                                                                +
                                                                + +
                                                                @@ -116,38 +183,38 @@

                                                                -
                                                                - $phpReservedVars +
                                                                + $phpReservedVars -  : array +  : array<string|int, mixed>
                                                                List of PHP Reserved variables.
                                                                - getMemberProperties() + getMemberProperties() -  : array +  : array<string|int, mixed>
                                                                Retrieve the visibility and implementation properties of a class member variable.
                                                                - isPHPReservedVarName() + isPHPReservedVarName() -  : bool +  : bool
                                                                Verify if a given variable name is the name of a PHP reserved variable.
                                                                - isSuperglobal() + isSuperglobal() -  : bool +  : bool
                                                                Verify if a given variable or array key token points to a PHP superglobal.
                                                                - isSuperglobalName() + isSuperglobalName() -  : bool +  : bool
                                                                Verify if a given variable name is the name of a PHP superglobal.
                                                                @@ -161,7 +228,7 @@

                                                                Properties - +

                                                                >

                                                                $phpReservedVars - +

                                                                + 46 + +

                                                                List of PHP Reserved variables.

                                                                public - static array + static array<string|int, mixed> $phpReservedVars = [ '_SERVER' => true, @@ -218,7 +286,11 @@

                                                                The array keys are the variable names without the leading dollar sign, the values indicate whether the variable is a superglobal or not.

                                                                The variables names are set without the leading dollar sign to allow this array -to be used with array index keys as well. Think: '_GET' in $GLOBALS['_GET'].}

                                                                +to be used with array index keys as well. Think: '_GET' in $GLOBALS['_GET'].}

                                                                +

                                                                + +

                                                                =>

                                                                +
                                                                @@ -227,20 +299,21 @@
                                                                - since + link
                                                                - 1.0.0 - -
                                                                +

                                                                PHP Manual on reserved variables

                                                                +
                                                                + +
                                                                - link + since
                                                                - http://php.net/reserved.variables -

                                                                PHP Manual on reserved variables

                                                                - -
                                                                + 1.0.0 + + +
                                                                @@ -249,7 +322,7 @@

                                                                Methods - +

                                                                >

                                                                getMemberProperties() - +

                                                                + 124 + +

                                                                Retrieve the visibility and implementation properties of a class member variable.

                                                                public - static getMemberProperties(File $phpcsFile, int $stackPtr) : array + static getMemberProperties(File $phpcsFile, int $stackPtr) : array<string|int, mixed>

                                                                Main differences with the PHPCS version:

                                                                  @@ -279,7 +353,10 @@

                                                                  This will now throw the same "$stackPtr is not a class member var" runtime exception as other non-property variables passed to the method.
                                                                • Defensive coding against incorrect calls to this method.
                                                                • -

                                                                +
                                                              • Support PHP 8.0 identifier name tokens in property types, cross-version PHP & PHPCS.
                                                              • +
                                                              • Support for the PHP 8.2 true type.
                                                              • + +
                                                                Parameters
                                                                @@ -288,7 +365,8 @@
                                                                Parameters
                                                                : File
                                                                -

                                                                The file being scanned.

                                                                +

                                                                The file being scanned.

                                                                +
                                                                @@ -297,7 +375,8 @@
                                                                Parameters

                                                                The position in the stack of the T_VARIABLE token -to acquire the properties for.

                                                                +to acquire the properties for.

                                                                +
                                                                @@ -313,46 +392,105 @@

                                                                File::getMemberProperties() -

                                                                Original source.

                                                                + +

                                                                Original source.

                                                                +
                                                                -
                                                                +
                                                                see
                                                                - BCFile::getMemberProperties() -

                                                                Cross-version compatible version of the original.

                                                                + BCFile::getMemberProperties() + +

                                                                Cross-version compatible version of the original.

                                                                +
                                                                -
                                                                +
                                                                since
                                                                1.0.0 - -
                                                                + + + +
                                                                + since +
                                                                +
                                                                + 1.0.0-alpha4 + +

                                                                Added support for PHP 8.0 union types.

                                                                +
                                                                + +
                                                                +
                                                                + since +
                                                                +
                                                                + 1.0.0-alpha4 + +

                                                                No longer gets confused by PHP 8.0 property attributes.

                                                                +
                                                                + +
                                                                +
                                                                + since +
                                                                +
                                                                + 1.0.0-alpha4 + +

                                                                Added support for PHP 8.1 readonly properties.

                                                                +
                                                                + +
                                                                +
                                                                + since +
                                                                +
                                                                + 1.0.0-alpha4 + +

                                                                Added support for PHP 8.1 intersection types.

                                                                +
                                                                + +
                                                                +
                                                                + since +
                                                                +
                                                                + 1.0.0-alpha4 + +

                                                                Added support for PHP 8.2 true type.

                                                                +
                                                                + +
                                                                throws
                                                                RuntimeException -

                                                                If the specified position is not a -T_VARIABLE token.

                                                                + +

                                                                If the specified position is not a +T_VARIABLE token.

                                                                +
                                                                -
                                                                +
                                                                throws
                                                                RuntimeException -

                                                                If the specified position is not a -class member variable.

                                                                + +

                                                                If the specified position is not a +class member variable.

                                                                +
                                                                -
                                                                +
                                                                Return values
                                                                - array + array<string|int, mixed>

                                                                Array with information about the class member variable. The format of the return value is:

                                                                @@ -360,13 +498,17 @@
                                                                Return values
                                                                'scope' => string, // Public, private, or protected. 'scope_specified' => boolean, // TRUE if the scope was explicitly specified. 'is_static' => boolean, // TRUE if the static keyword was found. + 'is_readonly' => boolean, // TRUE if the readonly keyword was found. 'type' => string, // The type of the var (empty if no type specified). 'type_token' => integer, // The stack pointer to the start of the type // or FALSE if there is no type. 'type_end_token' => integer, // The stack pointer to the end of the type // or FALSE if there is no type. - 'nullable_type' => boolean, // TRUE if the type is nullable. -);
                                                                + 'nullable_type' => boolean, // TRUE if the type is preceded by the + // nullability operator. +); + + @@ -378,19 +520,20 @@
                                                                Return values
                                                                >

                                                                isPHPReservedVarName() - +

                                                                + 247 + +

                                                                Verify if a given variable name is the name of a PHP reserved variable.

                                                                public - static isPHPReservedVarName(string $name) : bool + static isPHPReservedVarName(string $name) : bool
                                                                Parameters
                                                                @@ -406,8 +549,9 @@
                                                                Parameters

                                                                Note: when passing an array key, string quotes are expected to have been stripped already. -Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}.

                                                                -
                                                                +Also see: TextStrings::stripQuotes().

                                                                + + @@ -422,17 +566,20 @@
                                                                see
                                                                - Variables::$phpReservedVars -

                                                                List of variables names reserved by PHP.

                                                                + Variables::$phpReservedVars + +

                                                                List of variables names reserved by PHP.

                                                                +
                                                                -
                                                                +
                                                                since
                                                                1.0.0 - -
                                                                + + +
                                                                Return values
                                                                @@ -449,19 +596,20 @@
                                                                Return values
                                                                >

                                                                isSuperglobal() - +

                                                                + 272 + +

                                                                Verify if a given variable or array key token points to a PHP superglobal.

                                                                public - static isSuperglobal(File $phpcsFile, int $stackPtr) : bool + static isSuperglobal(File $phpcsFile, int $stackPtr) : bool
                                                                Parameters
                                                                @@ -471,7 +619,8 @@
                                                                Parameters
                                                                : File
                                                                -

                                                                The file where this token was found.

                                                                +

                                                                The file where this token was found.

                                                                +
                                                                @@ -481,7 +630,8 @@
                                                                Parameters

                                                                The position in the stack of a T_VARIABLE token or of the T_CONSTANT_ENCAPSED_STRING -array key to a variable in $GLOBALS.

                                                                +array key to a variable in $GLOBALS.

                                                                +
                                                                @@ -497,8 +647,9 @@
                                                                1.0.0 - -
                                                                + + +
                                                                Return values
                                                                @@ -510,7 +661,8 @@
                                                                Return values
                                                                been passed, when a T_CONSTANT_ENCAPSED_STRING has been passed which is not an array index key; or when it is, but is not an index to the $GLOBALS variable.

                                                                - + + @@ -522,19 +674,20 @@
                                                                Return values
                                                                >

                                                                isSuperglobalName() - +

                                                                + 325 + +

                                                                Verify if a given variable name is the name of a PHP superglobal.

                                                                public - static isSuperglobalName(string $name) : bool + static isSuperglobalName(string $name) : bool
                                                                Parameters
                                                                @@ -550,8 +703,9 @@
                                                                Parameters

                                                                Note: when passing an array key, string quotes are expected to have been stripped already. -Also see: {@see \PHPCSUtils\Utils\TextStrings::stripQuotes()}.

                                                                -
                                                                +Also see: TextStrings::stripQuotes().

                                                                + + @@ -567,8 +721,9 @@
                                                                1.0.0 - -
                                                                + + +
                                                                Return values
                                                                @@ -579,21 +734,92 @@
                                                                Return values
                                                                - -
                                                                + + -

                                                                Search results

                                                                -
                                                                  -
                                                                -
                                                                + +
                                                                +
                                                                +
                                                                +

                                                                Search results

                                                                + +
                                                                +
                                                                +
                                                                  +
                                                                  +
                                                                  +
                                                                  - +
                                                                  + + + + diff --git a/docs/phpdoc/css/base.css b/docs/phpdoc/css/base.css index fa35d3ee..b71c759f 100644 --- a/docs/phpdoc/css/base.css +++ b/docs/phpdoc/css/base.css @@ -3,6 +3,7 @@ /* Typography */ --font-primary: 'Source Sans Pro', Helvetica, Arial, sans-serif; --font-secondary: 'Source Sans Pro', Helvetica, Arial, sans-serif; + --font-monospace: 'Source Code Pro', monospace; --line-height--primary: 1.6; --letter-spacing--primary: .05rem; --text-base-size: 1em; @@ -20,26 +21,29 @@ --text-xxxxxl: calc(var(--text-base-size) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio) * var(--text-scale-ratio)); /* Colors */ - --primary-color: hsl(96, 57%, 60%); - --primary-color-darken: hsl(96, 57%, 40%); - --primary-color-darker: hsl(96, 57%, 20%); - --primary-color-lighten: hsl(96, 57%, 80%); - --primary-color-lighter: hsl(96, 57%, 97%); + --primary-color-hue: 96; + --primary-color-saturation: 57%; + --primary-color: hsl(var(--primary-color-hue), var(--primary-color-saturation), 60%); + --primary-color-darken: hsl(var(--primary-color-hue), var(--primary-color-saturation), 40%); + --primary-color-darker: hsl(var(--primary-color-hue), var(--primary-color-saturation), 20%); + --primary-color-darkest: hsl(var(--primary-color-hue), var(--primary-color-saturation), 10%); + --primary-color-lighten: hsl(var(--primary-color-hue), var(--primary-color-saturation), 80%); + --primary-color-lighter: hsl(var(--primary-color-hue), var(--primary-color-saturation), 99%); --dark-gray: #d1d1d1; --light-gray: #f0f0f0; - --text-color: #4b3b40; + --text-color: var(--primary-color-darkest); --header-height: var(--spacing-xxxxl); --header-bg-color: var(--primary-color); - --code-background-color: #f7faf5; - --code-border-color: #d6e7cb; + --code-background-color: var(--primary-color-lighter); + --code-border-color: --primary-color-lighten; --button-border-color: var(--primary-color-darken); --button-color: transparent; --button-color-primary: var(--primary-color); --button-text-color: #555; --button-text-color-primary: white; - --popover-background-color: hsla(96, 57%, 95%, 0.9); + --popover-background-color: rgba(255, 255, 255, 0.75); --link-color-primary: var(--primary-color-darken); --link-hover-color-primary: var(--primary-color-darker); --form-field-border-color: var(--dark-gray); @@ -80,6 +84,7 @@ body { font-size: var(--text-md); letter-spacing: var(--letter-spacing--primary); line-height: var(--line-height--primary); + width: 100%; } .phpdocumentor h1, @@ -104,7 +109,6 @@ body { font-size: var(--text-xxxl); letter-spacing: var(--letter-spacing--primary); line-height: 1.25; - margin-top: 0; } .phpdocumentor h3 { @@ -166,6 +170,17 @@ body { .phpdocumentor figure { margin-bottom: var(--spacing-md); } + +.phpdocumentor figcaption { + text-align: center; + font-style: italic; + font-size: 80%; +} + +.phpdocumentor-uml-diagram svg { + max-width: 100%; + height: auto !important; +} .phpdocumentor-line { border-top: 1px solid #E1E1E1; border-width: 0; @@ -187,12 +202,6 @@ body { width: 95%; } } - -@media (min-width: 1000px) { - .phpdocumentor-section { - width: 85%; - } -} .phpdocumentor-column { box-sizing: border-box; float: left; @@ -431,20 +440,25 @@ input[type="checkbox"].phpdocumentor-field, input[type="radio"].phpdocumentor-field { display: inline; } +.phpdocumentor-column ul, div.phpdocumentor-list > ul, ul.phpdocumentor-list { - list-style: circle inside; + list-style: circle; } +.phpdocumentor-column ol, +div.phpdocumentor-list > ol, ol.phpdocumentor-list { - list-style: decimal inside; + list-style: decimal; } + +.phpdocumentor-column ul, div.phpdocumentor-list > ul, ol.phpdocumentor-list, ul.phpdocumentor-list { margin-top: 0; - padding-left: 0; + padding-left: 1rem; margin-bottom: var(--spacing-md); } @@ -452,6 +466,7 @@ dl { margin-bottom: var(--spacing-md); } +.phpdocumentor-column ul ul, div.phpdocumentor-list > ul ul, ul.phpdocumentor-list ul.phpdocumentor-list, ul.phpdocumentor-list ol.phpdocumentor-list, @@ -461,7 +476,16 @@ ol.phpdocumentor-list ul.phpdocumentor-list { margin: var(--spacing-xs) 0 var(--spacing-xs) calc(var(--spacing-xs) * 2); } -li.phpdocumentor-list { +.phpdocumentor-column ul li, +.phpdocumentor-list li { + padding-bottom: var(--spacing-xs); +} + +.phpdocumentor dl dt { + margin-bottom: var(--spacing-xs); +} + +.phpdocumentor dl dd { margin-bottom: var(--spacing-md); } .phpdocumentor pre { @@ -469,6 +493,7 @@ li.phpdocumentor-list { } .phpdocumentor-code { + font-family: var(--font-monospace); background: var(--code-background-color); border: 1px solid var(--code-border-color); border-radius: var(--border-radius-base-size); @@ -478,10 +503,27 @@ li.phpdocumentor-list { box-sizing: border-box; } +.phpdocumentor-code.-dark { + background: var(--primary-color-darkest); + color: var(--light-gray); + box-shadow: 0 2px 3px var(--dark-gray); +} + pre > .phpdocumentor-code { display: block; white-space: pre; } +.phpdocumentor blockquote { + border-left: 4px solid var(--primary-color-darken); + margin: var(--spacing-md) 0; + padding: var(--spacing-xs) var(--spacing-sm); + color: var(--primary-color-darker); + font-style: italic; +} + +.phpdocumentor blockquote p:last-of-type { + margin-bottom: 0; +} .phpdocumentor table { margin-bottom: var(--spacing-md); } @@ -506,11 +548,51 @@ td.phpdocumentor-cell:last-child { .phpdocumentor-header { display: flex; flex-direction: row; - align-items: center; + align-items: stretch; + flex-wrap: wrap; + justify-content: space-between; + height: auto; + padding: var(--spacing-md) var(--spacing-md); +} + +.phpdocumentor-header__menu-button { + position: absolute; + top: -100%; + left: -100%; +} + +.phpdocumentor-header__menu-icon { + font-size: 2rem; + color: var(--primary-color); +} + +.phpdocumentor-header__menu-button:checked ~ .phpdocumentor-topnav { + max-height: 250px; + padding-top: var(--spacing-md); +} + +@media (min-width: 1000px) { + .phpdocumentor-header { + flex-direction: row; + padding: var(--spacing-lg) var(--spacing-lg); + min-height: var(--header-height); + } + + .phpdocumentor-header__menu-icon { + display: none; + } } -.phpdocumentor-header > * { - height: var(--header-height); +@media (min-width: 1000px) { + .phpdocumentor-header { + padding-top: 0; + padding-bottom: 0; + } +} +@media (min-width: 1200px) { + .phpdocumentor-header { + padding: 0; + } } .phpdocumentor-title { box-sizing: border-box; @@ -518,16 +600,19 @@ td.phpdocumentor-cell:last-child { font-size: var(--text-xxl); letter-spacing: .05rem; font-weight: normal; - width: 30.6666666667%; + width: auto; margin: 0; - border-right: var(--sidebar-border-color) solid 1px; display: flex; align-items: center; } +.phpdocumentor-title.-without-divider { + border: none; +} + .phpdocumentor-title__link { transition: all .3s ease-out; - display: block; + display: flex; color: var(--title-text-color); text-decoration: none; font-weight: normal; @@ -541,6 +626,17 @@ td.phpdocumentor-cell:last-child { font-weight: 600; } +@media (min-width: 1000px) { + .phpdocumentor-title { + width: 30.6666666667%; + border-right: var(--sidebar-border-color) solid 1px; + } + + .phpdocumentor-title__link { + transform-origin: left; + } +} + @media (min-width: 1000px) { .phpdocumentor-title__link { transform: scale(.85); @@ -554,32 +650,36 @@ td.phpdocumentor-cell:last-child { } .phpdocumentor-topnav { display: flex; - flex: 1; - margin-left: 4%; align-items: center; + margin: 0; + max-height: 0; + overflow: hidden; + transition: max-height 0.2s ease-out; + flex-basis: 100%; } .phpdocumentor-topnav__menu { - display: inline-block; + text-align: right; list-style: none; margin: 0; padding: 0; flex: 1; -} - -.phpdocumentor-topnav__menu.-social { - margin-left: auto; - flex: 0 auto; + display: flex; + flex-flow: row wrap; + justify-content: center; } .phpdocumentor-topnav__menu-item { - display: inline; margin: 0; - padding: 0 var(--spacing-lg) 0 0; + width: 100%; + display: inline-block; + text-align: center; + padding: var(--spacing-sm) 0 } -.phpdocumentor-topnav__menu-item:last-of-type { - padding: 0; +.phpdocumentor-topnav__menu-item.-social { + width: auto; + padding: var(--spacing-sm) } .phpdocumentor-topnav__menu-item a { @@ -596,14 +696,38 @@ td.phpdocumentor-cell:last-child { transform: perspective(15rem) translateY(.1rem); border-bottom: 1px dotted var(--text-color); } + +@media (min-width: 1000px) { + .phpdocumentor-topnav { + max-height: none; + overflow: visible; + flex-basis: auto; + } + + .phpdocumentor-topnav__menu { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + } + + .phpdocumentor-topnav__menu-item, + .phpdocumentor-topnav__menu-item.-social { + width: auto; + display: inline; + text-align: right; + padding: 0 0 0 var(--spacing-md) + } +} .phpdocumentor-sidebar { - border-right: var(--sidebar-border-color) solid 1px; + margin: 0; + overflow: hidden; + max-height: 0; } .phpdocumentor .phpdocumentor-sidebar .phpdocumentor-list { - padding-top: var(--spacing-xs); - padding-left: var(--spacing-md); + padding: var(--spacing-xs) var(--spacing-md); list-style: none; + margin: 0; } .phpdocumentor .phpdocumentor-sidebar li { @@ -623,7 +747,8 @@ td.phpdocumentor-cell:last-child { transition: padding-left .4s ease-out; } -.phpdocumentor .phpdocumentor-sidebar a:hover { +.phpdocumentor .phpdocumentor-sidebar a:hover, +.phpdocumentor .phpdocumentor-sidebar a.-active { padding-left: 5px; font-weight: 600; } @@ -653,15 +778,74 @@ td.phpdocumentor-cell:last-child { color: var(--text-color); font-weight: normal; } + +@media (min-width: 550px) { + .phpdocumentor-sidebar { + border-right: var(--sidebar-border-color) solid 1px; + } +} + +.phpdocumentor-sidebar__menu-button { + position: absolute; + top: -100%; + left: -100%; +} + +.phpdocumentor-sidebar__menu-icon { + font-size: var(--text-md); + font-weight: 600; + background: var(--primary-color); + color: white; + margin: 0 0 var(--spacing-lg); + display: block; + padding: var(--spacing-sm); + text-align: center; + border-radius: 3px; + text-transform: uppercase; + letter-spacing: .15rem; +} + +.phpdocumentor-sidebar__menu-button:checked ~ .phpdocumentor-sidebar { + max-height: 100%; + padding-top: var(--spacing-md); +} + +@media (min-width: 550px) { + .phpdocumentor-sidebar { + overflow: visible; + max-height: 100%; + } + + .phpdocumentor-sidebar__menu-icon { + display: none; + } +} .phpdocumentor-admonition { border: 1px solid var(--admonition-border-color); border-radius: var(--border-radius-base-size); - padding: var(--spacing-sm) var(--spacing-md); + border-color: var(--primary-color-lighten); + background-color: var(--primary-color-lighter); + padding: var(--spacing-lg); + margin: var(--spacing-lg) 0; + display: flex; + flex-direction: row; + align-items: flex-start; +} + +.phpdocumentor-admonition p:last-of-type { + margin-bottom: 0; } -.phpdocumentor-admonition--success { +.phpdocumentor-admonition--success, +.phpdocumentor-admonition.-success { border-color: var(--admonition-success-color); } + +.phpdocumentor-admonition__icon { + margin-right: var(--spacing-md); + color: var(--primary-color); + max-width: 3rem; +} .phpdocumentor ul.phpdocumentor-breadcrumbs { font-size: var(--text-md); list-style: none; @@ -702,36 +886,220 @@ td.phpdocumentor-cell:last-child { display: none; /** disable by default for non-js flow */ opacity: .3; /** white-out default for loading indication */ transition: opacity .3s, background .3s; + margin: var(--spacing-sm) 0; + flex: 1; + min-width: 100%; } -.phpdocumentor-search:before { - content: ''; - background: transparent; - left: calc(-1 * var(--spacing-md)); - height: 100%; - position: absolute; - right: -15px; - z-index: -1; - opacity: 0; - transition: opacity .3s, background .3s; + +.phpdocumentor-search label { + display: flex; + align-items: center; + flex: 1; +} + +.phpdocumentor-search__icon { + color: var(--primary-color); + margin-right: var(--spacing-sm); + width: 1rem; + height: 1rem; } .phpdocumentor-search--enabled { - display: block; + display: flex; } .phpdocumentor-search--active { opacity: 1; } -.phpdocumentor-search--has-results:before { + +.phpdocumentor-search input:disabled { + background-color: lightgray; +} + +.phpdocumentor-search__field:focus, +.phpdocumentor-search__field { + margin-bottom: 0; + border: 0; + border-bottom: 2px solid var(--primary-color); + padding: 0; + border-radius: 0; + flex: 1; +} + +@media (min-width: 1000px) { + .phpdocumentor-search { + min-width: auto; + max-width: 20rem; + margin: 0 0 0 auto; + } +} +.phpdocumentor-content { + position: relative; +} + +.phpdocumentor-search-results { + backdrop-filter: blur(5px); background: var(--popover-background-color); + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + padding: 0; opacity: 1; + pointer-events: all; + + transition: opacity .3s, background .3s; } -.phpdocumentor-search input:disabled { - background-color: lightgray; +.phpdocumentor-search-results--hidden { + background: transparent; + backdrop-filter: blur(0); + opacity: 0; + pointer-events: none; +} + +.phpdocumentor-search-results__dialog { + width: 100%; + background: white; + max-height: 100%; + display: flex; + flex-direction: column; +} + +.phpdocumentor-search-results__body { + overflow: auto; +} + +.phpdocumentor-search-results__header { + padding: var(--spacing-lg); + display: flex; + justify-content: space-between; + background: var(--primary-color-darken); + color: white; + align-items: center; +} + +.phpdocumentor-search-results__close { + font-size: var(--text-xl); + background: none; + border: none; + padding: 0; + margin: 0; +} + +.phpdocumentor .phpdocumentor-search-results__title { + font-size: var(--text-xl); + margin-bottom: 0; +} + +.phpdocumentor-search-results__entries { + list-style: none; + padding: 0 var(--spacing-lg); + margin: 0; +} + +.phpdocumentor-search-results__entry { + border-bottom: 1px solid var(--table-separator-color); + padding: var(--spacing-sm) 0; + text-align: left; +} + +.phpdocumentor-search-results__entry a { + display: block; +} + +.phpdocumentor-search-results__entry small { + margin-top: var(--spacing-xs); + margin-bottom: var(--spacing-md); + color: var(--primary-color-darker); + display: block; + word-break: break-word; +} + +.phpdocumentor-search-results__entry h3 { + font-size: var(--text-lg); + margin: 0; +} + +@media (min-width: 550px) { + .phpdocumentor-search-results { + padding: 0 var(--spacing-lg); + } + + .phpdocumentor-search-results__entry h3 { + font-size: var(--text-xxl); + } + + .phpdocumentor-search-results__dialog { + margin: var(--spacing-xl) auto; + max-width: 40rem; + background: white; + border: 1px solid silver; + box-shadow: 0 2px 5px silver; + max-height: 40rem; + border-radius: 3px; + } +} +.phpdocumentor-modal { + position: fixed; + width: 100vw; + height: 100vh; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + top: 0; + left: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.phpdocumentor-modal__open { + visibility: visible; + opacity: 1; + transition-delay: 0s; +} + +.phpdocumentor-modal-bg { + position: absolute; + background: gray; + opacity: 50%; + width: 100%; + height: 100%; +} + +.phpdocumentor-modal-container { + border-radius: 1em; + background: #fff; + position: relative; + padding: 2em; + box-sizing: border-box; + max-width:100vw; +} + +.phpdocumentor-modal__close { + position: absolute; + right: 0.75em; + top: 0.75em; + outline: none; + appearance: none; + color: var(--primary-color); + background: none; + border: 0px; + font-weight: bold; + cursor: pointer; } /* Used for screen readers and such */ .visually-hidden { display: none; } + +.float-right { + float: right; +} + +.float-left { + float: left; +} diff --git a/docs/phpdoc/css/normalize.css b/docs/phpdoc/css/normalize.css index 46f646a5..579152b0 100644 --- a/docs/phpdoc/css/normalize.css +++ b/docs/phpdoc/css/normalize.css @@ -230,7 +230,7 @@ code, kbd, pre, samp { - font-family: monospace, monospace; + font-family: var(--font-monospace); font-size: 1em; } diff --git a/docs/phpdoc/css/template.css b/docs/phpdoc/css/template.css index 35481e92..f7178281 100644 --- a/docs/phpdoc/css/template.css +++ b/docs/phpdoc/css/template.css @@ -142,60 +142,14 @@ content: 'P' } +.phpdocumentor-table-of-contents .phpdocumentor-table-of-contents__entry.-enum:before { + content: 'E' +} + .phpdocumentor-table-of-contents dd { font-style: italic; margin-left: 2rem; } -.phpdocumentor-content { - position: relative; -} - -.phpdocumentor-search-results { - backdrop-filter: blur(5px); - background: var(--popover-background-color); - min-height: 100%; - left: calc(var(--spacing-lg) * -1); - position: absolute; - right: calc(var(--spacing-lg) * -1); - top: 0; - padding: 0 var(--spacing-lg); - opacity: 1; - pointer-events: all; - - transition: opacity .3s, background .3s; -} - -.phpdocumentor-search-results--hidden { - background: transparent; - backdrop-filter: blur(0); - opacity: 0; - pointer-events: none; -} - -.phpdocumentor-search-results__entries { - list-style: none; - padding: 0; -} - -.phpdocumentor-search-results__entry { - border-bottom: 1px solid var(--table-separator-color); - padding: var(--spacing-sm) var(--spacing-md); - text-align: left; -} - -.phpdocumentor-search-results__entry a { - display: block; -} - -.phpdocumentor-search-results__entry small { - margin-top: var(--spacing-xs); - margin-bottom: var(--spacing-md); - color: var(--primary-color-darker); - display: block; -} -.phpdocumentor-search-results__entry h3 { - margin: 0; -} .phpdocumentor-element-found-in { position: absolute; top: 0; @@ -203,6 +157,25 @@ font-size: var(--text-sm); color: gray; } + +.phpdocumentor-element-found-in .phpdocumentor-element-found-in__source { + flex: 0 1 auto; + display: inline-flex; +} + +.phpdocumentor-element-found-in .phpdocumentor-element-found-in__source:after { + width: 1.25rem; + height: 1.25rem; + line-height: 1.25rem; + background: transparent url('data:image/svg+xml;utf8,') no-repeat center center; + content: ''; + left: 0; + border-radius: 50%; + font-weight: 600; + text-align: center; + font-size: .75rem; + margin-top: .2rem; +} .phpdocumentor-class-graph { width: 100%; height: 600px; border:1px solid black; overflow: hidden } diff --git a/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html b/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html index 09daba25..7d0bceab 100644 --- a/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html +++ b/docs/phpdoc/files/phpcsutils-abstractsniffs-abstractarraydeclarationsniff.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                  -

                                                                  PHPCSUtils

                                                                  - -
                                                                  - -
                                                                  -
                                                                  -
                                                                  - +
                                                                  + + + + diff --git a/docs/phpdoc/files/phpcsutils-autoload.html b/docs/phpdoc/files/phpcsutils-autoload.html index 3a0291b3..4827954a 100644 --- a/docs/phpdoc/files/phpcsutils-autoload.html +++ b/docs/phpdoc/files/phpcsutils-autoload.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                  -

                                                                  PHPCSUtils

                                                                  - -
                                                                  - -
                                                                  -
                                                                  -
                                                                  - +
                                                                  + + + + diff --git a/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html b/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html index fe6fe0a7..308276bb 100644 --- a/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html +++ b/docs/phpdoc/files/phpcsutils-backcompat-bcfile.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                  -

                                                                  PHPCSUtils

                                                                  - -
                                                                  - -
                                                                  -
                                                                  -
                                                                  - +
                                                                  + + + + diff --git a/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html b/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html index 1037abac..cce16ec2 100644 --- a/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html +++ b/docs/phpdoc/files/phpcsutils-backcompat-bctokens.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                  -

                                                                  PHPCSUtils

                                                                  - -
                                                                  - -
                                                                  -
                                                                  -
                                                                  - +
                                                                  + + + + diff --git a/docs/phpdoc/files/phpcsutils-backcompat-helper.html b/docs/phpdoc/files/phpcsutils-backcompat-helper.html index 822afe01..726db119 100644 --- a/docs/phpdoc/files/phpcsutils-backcompat-helper.html +++ b/docs/phpdoc/files/phpcsutils-backcompat-helper.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                  -

                                                                  PHPCSUtils

                                                                  - -
                                                                  - -
                                                                  -
                                                                  -
                                                                  - +
                                                                  + + + + diff --git a/docs/phpdoc/files/phpcsutils-exceptions-invalidtokenarray.html b/docs/phpdoc/files/phpcsutils-exceptions-invalidtokenarray.html new file mode 100644 index 00000000..1e0ccc50 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-exceptions-invalidtokenarray.html @@ -0,0 +1,206 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                  +

                                                                  PHPCSUtils

                                                                  + + + + + +
                                                                  + +
                                                                  +
                                                                  + + + + +
                                                                  +
                                                                    +
                                                                  + +
                                                                  +

                                                                  InvalidTokenArray.php

                                                                  + +

                                                                  PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                  + + + +
                                                                  + Tags + +
                                                                  +
                                                                  +
                                                                  + copyright +
                                                                  +
                                                                  + +

                                                                  2019-2020 PHPCSUtils Contributors

                                                                  +
                                                                  + +
                                                                  +
                                                                  + license +
                                                                  +
                                                                  + +

                                                                  https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                  +
                                                                  + +
                                                                  +
                                                                  + link +
                                                                  +
                                                                  + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                  +
                                                                  + + + + +

                                                                  + Interfaces, Classes, Traits and Enums + +

                                                                  + +
                                                                  + +
                                                                  InvalidTokenArray
                                                                  +
                                                                  Exception thrown when an non-existent token array is requested.
                                                                  + + +
                                                                  + + + + + + + + +
                                                                  +
                                                                  +
                                                                  +
                                                                  +

                                                                  Search results

                                                                  + +
                                                                  +
                                                                  +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    +
                                                                    + + +
                                                                    + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-exceptions-testfilenotfound.html b/docs/phpdoc/files/phpcsutils-exceptions-testfilenotfound.html new file mode 100644 index 00000000..a465b257 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-exceptions-testfilenotfound.html @@ -0,0 +1,207 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                    +

                                                                    PHPCSUtils

                                                                    + + + + + +
                                                                    + +
                                                                    +
                                                                    + + + + +
                                                                    +
                                                                      +
                                                                    + +
                                                                    +

                                                                    TestFileNotFound.php

                                                                    + +

                                                                    PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                    + + + +
                                                                    + Tags + +
                                                                    +
                                                                    +
                                                                    + copyright +
                                                                    +
                                                                    + +

                                                                    2019-2020 PHPCSUtils Contributors

                                                                    +
                                                                    + +
                                                                    +
                                                                    + license +
                                                                    +
                                                                    + +

                                                                    https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                    +
                                                                    + +
                                                                    +
                                                                    + link +
                                                                    +
                                                                    + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                    +
                                                                    + + + + +

                                                                    + Interfaces, Classes, Traits and Enums + +

                                                                    + +
                                                                    + +
                                                                    TestFileNotFound
                                                                    +
                                                                    Exception thrown when the UtilityMethodTestCase::getTargetToken() method is run without a +tokenized test case file being available.
                                                                    + + +
                                                                    + + + + + + + + +
                                                                    +
                                                                    +
                                                                    +
                                                                    +

                                                                    Search results

                                                                    + +
                                                                    +
                                                                    +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      +
                                                                      + + +
                                                                      + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-exceptions-testmarkernotfound.html b/docs/phpdoc/files/phpcsutils-exceptions-testmarkernotfound.html new file mode 100644 index 00000000..fde37f89 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-exceptions-testmarkernotfound.html @@ -0,0 +1,206 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                      +

                                                                      PHPCSUtils

                                                                      + + + + + +
                                                                      + +
                                                                      +
                                                                      + + + + +
                                                                      +
                                                                        +
                                                                      + +
                                                                      +

                                                                      TestMarkerNotFound.php

                                                                      + +

                                                                      PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                      + + + +
                                                                      + Tags + +
                                                                      +
                                                                      +
                                                                      + copyright +
                                                                      +
                                                                      + +

                                                                      2019-2020 PHPCSUtils Contributors

                                                                      +
                                                                      + +
                                                                      +
                                                                      + license +
                                                                      +
                                                                      + +

                                                                      https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                      +
                                                                      + +
                                                                      +
                                                                      + link +
                                                                      +
                                                                      + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                      +
                                                                      + + + + +

                                                                      + Interfaces, Classes, Traits and Enums + +

                                                                      + +
                                                                      + +
                                                                      TestMarkerNotFound
                                                                      +
                                                                      Exception thrown when a delimiter comment can not be found in a test case file.
                                                                      + + +
                                                                      + + + + + + + + +
                                                                      +
                                                                      +
                                                                      +
                                                                      +

                                                                      Search results

                                                                      + +
                                                                      +
                                                                      +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        +
                                                                        + + +
                                                                        + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-exceptions-testtargetnotfound.html b/docs/phpdoc/files/phpcsutils-exceptions-testtargetnotfound.html new file mode 100644 index 00000000..f4010c11 --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-exceptions-testtargetnotfound.html @@ -0,0 +1,206 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                        +

                                                                        PHPCSUtils

                                                                        + + + + + +
                                                                        + +
                                                                        +
                                                                        + + + + +
                                                                        +
                                                                          +
                                                                        + +
                                                                        +

                                                                        TestTargetNotFound.php

                                                                        + +

                                                                        PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                        + + + +
                                                                        + Tags + +
                                                                        +
                                                                        +
                                                                        + copyright +
                                                                        +
                                                                        + +

                                                                        2019-2020 PHPCSUtils Contributors

                                                                        +
                                                                        + +
                                                                        +
                                                                        + license +
                                                                        +
                                                                        + +

                                                                        https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                        +
                                                                        + +
                                                                        +
                                                                        + link +
                                                                        +
                                                                        + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                        +
                                                                        + + + + +

                                                                        + Interfaces, Classes, Traits and Enums + +

                                                                        + +
                                                                        + +
                                                                        TestTargetNotFound
                                                                        +
                                                                        Exception thrown when a test target token can not be found in a test case file.
                                                                        + + +
                                                                        + + + + + + + + +
                                                                        +
                                                                        +
                                                                        +
                                                                        +

                                                                        Search results

                                                                        + +
                                                                        +
                                                                        +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          +
                                                                          + + +
                                                                          + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html b/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html index 03fb1475..cf34b1f7 100644 --- a/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html +++ b/docs/phpdoc/files/phpcsutils-fixers-spacesfixer.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                          -

                                                                          PHPCSUtils

                                                                          - -
                                                                          - -
                                                                          -
                                                                          -
                                                                          - +
                                                                          + + + + diff --git a/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html b/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html index c3f11229..47e5a5bd 100644 --- a/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html +++ b/docs/phpdoc/files/phpcsutils-testutils-utilitymethodtestcase.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                          -

                                                                          PHPCSUtils

                                                                          - -
                                                                          - -
                                                                          -
                                                                          -
                                                                          - +
                                                                          + + + + diff --git a/docs/phpdoc/files/phpcsutils-tokens-collections.html b/docs/phpdoc/files/phpcsutils-tokens-collections.html index d7074436..a8f910f0 100644 --- a/docs/phpdoc/files/phpcsutils-tokens-collections.html +++ b/docs/phpdoc/files/phpcsutils-tokens-collections.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                          -

                                                                          PHPCSUtils

                                                                          - -
                                                                          - -
                                                                          -
                                                                          -
                                                                          - +
                                                                          + + + + diff --git a/docs/phpdoc/files/phpcsutils-tokens-tokenhelper.html b/docs/phpdoc/files/phpcsutils-tokens-tokenhelper.html new file mode 100644 index 00000000..101ad93d --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-tokens-tokenhelper.html @@ -0,0 +1,206 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                          +

                                                                          PHPCSUtils

                                                                          + + + + + +
                                                                          + +
                                                                          +
                                                                          + + + + +
                                                                          +
                                                                            +
                                                                          + +
                                                                          +

                                                                          TokenHelper.php

                                                                          + +

                                                                          PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                          + + + +
                                                                          + Tags + +
                                                                          +
                                                                          +
                                                                          + copyright +
                                                                          +
                                                                          + +

                                                                          2019-2020 PHPCSUtils Contributors

                                                                          +
                                                                          + +
                                                                          +
                                                                          + license +
                                                                          +
                                                                          + +

                                                                          https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                          +
                                                                          + +
                                                                          +
                                                                          + link +
                                                                          +
                                                                          + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                          +
                                                                          + + + + +

                                                                          + Interfaces, Classes, Traits and Enums + +

                                                                          + +
                                                                          + +
                                                                          TokenHelper
                                                                          +
                                                                          Helpers for working with tokens.
                                                                          + + +
                                                                          + + + + + + + + +
                                                                          +
                                                                          +
                                                                          +
                                                                          +

                                                                          Search results

                                                                          + +
                                                                          +
                                                                          +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            +
                                                                            + + +
                                                                            + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-arrays.html b/docs/phpdoc/files/phpcsutils-utils-arrays.html index 0d5ac3a7..e06e3510 100644 --- a/docs/phpdoc/files/phpcsutils-utils-arrays.html +++ b/docs/phpdoc/files/phpcsutils-utils-arrays.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                            -

                                                                            PHPCSUtils

                                                                            - -
                                                                            - -
                                                                            -
                                                                            -
                                                                            - +
                                                                            + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-conditions.html b/docs/phpdoc/files/phpcsutils-utils-conditions.html index f4f29973..6acae6f2 100644 --- a/docs/phpdoc/files/phpcsutils-utils-conditions.html +++ b/docs/phpdoc/files/phpcsutils-utils-conditions.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                            -

                                                                            PHPCSUtils

                                                                            - -
                                                                            - -
                                                                            -
                                                                            -
                                                                            - +
                                                                            + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-context.html b/docs/phpdoc/files/phpcsutils-utils-context.html new file mode 100644 index 00000000..a733b95d --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-context.html @@ -0,0 +1,206 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                            +

                                                                            PHPCSUtils

                                                                            + + + + + +
                                                                            + +
                                                                            +
                                                                            + + + + +
                                                                            +
                                                                              +
                                                                            + +
                                                                            +

                                                                            Context.php

                                                                            + +

                                                                            PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                            + + + +
                                                                            + Tags + +
                                                                            +
                                                                            +
                                                                            + copyright +
                                                                            +
                                                                            + +

                                                                            2019-2020 PHPCSUtils Contributors

                                                                            +
                                                                            + +
                                                                            +
                                                                            + license +
                                                                            +
                                                                            + +

                                                                            https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                            +
                                                                            + +
                                                                            +
                                                                            + link +
                                                                            +
                                                                            + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                            +
                                                                            + + + + +

                                                                            + Interfaces, Classes, Traits and Enums + +

                                                                            + +
                                                                            + +
                                                                            Context
                                                                            +
                                                                            Utility functions for examining in which context a certain token is used.
                                                                            + + +
                                                                            + + + + + + + + +
                                                                            +
                                                                            +
                                                                            +
                                                                            +

                                                                            Search results

                                                                            + +
                                                                            +
                                                                            +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              +
                                                                              + + +
                                                                              + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-controlstructures.html b/docs/phpdoc/files/phpcsutils-utils-controlstructures.html index bcd937ef..db4b524a 100644 --- a/docs/phpdoc/files/phpcsutils-utils-controlstructures.html +++ b/docs/phpdoc/files/phpcsutils-utils-controlstructures.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                              -

                                                                              PHPCSUtils

                                                                              - -
                                                                              - -
                                                                              -
                                                                              -
                                                                              - +
                                                                              + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html b/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html index 0199415f..8ffe182e 100644 --- a/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html +++ b/docs/phpdoc/files/phpcsutils-utils-functiondeclarations.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                              -

                                                                              PHPCSUtils

                                                                              - -
                                                                              - -
                                                                              -
                                                                              -
                                                                              - +
                                                                              + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html b/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html index ed28f14d..534a68a5 100644 --- a/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html +++ b/docs/phpdoc/files/phpcsutils-utils-gettokensasstring.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                              -

                                                                              PHPCSUtils

                                                                              - -
                                                                              - -
                                                                              -
                                                                              -
                                                                              - +
                                                                              + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-lists.html b/docs/phpdoc/files/phpcsutils-utils-lists.html index 494dc50c..5e3d5098 100644 --- a/docs/phpdoc/files/phpcsutils-utils-lists.html +++ b/docs/phpdoc/files/phpcsutils-utils-lists.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                              -

                                                                              PHPCSUtils

                                                                              - -
                                                                              - -
                                                                              -
                                                                              -
                                                                              - +
                                                                              + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-messagehelper.html b/docs/phpdoc/files/phpcsutils-utils-messagehelper.html new file mode 100644 index 00000000..bd1587ec --- /dev/null +++ b/docs/phpdoc/files/phpcsutils-utils-messagehelper.html @@ -0,0 +1,206 @@ + + + + + PHPCSUtils + + + + + + + + + + + + + + + + + + + + +
                                                                              +

                                                                              PHPCSUtils

                                                                              + + + + + +
                                                                              + +
                                                                              +
                                                                              + + + + +
                                                                              +
                                                                                +
                                                                              + +
                                                                              +

                                                                              MessageHelper.php

                                                                              + +

                                                                              PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.

                                                                              + + + +
                                                                              + Tags + +
                                                                              +
                                                                              +
                                                                              + copyright +
                                                                              +
                                                                              + +

                                                                              2019-2020 PHPCSUtils Contributors

                                                                              +
                                                                              + +
                                                                              +
                                                                              + license +
                                                                              +
                                                                              + +

                                                                              https://opensource.org/licenses/LGPL-3.0 LGPL3

                                                                              +
                                                                              + +
                                                                              +
                                                                              + link +
                                                                              +
                                                                              + https://github.com/PHPCSStandards/PHPCSUtils + +
                                                                              +
                                                                              + + + + +

                                                                              + Interfaces, Classes, Traits and Enums + +

                                                                              + +
                                                                              + +
                                                                              MessageHelper
                                                                              +
                                                                              Helper functions for creating PHPCS error/warning messages.
                                                                              + + +
                                                                              + + + + + + + + +
                                                                              +
                                                                              +
                                                                              +
                                                                              +

                                                                              Search results

                                                                              + +
                                                                              +
                                                                              +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                +
                                                                                + + +
                                                                                + + + + + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-namespaces.html b/docs/phpdoc/files/phpcsutils-utils-namespaces.html index 142f949b..ce905755 100644 --- a/docs/phpdoc/files/phpcsutils-utils-namespaces.html +++ b/docs/phpdoc/files/phpcsutils-utils-namespaces.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-namingconventions.html b/docs/phpdoc/files/phpcsutils-utils-namingconventions.html index 4f37b568..d8c2f56f 100644 --- a/docs/phpdoc/files/phpcsutils-utils-namingconventions.html +++ b/docs/phpdoc/files/phpcsutils-utils-namingconventions.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-numbers.html b/docs/phpdoc/files/phpcsutils-utils-numbers.html index de43e423..e564061c 100644 --- a/docs/phpdoc/files/phpcsutils-utils-numbers.html +++ b/docs/phpdoc/files/phpcsutils-utils-numbers.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html b/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html index f030ac30..69e4d22d 100644 --- a/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html +++ b/docs/phpdoc/files/phpcsutils-utils-objectdeclarations.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-operators.html b/docs/phpdoc/files/phpcsutils-utils-operators.html index 69ca48f5..59fba558 100644 --- a/docs/phpdoc/files/phpcsutils-utils-operators.html +++ b/docs/phpdoc/files/phpcsutils-utils-operators.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-orthography.html b/docs/phpdoc/files/phpcsutils-utils-orthography.html index 7384a960..ad6ce3e7 100644 --- a/docs/phpdoc/files/phpcsutils-utils-orthography.html +++ b/docs/phpdoc/files/phpcsutils-utils-orthography.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-parentheses.html b/docs/phpdoc/files/phpcsutils-utils-parentheses.html index 8e768f2e..fa220ded 100644 --- a/docs/phpdoc/files/phpcsutils-utils-parentheses.html +++ b/docs/phpdoc/files/phpcsutils-utils-parentheses.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-passedparameters.html b/docs/phpdoc/files/phpcsutils-utils-passedparameters.html index bbc734b8..e20bb3c0 100644 --- a/docs/phpdoc/files/phpcsutils-utils-passedparameters.html +++ b/docs/phpdoc/files/phpcsutils-utils-passedparameters.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-scopes.html b/docs/phpdoc/files/phpcsutils-utils-scopes.html index 239ef642..479a4757 100644 --- a/docs/phpdoc/files/phpcsutils-utils-scopes.html +++ b/docs/phpdoc/files/phpcsutils-utils-scopes.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-textstrings.html b/docs/phpdoc/files/phpcsutils-utils-textstrings.html index 745d38f1..8b546a22 100644 --- a/docs/phpdoc/files/phpcsutils-utils-textstrings.html +++ b/docs/phpdoc/files/phpcsutils-utils-textstrings.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-usestatements.html b/docs/phpdoc/files/phpcsutils-utils-usestatements.html index b0cae9b4..e00a5c80 100644 --- a/docs/phpdoc/files/phpcsutils-utils-usestatements.html +++ b/docs/phpdoc/files/phpcsutils-utils-usestatements.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/files/phpcsutils-utils-variables.html b/docs/phpdoc/files/phpcsutils-utils-variables.html index 86437334..82e4403d 100644 --- a/docs/phpdoc/files/phpcsutils-utils-variables.html +++ b/docs/phpdoc/files/phpcsutils-utils-variables.html @@ -2,64 +2,112 @@ - PHPCSUtils + PHPCSUtils + - - - - - + + + + + + + + + + + - - - + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -
                                                                                - +
                                                                                + + + + diff --git a/docs/phpdoc/graphs/classes.html b/docs/phpdoc/graphs/classes.html index ace953ba..2c8bde75 100644 --- a/docs/phpdoc/graphs/classes.html +++ b/docs/phpdoc/graphs/classes.html @@ -2,63 +2,107 @@ - PHPCSUtils + PHPCSUtils + - - - + + + +
                                                                                -

                                                                                PHPCSUtils

                                                                                - -
                                                                                - -
                                                                                -
                                                                                -