From c2b576c1d0a17009c56bcadd378a2b92d0fc0549 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 15:57:07 +0100 Subject: [PATCH 01/47] Open 2.0.x-dev --- .github/workflows/backward-compatibility.yml | 2 +- .github/workflows/build-issue-bot.yml | 2 +- .github/workflows/changelog-generator.yml | 2 +- .github/workflows/checksum-phar.yml | 2 +- .github/workflows/e2e-tests.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/phar.yml | 26 +++++++++++++++++-- .../workflows/pr-base-on-previous-branch.yml | 2 +- .github/workflows/reflection-golden-test.yml | 2 +- .github/workflows/spelling.yml | 2 +- .github/workflows/static-analysis.yml | 2 +- .github/workflows/tests.yml | 2 +- 12 files changed, 35 insertions(+), 13 deletions(-) diff --git a/.github/workflows/backward-compatibility.yml b/.github/workflows/backward-compatibility.yml index 0233e1e422..d7651c9202 100644 --- a/.github/workflows/backward-compatibility.yml +++ b/.github/workflows/backward-compatibility.yml @@ -6,7 +6,7 @@ on: pull_request: push: branches: - - "1.12.x" + - "2.0.x" paths: - 'src/**' - '.github/workflows/backward-compatibility.yml' diff --git a/.github/workflows/build-issue-bot.yml b/.github/workflows/build-issue-bot.yml index 278470b466..0e541ca5b1 100644 --- a/.github/workflows/build-issue-bot.yml +++ b/.github/workflows/build-issue-bot.yml @@ -9,7 +9,7 @@ on: - '.github/workflows/build-issue-bot.yml' push: branches: - - "1.12.x" + - "2.0.x" paths: - 'issue-bot/**' - '.github/workflows/build-issue-bot.yml' diff --git a/.github/workflows/changelog-generator.yml b/.github/workflows/changelog-generator.yml index 21971571f3..bda67d4725 100644 --- a/.github/workflows/changelog-generator.yml +++ b/.github/workflows/changelog-generator.yml @@ -9,7 +9,7 @@ on: - '.github/workflows/changelog-generator.yml' push: branches: - - "1.12.x" + - "2.0.x" paths: - 'changelog-generator/**' - '.github/workflows/changelog-generator.yml' diff --git a/.github/workflows/checksum-phar.yml b/.github/workflows/checksum-phar.yml index 47256373d0..994f11ba06 100644 --- a/.github/workflows/checksum-phar.yml +++ b/.github/workflows/checksum-phar.yml @@ -12,7 +12,7 @@ on: - '.github/workflows/checksum-phar.yml' push: branches: - - "1.12.x" + - "2.0.x" paths: - 'compiler/**' - '.github/workflows/checksum-phar.yml' diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 53fded3322..239a5e3781 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -11,7 +11,7 @@ on: - 'issue-bot/**' push: branches: - - "1.12.x" + - "2.0.x" paths-ignore: - 'compiler/**' - 'apigen/**' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 03420615cd..105fff7588 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,7 +6,7 @@ on: pull_request: push: branches: - - "1.12.x" + - "2.0.x" env: COMPOSER_ROOT_VERSION: "1.12.x-dev" diff --git a/.github/workflows/phar.yml b/.github/workflows/phar.yml index c6c4934b44..723e8a93be 100644 --- a/.github/workflows/phar.yml +++ b/.github/workflows/phar.yml @@ -6,9 +6,9 @@ on: pull_request: push: branches: - - "1.12.x" + - "2.0.x" tags: - - '1.12.*' + - '2.0.*' concurrency: group: phar-${{ github.ref }} # will be canceled on subsequent pushes in both branches and pull requests @@ -107,25 +107,43 @@ jobs: integration-tests: if: github.event_name == 'pull_request' needs: compiler-tests +<<<<<<< HEAD uses: phpstan/phpstan/.github/workflows/integration-tests.yml@1.12.x with: ref: 1.12.x +======= + uses: phpstan/phpstan/.github/workflows/integration-tests.yml@2.0.x + with: + ref: 2.0.x +>>>>>>> 264ce7a58b (Open 2.0.x-dev) phar-checksum: ${{needs.compiler-tests.outputs.checksum}} extension-tests: if: github.event_name == 'pull_request' needs: compiler-tests +<<<<<<< HEAD uses: phpstan/phpstan/.github/workflows/extension-tests.yml@1.12.x with: ref: 1.12.x +======= + uses: phpstan/phpstan/.github/workflows/extension-tests.yml@2.0.x + with: + ref: 2.0.x +>>>>>>> 264ce7a58b (Open 2.0.x-dev) phar-checksum: ${{needs.compiler-tests.outputs.checksum}} other-tests: if: github.event_name == 'pull_request' needs: compiler-tests +<<<<<<< HEAD uses: phpstan/phpstan/.github/workflows/other-tests.yml@1.12.x with: ref: 1.12.x +======= + uses: phpstan/phpstan/.github/workflows/other-tests.yml@2.0.x + with: + ref: 2.0.x +>>>>>>> 264ce7a58b (Open 2.0.x-dev) phar-checksum: ${{needs.compiler-tests.outputs.checksum}} commit: @@ -152,7 +170,11 @@ jobs: repository: phpstan/phpstan path: phpstan-dist token: ${{ secrets.PHPSTAN_BOT_TOKEN }} +<<<<<<< HEAD ref: 1.12.x +======= + ref: 2.0.x +>>>>>>> 264ce7a58b (Open 2.0.x-dev) - name: "Get previous pushed dist commit" id: previous-commit diff --git a/.github/workflows/pr-base-on-previous-branch.yml b/.github/workflows/pr-base-on-previous-branch.yml index 85b8974449..f522ea446e 100644 --- a/.github/workflows/pr-base-on-previous-branch.yml +++ b/.github/workflows/pr-base-on-previous-branch.yml @@ -19,6 +19,6 @@ jobs: - name: Comment PR uses: peter-evans/create-or-update-comment@v4 with: - body: "You've opened the pull request against the latest branch 2.0.x. If your code is relevant on 1.12.x and you want it to be released sooner, please rebase your pull request and change its target to 1.12.x." + body: "You've opened the pull request against the latest branch 2.0.x. PHPStan 2.0 is not going to be released for months. If your code is relevant on 1.12.x and you want it to be released sooner, please rebase your pull request and change its target to 1.12.x." token: ${{ secrets.PHPSTAN_BOT_TOKEN }} issue-number: ${{ github.event.pull_request.number }} diff --git a/.github/workflows/reflection-golden-test.yml b/.github/workflows/reflection-golden-test.yml index 6d16f21aaa..d996728a38 100644 --- a/.github/workflows/reflection-golden-test.yml +++ b/.github/workflows/reflection-golden-test.yml @@ -11,7 +11,7 @@ on: - 'issue-bot/**' push: branches: - - "1.12.x" + - "2.0.x" paths-ignore: - 'compiler/**' - 'apigen/**' diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index d91ab1ff1f..4304d27005 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -6,7 +6,7 @@ on: pull_request: push: branches: - - "1.12.x" + - "2.0.x" jobs: typos: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index b19b6c10f7..fb498cd9bc 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -9,7 +9,7 @@ on: - 'apigen/**' push: branches: - - "1.12.x" + - "2.0.x" paths-ignore: - 'compiler/**' - 'apigen/**' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 59d834e9c7..0080b3d697 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ on: - 'issue-bot/**' push: branches: - - "1.12.x" + - "2.0.x" paths-ignore: - 'compiler/**' - 'apigen/**' From 88ef6d54e6d09a9c92515c9b203d15118b6cec51 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:01:14 +0100 Subject: [PATCH 02/47] Drop support for PHP 7.2 and 7.3 --- .github/workflows/lint.yml | 2 - .github/workflows/reflection-golden-test.yml | 1 - .github/workflows/static-analysis.yml | 20 +++------ .github/workflows/tests.yml | 44 -------------------- 4 files changed, 6 insertions(+), 61 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 105fff7588..bdc15d968a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,8 +25,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" diff --git a/.github/workflows/reflection-golden-test.yml b/.github/workflows/reflection-golden-test.yml index d996728a38..2bf67cb14f 100644 --- a/.github/workflows/reflection-golden-test.yml +++ b/.github/workflows/reflection-golden-test.yml @@ -65,7 +65,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.3" - "7.4" - "8.0" - "8.1" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index fb498cd9bc..24760de756 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -31,8 +31,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" @@ -61,18 +59,12 @@ jobs: shell: bash run: "vendor/bin/simple-downgrade downgrade -c build/downgrade.php ${{ matrix.php-version }}" - - name: "Paratest patch" - if: matrix.php-version == '7.2' - run: composer config extra.patches.brianium/paratest --json --merge '["patches/paratest.patch"]' - shell: bash - - - name: "Downgrade PHPUnit" - if: matrix.php-version == '7.2' - run: "composer require --dev phpunit/phpunit:^8.5.31 brianium/paratest:^4.0 composer/semver:^1.2 --update-with-dependencies --ignore-platform-reqs" - - - name: "Update PHPUnit" - if: matrix.php-version != '7.2' && matrix.php-version != '7.3' - run: "composer update phpunit/phpunit -W" + - name: "Upload transformed sources" + if: matrix.php-version == '7.4' + uses: actions/upload-artifact@v3 + with: + name: transformed-src + path: src - name: "PHPStan" run: "make phpstan" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0080b3d697..75f5de1627 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,7 +35,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.3" - "7.4" - "8.0" - "8.1" @@ -162,46 +161,3 @@ jobs: - name: "Tests" run: "${{ matrix.script }}" - - tests-old-phpunit: - name: "Tests with old PHPUnit" - runs-on: ${{ matrix.operating-system }} - timeout-minutes: 60 - - strategy: - fail-fast: false - matrix: - php-version: - - "7.2" - operating-system: [ ubuntu-latest ] - - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "${{ matrix.php-version }}" - tools: pecl - extensions: ds,mbstring - ini-file: development - ini-values: memory_limit=2G - - - name: "Install dependencies" - run: "composer install --no-interaction --no-progress" - - - name: "Transform source code" - shell: bash - run: "vendor/bin/simple-downgrade downgrade -c build/downgrade.php ${{ matrix.php-version }}" - - - name: "Paratest patch" - run: composer config extra.patches.brianium/paratest --json --merge '["patches/paratest.patch"]' - shell: bash - - - name: "Downgrade PHPUnit" - run: "composer require --dev phpunit/phpunit:^8.5.31 brianium/paratest:^4.0 composer/semver:^1.2 --update-with-dependencies --ignore-platform-reqs" - - - name: "Tests" - run: "make tests-coverage" From 778af2f3ef1fe93ff2e9f76ca43a592783cd5999 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 22 Dec 2023 08:42:44 +0100 Subject: [PATCH 03/47] Update nikic/php-parser to v5 --- composer.json | 7 ++-- composer.lock | 112 +++++++++++++++++++++++++------------------------- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/composer.json b/composer.json index f6cb9c01db..7e859b19e4 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,9 @@ "nette/php-generator": "3.6.9", "nette/schema": "^1.2.2", "nette/utils": "^3.2.5", - "nikic/php-parser": "^4.17.1", + "nikic/php-parser": "^5.1.0", "ondram/ci-detector": "^3.4.0", - "ondrejmirtes/better-reflection": "6.25.0.17", + "ondrejmirtes/better-reflection": "6.42.0.3", "phpstan/php-8-stubs": "0.3.101", "phpstan/phpdoc-parser": "1.30.0", "psr/http-message": "^1.1", @@ -55,8 +55,7 @@ "require-dev": { "brianium/paratest": "^6.5", "cweagans/composer-patches": "^1.7.3", - "nette/finder": "^2.5", - "ondrejmirtes/simple-downgrader": "^1.0", + "ondrejmirtes/simple-downgrader": "^2.0", "php-parallel-lint/php-parallel-lint": "^1.2.0", "phpstan/phpstan-deprecation-rules": "^1.2", "phpstan/phpstan-nette": "^1.0", diff --git a/composer.lock b/composer.lock index 71beaf624c..aba98b1475 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f5af1898ab9d95520d1511334b2000c0", + "content-hash": "6ecf16b4614aa87f10e85e795af26169", "packages": [ { "name": "clue/ndjson-react", @@ -1474,7 +1474,7 @@ "support": { "source": "https://github.com/JetBrains/phpstorm-stubs/tree/master" }, - "time": "2024-07-24T19:11:43+00:00" + "time": "2024-09-01T14:35:14+00:00" }, { "name": "nette/bootstrap", @@ -1963,25 +1963,26 @@ }, { "name": "nette/utils", - "version": "v3.2.7", + "version": "v3.2.10", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99" + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/0af4e3de4df9f1543534beab255ccf459e7a2c99", - "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99", + "url": "https://api.github.com/repos/nette/utils/zipball/a4175c62652f2300c8017fb7e640f9ccb11648d2", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2", "shasum": "" }, "require": { - "php": ">=7.2 <8.2" + "php": ">=7.2 <8.4" }, "conflict": { "nette/di": "<3.0.6" }, "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", "nette/tester": "~2.0", "phpstan/phpstan": "^1.0", "tracy/tracy": "^2.3" @@ -2042,31 +2043,33 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v3.2.7" + "source": "https://github.com/nette/utils/tree/v3.2.10" }, - "time": "2022-01-24T11:29:14+00:00" + "time": "2023-07-30T15:38:18+00:00" }, { "name": "nikic/php-parser", - "version": "v4.19.1", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", - "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1", + "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.1" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -2074,7 +2077,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2098,9 +2101,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0" }, - "time": "2024-03-17T08:10:35+00:00" + "time": "2024-07-01T20:03:41+00:00" }, { "name": "ondram/ci-detector", @@ -2176,23 +2179,23 @@ }, { "name": "ondrejmirtes/better-reflection", - "version": "6.25.0.17", + "version": "6.42.0.3", "source": { "type": "git", "url": "https://github.com/ondrejmirtes/BetterReflection.git", - "reference": "2c9cf932ab3306e0fcb90471f3b63fa3190bf7b2" + "reference": "bdb626a5e2fb52bfe3fec1d367a9c72e48550954" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/2c9cf932ab3306e0fcb90471f3b63fa3190bf7b2", - "reference": "2c9cf932ab3306e0fcb90471f3b63fa3190bf7b2", + "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/bdb626a5e2fb52bfe3fec1d367a9c72e48550954", + "reference": "bdb626a5e2fb52bfe3fec1d367a9c72e48550954", "shasum": "" }, "require": { "ext-json": "*", "jetbrains/phpstorm-stubs": "dev-master#217ed9356d07ef89109d3cd7d8c5df10aab4b0d4", - "nikic/php-parser": "^4.18.0", - "php": "^7.2 || ^8.0" + "nikic/php-parser": "^5.1.0", + "php": "^7.4 || ^8.0" }, "conflict": { "thecodingmachine/safe": "<1.1.3" @@ -2201,9 +2204,8 @@ "doctrine/coding-standard": "^12.0.0", "phpstan/phpstan": "^1.10.60", "phpstan/phpstan-phpunit": "^1.3.16", - "phpunit/phpunit": "^10.5.12", - "rector/rector": "0.14.3", - "vimeo/psalm": "5.23.0" + "phpunit/phpunit": "^11.3.2", + "rector/rector": "0.14.3" }, "suggest": { "composer/composer": "Required to use the ComposerSourceLocator" @@ -2242,9 +2244,9 @@ ], "description": "Better Reflection - an improved code reflection API", "support": { - "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.25.0.17" + "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.42.0.3" }, - "time": "2024-08-26T20:47:13+00:00" + "time": "2024-09-04T11:06:34+00:00" }, { "name": "phpstan/php-8-stubs", @@ -3168,16 +3170,16 @@ }, { "name": "symfony/console", - "version": "v5.4.41", + "version": "v5.4.43", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "6473d441a913cb997123b59ff2dbe3d1cf9e11ba" + "reference": "e86f8554de667c16dde8aeb89a3990cfde924df9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/6473d441a913cb997123b59ff2dbe3d1cf9e11ba", - "reference": "6473d441a913cb997123b59ff2dbe3d1cf9e11ba", + "url": "https://api.github.com/repos/symfony/console/zipball/e86f8554de667c16dde8aeb89a3990cfde924df9", + "reference": "e86f8554de667c16dde8aeb89a3990cfde924df9", "shasum": "" }, "require": { @@ -3247,7 +3249,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.41" + "source": "https://github.com/symfony/console/tree/v5.4.43" }, "funding": [ { @@ -3263,7 +3265,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T07:48:55+00:00" + "time": "2024-08-13T16:31:56+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3334,16 +3336,16 @@ }, { "name": "symfony/finder", - "version": "v5.4.40", + "version": "v5.4.43", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "f51cff4687547641c7d8180d74932ab40b2205ce" + "reference": "ae25a9145a900764158d439653d5630191155ca0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/f51cff4687547641c7d8180d74932ab40b2205ce", - "reference": "f51cff4687547641c7d8180d74932ab40b2205ce", + "url": "https://api.github.com/repos/symfony/finder/zipball/ae25a9145a900764158d439653d5630191155ca0", + "reference": "ae25a9145a900764158d439653d5630191155ca0", "shasum": "" }, "require": { @@ -3377,7 +3379,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.40" + "source": "https://github.com/symfony/finder/tree/v5.4.43" }, "funding": [ { @@ -3393,7 +3395,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2024-08-13T14:03:51+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4169,16 +4171,16 @@ }, { "name": "symfony/string", - "version": "v5.4.41", + "version": "v5.4.43", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "065a9611e0b1fd2197a867e1fb7f2238191b7096" + "reference": "8be1d484951ff5ca995eaf8edcbcb8b9a5888450" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/065a9611e0b1fd2197a867e1fb7f2238191b7096", - "reference": "065a9611e0b1fd2197a867e1fb7f2238191b7096", + "url": "https://api.github.com/repos/symfony/string/zipball/8be1d484951ff5ca995eaf8edcbcb8b9a5888450", + "reference": "8be1d484951ff5ca995eaf8edcbcb8b9a5888450", "shasum": "" }, "require": { @@ -4235,7 +4237,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.41" + "source": "https://github.com/symfony/string/tree/v5.4.43" }, "funding": [ { @@ -4251,7 +4253,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:20:55+00:00" + "time": "2024-08-01T10:24:28+00:00" } ], "packages-dev": [ @@ -4586,22 +4588,22 @@ }, { "name": "ondrejmirtes/simple-downgrader", - "version": "1.0.2", + "version": "2.x-dev", "source": { "type": "git", "url": "https://github.com/ondrejmirtes/simple-downgrader.git", - "reference": "832aaae53dcfe358f63180494de8734244773d46" + "reference": "dbbf56fab0bc71310ff3766ea204d84f019e99b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ondrejmirtes/simple-downgrader/zipball/832aaae53dcfe358f63180494de8734244773d46", - "reference": "832aaae53dcfe358f63180494de8734244773d46", + "url": "https://api.github.com/repos/ondrejmirtes/simple-downgrader/zipball/dbbf56fab0bc71310ff3766ea204d84f019e99b7", + "reference": "dbbf56fab0bc71310ff3766ea204d84f019e99b7", "shasum": "" }, "require": { "nette/utils": "^3.2.5", - "nikic/php-parser": "^4.18", - "php": "^7.2|^8.0", + "nikic/php-parser": "^5.0", + "php": "^7.4|^8.0", "phpstan/phpdoc-parser": "^1.24.5", "symfony/console": "^5.4", "symfony/finder": "^5.4" @@ -4629,9 +4631,9 @@ "description": "Simple Downgrader", "support": { "issues": "https://github.com/ondrejmirtes/simple-downgrader/issues", - "source": "https://github.com/ondrejmirtes/simple-downgrader/tree/1.0.2" + "source": "https://github.com/ondrejmirtes/simple-downgrader/tree/2.x" }, - "time": "2024-02-12T19:22:32+00:00" + "time": "2024-02-12T19:24:54+00:00" }, { "name": "phar-io/manifest", From 46e8f1b3b2beec1e358da146e1bb0399614d4dd4 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:10:06 +0100 Subject: [PATCH 04/47] Compatibility with PHP-Parser v5 --- conf/config.neon | 4 ++-- src/Parser/LexerFactory.php | 11 +++-------- src/Parser/PhpParserDecorator.php | 5 +++++ src/Parser/RichParser.php | 25 ++++++++++--------------- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/conf/config.neon b/conf/config.neon index 255be78dc2..dac1e96e5f 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -2045,7 +2045,7 @@ services: autowired: false currentPhpVersionPhpParser: - class: PhpParser\Parser\Php7 + class: PhpParser\Parser\Php8 # todo use factory and create Php7/Php8 arguments: lexer: @currentPhpVersionLexer autowired: false @@ -2161,7 +2161,7 @@ services: autowired: false php8PhpParser: - class: PhpParser\Parser\Php7 + class: PhpParser\Parser\Php8 arguments: lexer: @php8Lexer autowired: false diff --git a/src/Parser/LexerFactory.php b/src/Parser/LexerFactory.php index 5fa801ddec..e02bc5ed2c 100644 --- a/src/Parser/LexerFactory.php +++ b/src/Parser/LexerFactory.php @@ -9,27 +9,22 @@ final class LexerFactory { - private const OPTIONS = ['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos']]; - public function __construct(private PhpVersion $phpVersion) { } public function create(): Lexer { - $options = self::OPTIONS; if ($this->phpVersion->getVersionId() === PHP_VERSION_ID) { - return new Lexer($options); + return new Lexer(); } - $options['phpVersion'] = $this->phpVersion->getVersionString(); - - return new Lexer\Emulative($options); + return new Lexer\Emulative(\PhpParser\PhpVersion::fromString($this->phpVersion->getVersionString())); } public function createEmulative(): Lexer\Emulative { - return new Lexer\Emulative(self::OPTIONS); + return new Lexer\Emulative(); } } diff --git a/src/Parser/PhpParserDecorator.php b/src/Parser/PhpParserDecorator.php index 14c462c39f..d4e00547a0 100644 --- a/src/Parser/PhpParserDecorator.php +++ b/src/Parser/PhpParserDecorator.php @@ -31,4 +31,9 @@ public function parse(string $code, ?ErrorHandler $errorHandler = null): array } } + public function getTokens(): array + { + return $this->wrappedParser->getTokens(); + } + } diff --git a/src/Parser/RichParser.php b/src/Parser/RichParser.php index b5863a4b80..e3f2a5e310 100644 --- a/src/Parser/RichParser.php +++ b/src/Parser/RichParser.php @@ -7,6 +7,7 @@ use PhpParser\Node; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\NameResolver; +use PhpParser\Token; use PHPStan\Analyser\Ignore\IgnoreLexer; use PHPStan\Analyser\Ignore\IgnoreParseException; use PHPStan\DependencyInjection\Container; @@ -17,7 +18,6 @@ use function count; use function implode; use function in_array; -use function is_string; use function preg_match_all; use function sprintf; use function str_contains; @@ -72,8 +72,7 @@ public function parseString(string $sourceCode): array $errorHandler = new Collecting(); $nodes = $this->parser->parse($sourceCode, $errorHandler); - /** @var list $tokens */ - $tokens = $this->lexer->getTokens(); + $tokens = $this->parser->getTokens(); if ($errorHandler->hasErrors()) { throw new ParserErrorsException($errorHandler->getErrors(), null); } @@ -109,7 +108,7 @@ public function parseString(string $sourceCode): array } /** - * @param list $tokens + * @param Token[] $tokens * @return array{lines: array|null>, errors: array>} */ private function getLinesToIgnore(array $tokens): array @@ -119,12 +118,8 @@ private function getLinesToIgnore(array $tokens): array $pendingToken = null; $errors = []; foreach ($tokens as $token) { - if (is_string($token)) { - continue; - } - - $type = $token[0]; - $line = $token[2]; + $type = $token->id; + $line = $token->line; if ($type !== T_COMMENT && $type !== T_DOC_COMMENT) { if ($type !== T_WHITESPACE) { if ($pendingToken !== null) { @@ -155,7 +150,7 @@ private function getLinesToIgnore(array $tokens): array continue; } - $text = $token[1]; + $text = $token->text; $isNextLine = str_contains($text, '@phpstan-ignore-next-line'); $isCurrentLine = str_contains($text, '@phpstan-ignore-line'); @@ -204,20 +199,20 @@ private function getLinesToIgnore(array $tokens): array $ignoreLine = substr_count(substr($text, 0, $ignorePos), "\n") - 1; - if ($previousToken !== null && $previousToken[2] === $line) { + if ($previousToken !== null && $previousToken->line === $line) { try { foreach ($this->parseIdentifiers($text, $ignorePos) as $identifier) { $lines[$line][] = $identifier; } } catch (IgnoreParseException $e) { - $errors[] = [$token[2] + $e->getPhpDocLine() + $ignoreLine, $e->getMessage()]; + $errors[] = [$token->line + $e->getPhpDocLine() + $ignoreLine, $e->getMessage()]; } continue; } - $line += substr_count($token[1], "\n"); - $pendingToken = [$text, $ignorePos, $token[2] + $ignoreLine, $line]; + $line += substr_count($token->text, "\n"); + $pendingToken = [$text, $ignorePos, $token->line + $ignoreLine, $line]; } if ($pendingToken !== null) { From 8a4771308495dd9c0699fbd31f1407ec7e1b4f4f Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:19:24 +0100 Subject: [PATCH 05/47] PHP-Parser 5 - compiler --- compiler/src/Console/PrepareCommand.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/src/Console/PrepareCommand.php b/compiler/src/Console/PrepareCommand.php index f7f2b6cdf6..7bef8b99db 100644 --- a/compiler/src/Console/PrepareCommand.php +++ b/compiler/src/Console/PrepareCommand.php @@ -16,6 +16,7 @@ use function file_get_contents; use function file_put_contents; use function implode; +use function in_array; use function is_dir; use function json_decode; use function json_encode; @@ -184,6 +185,20 @@ private function buildPreloadScript(): void if ($realPath === false) { return; } + if (in_array($realPath, [ + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php', + $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php', + ], true)) { + continue; + } $path = substr($realPath, strlen($root)); $output .= 'require_once __DIR__ . ' . var_export($path, true) . ';' . "\n"; } From f056972b9d5ebef4849e31707cc8f249ec67652b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 22 Dec 2023 13:39:40 +0100 Subject: [PATCH 06/47] Scope changes --- src/Analyser/MutatingScope.php | 19 +++++++-------- src/Analyser/NodeScopeResolver.php | 38 +++++++++++++----------------- 2 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index cb4dd6b858..3a251908c9 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -21,10 +21,10 @@ use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\InterpolatedStringPart; use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\Scalar\DNumber; -use PhpParser\Node\Scalar\EncapsedStringPart; use PhpParser\Node\Scalar\LNumber; use PhpParser\Node\Scalar\String_; use PhpParser\NodeFinder; @@ -1129,16 +1129,16 @@ private function resolveType(string $exprString, Expr $node): Type return $this->initializerExprTypeResolver->getType($node, InitializerExprContext::fromScope($this)); } elseif ($node instanceof String_) { return $this->initializerExprTypeResolver->getType($node, InitializerExprContext::fromScope($this)); - } elseif ($node instanceof Node\Scalar\Encapsed) { + } elseif ($node instanceof Node\Scalar\InterpolatedString) { $resultType = null; - foreach ($node->parts as $part) { - $partType = $part instanceof EncapsedStringPart - ? new ConstantStringType($part->value) - : $this->getType($part)->toString(); + if ($part instanceof InterpolatedStringPart) { + $partType = new ConstantStringType($part->value); + } else { + $partType = $this->getType($part); + } if ($resultType === null) { $resultType = $partType; - continue; } @@ -3455,9 +3455,6 @@ private function enterAnonymousFunctionWithoutReflection( continue; } foreach ($variables as $variable) { - if (!$variable instanceof Variable) { - continue 2; - } if (!is_string($variable->name)) { continue 2; } @@ -4785,7 +4782,7 @@ private function processFinallyScopeVariableTypeHolders( } /** - * @param Expr\ClosureUse[] $byRefUses + * @param Node\ClosureUse[] $byRefUses */ public function processClosureScope( self $closureScope, diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index b22d651f99..e7b3a0abab 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -6,13 +6,13 @@ use Closure; use DivisionByZeroError; use PhpParser\Comment\Doc; +use PhpParser\Modifiers; use PhpParser\Node; use PhpParser\Node\Arg; use PhpParser\Node\AttributeGroup; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\ArrayItem; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\AssignRef; use PhpParser\Node\Expr\BinaryOp; @@ -48,7 +48,6 @@ use PhpParser\Node\Stmt\Return_; use PhpParser\Node\Stmt\Static_; use PhpParser\Node\Stmt\Switch_; -use PhpParser\Node\Stmt\Throw_; use PhpParser\Node\Stmt\TryCatch; use PhpParser\Node\Stmt\Unset_; use PhpParser\Node\Stmt\While_; @@ -474,7 +473,10 @@ private function processStmtNode( } $stmtScope = $scope; - if ($stmt instanceof Throw_ || $stmt instanceof Return_) { + if ($stmt instanceof Node\Stmt\Expression && $stmt->expr instanceof Expr\Throw_) { + $stmtScope = $this->processStmtVarAnnotation($scope, $stmt, $stmt->expr->expr, $nodeCallback); + } + if ($stmt instanceof Return_) { $stmtScope = $this->processStmtVarAnnotation($scope, $stmt, $stmt->expr, $nodeCallback); } @@ -922,14 +924,6 @@ private function processStmtNode( if ($stmt->type !== null) { $nodeCallback($stmt->type, $scope); } - } elseif ($stmt instanceof Throw_) { - $result = $this->processExprNode($stmt, $stmt->expr, $scope, $nodeCallback, ExpressionContext::createDeep()); - $throwPoints = $result->getThrowPoints(); - $throwPoints[] = ThrowPoint::createExplicit($result->getScope(), $scope->getType($stmt->expr), $stmt, false); - $impurePoints = $result->getImpurePoints(); - return new StatementResult($result->getScope(), $result->hasYield(), true, [ - new StatementExitPoint($stmt, $scope), - ], $throwPoints, $impurePoints); } elseif ($stmt instanceof If_) { $conditionType = ($this->treatPhpDocTypesAsCertain ? $scope->getType($stmt->cond) : $scope->getNativeType($stmt->cond))->toBoolean(); $ifAlwaysTrue = $conditionType->isTrue()->yes(); @@ -1506,7 +1500,7 @@ private function processStmtNode( } foreach ($branchScopeResult->getExitPoints() as $exitPoint) { $finallyExitPoints[] = $exitPoint; - if ($exitPoint->getStatement() instanceof Throw_) { + if ($exitPoint->getStatement() instanceof Node\Stmt\Expression && $exitPoint->getStatement()->expr instanceof Expr\Throw_) { continue; } if ($finallyScope !== null) { @@ -1668,7 +1662,7 @@ private function processStmtNode( } foreach ($catchScopeResult->getExitPoints() as $exitPoint) { $finallyExitPoints[] = $exitPoint; - if ($exitPoint->getStatement() instanceof Throw_) { + if ($exitPoint->getStatement() instanceof Node\Stmt\Expression && $exitPoint->getStatement()->expr instanceof Expr\Throw_) { continue; } if ($finallyScope !== null) { @@ -2037,7 +2031,7 @@ private function lookForExpressionCallback(MutatingScope $scope, Expr $expr, Clo $scope = $this->lookForExpressionCallback($scope, $expr->var, $callback); } elseif ($expr instanceof StaticPropertyFetch && $expr->class instanceof Expr) { $scope = $this->lookForExpressionCallback($scope, $expr->class, $callback); - } elseif ($expr instanceof Array_ || $expr instanceof List_) { + } elseif ($expr instanceof List_) { foreach ($expr->items as $item) { if ($item === null) { continue; @@ -2942,11 +2936,14 @@ static function (): void { $impurePoints = array_merge($impurePoints, $result->getImpurePoints()); $scope = $result->getScope(); } - } elseif ($expr instanceof Node\Scalar\Encapsed) { + } elseif ($expr instanceof Node\Scalar\InterpolatedString) { $hasYield = false; $throwPoints = []; $impurePoints = []; foreach ($expr->parts as $part) { + if (!$part instanceof Expr) { + continue; + } $result = $this->processExprNode($stmt, $part, $scope, $nodeCallback, $context->enterDeep()); $hasYield = $hasYield || $result->hasYield(); $throwPoints = array_merge($throwPoints, $result->getThrowPoints()); @@ -3630,7 +3627,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { } else { $items = []; foreach ($filteringExprs as $filteringExpr) { - $items[] = new ArrayItem($filteringExpr); + $items[] = new Node\ArrayItem($filteringExpr); } $filteringExpr = new FuncCall( new Name\FullyQualified('in_array'), @@ -4113,7 +4110,7 @@ private function getAssignedVariables(Expr $expr): array return []; } - if ($expr instanceof Expr\List_ || $expr instanceof Expr\Array_) { + if ($expr instanceof Expr\List_) { $names = []; foreach ($expr->items as $item) { if ($item === null) { @@ -5271,7 +5268,7 @@ static function (): void { $nodeCallback(new PropertyAssignNode($var, $assignedExpr, $isAssignOp), $scope); $scope = $scope->assignExpression($var, $assignedExprType, $scope->getNativeType($assignedExpr)); } - } elseif ($var instanceof List_ || $var instanceof Array_) { + } elseif ($var instanceof List_) { $result = $processExprCallback($scope); $hasYield = $result->hasYield(); $throwPoints = array_merge($throwPoints, $result->getThrowPoints()); @@ -5778,7 +5775,7 @@ private function processNodesForTraitUse($node, ClassReflection $traitReflection $methodAst = clone $stmt; $stmts[$i] = $methodAst; if (array_key_exists($methodName, $methodModifiers)) { - $methodAst->flags = ($methodAst->flags & ~ Node\Stmt\Class_::VISIBILITY_MODIFIER_MASK) | $methodModifiers[$methodName]; + $methodAst->flags = ($methodAst->flags & ~ Modifiers::VISIBILITY_MASK) | $methodModifiers[$methodName]; } if (!array_key_exists($methodName, $methodNames)) { @@ -5867,9 +5864,6 @@ private function processCalledMethod(MethodReflection $methodReflection): ?Mutat foreach ($returnStatement->getExecutionEnds() as $executionEnd) { $statementResult = $executionEnd->getStatementResult(); $endNode = $executionEnd->getNode(); - if ($endNode instanceof Node\Stmt\Throw_) { - continue; - } if ($endNode instanceof Node\Stmt\Expression) { $exprType = $statementResult->getScope()->getType($endNode->expr); if ($exprType instanceof NeverType && $exprType->isExplicit()) { From 4d7d6ed7da5c46ed43a6d05d1d481c13c1e59846 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:20:31 +0100 Subject: [PATCH 07/47] Rest of src/ changes --- phpstan-baseline.neon | 16 ++++++++++++++++ src/Dependency/DependencyResolver.php | 4 ---- src/Node/ClassPropertiesNode.php | 3 --- src/Node/ClassPropertyNode.php | 14 +++++++------- src/Node/ClassStatementsGatherer.php | 3 --- src/Node/LiteralArrayItem.php | 2 +- src/Parser/LastConditionVisitor.php | 6 +++++- src/Reflection/InitializerExprTypeResolver.php | 4 ---- src/Rules/Arrays/ArrayDestructuringRule.php | 7 +++---- src/Rules/Arrays/ArrayUnpackingRule.php | 2 +- src/Rules/Arrays/EmptyArrayItemRule.php | 1 + src/Rules/Arrays/InvalidKeyInArrayItemRule.php | 4 ++-- .../Cast/InvalidPartOfEncapsedStringRule.php | 6 +++--- src/Rules/Functions/UnusedClosureUsesRule.php | 2 +- src/Rules/NullsafeCheck.php | 2 +- src/Rules/Operators/InvalidAssignVarRule.php | 2 +- .../PhpDoc/WrongVariableNameInVarTagRule.php | 2 +- src/Rules/UnusedFunctionParametersCheck.php | 2 +- src/Type/FileTypeMapper.php | 1 - ...IsCallableFunctionTypeSpecifyingExtension.php | 4 ---- 20 files changed, 44 insertions(+), 43 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 77ff81fd1a..cdbd956fa2 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1835,3 +1835,19 @@ parameters: message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Generic\\\\TemplateType is always PHPStan\\\\Type\\\\Generic\\\\TemplateMixedType but it's error\\-prone and dangerous\\.$#" count: 1 path: tests/PHPStan/Type/IterableTypeTest.php + + - + message: """ + #^Instantiation of deprecated class PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRule\\: + Since PHP\\-Parser 5\\.0 this is a parse error\\.$# + """ + count: 1 + path: tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php + + - + message: """ + #^Return type of method PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRuleTest\\:\\:getRule\\(\\) has typehint with deprecated class PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRule\\: + Since PHP\\-Parser 5\\.0 this is a parse error\\.$# + """ + count: 1 + path: tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 57a80a5a2e..2c7d3f581a 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -479,10 +479,6 @@ private function considerArrayForCallableTest(Scope $scope, Array_ $arrayNode): return false; } - if ($items[0] === null) { - return false; - } - $itemType = $scope->getType($items[0]->value); return $itemType->isClassStringType()->yes(); } diff --git a/src/Node/ClassPropertiesNode.php b/src/Node/ClassPropertiesNode.php index 7afc4bc874..0707a5bc6d 100644 --- a/src/Node/ClassPropertiesNode.php +++ b/src/Node/ClassPropertiesNode.php @@ -271,9 +271,6 @@ private function collectUninitializedProperties(array $constructors, array $unin $statementResult = $executionEnd->getStatementResult(); $endNode = $executionEnd->getNode(); if ($statementResult->isAlwaysTerminating()) { - if ($endNode instanceof Node\Stmt\Throw_) { - continue; - } if ($endNode instanceof Node\Stmt\Expression) { $exprType = $statementResult->getScope()->getType($endNode->expr); if ($exprType instanceof NeverType && $exprType->isExplicit()) { diff --git a/src/Node/ClassPropertyNode.php b/src/Node/ClassPropertyNode.php index d8aaea6218..f0ad86ff8c 100644 --- a/src/Node/ClassPropertyNode.php +++ b/src/Node/ClassPropertyNode.php @@ -2,11 +2,11 @@ namespace PHPStan\Node; +use PhpParser\Modifiers; use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Identifier; use PhpParser\Node\Name; -use PhpParser\Node\Stmt\Class_; use PhpParser\NodeAbstract; use PHPStan\Reflection\ClassReflection; use PHPStan\Type\Type; @@ -75,28 +75,28 @@ public function getPhpDocType(): ?Type public function isPublic(): bool { - return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 - || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + return ($this->flags & Modifiers::PUBLIC) !== 0 + || ($this->flags & Modifiers::VISIBILITY_MASK) === 0; } public function isProtected(): bool { - return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + return (bool) ($this->flags & Modifiers::PROTECTED); } public function isPrivate(): bool { - return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + return (bool) ($this->flags & Modifiers::PRIVATE); } public function isStatic(): bool { - return (bool) ($this->flags & Class_::MODIFIER_STATIC); + return (bool) ($this->flags & Modifiers::STATIC); } public function isReadOnly(): bool { - return (bool) ($this->flags & Class_::MODIFIER_READONLY) || $this->isReadonlyClass; + return (bool) ($this->flags & Modifiers::READONLY) || $this->isReadonlyClass; } public function isReadOnlyByPhpDoc(): bool diff --git a/src/Node/ClassStatementsGatherer.php b/src/Node/ClassStatementsGatherer.php index 55ef907799..7fb27f8351 100644 --- a/src/Node/ClassStatementsGatherer.php +++ b/src/Node/ClassStatementsGatherer.php @@ -221,9 +221,6 @@ private function gatherNodes(Node $node, Scope $scope): void $this->propertyUsages[] = new PropertyWrite($node->expr, $scope, false); return; } - if ($node instanceof Node\Scalar\EncapsedStringPart) { - return; - } if ($node instanceof FunctionCallableNode) { $node = $node->getOriginalNode(); } elseif ($node instanceof InstantiationCallableNode) { diff --git a/src/Node/LiteralArrayItem.php b/src/Node/LiteralArrayItem.php index ea9be27be6..1ba0c04ef5 100644 --- a/src/Node/LiteralArrayItem.php +++ b/src/Node/LiteralArrayItem.php @@ -2,7 +2,7 @@ namespace PHPStan\Node; -use PhpParser\Node\Expr\ArrayItem; +use PhpParser\Node\ArrayItem; use PHPStan\Analyser\Scope; /** diff --git a/src/Parser/LastConditionVisitor.php b/src/Parser/LastConditionVisitor.php index ce21f571fd..d4c4b53ac3 100644 --- a/src/Parser/LastConditionVisitor.php +++ b/src/Parser/LastConditionVisitor.php @@ -18,7 +18,11 @@ public function enterNode(Node $node): ?Node $lastElseIf = count($node->elseifs) - 1; $elseIsMissingOrThrowing = $node->else === null - || (count($node->else->stmts) === 1 && $node->else->stmts[0] instanceof Node\Stmt\Throw_); + || ( + count($node->else->stmts) === 1 + && $node->else->stmts[0] instanceof Node\Stmt\Expression + && $node->else->stmts[0]->expr instanceof Node\Expr\Throw_ + ); foreach ($node->elseifs as $i => $elseif) { $isLast = $i === $lastElseIf && $elseIsMissingOrThrowing; diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index dae4e11140..2f1aaa96a0 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -525,10 +525,6 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); $isList = null; foreach ($expr->items as $arrayItem) { - if ($arrayItem === null) { - continue; - } - $valueType = $getTypeCallback($arrayItem->value); if ($arrayItem->unpack) { $constantArrays = $valueType->getConstantArrays(); diff --git a/src/Rules/Arrays/ArrayDestructuringRule.php b/src/Rules/Arrays/ArrayDestructuringRule.php index ab83f1d019..d8281b1d88 100644 --- a/src/Rules/Arrays/ArrayDestructuringRule.php +++ b/src/Rules/Arrays/ArrayDestructuringRule.php @@ -40,7 +40,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$node->var instanceof Node\Expr\List_ && !$node->var instanceof Node\Expr\Array_) { + if (!$node->var instanceof Node\Expr\List_) { return []; } @@ -52,10 +52,9 @@ public function processNode(Node $node, Scope $scope): array } /** - * @param Node\Expr\List_|Node\Expr\Array_ $var * @return list */ - private function getErrors(Scope $scope, Expr $var, Expr $expr): array + private function getErrors(Scope $scope, Node\Expr\List_ $var, Expr $expr): array { $exprTypeResult = $this->ruleLevelHelper->findTypeToCheck( $scope, @@ -100,7 +99,7 @@ private function getErrors(Scope $scope, Expr $var, Expr $expr): array ); $errors = array_merge($errors, $itemErrors); - if (!$item->value instanceof Node\Expr\List_ && !$item->value instanceof Node\Expr\Array_) { + if (!$item->value instanceof Node\Expr\List_) { $i++; continue; } diff --git a/src/Rules/Arrays/ArrayUnpackingRule.php b/src/Rules/Arrays/ArrayUnpackingRule.php index 4be69c0ac0..f1573bec6d 100644 --- a/src/Rules/Arrays/ArrayUnpackingRule.php +++ b/src/Rules/Arrays/ArrayUnpackingRule.php @@ -3,7 +3,7 @@ namespace PHPStan\Rules\Arrays; use PhpParser\Node; -use PhpParser\Node\Expr\ArrayItem; +use PhpParser\Node\ArrayItem; use PHPStan\Analyser\Scope; use PHPStan\Node\Expr\GetIterableKeyTypeExpr; use PHPStan\Php\PhpVersion; diff --git a/src/Rules/Arrays/EmptyArrayItemRule.php b/src/Rules/Arrays/EmptyArrayItemRule.php index 0bfcebf956..dfe2a48d4b 100644 --- a/src/Rules/Arrays/EmptyArrayItemRule.php +++ b/src/Rules/Arrays/EmptyArrayItemRule.php @@ -9,6 +9,7 @@ use PHPStan\Rules\RuleErrorBuilder; /** + * @deprecated Since PHP-Parser 5.0 this is a parse error. * @implements Rule */ final class EmptyArrayItemRule implements Rule diff --git a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php index 5b5f3545a9..fb4ab23162 100644 --- a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php +++ b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php @@ -11,7 +11,7 @@ use function sprintf; /** - * @implements Rule + * @implements Rule */ final class InvalidKeyInArrayItemRule implements Rule { @@ -22,7 +22,7 @@ public function __construct(private bool $reportMaybes) public function getNodeType(): string { - return Node\Expr\ArrayItem::class; + return Node\ArrayItem::class; } public function processNode(Node $node, Scope $scope): array diff --git a/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php b/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php index 5cf96d8ad2..a2c04dc054 100644 --- a/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php +++ b/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php @@ -14,7 +14,7 @@ use function sprintf; /** - * @implements Rule + * @implements Rule */ final class InvalidPartOfEncapsedStringRule implements Rule { @@ -28,14 +28,14 @@ public function __construct( public function getNodeType(): string { - return Node\Scalar\Encapsed::class; + return Node\Scalar\InterpolatedString::class; } public function processNode(Node $node, Scope $scope): array { $messages = []; foreach ($node->parts as $part) { - if ($part instanceof Node\Scalar\EncapsedStringPart) { + if ($part instanceof Node\InterpolatedStringPart) { continue; } diff --git a/src/Rules/Functions/UnusedClosureUsesRule.php b/src/Rules/Functions/UnusedClosureUsesRule.php index 1494208b5b..c019d69240 100644 --- a/src/Rules/Functions/UnusedClosureUsesRule.php +++ b/src/Rules/Functions/UnusedClosureUsesRule.php @@ -34,7 +34,7 @@ public function processNode(Node $node, Scope $scope): array return $this->check->getUnusedParameters( $scope, - array_map(static function (Node\Expr\ClosureUse $use): string { + array_map(static function (Node\ClosureUse $use): string { if (!is_string($use->var->name)) { throw new ShouldNotHappenException(); } diff --git a/src/Rules/NullsafeCheck.php b/src/Rules/NullsafeCheck.php index b8ff7713bf..a4424b69ac 100644 --- a/src/Rules/NullsafeCheck.php +++ b/src/Rules/NullsafeCheck.php @@ -36,7 +36,7 @@ public function containsNullSafe(Expr $expr): bool return $this->containsNullSafe($expr->class); } - if ($expr instanceof Expr\List_ || $expr instanceof Expr\Array_) { + if ($expr instanceof Expr\List_) { foreach ($expr->items as $item) { if ($item === null) { continue; diff --git a/src/Rules/Operators/InvalidAssignVarRule.php b/src/Rules/Operators/InvalidAssignVarRule.php index 7b24c91c52..a5ae2ac291 100644 --- a/src/Rules/Operators/InvalidAssignVarRule.php +++ b/src/Rules/Operators/InvalidAssignVarRule.php @@ -85,7 +85,7 @@ private function containsNonAssignableExpression(Expr $expr): bool return false; } - if ($expr instanceof Expr\List_ || $expr instanceof Expr\Array_) { + if ($expr instanceof Expr\List_) { foreach ($expr->items as $item) { if ($item === null) { continue; diff --git a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php index 9e4fc3ebf1..b7021dfe92 100644 --- a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php +++ b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php @@ -195,7 +195,7 @@ private function getAssignedVariables(Expr $expr): array return []; } - if ($expr instanceof Expr\List_ || $expr instanceof Expr\Array_) { + if ($expr instanceof Expr\List_) { $names = []; foreach ($expr->items as $item) { if ($item === null) { diff --git a/src/Rules/UnusedFunctionParametersCheck.php b/src/Rules/UnusedFunctionParametersCheck.php index b85150e267..4fbe76d20d 100644 --- a/src/Rules/UnusedFunctionParametersCheck.php +++ b/src/Rules/UnusedFunctionParametersCheck.php @@ -69,7 +69,7 @@ private function getUsedVariables(Scope $scope, $node): array if ($node instanceof Node\Expr\Variable && is_string($node->name) && $node->name !== 'this') { return [$node->name]; } - if ($node instanceof Node\Expr\ClosureUse && is_string($node->var->name)) { + if ($node instanceof Node\ClosureUse && is_string($node->var->name)) { return [$node->var->name]; } if ( diff --git a/src/Type/FileTypeMapper.php b/src/Type/FileTypeMapper.php index edd8d3eef6..db5d8983f5 100644 --- a/src/Type/FileTypeMapper.php +++ b/src/Type/FileTypeMapper.php @@ -519,7 +519,6 @@ function (Node $node) use ($fileName, $lookForTrait, $phpDocNodeMap, &$traitFoun $node instanceof Node\Stmt && !$node instanceof Node\Stmt\Namespace_ && !$node instanceof Node\Stmt\Declare_ - && !$node instanceof Node\Stmt\DeclareDeclare && !$node instanceof Node\Stmt\Use_ && !$node instanceof Node\Stmt\UseUse && !$node instanceof Node\Stmt\GroupUse diff --git a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php index 472683ffb1..a571338e18 100644 --- a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php @@ -51,10 +51,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n && $valueType->isConstantArray()->yes() && !$valueType->isCallable()->no() ) { - if ($value->items[0] === null || $value->items[1] === null) { - throw new ShouldNotHappenException(); - } - $functionCall = new FuncCall(new Name('method_exists'), [ new Arg($value->items[0]->value), new Arg($value->items[1]->value), From 71c179035f6eb0afd6b63bddf0c2cb10b84d52af Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:20:13 +0100 Subject: [PATCH 08/47] Tests changes --- tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php b/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php index 51ba629e16..df14e33493 100644 --- a/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php @@ -20,7 +20,7 @@ public function testRule(): void { $this->analyse([__DIR__ . '/data/empty-array-item.php'], [ [ - 'Literal array contains empty item.', + 'Cannot use empty array elements in arrays on line 5', 5, ], ]); From 33f3ce9387645224bc5f822eacf04bcbc8861575 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:32:08 +0100 Subject: [PATCH 09/47] Fixes --- src/Analyser/MutatingScope.php | 2 +- .../BetterReflection/SourceLocator/AutoloadSourceLocator.php | 1 + src/Type/Constant/OversizedArrayBuilder.php | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 3a251908c9..36eedbe816 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1837,7 +1837,7 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu } else { $items = []; foreach ($arm->conds as $filteringExpr) { - $items[] = new Expr\ArrayItem($filteringExpr); + $items[] = new Node\ArrayItem($filteringExpr); } $filteringExpr = new FuncCall( new Name\FullyQualified('in_array'), diff --git a/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php index 7506682426..2edde64fbc 100644 --- a/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php @@ -114,6 +114,7 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): 'startFilePos' => 1, 'endFilePos' => 4, ]), + null, new LocatedSource('getIterableValueType()), new TypeExpr($valueType->getIterableKeyType()), )]); From e7f9a775aeb364b958bd751475d89cbb9b252314 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 20 Dec 2023 16:46:18 +0100 Subject: [PATCH 10/47] Fix deprecations --- src/Dependency/ExportedNodeVisitor.php | 4 ++-- .../BetterReflection/SourceLocator/CachingVisitor.php | 10 +++++----- src/Rules/Whitespace/FileWhitespaceRule.php | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Dependency/ExportedNodeVisitor.php b/src/Dependency/ExportedNodeVisitor.php index 90df53887b..34dfd1efe1 100644 --- a/src/Dependency/ExportedNodeVisitor.php +++ b/src/Dependency/ExportedNodeVisitor.php @@ -3,7 +3,7 @@ namespace PHPStan\Dependency; use PhpParser\Node; -use PhpParser\NodeTraverser; +use PhpParser\NodeVisitor; use PhpParser\NodeVisitorAbstract; use PHPStan\ShouldNotHappenException; @@ -52,7 +52,7 @@ public function enterNode(Node $node): ?int || $node instanceof Node\Stmt\Function_ || $node instanceof Node\Stmt\Trait_ ) { - return NodeTraverser::DONT_TRAVERSE_CHILDREN; + return NodeVisitor::DONT_TRAVERSE_CHILDREN; } return null; diff --git a/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php b/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php index 3a6d194395..6eb1f57604 100644 --- a/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php +++ b/src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php @@ -4,7 +4,7 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Namespace_; -use PhpParser\NodeTraverser; +use PhpParser\NodeVisitor; use PhpParser\NodeVisitorAbstract; use PHPStan\BetterReflection\Reflection\Exception\InvalidConstantNode; use PHPStan\BetterReflection\SourceLocator\Located\LocatedSource; @@ -51,7 +51,7 @@ public function enterNode(Node $node): ?int ); } - return NodeTraverser::DONT_TRAVERSE_CHILDREN; + return NodeVisitor::DONT_TRAVERSE_CHILDREN; } if ($node instanceof Node\Stmt\Function_) { @@ -64,7 +64,7 @@ public function enterNode(Node $node): ?int ); } - return NodeTraverser::DONT_TRAVERSE_CHILDREN; + return NodeVisitor::DONT_TRAVERSE_CHILDREN; } if ($node instanceof Node\Stmt\Const_) { @@ -80,7 +80,7 @@ public function enterNode(Node $node): ?int ); } - return NodeTraverser::DONT_TRAVERSE_CHILDREN; + return NodeVisitor::DONT_TRAVERSE_CHILDREN; } if ($node instanceof Node\Expr\FuncCall) { @@ -101,7 +101,7 @@ public function enterNode(Node $node): ?int ); $this->constantNodes[ConstantNameHelper::normalize($constantName)][] = $constantNode; - return NodeTraverser::DONT_TRAVERSE_CHILDREN; + return NodeVisitor::DONT_TRAVERSE_CHILDREN; } return null; diff --git a/src/Rules/Whitespace/FileWhitespaceRule.php b/src/Rules/Whitespace/FileWhitespaceRule.php index d234baa6b1..3fb3cbf239 100644 --- a/src/Rules/Whitespace/FileWhitespaceRule.php +++ b/src/Rules/Whitespace/FileWhitespaceRule.php @@ -5,6 +5,7 @@ use Nette\Utils\Strings; use PhpParser\Node; use PhpParser\NodeTraverser; +use PhpParser\NodeVisitor; use PhpParser\NodeVisitorAbstract; use PHPStan\Analyser\Scope; use PHPStan\Node\FileNode; @@ -61,7 +62,7 @@ public function enterNode(Node $node) } return null; } - return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN; + return NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN; } /** From d68e55c3ca6a04f0c240f0123068b2c20dfcc417 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 22 Dec 2023 14:46:05 +0100 Subject: [PATCH 11/47] Fix phar.yml --- .github/workflows/phar.yml | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/.github/workflows/phar.yml b/.github/workflows/phar.yml index 723e8a93be..f2f75906b3 100644 --- a/.github/workflows/phar.yml +++ b/.github/workflows/phar.yml @@ -10,6 +10,9 @@ on: tags: - '2.0.*' +env: + COMPOSER_ROOT_VERSION: "1.12.x-dev" + concurrency: group: phar-${{ github.ref }} # will be canceled on subsequent pushes in both branches and pull requests cancel-in-progress: true @@ -76,15 +79,12 @@ jobs: - name: "Composer dump" run: "composer install --no-interaction --no-progress" - env: - COMPOSER_ROOT_VERSION: "1.12.x-dev" - name: "Compile PHAR for checksum" working-directory: "compiler/build" run: "php box.phar compile --no-parallel" env: PHAR_CHECKSUM: "1" - COMPOSER_ROOT_VERSION: "1.12.x-dev" - name: "Re-sign PHAR" run: "php compiler/build/resign.php tmp/phpstan.phar" @@ -107,43 +107,25 @@ jobs: integration-tests: if: github.event_name == 'pull_request' needs: compiler-tests -<<<<<<< HEAD - uses: phpstan/phpstan/.github/workflows/integration-tests.yml@1.12.x - with: - ref: 1.12.x -======= uses: phpstan/phpstan/.github/workflows/integration-tests.yml@2.0.x with: ref: 2.0.x ->>>>>>> 264ce7a58b (Open 2.0.x-dev) phar-checksum: ${{needs.compiler-tests.outputs.checksum}} extension-tests: if: github.event_name == 'pull_request' needs: compiler-tests -<<<<<<< HEAD - uses: phpstan/phpstan/.github/workflows/extension-tests.yml@1.12.x - with: - ref: 1.12.x -======= uses: phpstan/phpstan/.github/workflows/extension-tests.yml@2.0.x with: ref: 2.0.x ->>>>>>> 264ce7a58b (Open 2.0.x-dev) phar-checksum: ${{needs.compiler-tests.outputs.checksum}} other-tests: if: github.event_name == 'pull_request' needs: compiler-tests -<<<<<<< HEAD - uses: phpstan/phpstan/.github/workflows/other-tests.yml@1.12.x - with: - ref: 1.12.x -======= uses: phpstan/phpstan/.github/workflows/other-tests.yml@2.0.x with: ref: 2.0.x ->>>>>>> 264ce7a58b (Open 2.0.x-dev) phar-checksum: ${{needs.compiler-tests.outputs.checksum}} commit: @@ -170,11 +152,7 @@ jobs: repository: phpstan/phpstan path: phpstan-dist token: ${{ secrets.PHPSTAN_BOT_TOKEN }} -<<<<<<< HEAD - ref: 1.12.x -======= ref: 2.0.x ->>>>>>> 264ce7a58b (Open 2.0.x-dev) - name: "Get previous pushed dist commit" id: previous-commit From 1620cabbf74e2e40297a290ba724f96a1987de3a Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 29 Dec 2023 10:01:35 +0100 Subject: [PATCH 12/47] Fix ThrowExprTypeRuleTest --- .../Rules/Exceptions/ThrowExprTypeRuleTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php index 8ef6277fe1..9ece8025a0 100644 --- a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php @@ -23,16 +23,16 @@ public function testRule(): void $this->analyse( [__DIR__ . '/data/throw-values.php'], [ - /*[ + [ 'Invalid type int to throw.', 29, ], [ - 'Invalid type ThrowValues\InvalidException to throw.', + 'Invalid type ThrowExprValues\InvalidException to throw.', 32, ], [ - 'Invalid type ThrowValues\InvalidInterfaceException to throw.', + 'Invalid type ThrowExprValues\InvalidInterfaceException to throw.', 35, ], [ @@ -40,10 +40,10 @@ public function testRule(): void 38, ], [ - 'Throwing object of an unknown class ThrowValues\NonexistentClass.', + 'Throwing object of an unknown class ThrowExprValues\NonexistentClass.', 44, 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ],*/ + ], [ 'Invalid type int to throw.', 65, @@ -64,10 +64,10 @@ public function testRuleWithNullsafeVariant(): void } $this->analyse([__DIR__ . '/data/throw-values-nullsafe.php'], [ - /*[ + [ 'Invalid type Exception|null to throw.', 17, - ],*/ + ], ]); } From 78c1b40778346b4c0cbace0ffd7b8004dc9f4b27 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Fri, 29 Dec 2023 10:02:00 +0100 Subject: [PATCH 13/47] Remove obsolete ThrowTypeRule because it targeted Stmt\Throw_ --- conf/config.level3.neon | 1 - src/Rules/Variables/ThrowTypeRule.php | 62 ---------------- .../Rules/Variables/ThrowTypeRuleTest.php | 70 ------------------- .../Variables/data/throw-class-exists.php | 19 ----- .../Variables/data/throw-values-nullsafe.php | 18 ----- .../Rules/Variables/data/throw-values.php | 62 ---------------- 6 files changed, 232 deletions(-) delete mode 100644 src/Rules/Variables/ThrowTypeRule.php delete mode 100644 tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php delete mode 100644 tests/PHPStan/Rules/Variables/data/throw-class-exists.php delete mode 100644 tests/PHPStan/Rules/Variables/data/throw-values-nullsafe.php delete mode 100644 tests/PHPStan/Rules/Variables/data/throw-values.php diff --git a/conf/config.level3.neon b/conf/config.level3.neon index 5540500714..f205db23b6 100644 --- a/conf/config.level3.neon +++ b/conf/config.level3.neon @@ -30,7 +30,6 @@ rules: - PHPStan\Rules\Properties\ReadOnlyPropertyAssignRule - PHPStan\Rules\Properties\ReadOnlyPropertyAssignRefRule - PHPStan\Rules\Properties\TypesAssignedToPropertiesRule - - PHPStan\Rules\Variables\ThrowTypeRule - PHPStan\Rules\Variables\VariableCloningRule parameters: diff --git a/src/Rules/Variables/ThrowTypeRule.php b/src/Rules/Variables/ThrowTypeRule.php deleted file mode 100644 index 03a80e73bf..0000000000 --- a/src/Rules/Variables/ThrowTypeRule.php +++ /dev/null @@ -1,62 +0,0 @@ - - */ -final class ThrowTypeRule implements Rule -{ - - public function __construct( - private RuleLevelHelper $ruleLevelHelper, - ) - { - } - - public function getNodeType(): string - { - return Node\Stmt\Throw_::class; - } - - public function processNode(Node $node, Scope $scope): array - { - $throwableType = new ObjectType(Throwable::class); - $typeResult = $this->ruleLevelHelper->findTypeToCheck( - $scope, - $node->expr, - 'Throwing object of an unknown class %s.', - static fn (Type $type): bool => $throwableType->isSuperTypeOf($type)->yes(), - ); - - $foundType = $typeResult->getType(); - if ($foundType instanceof ErrorType) { - return $typeResult->getUnknownClassErrors(); - } - - $isSuperType = $throwableType->isSuperTypeOf($foundType); - if ($isSuperType->yes()) { - return []; - } - - return [ - RuleErrorBuilder::message(sprintf( - 'Invalid type %s to throw.', - $foundType->describe(VerbosityLevel::typeOnly()), - ))->identifier('throw.notThrowable')->build(), - ]; - } - -} diff --git a/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php deleted file mode 100644 index 020f713708..0000000000 --- a/tests/PHPStan/Rules/Variables/ThrowTypeRuleTest.php +++ /dev/null @@ -1,70 +0,0 @@ - - */ -class ThrowTypeRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new ThrowTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); - } - - public function testRule(): void - { - $this->analyse( - [__DIR__ . '/data/throw-values.php'], - [ - [ - 'Invalid type int to throw.', - 29, - ], - [ - 'Invalid type ThrowValues\InvalidException to throw.', - 32, - ], - [ - 'Invalid type ThrowValues\InvalidInterfaceException to throw.', - 35, - ], - [ - 'Invalid type Exception|null to throw.', - 38, - ], - [ - 'Throwing object of an unknown class ThrowValues\NonexistentClass.', - 44, - 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ], - ], - ); - } - - public function testClassExists(): void - { - $this->analyse([__DIR__ . '/data/throw-class-exists.php'], []); - } - - public function testRuleWithNullsafeVariant(): void - { - if (PHP_VERSION_ID < 80000) { - $this->markTestSkipped('Test requires PHP 8.0.'); - } - - $this->analyse([__DIR__ . '/data/throw-values-nullsafe.php'], [ - [ - 'Invalid type Exception|null to throw.', - 17, - ], - ]); - } - -} diff --git a/tests/PHPStan/Rules/Variables/data/throw-class-exists.php b/tests/PHPStan/Rules/Variables/data/throw-class-exists.php deleted file mode 100644 index f819307398..0000000000 --- a/tests/PHPStan/Rules/Variables/data/throw-class-exists.php +++ /dev/null @@ -1,19 +0,0 @@ -= 8.0 - -namespace ThrowValuesNullsafe; - -class Bar -{ - - function doException(): \Exception - { - return new \Exception(); - } - -} - -function doFoo(?Bar $bar) -{ - throw $bar?->doException(); -} diff --git a/tests/PHPStan/Rules/Variables/data/throw-values.php b/tests/PHPStan/Rules/Variables/data/throw-values.php deleted file mode 100644 index 5582923fa2..0000000000 --- a/tests/PHPStan/Rules/Variables/data/throw-values.php +++ /dev/null @@ -1,62 +0,0 @@ - $genericExceptionClassName - * @param T $genericException - */ -function test($genericExceptionClassName, $genericException) { - /** @var ValidInterfaceException $validInterface */ - $validInterface = new \Exception(); - /** @var InvalidInterfaceException $invalidInterface */ - $invalidInterface = new \Exception(); - /** @var \Exception|null $nullableException */ - $nullableException = new \Exception(); - - if (rand(0, 1)) { - throw new \Exception(); - } - if (rand(0, 1)) { - throw $validInterface; - } - if (rand(0, 1)) { - throw 123; - } - if (rand(0, 1)) { - throw new InvalidException(); - } - if (rand(0, 1)) { - throw $invalidInterface; - } - if (rand(0, 1)) { - throw $nullableException; - } - if (rand(0, 1)) { - throw foo(); - } - if (rand(0, 1)) { - throw new NonexistentClass(); - } - if (rand(0, 1)) { - throw new $genericExceptionClassName; - } - if (rand(0, 1)) { - throw $genericException; - } -} - -function (\stdClass $foo) { - /** @var \Exception $foo */ - throw $foo; -}; - -function (\stdClass $foo) { - /** @var \Exception */ - throw $foo; -}; From 7f515bb1f27c16292ddaff3968df95b4c5be9885 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:07:57 +0100 Subject: [PATCH 14/47] Fix ThrowExpressionRule --- conf/config.neon | 5 ++++ src/Parser/StandaloneThrowExprVisitor.php | 28 ++++++++++++++++++++ src/Rules/Exceptions/ThrowExpressionRule.php | 5 ++++ 3 files changed, 38 insertions(+) create mode 100644 src/Parser/StandaloneThrowExprVisitor.php diff --git a/conf/config.neon b/conf/config.neon index dac1e96e5f..4558955396 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -372,6 +372,11 @@ services: tags: - phpstan.parser.richParserNodeVisitor + - + class: PHPStan\Parser\StandaloneThrowExprVisitor + tags: + - phpstan.parser.richParserNodeVisitor + - class: PHPStan\Parser\TryCatchTypeVisitor tags: diff --git a/src/Parser/StandaloneThrowExprVisitor.php b/src/Parser/StandaloneThrowExprVisitor.php new file mode 100644 index 0000000000..e108246128 --- /dev/null +++ b/src/Parser/StandaloneThrowExprVisitor.php @@ -0,0 +1,28 @@ +expr instanceof Node\Expr\Throw_) { + return null; + } + + $node->expr->setAttribute(self::ATTRIBUTE_NAME, true); + + return $node; + } + +} diff --git a/src/Rules/Exceptions/ThrowExpressionRule.php b/src/Rules/Exceptions/ThrowExpressionRule.php index 5d3c7c2576..9fcc9c9e88 100644 --- a/src/Rules/Exceptions/ThrowExpressionRule.php +++ b/src/Rules/Exceptions/ThrowExpressionRule.php @@ -4,6 +4,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Parser\StandaloneThrowExprVisitor; use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -29,6 +30,10 @@ public function processNode(Node $node, Scope $scope): array return []; } + if ($node->getAttribute(StandaloneThrowExprVisitor::ATTRIBUTE_NAME) === true) { + return []; + } + return [ RuleErrorBuilder::message('Throw expression is supported only on PHP 8.0 and later.')->nonIgnorable() ->identifier('throw.notSupported') From a23e389a4196b9ad24b902dae91e3e0ebfeb7c74 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:14:46 +0100 Subject: [PATCH 15/47] Fixes --- src/Analyser/MutatingScope.php | 10 ++++------ src/Analyser/NodeScopeResolver.php | 1 - src/Dependency/ExportedNodeResolver.php | 2 +- src/Reflection/InitializerExprTypeResolver.php | 8 ++++---- src/Rules/Namespaces/ExistingNamesInUseRule.php | 8 ++++---- src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php | 1 - src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php | 1 - src/Type/FileTypeMapper.php | 1 - 8 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 36eedbe816..c3f58e1c92 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -24,8 +24,6 @@ use PhpParser\Node\InterpolatedStringPart; use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Scalar\DNumber; -use PhpParser\Node\Scalar\LNumber; use PhpParser\Node\Scalar\String_; use PhpParser\NodeFinder; use PHPStan\Node\ExecutionEndNode; @@ -1125,7 +1123,7 @@ private function resolveType(string $exprString, Expr $node): Type return $this->getType($node->expr); } - if ($node instanceof LNumber) { + if ($node instanceof Node\Scalar\Int_) { return $this->initializerExprTypeResolver->getType($node, InitializerExprContext::fromScope($this)); } elseif ($node instanceof String_) { return $this->initializerExprTypeResolver->getType($node, InitializerExprContext::fromScope($this)); @@ -1149,7 +1147,7 @@ private function resolveType(string $exprString, Expr $node): Type } return $resultType ?? new ConstantStringType(''); - } elseif ($node instanceof DNumber) { + } elseif ($node instanceof Node\Scalar\Float_) { return $this->initializerExprTypeResolver->getType($node, InitializerExprContext::fromScope($this)); } elseif ($node instanceof Expr\CallLike && $node->isFirstClassCallable()) { if ($node instanceof FuncCall) { @@ -1707,10 +1705,10 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu } if ($node instanceof Expr\PreInc) { - return $this->getType(new BinaryOp\Plus($node->var, new LNumber(1))); + return $this->getType(new BinaryOp\Plus($node->var, new Node\Scalar\Int_(1))); } - return $this->getType(new BinaryOp\Minus($node->var, new LNumber(1))); + return $this->getType(new BinaryOp\Minus($node->var, new Node\Scalar\Int_(1))); } elseif ($node instanceof Expr\Yield_) { $functionReflection = $this->getFunction(); if ($functionReflection === null) { diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index e7b3a0abab..e11eeff70a 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -444,7 +444,6 @@ private function processStmtNode( && !$stmt instanceof Foreach_ && !$stmt instanceof Node\Stmt\Global_ && !$stmt instanceof Node\Stmt\Property - && !$stmt instanceof Node\Stmt\PropertyProperty && !$stmt instanceof Node\Stmt\ClassConst && !$stmt instanceof Node\Stmt\Const_ ) { diff --git a/src/Dependency/ExportedNodeResolver.php b/src/Dependency/ExportedNodeResolver.php index c9a0c52154..36a752735d 100644 --- a/src/Dependency/ExportedNodeResolver.php +++ b/src/Dependency/ExportedNodeResolver.php @@ -336,7 +336,7 @@ private function exportClassStatement(Node\Stmt $node, string $fileName, string $docComment = $node->getDocComment(); return new ExportedPropertiesNode( - array_map(static fn (Node\Stmt\PropertyProperty $prop): string => $prop->name->toString(), $node->props), + array_map(static fn (Node\PropertyItem $prop): string => $prop->name->toString(), $node->props), $this->exportPhpDocNode( $fileName, $namespacedName, diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 2f1aaa96a0..6013737759 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -11,8 +11,8 @@ use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Identifier; use PhpParser\Node\Name; -use PhpParser\Node\Scalar\DNumber; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\Float_; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Scalar\MagicConst; use PhpParser\Node\Scalar\MagicConst\Dir; use PhpParser\Node\Scalar\MagicConst\File; @@ -113,10 +113,10 @@ public function getType(Expr $expr, InitializerExprContext $context): Type if ($expr instanceof TypeExpr) { return $expr->getExprType(); } - if ($expr instanceof LNumber) { + if ($expr instanceof Int_) { return new ConstantIntegerType($expr->value); } - if ($expr instanceof DNumber) { + if ($expr instanceof Float_) { return new ConstantFloatType($expr->value); } if ($expr instanceof String_) { diff --git a/src/Rules/Namespaces/ExistingNamesInUseRule.php b/src/Rules/Namespaces/ExistingNamesInUseRule.php index 381a2e1de6..b93db1ea45 100644 --- a/src/Rules/Namespaces/ExistingNamesInUseRule.php +++ b/src/Rules/Namespaces/ExistingNamesInUseRule.php @@ -58,7 +58,7 @@ public function processNode(Node $node, Scope $scope): array } /** - * @param Node\Stmt\UseUse[] $uses + * @param Node\UseItem[] $uses * @return list */ private function checkConstants(array $uses): array @@ -80,7 +80,7 @@ private function checkConstants(array $uses): array } /** - * @param Node\Stmt\UseUse[] $uses + * @param Node\UseItem[] $uses * @return list */ private function checkFunctions(array $uses): array @@ -117,13 +117,13 @@ private function checkFunctions(array $uses): array } /** - * @param Node\Stmt\UseUse[] $uses + * @param Node\UseItem[] $uses * @return list */ private function checkClasses(array $uses): array { return $this->classCheck->checkClassNames( - array_map(static fn (Node\Stmt\UseUse $use): ClassNameNodePair => new ClassNameNodePair((string) $use->name, $use->name), $uses), + array_map(static fn (Node\UseItem $use): ClassNameNodePair => new ClassNameNodePair((string) $use->name, $use->name), $uses), ); } diff --git a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php index 4a227ffd07..81b4296100 100644 --- a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php +++ b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php @@ -48,7 +48,6 @@ public function processNode(Node $node, Scope $scope): array { if ( $node instanceof Node\Stmt\Property - || $node instanceof Node\Stmt\PropertyProperty || $node instanceof Node\Stmt\ClassConst || $node instanceof Node\Stmt\Const_ ) { diff --git a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php index b7021dfe92..5ff12a4206 100644 --- a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php +++ b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php @@ -51,7 +51,6 @@ public function processNode(Node $node, Scope $scope): array { if ( $node instanceof Node\Stmt\Property - || $node instanceof Node\Stmt\PropertyProperty || $node instanceof Node\Stmt\ClassConst || $node instanceof Node\Stmt\Const_ || ($node instanceof VirtualNode && !$node instanceof InFunctionNode && !$node instanceof InClassMethodNode && !$node instanceof InClassNode) diff --git a/src/Type/FileTypeMapper.php b/src/Type/FileTypeMapper.php index db5d8983f5..a0af548147 100644 --- a/src/Type/FileTypeMapper.php +++ b/src/Type/FileTypeMapper.php @@ -520,7 +520,6 @@ function (Node $node) use ($fileName, $lookForTrait, $phpDocNodeMap, &$traitFoun && !$node instanceof Node\Stmt\Namespace_ && !$node instanceof Node\Stmt\Declare_ && !$node instanceof Node\Stmt\Use_ - && !$node instanceof Node\Stmt\UseUse && !$node instanceof Node\Stmt\GroupUse && !$node instanceof Node\Stmt\TraitUse && !$node instanceof Node\Stmt\TraitUseAdaptation From 21bb404232b16d05774575989b75d9cf022bd234 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:26:02 +0100 Subject: [PATCH 16/47] ParserFactory to correctly create Php7/Php8 --- conf/config.neon | 6 +++++- src/Parser/PhpParserFactory.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/Parser/PhpParserFactory.php diff --git a/conf/config.neon b/conf/config.neon index 4558955396..d1b5182fe0 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -2050,7 +2050,11 @@ services: autowired: false currentPhpVersionPhpParser: - class: PhpParser\Parser\Php8 # todo use factory and create Php7/Php8 + factory: @currentPhpVersionPhpParserFactory::create() + autowired: false + + currentPhpVersionPhpParserFactory: + class: PHPStan\Parser\PhpParserFactory arguments: lexer: @currentPhpVersionLexer autowired: false diff --git a/src/Parser/PhpParserFactory.php b/src/Parser/PhpParserFactory.php new file mode 100644 index 0000000000..dee78b35d2 --- /dev/null +++ b/src/Parser/PhpParserFactory.php @@ -0,0 +1,28 @@ +phpVersion->getVersionString()); + if ($this->phpVersion->getVersionId() >= 80000) { + return new Php8($this->lexer, $phpVersion); + } + + return new Php7($this->lexer, $phpVersion); + } + +} From 5849a84320046edc7ea628f4dac14a28c1aa1644 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:31:15 +0100 Subject: [PATCH 17/47] This hack is no longer needed because there is now clear separation between Name and Identifier --- src/Type/TypehintHelper.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index 8f9f5616f3..dbfb14973a 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -16,7 +16,6 @@ use function get_class; use function is_string; use function sprintf; -use function str_ends_with; use function strtolower; final class TypehintHelper @@ -132,20 +131,6 @@ public static function decideTypeFromReflection( } $reflectionTypeString = $reflectionType->getName(); - $loweredReflectionTypeString = strtolower($reflectionTypeString); - if (str_ends_with($loweredReflectionTypeString, '\\object')) { - $reflectionTypeString = 'object'; - } elseif (str_ends_with($loweredReflectionTypeString, '\\mixed')) { - $reflectionTypeString = 'mixed'; - } elseif (str_ends_with($loweredReflectionTypeString, '\\true')) { - $reflectionTypeString = 'true'; - } elseif (str_ends_with($loweredReflectionTypeString, '\\false')) { - $reflectionTypeString = 'false'; - } elseif (str_ends_with($loweredReflectionTypeString, '\\null')) { - $reflectionTypeString = 'null'; - } elseif (str_ends_with($loweredReflectionTypeString, '\\never')) { - $reflectionTypeString = 'never'; - } $type = self::getTypeObjectFromTypehint($reflectionTypeString, $selfClass); if ($reflectionType->allowsNull()) { From 59747b60649322811fa6213541a413aa102c7b5f Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:39:24 +0100 Subject: [PATCH 18/47] Fix NeverRuleHelper --- src/Rules/Playground/NeverRuleHelper.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Rules/Playground/NeverRuleHelper.php b/src/Rules/Playground/NeverRuleHelper.php index 520b426424..9865d3d1ce 100644 --- a/src/Rules/Playground/NeverRuleHelper.php +++ b/src/Rules/Playground/NeverRuleHelper.php @@ -26,10 +26,17 @@ public function shouldReturnNever(ReturnStatementsNode $node, Type $returnType): $other = []; foreach ($node->getExecutionEnds() as $executionEnd) { if ($executionEnd->getStatementResult()->isAlwaysTerminating()) { - if (!$executionEnd->getNode() instanceof Node\Stmt\Throw_) { + $executionEndNode = $executionEnd->getNode(); + if (!$executionEndNode instanceof Node\Stmt\Expression) { $other[] = $executionEnd->getNode(); + continue; } + if ($executionEndNode->expr instanceof Node\Expr\Throw_) { + continue; + } + + $other[] = $executionEnd->getNode(); continue; } From d6983c008522fee2c183ccd898b06387e527fe49 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:41:45 +0100 Subject: [PATCH 19/47] Get rid of more Stmt\Throw_ instances --- src/Parser/LastConditionVisitor.php | 8 +++++++- .../Exceptions/OverwrittenExitPointByFinallyRule.php | 2 +- src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Parser/LastConditionVisitor.php b/src/Parser/LastConditionVisitor.php index d4c4b53ac3..d20a8f4b90 100644 --- a/src/Parser/LastConditionVisitor.php +++ b/src/Parser/LastConditionVisitor.php @@ -68,7 +68,13 @@ public function enterNode(Node $node): ?Node return null; } - if (!$statements[$statementCount - 1] instanceof Node\Stmt\Throw_) { + $lastStatement = $statements[$statementCount - 1]; + + if (!$lastStatement instanceof Node\Stmt\Expression) { + return null; + } + + if (!$lastStatement->expr instanceof Node\Expr\Throw_) { return null; } diff --git a/src/Rules/Exceptions/OverwrittenExitPointByFinallyRule.php b/src/Rules/Exceptions/OverwrittenExitPointByFinallyRule.php index f4a6e17499..74fa2eb0ae 100644 --- a/src/Rules/Exceptions/OverwrittenExitPointByFinallyRule.php +++ b/src/Rules/Exceptions/OverwrittenExitPointByFinallyRule.php @@ -51,7 +51,7 @@ private function describeExitPoint(Node\Stmt $stmt): string return 'return'; } - if ($stmt instanceof Node\Stmt\Throw_) { + if ($stmt instanceof Node\Stmt\Expression && $stmt->expr instanceof Node\Expr\Throw_) { return 'throw'; } diff --git a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php index 5ff12a4206..87784c71d6 100644 --- a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php +++ b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php @@ -89,10 +89,13 @@ public function processNode(Node $node, Scope $scope): array } if ($node instanceof Node\Stmt\Expression) { + if ($node->expr instanceof Expr\Throw_) { + return $this->processStmt($scope, $varTags, $node->expr); + } return $this->processExpression($scope, $node->expr, $varTags); } - if ($node instanceof Node\Stmt\Throw_ || $node instanceof Node\Stmt\Return_) { + if ($node instanceof Node\Stmt\Return_) { return $this->processStmt($scope, $varTags, $node->expr); } From 3884d2ebe3741e8620f3b3f4f585b1ec5f3493fb Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:44:34 +0100 Subject: [PATCH 20/47] Fixes --- src/Analyser/NodeScopeResolver.php | 4 ++-- src/Analyser/StatementResult.php | 10 +++++----- src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php | 4 ++-- src/Reflection/InitializerExprTypeResolver.php | 2 +- src/Rules/Arrays/ArrayDestructuringRule.php | 2 +- src/Rules/Classes/EnumSanityRule.php | 2 +- .../Comparison/DoWhileLoopConstantConditionRule.php | 4 ++-- .../Comparison/WhileLoopAlwaysTrueConditionRule.php | 4 ++-- src/Rules/Keywords/ContinueBreakInLoopRule.php | 2 +- src/Rules/Keywords/DeclareStrictTypesRule.php | 2 +- src/Rules/PhpDoc/VarTagTypeRuleHelper.php | 2 +- .../Php/ArraySumFunctionDynamicReturnTypeExtension.php | 4 ++-- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index e11eeff70a..a15060536b 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -494,7 +494,7 @@ private function processStmtNode( $nodeCallback($declare->value, $scope); if ( $declare->key->name !== 'strict_types' - || !($declare->value instanceof Node\Scalar\LNumber) + || !($declare->value instanceof Node\Scalar\Int_) || $declare->value->value !== 1 ) { continue; @@ -5298,7 +5298,7 @@ static function (): void { $impurePoints = array_merge($impurePoints, $valueResult->getImpurePoints()); if ($arrayItem->key === null) { - $dimExpr = new Node\Scalar\LNumber($i); + $dimExpr = new Node\Scalar\Int_($i); } else { $dimExpr = $arrayItem->key; } diff --git a/src/Analyser/StatementResult.php b/src/Analyser/StatementResult.php index bb9ae78f2e..985777317e 100644 --- a/src/Analyser/StatementResult.php +++ b/src/Analyser/StatementResult.php @@ -2,7 +2,7 @@ namespace PHPStan\Analyser; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Stmt; /** @@ -58,7 +58,7 @@ public function filterOutLoopExitPoints(): self } $num = $statement->num; - if (!$num instanceof LNumber) { + if (!$num instanceof Int_) { return new self($this->scope, $this->hasYield, false, $this->exitPoints, $this->throwPoints, $this->impurePoints); } @@ -99,7 +99,7 @@ public function getExitPointsByType(string $stmtClass): array continue; } - if (!$value instanceof LNumber) { + if (!$value instanceof Int_) { $exitPoints[] = $exitPoint; continue; } @@ -130,7 +130,7 @@ public function getExitPointsForOuterLoop(): array if ($statement->num === null) { continue; } - if (!$statement->num instanceof LNumber) { + if (!$statement->num instanceof Int_) { continue; } $value = $statement->num->value; @@ -140,7 +140,7 @@ public function getExitPointsForOuterLoop(): array $newNode = null; if ($value > 2) { - $newNode = new LNumber($value - 1); + $newNode = new Int_($value - 1); } if ($statement instanceof Stmt\Continue_) { $newStatement = new Stmt\Continue_($newNode); diff --git a/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php b/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php index 48722eeca5..b57afc5fba 100644 --- a/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php +++ b/src/Parser/RemoveUnusedCodeByPhpVersionIdVisitor.php @@ -77,7 +77,7 @@ public function enterNode(Node $node): ?Node private function getOperands(Node\Expr $left, Node\Expr $right): ?array { if ( - $left instanceof Node\Scalar\LNumber + $left instanceof Node\Scalar\Int_ && $right instanceof Node\Expr\ConstFetch && $right->name->toString() === 'PHP_VERSION_ID' ) { @@ -85,7 +85,7 @@ private function getOperands(Node\Expr $left, Node\Expr $right): ?array } if ( - $right instanceof Node\Scalar\LNumber + $right instanceof Node\Scalar\Int_ && $left instanceof Node\Expr\ConstFetch && $left->name->toString() === 'PHP_VERSION_ID' ) { diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 6013737759..174adae5c1 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -2044,7 +2044,7 @@ public function getUnaryMinusType(Expr $expr, callable $getTypeCallback): Type } if ($type instanceof IntegerRangeType) { - return $getTypeCallback(new Expr\BinaryOp\Mul($expr, new LNumber(-1))); + return $getTypeCallback(new Expr\BinaryOp\Mul($expr, new Int_(-1))); } return $type; diff --git a/src/Rules/Arrays/ArrayDestructuringRule.php b/src/Rules/Arrays/ArrayDestructuringRule.php index d8281b1d88..1d9537d274 100644 --- a/src/Rules/Arrays/ArrayDestructuringRule.php +++ b/src/Rules/Arrays/ArrayDestructuringRule.php @@ -85,7 +85,7 @@ private function getErrors(Scope $scope, Node\Expr\List_ $var, Expr $expr): arra $keyExpr = null; if ($item->key === null) { $keyType = new ConstantIntegerType($i); - $keyExpr = new Node\Scalar\LNumber($i); + $keyExpr = new Node\Scalar\Int_($i); } else { $keyType = $scope->getType($item->key); $keyExpr = new TypeExpr($keyType); diff --git a/src/Rules/Classes/EnumSanityRule.php b/src/Rules/Classes/EnumSanityRule.php index 2d193095d4..51c07fdfd8 100644 --- a/src/Rules/Classes/EnumSanityRule.php +++ b/src/Rules/Classes/EnumSanityRule.php @@ -143,7 +143,7 @@ public function processNode(Node $node, Scope $scope): array } $caseName = $stmt->name->name; - if ($stmt->expr instanceof Node\Scalar\LNumber || $stmt->expr instanceof Node\Scalar\String_) { + if ($stmt->expr instanceof Node\Scalar\Int_ || $stmt->expr instanceof Node\Scalar\String_) { if ($enumNode->scalarType === null) { $errors[] = RuleErrorBuilder::message(sprintf( 'Enum %s is not backed, but case %s has value %s.', diff --git a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php index 3777b5d6e5..4b43745923 100644 --- a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php +++ b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php @@ -3,7 +3,7 @@ namespace PHPStan\Rules\Comparison; use PhpParser\Node; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Stmt\Break_; use PhpParser\Node\Stmt\Continue_; use PHPStan\Analyser\Scope; @@ -47,7 +47,7 @@ public function processNode(Node $node, Scope $scope): array if ($statement->num === null) { continue; } - if (!$statement->num instanceof LNumber) { + if (!$statement->num instanceof Int_) { continue; } $value = $statement->num->value; diff --git a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php index 68ac27fbf2..505c57d7c6 100644 --- a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php +++ b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php @@ -3,7 +3,7 @@ namespace PHPStan\Rules\Comparison; use PhpParser\Node; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Stmt\Break_; use PhpParser\Node\Stmt\Continue_; use PHPStan\Analyser\Scope; @@ -46,7 +46,7 @@ public function processNode( if ($statement->num === null) { continue; } - if (!$statement->num instanceof LNumber) { + if (!$statement->num instanceof Int_) { continue; } $value = $statement->num->value; diff --git a/src/Rules/Keywords/ContinueBreakInLoopRule.php b/src/Rules/Keywords/ContinueBreakInLoopRule.php index d8e8b00fcb..75657f232f 100644 --- a/src/Rules/Keywords/ContinueBreakInLoopRule.php +++ b/src/Rules/Keywords/ContinueBreakInLoopRule.php @@ -28,7 +28,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!$node->num instanceof Node\Scalar\LNumber) { + if (!$node->num instanceof Node\Scalar\Int_) { $value = 1; } else { $value = $node->num->value; diff --git a/src/Rules/Keywords/DeclareStrictTypesRule.php b/src/Rules/Keywords/DeclareStrictTypesRule.php index b0b364030a..66aaa94026 100644 --- a/src/Rules/Keywords/DeclareStrictTypesRule.php +++ b/src/Rules/Keywords/DeclareStrictTypesRule.php @@ -40,7 +40,7 @@ public function processNode(Node $node, Scope $scope): array } if ( - !$declare->value instanceof Node\Scalar\LNumber + !$declare->value instanceof Node\Scalar\Int_ || !in_array($declare->value->value, [0, 1], true) ) { return [ diff --git a/src/Rules/PhpDoc/VarTagTypeRuleHelper.php b/src/Rules/PhpDoc/VarTagTypeRuleHelper.php index 0070554896..67bcd8f88a 100644 --- a/src/Rules/PhpDoc/VarTagTypeRuleHelper.php +++ b/src/Rules/PhpDoc/VarTagTypeRuleHelper.php @@ -53,7 +53,7 @@ public function checkVarType(Scope $scope, Node\Expr $var, Node\Expr $expr, arra continue; } if ($arrayItem->key === null) { - $dimExpr = new Node\Scalar\LNumber($i); + $dimExpr = new Node\Scalar\Int_($i); } else { $dimExpr = $arrayItem->key; } diff --git a/src/Type/Php/ArraySumFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ArraySumFunctionDynamicReturnTypeExtension.php index b60730e828..5185fbccc1 100644 --- a/src/Type/Php/ArraySumFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArraySumFunctionDynamicReturnTypeExtension.php @@ -5,7 +5,7 @@ use PhpParser\Node\Expr\BinaryOp\Mul; use PhpParser\Node\Expr\BinaryOp\Plus; use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\Int_; use PHPStan\Analyser\Scope; use PHPStan\Node\Expr\TypeExpr; use PHPStan\Reflection\FunctionReflection; @@ -35,7 +35,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if (count($argType->getConstantArrays()) > 0) { foreach ($argType->getConstantArrays() as $constantArray) { - $node = new LNumber(0); + $node = new Int_(0); foreach ($constantArray->getValueTypes() as $i => $type) { if ($constantArray->isOptionalKey($i)) { From 65368e3b705f2e237ae87e4d218b1bbc47ad3522 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 17:47:49 +0100 Subject: [PATCH 21/47] Fixes --- conf/config.neon | 1 - src/Parser/RichParser.php | 2 -- tests/PHPStan/Analyser/AnalyserTest.php | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/conf/config.neon b/conf/config.neon index d1b5182fe0..4d897a4587 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -2015,7 +2015,6 @@ services: class: PHPStan\Parser\RichParser arguments: parser: @currentPhpVersionPhpParser - lexer: @currentPhpVersionLexer enableIgnoreErrorsWithinPhpDocs: %featureToggles.enableIgnoreErrorsWithinPhpDocs% autowired: no diff --git a/src/Parser/RichParser.php b/src/Parser/RichParser.php index e3f2a5e310..ed0f1840a0 100644 --- a/src/Parser/RichParser.php +++ b/src/Parser/RichParser.php @@ -3,7 +3,6 @@ namespace PHPStan\Parser; use PhpParser\ErrorHandler\Collecting; -use PhpParser\Lexer; use PhpParser\Node; use PhpParser\NodeTraverser; use PhpParser\NodeVisitor\NameResolver; @@ -42,7 +41,6 @@ final class RichParser implements Parser public function __construct( private \PhpParser\Parser $parser, - private Lexer $lexer, private NameResolver $nameResolver, private Container $container, private IgnoreLexer $ignoreLexer, diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index f820c64aff..d59549b9da 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -745,13 +745,12 @@ private function createAnalyser(bool $enableIgnoreErrorsWithinPhpDocs): Analyser self::getContainer()->getParameter('featureToggles')['preciseMissingReturn'], self::getContainer()->getParameter('featureToggles')['explicitThrow'], ); - $lexer = new Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos']]); + $lexer = new Lexer(); $fileAnalyser = new FileAnalyser( $this->createScopeFactory($reflectionProvider, $typeSpecifier), $nodeScopeResolver, new RichParser( new Php7($lexer), - $lexer, new NameResolver(), self::getContainer(), new IgnoreLexer(), From 4178be18514f584210e1afe49806a8c4074a1180 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 20:38:56 +0100 Subject: [PATCH 22/47] Simplify TypehintHelper and use ParserNodeTypeToPHPStanType --- src/Type/TypehintHelper.php | 96 ++++++++----------------------------- 1 file changed, 19 insertions(+), 77 deletions(-) diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index dbfb14973a..5538370ccb 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -2,95 +2,25 @@ namespace PHPStan\Type; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name\FullyQualified; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionIntersectionType; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionNamedType; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionUnionType; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProviderStaticAccessor; use PHPStan\ShouldNotHappenException; -use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Generic\TemplateTypeHelper; -use ReflectionIntersectionType; -use ReflectionNamedType; use ReflectionType; -use ReflectionUnionType; use function array_map; use function count; use function get_class; use function is_string; use function sprintf; -use function strtolower; final class TypehintHelper { - private static function getTypeObjectFromTypehint(string $typeString, ClassReflection|string|null $selfClass): Type - { - switch (strtolower($typeString)) { - case 'int': - return new IntegerType(); - case 'bool': - return new BooleanType(); - case 'false': - return new ConstantBooleanType(false); - case 'true': - return new ConstantBooleanType(true); - case 'string': - return new StringType(); - case 'float': - return new FloatType(); - case 'array': - return new ArrayType(new MixedType(), new MixedType()); - case 'iterable': - return new IterableType(new MixedType(), new MixedType()); - case 'callable': - return new CallableType(); - case 'void': - return new VoidType(); - case 'object': - return new ObjectWithoutClassType(); - case 'mixed': - return new MixedType(true); - case 'self': - if ($selfClass instanceof ClassReflection) { - $selfClass = $selfClass->getName(); - } - return $selfClass !== null ? new ObjectType($selfClass) : new ErrorType(); - case 'parent': - $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); - if (is_string($selfClass)) { - if ($reflectionProvider->hasClass($selfClass)) { - $selfClass = $reflectionProvider->getClass($selfClass); - } else { - $selfClass = null; - } - } - if ($selfClass !== null) { - if ($selfClass->getParentClass() !== null) { - return new ObjectType($selfClass->getParentClass()->getName()); - } - } - return new NonexistentParentClassType(); - case 'static': - $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); - if (is_string($selfClass)) { - if ($reflectionProvider->hasClass($selfClass)) { - $selfClass = $reflectionProvider->getClass($selfClass); - } else { - $selfClass = null; - } - } - if ($selfClass !== null) { - return new StaticType($selfClass); - } - - return new ErrorType(); - case 'null': - return new NullType(); - case 'never': - return new NonAcceptingNeverType(); - default: - return new ObjectType($typeString); - } - } - /** @api */ public static function decideTypeFromReflection( ?ReflectionType $reflectionType, @@ -130,9 +60,21 @@ public static function decideTypeFromReflection( throw new ShouldNotHappenException(sprintf('Unexpected type: %s', get_class($reflectionType))); } - $reflectionTypeString = $reflectionType->getName(); + if ($reflectionType->isIdentifier()) { + $typeNode = new Identifier($reflectionType->getName()); + } else { + $typeNode = new FullyQualified($reflectionType->getName()); + } - $type = self::getTypeObjectFromTypehint($reflectionTypeString, $selfClass); + if (is_string($selfClass)) { + $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); + if ($reflectionProvider->hasClass($selfClass)) { + $selfClass = $reflectionProvider->getClass($selfClass); + } else { + $selfClass = null; + } + } + $type = ParserNodeTypeToPHPStanType::resolve($typeNode, $selfClass); if ($reflectionType->allowsNull()) { $type = TypeCombinator::addNull($type); } elseif ($phpDocType !== null) { From 58f630ed66d3049de76d162492203ae96db461f3 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Sat, 30 Dec 2023 20:58:53 +0100 Subject: [PATCH 23/47] Stub validator - always use latest PHP 8 parser --- conf/config.stubValidator.neon | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/conf/config.stubValidator.neon b/conf/config.stubValidator.neon index 1645698a92..ae22e5ccdc 100644 --- a/conf/config.stubValidator.neon +++ b/conf/config.stubValidator.neon @@ -13,7 +13,7 @@ services: arguments: php8Parser: @php8PhpParser - nodeScopeResolverClassReflector: + nodeScopeResolverReflector: factory: @stubReflector stubBetterReflectionProvider: @@ -38,3 +38,11 @@ services: factory: @stubBetterReflectionProvider autowired: - PHPStan\Reflection\ReflectionProvider + + currentPhpVersionLexer: + factory: @php8Lexer + autowired: false + + currentPhpVersionPhpParser: + factory: @php8PhpParser + autowired: false From 94c9bce7f609c74c0b23970055ed80f6675fc054 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 1 Jan 2024 14:31:39 +0100 Subject: [PATCH 24/47] Fix PHPStan errors --- phpstan-baseline.neon | 52 ++++--------------- src/Analyser/NodeScopeResolver.php | 5 +- src/Parser/PhpParserDecorator.php | 3 +- src/Type/Constant/OversizedArrayBuilder.php | 6 --- ...InArrayFunctionTypeSpecifyingExtension.php | 3 -- 5 files changed, 13 insertions(+), 56 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index cdbd956fa2..fbfeafa608 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -70,7 +70,7 @@ parameters: path: src/Analyser/NodeScopeResolver.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" count: 1 path: src/Analyser/NodeScopeResolver.php @@ -276,7 +276,7 @@ parameters: path: src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" count: 1 path: src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php @@ -286,17 +286,17 @@ parameters: path: src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" count: 1 path: src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" count: 1 path: src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" count: 2 path: src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php @@ -1799,43 +1799,6 @@ parameters: count: 1 path: tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php - - - message: """ - #^Instantiation of deprecated class PHPStan\\\\Rules\\\\DeadCode\\\\NoopRule\\: - Replaced by PHPStan\\\\Rules\\\\DeadCode\\\\BetterNoopRule$# - """ - count: 1 - path: tests/PHPStan/Rules/DeadCode/NoopRuleTest.php - - - - message: """ - #^Return type of method PHPStan\\\\Rules\\\\DeadCode\\\\NoopRuleTest\\:\\:getRule\\(\\) has typehint with deprecated class PHPStan\\\\Rules\\\\DeadCode\\\\NoopRule\\: - Replaced by PHPStan\\\\Rules\\\\DeadCode\\\\BetterNoopRule$# - """ - count: 1 - path: tests/PHPStan/Rules/DeadCode/NoopRuleTest.php - - - - message: """ - #^Instantiation of deprecated class PHPStan\\\\Rules\\\\Functions\\\\ImplodeFunctionRule\\: - Replaced by PHPStan\\\\Rules\\\\Functions\\\\ImplodeParameterCastableToStringRuleTest$# - """ - count: 1 - path: tests/PHPStan/Rules/Functions/ImplodeFunctionRuleTest.php - - - - message: """ - #^Return type of method PHPStan\\\\Rules\\\\Functions\\\\ImplodeFunctionRuleTest\\:\\:getRule\\(\\) has typehint with deprecated class PHPStan\\\\Rules\\\\Functions\\\\ImplodeFunctionRule\\: - Replaced by PHPStan\\\\Rules\\\\Functions\\\\ImplodeParameterCastableToStringRuleTest$# - """ - count: 1 - path: tests/PHPStan/Rules/Functions/ImplodeFunctionRuleTest.php - - - - message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Generic\\\\TemplateType is always PHPStan\\\\Type\\\\Generic\\\\TemplateMixedType but it's error\\-prone and dangerous\\.$#" - count: 1 - path: tests/PHPStan/Type/IterableTypeTest.php - - message: """ #^Instantiation of deprecated class PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRule\\: @@ -1851,3 +1814,8 @@ parameters: """ count: 1 path: tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php + + - + message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Generic\\\\TemplateType is always PHPStan\\\\Type\\\\Generic\\\\TemplateMixedType but it's error\\-prone and dangerous\\.$#" + count: 1 + path: tests/PHPStan/Type/IterableTypeTest.php diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index a15060536b..345a323d03 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1689,7 +1689,7 @@ private function processStmtNode( $finallyScope = $finallyScope->mergeWith($throwPoint->getScope()); } - if ($finallyScope !== null && $stmt->finally !== null) { + if ($finallyScope !== null) { $originalFinallyScope = $finallyScope; $finallyResult = $this->processStmtNodes($stmt->finally, $stmt->finally->stmts, $finallyScope, $nodeCallback, $context); $alwaysTerminating = $alwaysTerminating || $finallyResult->isAlwaysTerminating(); @@ -2973,9 +2973,6 @@ static function (): void { $impurePoints = []; foreach ($expr->items as $arrayItem) { $itemNodes[] = new LiteralArrayItem($scope, $arrayItem); - if ($arrayItem === null) { - continue; - } $nodeCallback($arrayItem, $scope); if ($arrayItem->key !== null) { $keyResult = $this->processExprNode($stmt, $arrayItem->key, $scope, $nodeCallback, $context->enterDeep()); diff --git a/src/Parser/PhpParserDecorator.php b/src/Parser/PhpParserDecorator.php index d4e00547a0..7481574450 100644 --- a/src/Parser/PhpParserDecorator.php +++ b/src/Parser/PhpParserDecorator.php @@ -6,6 +6,7 @@ use PhpParser\ErrorHandler; use PhpParser\Node; use PhpParser\Parser; +use PHPStan\ShouldNotHappenException; use function sprintf; final class PhpParserDecorator implements Parser @@ -33,7 +34,7 @@ public function parse(string $code, ?ErrorHandler $errorHandler = null): array public function getTokens(): array { - return $this->wrappedParser->getTokens(); + throw new ShouldNotHappenException('PhpParserDecorator::getTokens() should not be called'); } } diff --git a/src/Type/Constant/OversizedArrayBuilder.php b/src/Type/Constant/OversizedArrayBuilder.php index c365e0581f..e6ac71ded5 100644 --- a/src/Type/Constant/OversizedArrayBuilder.php +++ b/src/Type/Constant/OversizedArrayBuilder.php @@ -34,9 +34,6 @@ public function build(Array_ $expr, callable $getTypeCallback): Type $items = $expr->items; for ($i = 0; $i < count($items); $i++) { $item = $items[$i]; - if ($item === null) { - continue; - } if (!$item->unpack) { continue; } @@ -64,9 +61,6 @@ public function build(Array_ $expr, callable $getTypeCallback): Type } } foreach ($items as $item) { - if ($item === null) { - continue; - } if ($item->unpack) { throw new ShouldNotHappenException(); } diff --git a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php index df1bf3499a..1c4436ca46 100644 --- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php @@ -65,9 +65,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n if ($arrayExpr instanceof Array_) { $types = null; foreach ($arrayExpr->items as $item) { - if ($item === null) { - continue; - } if ($item->unpack) { $types = null; break; From e131739bba0e6c4cda06493b67125c9db4033e58 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Mon, 1 Jan 2024 14:42:54 +0100 Subject: [PATCH 25/47] Fix --- src/Analyser/MutatingScope.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index c3f58e1c92..b6a38997a8 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -1133,7 +1133,7 @@ private function resolveType(string $exprString, Expr $node): Type if ($part instanceof InterpolatedStringPart) { $partType = new ConstantStringType($part->value); } else { - $partType = $this->getType($part); + $partType = $this->getType($part)->toString(); } if ($resultType === null) { $resultType = $partType; From 8b462d257dec4022569482ca71df35dbde36cc1b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 09:39:07 +0200 Subject: [PATCH 26/47] Fix --- .../BetterReflection/SourceLocator/AutoloadSourceLocator.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php index 2edde64fbc..7506682426 100644 --- a/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php @@ -114,7 +114,6 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): 'startFilePos' => 1, 'endFilePos' => 4, ]), - null, new LocatedSource(' Date: Wed, 4 Sep 2024 11:16:22 +0200 Subject: [PATCH 27/47] Handle Block statement --- src/Analyser/NodeScopeResolver.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 345a323d03..0b7133e631 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1895,6 +1895,8 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $impurePoints = [ new ImpurePoint($scope, $stmt, 'betweenPhpTags', 'output between PHP opening and closing tags', true), ]; + } elseif ($stmt instanceof Node\Stmt\Block) { + return $this->processStmtNodes($stmt, $stmt->stmts, $scope, $nodeCallback, $context); } elseif ($stmt instanceof Node\Stmt\Nop) { $hasYield = false; $throwPoints = $overridingThrowPoints ?? []; From f13af95a882dea22a96b3199fcb9538e20e4c3c4 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 11:19:37 +0200 Subject: [PATCH 28/47] Fix standalone Throw_ expr handling --- src/Analyser/NodeScopeResolver.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 0b7133e631..f32e3345b7 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -791,6 +791,9 @@ private function processStmtNode( new StatementExitPoint($stmt, $scope), ], $overridingThrowPoints ?? $throwPoints, $impurePoints); } elseif ($stmt instanceof Node\Stmt\Expression) { + if ($stmt->expr instanceof Expr\Throw_) { + $scope = $stmtScope; + } $earlyTerminationExpr = $this->findEarlyTerminatingExpr($stmt->expr, $scope); $hasAssign = false; $currentScope = $scope; From a22ed83bf130197d80b38005cb4837959550d58e Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 11:36:07 +0200 Subject: [PATCH 29/47] Remove obsolete NoBleedingEdge tests --- .../CallMethodsRuleNoBleedingEdgeTest.php | 61 -------- .../PhpDoc/InvalidPHPStanDocTagRuleTest.php | 25 +-- ...idPhpDocTagValueRuleNoBleedingEdgeTest.php | 146 ------------------ .../PhpDoc/InvalidPhpDocTagValueRuleTest.php | 28 +--- ...gnedToPropertiesRuleNoBleedingEdgeTest.php | 50 ------ 5 files changed, 8 insertions(+), 302 deletions(-) delete mode 100644 tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php delete mode 100644 tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php delete mode 100644 tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php deleted file mode 100644 index 71678d99ff..0000000000 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleNoBleedingEdgeTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - */ -class CallMethodsRuleNoBleedingEdgeTest extends RuleTestCase -{ - - private bool $checkExplicitMixed; - - protected function getRule(): Rule - { - $reflectionProvider = $this->createReflectionProvider(); - $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, false, true, false); - return new CallMethodsRule( - new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), - new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion(PHP_VERSION_ID), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, false), - ); - } - - public function testGenericsInferCollection(): void - { - $this->checkExplicitMixed = true; - $this->analyse([__DIR__ . '/data/generics-infer-collection.php'], [ - [ - 'Parameter #1 $c of method GenericsInferCollection\Foo::doBar() expects GenericsInferCollection\ArrayCollection, GenericsInferCollection\ArrayCollection given.', - 43, - ], - ]); - } - - public function testGenericsInferCollectionLevel8(): void - { - $this->checkExplicitMixed = false; - $this->analyse([__DIR__ . '/data/generics-infer-collection.php'], [ - [ - 'Parameter #1 $c of method GenericsInferCollection\Foo::doBar() expects GenericsInferCollection\ArrayCollection, GenericsInferCollection\ArrayCollection given.', - 43, - ], - ]); - } - - public static function getAdditionalConfigFiles(): array - { - // no bleeding edge - return []; - } - -} diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php index 7995c696f4..e3e82da0ff 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php @@ -6,7 +6,6 @@ use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use function array_merge; /** * @extends RuleTestCase @@ -14,20 +13,18 @@ class InvalidPHPStanDocTagRuleTest extends RuleTestCase { - private bool $checkAllInvalidPhpDocs; - protected function getRule(): Rule { return new InvalidPHPStanDocTagRule( self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), - $this->checkAllInvalidPhpDocs, + true, ); } - public function dataRule(): iterable + public function testRule(): void { - $errors = [ + $this->analyse([__DIR__ . '/data/invalid-phpstan-doc.php'], [ [ 'Unknown PHPDoc tag: @phpstan-extens', 6, @@ -44,29 +41,15 @@ public function dataRule(): iterable 'Unknown PHPDoc tag: @phpstan-varr', 46, ], - ]; - yield [false, $errors]; - yield [true, array_merge($errors, [ [ 'Unknown PHPDoc tag: @phpstan-varr', 56, ], - ])]; - } - - /** - * @dataProvider dataRule - * @param list $expectedErrors - */ - public function testRule(bool $checkAllInvalidPhpDocs, array $expectedErrors): void - { - $this->checkAllInvalidPhpDocs = $checkAllInvalidPhpDocs; - $this->analyse([__DIR__ . '/data/invalid-phpstan-doc.php'], $expectedErrors); + ]); } public function testBug8697(): void { - $this->checkAllInvalidPhpDocs = true; $this->analyse([__DIR__ . '/data/bug-8697.php'], []); } diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php deleted file mode 100644 index b0bb271349..0000000000 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleNoBleedingEdgeTest.php +++ /dev/null @@ -1,146 +0,0 @@ - - */ -class InvalidPhpDocTagValueRuleNoBleedingEdgeTest extends RuleTestCase -{ - - private bool $checkAllInvalidPhpDocs; - - protected function getRule(): Rule - { - return new InvalidPhpDocTagValueRule( - self::getContainer()->getByType(Lexer::class), - self::getContainer()->getByType(PhpDocParser::class), - $this->checkAllInvalidPhpDocs, - false, - ); - } - - public function dataRule(): iterable - { - $errors = [ - [ - 'PHPDoc tag @param has invalid value (): Unexpected token "\n * ", expected type at offset 13', - 25, - ], - [ - 'PHPDoc tag @param has invalid value (A & B | C $paramNameA): Unexpected token "|", expected variable at offset 72', - 25, - ], - [ - 'PHPDoc tag @param has invalid value ((A & B $paramNameB): Unexpected token "$paramNameB", expected \')\' at offset 105', - 25, - ], - [ - 'PHPDoc tag @param has invalid value (~A & B $paramNameC): Unexpected token "~A", expected type at offset 127', - 25, - ], - [ - 'PHPDoc tag @var has invalid value (): Unexpected token "\n * ", expected type at offset 156', - 25, - ], - [ - 'PHPDoc tag @var has invalid value ($invalid): Unexpected token "$invalid", expected type at offset 165', - 25, - ], - [ - 'PHPDoc tag @var has invalid value ($invalid Foo): Unexpected token "$invalid", expected type at offset 182', - 25, - ], - [ - 'PHPDoc tag @return has invalid value (): Unexpected token "\n * ", expected type at offset 208', - 25, - ], - [ - 'PHPDoc tag @return has invalid value ([int, string]): Unexpected token "[", expected type at offset 220', - 25, - ], - [ - 'PHPDoc tag @return has invalid value (A & B | C): Unexpected token "|", expected TOKEN_OTHER at offset 251', - 25, - ], - [ - 'PHPDoc tag @var has invalid value (\\\Foo|\Bar $test): Unexpected token "\\\\\\\Foo|\\\Bar", expected type at offset 9', - 29, - ], - [ - 'PHPDoc tag @var has invalid value ((Foo|Bar): Unexpected token "*/", expected \')\' at offset 18', - 62, - ], - [ - 'PHPDoc tag @throws has invalid value ((\Exception): Unexpected token "*/", expected \')\' at offset 24', - 72, - ], - [ - 'PHPDoc tag @var has invalid value ((Foo|Bar): Unexpected token "*/", expected \')\' at offset 18', - 81, - ], - [ - 'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15', - 89, - ], - [ - 'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15', - 92, - ], - ]; - - yield [false, $errors]; - yield [true, array_merge($errors, [ - [ - 'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15', - 102, - ], - ])]; - } - - /** - * @dataProvider dataRule - * @param list $expectedErrors - */ - public function testRule(bool $checkAllInvalidPhpDocs, array $expectedErrors): void - { - $this->checkAllInvalidPhpDocs = $checkAllInvalidPhpDocs; - $this->analyse([__DIR__ . '/data/invalid-phpdoc.php'], $expectedErrors); - } - - public function testBug4731(): void - { - $this->checkAllInvalidPhpDocs = true; - $this->analyse([__DIR__ . '/data/bug-4731.php'], []); - } - - public function testBug4731WithoutFirstTag(): void - { - $this->checkAllInvalidPhpDocs = true; - $this->analyse([__DIR__ . '/data/bug-4731-no-first-tag.php'], []); - } - - public function testInvalidTypeInTypeAlias(): void - { - $this->checkAllInvalidPhpDocs = true; - $this->analyse([__DIR__ . '/data/invalid-type-type-alias.php'], [ - [ - 'PHPDoc tag @phpstan-type InvalidFoo has invalid value: Unexpected token "{", expected TOKEN_PHPDOC_EOL at offset 65', - 15, - ], - ]); - } - - public static function getAdditionalConfigFiles(): array - { - // reset bleedingEdge - return []; - } - -} diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php index c726559432..a82880302d 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php @@ -6,7 +6,6 @@ use PHPStan\PhpDocParser\Parser\PhpDocParser; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use function array_merge; /** * @extends RuleTestCase @@ -14,21 +13,19 @@ class InvalidPhpDocTagValueRuleTest extends RuleTestCase { - private bool $checkAllInvalidPhpDocs; - protected function getRule(): Rule { return new InvalidPhpDocTagValueRule( self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), - $this->checkAllInvalidPhpDocs, + true, true, ); } - public function dataRule(): iterable + public function testRule(): void { - $errors = [ + $this->analyse([__DIR__ . '/data/invalid-phpdoc.php'], [ [ 'PHPDoc tag @param has invalid value (): Unexpected token "\n * ", expected type at offset 13 on line 2', 6, @@ -97,42 +94,25 @@ public function dataRule(): iterable 'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15 on line 1', 91, ], - ]; - - yield [false, $errors]; - yield [true, array_merge($errors, [ [ 'PHPDoc tag @var has invalid value ((Foo&): Unexpected token "*/", expected type at offset 15 on line 1', 101, ], - ])]; - } - - /** - * @dataProvider dataRule - * @param list $expectedErrors - */ - public function testRule(bool $checkAllInvalidPhpDocs, array $expectedErrors): void - { - $this->checkAllInvalidPhpDocs = $checkAllInvalidPhpDocs; - $this->analyse([__DIR__ . '/data/invalid-phpdoc.php'], $expectedErrors); + ]); } public function testBug4731(): void { - $this->checkAllInvalidPhpDocs = true; $this->analyse([__DIR__ . '/data/bug-4731.php'], []); } public function testBug4731WithoutFirstTag(): void { - $this->checkAllInvalidPhpDocs = true; $this->analyse([__DIR__ . '/data/bug-4731-no-first-tag.php'], []); } public function testInvalidTypeInTypeAlias(): void { - $this->checkAllInvalidPhpDocs = true; $this->analyse([__DIR__ . '/data/invalid-type-type-alias.php'], [ [ 'PHPDoc tag @phpstan-type InvalidFoo has invalid value: Unexpected token "{", expected TOKEN_PHPDOC_EOL at offset 65 on line 3', diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php deleted file mode 100644 index 9b0aaf913d..0000000000 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleNoBleedingEdgeTest.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ -class TypesAssignedToPropertiesRuleNoBleedingEdgeTest extends RuleTestCase -{ - - private bool $checkExplicitMixed = false; - - protected function getRule(): Rule - { - return new TypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, true, false), new PropertyReflectionFinder()); - } - - public function testGenericObjectWithUnspecifiedTemplateTypes(): void - { - $this->checkExplicitMixed = true; - $this->analyse([__DIR__ . '/data/generic-object-unspecified-template-types.php'], [ - [ - 'Property GenericObjectUnspecifiedTemplateTypes\Bar::$ints (GenericObjectUnspecifiedTemplateTypes\ArrayCollection) does not accept GenericObjectUnspecifiedTemplateTypes\ArrayCollection.', - 67, - ], - ]); - } - - public function testGenericObjectWithUnspecifiedTemplateTypesLevel8(): void - { - $this->checkExplicitMixed = false; - $this->analyse([__DIR__ . '/data/generic-object-unspecified-template-types.php'], [ - [ - 'Property GenericObjectUnspecifiedTemplateTypes\Bar::$ints (GenericObjectUnspecifiedTemplateTypes\ArrayCollection) does not accept GenericObjectUnspecifiedTemplateTypes\ArrayCollection.', - 67, - ], - ]); - } - - public static function getAdditionalConfigFiles(): array - { - // no bleeding edge - return []; - } - -} From cbd3fd7dc4ba431f20f3e555d25d6033f1c03669 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 11:38:31 +0200 Subject: [PATCH 30/47] Fix detecting invalid PHPDocs --- conf/bleedingEdge.neon | 1 - conf/config.level2.neon | 3 -- conf/config.neon | 2 +- conf/parametersSchema.neon | 1 - src/PhpDoc/StubValidator.php | 13 +++----- src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php | 32 +++++-------------- .../PhpDoc/InvalidPhpDocTagValueRule.php | 32 +++++-------------- .../PhpDoc/InvalidPHPStanDocTagRuleTest.php | 1 - .../PhpDoc/InvalidPhpDocTagValueRuleTest.php | 1 - 9 files changed, 21 insertions(+), 65 deletions(-) diff --git a/conf/bleedingEdge.neon b/conf/bleedingEdge.neon index 8fb6e4da6a..12694539ae 100644 --- a/conf/bleedingEdge.neon +++ b/conf/bleedingEdge.neon @@ -39,7 +39,6 @@ parameters: newRuleLevelHelper: true instanceofType: true paramOutVariance: true - allInvalidPhpDocs: true strictStaticMethodTemplateTypeVariance: true propertyVariance: true genericPrototypeMessage: true diff --git a/conf/config.level2.neon b/conf/config.level2.neon index 1399394032..d7a7cc943b 100644 --- a/conf/config.level2.neon +++ b/conf/config.level2.neon @@ -146,7 +146,6 @@ services: - class: PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule arguments: - checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs% invalidPhpDocTagLine: %featureToggles.invalidPhpDocTagLine% tags: - phpstan.rules.rule @@ -159,8 +158,6 @@ services: - phpstan.rules.rule - class: PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule - arguments: - checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs% tags: - phpstan.rules.rule - diff --git a/conf/config.neon b/conf/config.neon index 4d897a4587..ae411edcca 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -74,7 +74,7 @@ parameters: newRuleLevelHelper: false instanceofType: false paramOutVariance: false - allInvalidPhpDocs: false + strictStaticMethodTemplateTypeVariance: false propertyVariance: false genericPrototypeMessage: false diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index 05d6d79f0c..8b986b0442 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -69,7 +69,6 @@ parametersSchema: newRuleLevelHelper: bool() instanceofType: bool() paramOutVariance: bool() - allInvalidPhpDocs: bool() strictStaticMethodTemplateTypeVariance: bool() propertyVariance: bool() genericPrototypeMessage: bool() diff --git a/src/PhpDoc/StubValidator.php b/src/PhpDoc/StubValidator.php index 43ecfdd0a5..7260542411 100644 --- a/src/PhpDoc/StubValidator.php +++ b/src/PhpDoc/StubValidator.php @@ -217,12 +217,15 @@ private function getRuleRegistry(Container $container): RuleRegistry new InvalidPhpDocTagValueRule( $container->getByType(Lexer::class), $container->getByType(PhpDocParser::class), - $container->getParameter('featureToggles')['allInvalidPhpDocs'], $container->getParameter('featureToggles')['invalidPhpDocTagLine'], ), new IncompatibleParamImmediatelyInvokedCallableRule($fileTypeMapper), new IncompatibleSelfOutTypeRule($unresolvableTypeHelper, $genericObjectTypeCheck), new IncompatibleClassConstantPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper), + new InvalidPHPStanDocTagRule( + $container->getByType(Lexer::class), + $container->getByType(PhpDocParser::class), + ), new InvalidThrowsPhpDocValueRule($fileTypeMapper), // level 6 @@ -240,14 +243,6 @@ private function getRuleRegistry(Container $container): RuleRegistry $rules[] = new DuplicateFunctionDeclarationRule($reflector, $relativePathHelper); } - if ((bool) $container->getParameter('featureToggles')['allInvalidPhpDocs']) { - $rules[] = new InvalidPHPStanDocTagRule( - $container->getByType(Lexer::class), - $container->getByType(PhpDocParser::class), - true, - ); - } - if ((bool) $container->getParameter('featureToggles')['absentTypeChecks']) { $rules[] = new MissingMethodSelfOutTypeRule($missingTypehintCheck); diff --git a/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php b/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php index 923d65e143..51b22dd564 100644 --- a/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php +++ b/src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php @@ -15,7 +15,7 @@ use function str_starts_with; /** - * @implements Rule + * @implements Rule */ final class InvalidPHPStanDocTagRule implements Rule { @@ -63,39 +63,23 @@ final class InvalidPHPStanDocTagRule implements Rule public function __construct( private Lexer $phpDocLexer, private PhpDocParser $phpDocParser, - private bool $checkAllInvalidPhpDocs, ) { } public function getNodeType(): string { - return Node::class; + return Node\Stmt::class; } public function processNode(Node $node, Scope $scope): array { - if (!$this->checkAllInvalidPhpDocs) { - if ( - !$node instanceof Node\Stmt\ClassLike - && !$node instanceof Node\FunctionLike - && !$node instanceof Node\Stmt\Foreach_ - && !$node instanceof Node\Stmt\Property - && !$node instanceof Node\Expr\Assign - && !$node instanceof Node\Expr\AssignRef - && !$node instanceof Node\Stmt\ClassConst - ) { - return []; - } - } else { - // mirrored with InvalidPhpDocTagValueRule - if ($node instanceof VirtualNode) { - return []; - } - if ($node instanceof Node\Stmt\Expression) { - return []; - } - if ($node instanceof Node\Expr && !$node instanceof Node\Expr\Assign && !$node instanceof Node\Expr\AssignRef) { + // mirrored with InvalidPhpDocTagValueRule + if ($node instanceof VirtualNode) { + return []; + } + if ($node instanceof Node\Stmt\Expression) { + if (!$node->expr instanceof Node\Expr\Assign && !$node->expr instanceof Node\Expr\AssignRef) { return []; } } diff --git a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php index fe40a1bd61..569c776df3 100644 --- a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php +++ b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php @@ -18,7 +18,7 @@ use function str_starts_with; /** - * @implements Rule + * @implements Rule */ final class InvalidPhpDocTagValueRule implements Rule { @@ -26,7 +26,6 @@ final class InvalidPhpDocTagValueRule implements Rule public function __construct( private Lexer $phpDocLexer, private PhpDocParser $phpDocParser, - private bool $checkAllInvalidPhpDocs, private bool $invalidPhpDocTagLine, ) { @@ -34,32 +33,17 @@ public function __construct( public function getNodeType(): string { - return Node::class; + return Node\Stmt::class; } public function processNode(Node $node, Scope $scope): array { - if (!$this->checkAllInvalidPhpDocs) { - if ( - !$node instanceof Node\Stmt\ClassLike - && !$node instanceof Node\FunctionLike - && !$node instanceof Node\Stmt\Foreach_ - && !$node instanceof Node\Stmt\Property - && !$node instanceof Node\Expr\Assign - && !$node instanceof Node\Expr\AssignRef - && !$node instanceof Node\Stmt\ClassConst - ) { - return []; - } - } else { - // mirrored with InvalidPHPStanDocTagRule - if ($node instanceof VirtualNode) { - return []; - } - if ($node instanceof Node\Stmt\Expression) { - return []; - } - if ($node instanceof Node\Expr && !$node instanceof Node\Expr\Assign && !$node instanceof Node\Expr\AssignRef) { + // mirrored with InvalidPHPStanDocTagRule + if ($node instanceof VirtualNode) { + return []; + } + if ($node instanceof Node\Stmt\Expression) { + if (!$node->expr instanceof Node\Expr\Assign && !$node->expr instanceof Node\Expr\AssignRef) { return []; } } diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php index e3e82da0ff..c664e1658a 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php @@ -18,7 +18,6 @@ protected function getRule(): Rule return new InvalidPHPStanDocTagRule( self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), - true, ); } diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php index a82880302d..542b38f13f 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php @@ -19,7 +19,6 @@ protected function getRule(): Rule self::getContainer()->getByType(Lexer::class), self::getContainer()->getByType(PhpDocParser::class), true, - true, ); } From 7d1fec93d96db7111080b89f3a178f045a2c066a Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 11:45:44 +0200 Subject: [PATCH 31/47] Fix minor change --- tests/PHPStan/Parser/RichParserTest.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/PHPStan/Parser/RichParserTest.php b/tests/PHPStan/Parser/RichParserTest.php index 103eb129b4..69fc99cbab 100644 --- a/tests/PHPStan/Parser/RichParserTest.php +++ b/tests/PHPStan/Parser/RichParserTest.php @@ -193,7 +193,17 @@ public function dataLinesToIgnore(): iterable PHP_EOL . '/** @phpstan-ignore test */' . PHP_EOL, [ - 3 => ['test'], + 4 => ['test'], + ], + ]; + + yield [ + ' ['test'], ], ]; From c7e9e3e1b78b370d69d5f334f586e1fb5dabddb7 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 12:48:43 +0200 Subject: [PATCH 32/47] Fix baseline --- phpstan-baseline.neon | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index fbfeafa608..7bbba41b08 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -70,7 +70,7 @@ parameters: path: src/Analyser/NodeScopeResolver.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" count: 1 path: src/Analyser/NodeScopeResolver.php @@ -276,7 +276,7 @@ parameters: path: src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" count: 1 path: src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php @@ -286,17 +286,17 @@ parameters: path: src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" count: 1 path: src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\ClassLike\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_ given\\.$#" count: 1 path: src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php - - message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Expression\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" + message: "#^Parameter \\#2 \\$node of method PHPStan\\\\BetterReflection\\\\SourceLocator\\\\Ast\\\\Strategy\\\\NodeToReflection\\:\\:__invoke\\(\\) expects PhpParser\\\\Node\\\\Expr\\\\ArrowFunction\\|PhpParser\\\\Node\\\\Expr\\\\Closure\\|PhpParser\\\\Node\\\\Expr\\\\FuncCall\\|PhpParser\\\\Node\\\\Stmt\\\\Class_\\|PhpParser\\\\Node\\\\Stmt\\\\Const_\\|PhpParser\\\\Node\\\\Stmt\\\\Enum_\\|PhpParser\\\\Node\\\\Stmt\\\\Function_\\|PhpParser\\\\Node\\\\Stmt\\\\Interface_\\|PhpParser\\\\Node\\\\Stmt\\\\Trait_, PhpParser\\\\Node\\\\Stmt\\\\ClassLike given\\.$#" count: 2 path: src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php From e2f0c7758d21892409544a20900c2f141c80a406 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:11:59 +0200 Subject: [PATCH 33/47] Preparing PHAR - fix php constraint --- compiler/src/Console/PrepareCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/Console/PrepareCommand.php b/compiler/src/Console/PrepareCommand.php index 7bef8b99db..6d23dde7a6 100644 --- a/compiler/src/Console/PrepareCommand.php +++ b/compiler/src/Console/PrepareCommand.php @@ -65,7 +65,7 @@ private function fixComposerJson(string $buildDir): void unset($json['replace']); $json['name'] = 'phpstan/phpstan'; - $json['require']['php'] = '^7.2|^8.0'; + $json['require']['php'] = '^7.4|^8.0'; // simplify autoload (remove not packed build directory] $json['autoload']['psr-4']['PHPStan\\'] = 'src/'; From 987009adf4464a848da181afcbb09a032f11e25e Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:16:03 +0200 Subject: [PATCH 34/47] Fix tests --- .../ExistingClassesInTypehintsRuleTest.php | 17 +++++---- .../ExistingClassesInTypehintsRuleTest.php | 36 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index 78415d4616..056740ed99 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -421,13 +421,18 @@ public function dataTrueTypes(): array ]; } - /** - * @dataProvider dataTrueTypes - * @param list $errors - */ - public function testTrueTypehint(int $phpVersion, array $errors): void + public function testTrueTypehint(): void { - $this->phpVersionId = $phpVersion; + if (PHP_VERSION_ID >= 80200) { + $errors = []; + } else { + $errors = [ + [ + 'Function NativeTrueType\alwaysTrue() has invalid return type NativeTrueType\true.', + 5, + ], + ]; + } $this->analyse([__DIR__ . '/data/true-typehint.php'], $errors); } diff --git a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php index b86302f453..df40cbac04 100644 --- a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php @@ -429,20 +429,30 @@ public function testEnums(): void ]); } - public function dataTrueTypes(): array + public function testTrueTypehint(): void { - return [ - [80200, []], - ]; - } - - /** - * @dataProvider dataTrueTypes - * @param list $errors - */ - public function testTrueTypehint(int $phpVersion, array $errors): void - { - $this->phpVersionId = $phpVersion; + if (PHP_VERSION_ID >= 80200) { + $errors = []; + } else { + $errors = [ + [ + 'Parameter $v of method NativeTrueType\Truthy::foo() has invalid type NativeTrueType\true.', + 10, + ], + [ + 'Method NativeTrueType\Truthy::foo() has invalid return type NativeTrueType\true.', + 10, + ], + [ + 'Parameter $trueUnion of method NativeTrueType\Truthy::trueUnion() has invalid type NativeTrueType\true.', + 14, + ], + [ + 'Method NativeTrueType\Truthy::trueUnionReturn() has invalid return type NativeTrueType\true.', + 31, + ], + ]; + } $this->analyse([__DIR__ . '/data/true-typehint.php'], $errors); } From 644dbbc6da31660ffa2a8c2c47dc71014a4055ed Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:35:21 +0200 Subject: [PATCH 35/47] Update PHPUnit --- .github/workflows/static-analysis.yml | 3 - .github/workflows/tests.yml | 4 - composer.json | 2 +- composer.lock | 270 ++++++++++++++------------ 4 files changed, 142 insertions(+), 137 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 24760de756..a0c08f6171 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -99,9 +99,6 @@ jobs: - name: "Install dependencies" run: "composer install --no-interaction --no-progress" - - name: "Update PHPUnit" - run: "composer update phpunit/phpunit -W" - - name: "Cache Result cache" uses: actions/cache@v4 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 75f5de1627..5533bd7e6a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,10 +65,6 @@ jobs: shell: bash run: "vendor/bin/simple-downgrade downgrade -c build/downgrade.php ${{ matrix.php-version }}" - - name: "Update PHPUnit" - if: matrix.php-version != '7.3' - run: "composer update phpunit/phpunit -W" - - name: "Tests" run: "make tests" diff --git a/composer.json b/composer.json index 7e859b19e4..64c143fd28 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "phpstan/phpstan-nette": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "^9.5.4", + "phpunit/phpunit": "^9.6", "shipmonk/composer-dependency-analyser": "^1.5", "shipmonk/name-collision-detector": "^2.0" }, diff --git a/composer.lock b/composer.lock index aba98b1475..6ef0c6b966 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6ecf16b4614aa87f10e85e795af26169", + "content-hash": "b0a75f027cffe40f37c639ade2ee9361", "packages": [ { "name": "clue/ndjson-react", @@ -4400,30 +4400,30 @@ }, { "name": "doctrine/instantiator", - "version": "1.4.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -4450,7 +4450,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -4466,7 +4466,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "jean85/pretty-package-versions", @@ -4529,16 +4529,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", "shasum": "" }, "require": { @@ -4546,11 +4546,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -4576,7 +4577,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" }, "funding": [ { @@ -4584,7 +4585,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2024-06-12T14:39:25+00:00" }, { "name": "ondrejmirtes/simple-downgrader", @@ -4637,20 +4638,21 @@ }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -4691,9 +4693,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -5018,35 +5026,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.30", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -5055,7 +5063,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -5084,7 +5092,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -5092,7 +5100,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5337,50 +5345,50 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.23", + "version": "9.6.20", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "888556852e7e9bbeeedb9656afe46118765ade34" + "reference": "49d7820565836236411f5dc002d16dd689cde42f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/888556852e7e9bbeeedb9656afe46118765ade34", - "reference": "888556852e7e9bbeeedb9656afe46118765ade34", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", + "reference": "49d7820565836236411f5dc002d16dd689cde42f", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.0", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -5388,7 +5396,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -5419,7 +5427,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.23" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" }, "funding": [ { @@ -5429,22 +5438,26 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2022-08-22T14:01:36+00:00" + "time": "2024-07-10T11:45:39+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -5479,7 +5492,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -5487,7 +5500,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -5602,16 +5615,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { @@ -5664,7 +5677,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" }, "funding": [ { @@ -5672,7 +5685,7 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { "name": "sebastian/complexity", @@ -5733,16 +5746,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -5787,7 +5800,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -5795,7 +5808,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -5862,16 +5875,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -5927,7 +5940,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -5935,20 +5948,20 @@ "type": "github" } ], - "time": "2021-11-11T14:18:36+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -5991,7 +6004,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -5999,7 +6012,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", @@ -6172,16 +6185,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { @@ -6220,10 +6233,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -6231,20 +6244,20 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -6256,7 +6269,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -6277,8 +6290,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -6286,20 +6298,20 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2024-03-14T16:00:52+00:00" }, { "name": "sebastian/type", - "version": "3.0.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", - "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { @@ -6311,7 +6323,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -6334,7 +6346,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.0.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -6342,7 +6354,7 @@ "type": "github" } ], - "time": "2022-03-15T09:54:48+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -6523,16 +6535,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -6561,7 +6573,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -6569,7 +6581,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], From 4ce29a785a4664697595d8d86167c5ec433b5d05 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:43:12 +0200 Subject: [PATCH 36/47] Fix anonymous class --- src/Reflection/BetterReflection/BetterReflectionProvider.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php index 6ae28ec9c6..54b26ec9f8 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProvider.php +++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php @@ -204,6 +204,7 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $ $scopeFile, ); $classNode->name = new Node\Identifier($className); + $classNode->namespacedName = null; if (isset(self::$anonymousClasses[$className])) { return self::$anonymousClasses[$className]; From b4c231be5e33f8abb19942fb58b8747129efab16 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:46:03 +0200 Subject: [PATCH 37/47] Fix RichParser --- src/Parser/RichParser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parser/RichParser.php b/src/Parser/RichParser.php index ed0f1840a0..14ade510c3 100644 --- a/src/Parser/RichParser.php +++ b/src/Parser/RichParser.php @@ -183,7 +183,7 @@ private function getLinesToIgnore(array $tokens): array $line++; } if ($isNextLine || $isCurrentLine) { - $line += substr_count($token[1], "\n"); + $line += substr_count($token->text, "\n"); $lines[$line] = null; continue; From 151896f5c5ec67fc57a0b544389a11ed7e4dcbaf Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:49:37 +0200 Subject: [PATCH 38/47] Fix --- tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php index 542b38f13f..405e3668a8 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php @@ -122,7 +122,6 @@ public function testInvalidTypeInTypeAlias(): void public function testIgnoreWithinPhpDoc(): void { - $this->checkAllInvalidPhpDocs = true; $this->analyse([__DIR__ . '/data/ignore-line-within-phpdoc.php'], []); } From 2f9c8d4e031b20b09d4a4bcfdb5c79e049667ff3 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:56:24 +0200 Subject: [PATCH 39/47] Fixes --- src/Analyser/NodeScopeResolver.php | 6 +----- src/Parser/PhpParserFactory.php | 2 +- src/Parser/StandaloneThrowExprVisitor.php | 2 +- src/Rules/ClassForbiddenNameCheck.php | 2 +- src/Rules/FunctionDefinitionCheck.php | 2 +- src/Rules/Names/UsedNamesRule.php | 9 ++++----- src/Rules/PhpDoc/PhpDocLineHelper.php | 2 +- src/Rules/Variables/ParameterOutExecutionEndTypeRule.php | 3 --- src/Testing/TypeInferenceTestCase.php | 4 ++-- src/Type/FileTypeMapper.php | 4 ---- 10 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index f32e3345b7..8a992f5c13 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1556,8 +1556,7 @@ private function processStmtNode( } $throwNode = $throwPoint->getNode(); if ( - !$throwNode instanceof Throw_ - && !$throwNode instanceof Expr\Throw_ + !$throwNode instanceof Expr\Throw_ && !($throwNode instanceof Node\Stmt\Expression && $throwNode->expr instanceof Expr\Throw_) ) { $onlyExplicitIsThrow = false; @@ -1858,9 +1857,6 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { if ($const->namespacedName !== null) { $constantName = new Name\FullyQualified($const->namespacedName->toString()); } else { - if ($const->name->toString() === '') { - throw new ShouldNotHappenException('Constant cannot have a empty name'); - } $constantName = new Name\FullyQualified($const->name->toString()); } $scope = $scope->assignExpression(new ConstFetch($constantName), $scope->getType($const->value), $scope->getNativeType($const->value)); diff --git a/src/Parser/PhpParserFactory.php b/src/Parser/PhpParserFactory.php index dee78b35d2..3a1f2cb4ea 100644 --- a/src/Parser/PhpParserFactory.php +++ b/src/Parser/PhpParserFactory.php @@ -8,7 +8,7 @@ use PhpParser\ParserAbstract; use PHPStan\Php\PhpVersion; -class PhpParserFactory +final class PhpParserFactory { public function __construct(private Lexer $lexer, private PhpVersion $phpVersion) diff --git a/src/Parser/StandaloneThrowExprVisitor.php b/src/Parser/StandaloneThrowExprVisitor.php index e108246128..772a3a1c43 100644 --- a/src/Parser/StandaloneThrowExprVisitor.php +++ b/src/Parser/StandaloneThrowExprVisitor.php @@ -5,7 +5,7 @@ use PhpParser\Node; use PhpParser\NodeVisitorAbstract; -class StandaloneThrowExprVisitor extends NodeVisitorAbstract +final class StandaloneThrowExprVisitor extends NodeVisitorAbstract { public const ATTRIBUTE_NAME = 'standaloneThrowExpr'; diff --git a/src/Rules/ClassForbiddenNameCheck.php b/src/Rules/ClassForbiddenNameCheck.php index c7658440ab..f1f9f032a3 100644 --- a/src/Rules/ClassForbiddenNameCheck.php +++ b/src/Rules/ClassForbiddenNameCheck.php @@ -73,7 +73,7 @@ public function checkClassNames(array $pairs): array $projectName, $className, )) - ->line($pair->getNode()->getLine()) + ->line($pair->getNode()->getStartLine()) ->identifier('class.prefixed') ->nonIgnorable(); diff --git a/src/Rules/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php index 19a76e042c..a9ea3ff521 100644 --- a/src/Rules/FunctionDefinitionCheck.php +++ b/src/Rules/FunctionDefinitionCheck.php @@ -204,7 +204,7 @@ public function checkAnonymousFunction( foreach ($returnType->getReferencedClasses() as $returnTypeClass) { if (!$this->reflectionProvider->hasClass($returnTypeClass)) { $errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $returnTypeClass)) - ->line($returnTypeNode->getLine()) + ->line($returnTypeNode->getStartLine()) ->identifier('class.notFound') ->build(); continue; diff --git a/src/Rules/Names/UsedNamesRule.php b/src/Rules/Names/UsedNamesRule.php index a1afbb742b..5462137e5d 100644 --- a/src/Rules/Names/UsedNamesRule.php +++ b/src/Rules/Names/UsedNamesRule.php @@ -10,7 +10,6 @@ use PhpParser\Node\Stmt\Namespace_; use PhpParser\Node\Stmt\Trait_; use PhpParser\Node\Stmt\Use_; -use PhpParser\Node\Stmt\UseUse; use PHPStan\Analyser\Scope; use PHPStan\Node\FileNode; use PHPStan\Rules\IdentifierRuleError; @@ -100,7 +99,7 @@ private function findErrorsForNode(Node $node, string $namespace, array &$usedNa $namespace !== '' ? $namespace . '\\' . $node->name->toString() : $node->name->toString(), )) ->identifier(sprintf('%s.nameInUse', $type)) - ->line($node->getLine()) + ->line($node->getStartLine()) ->nonIgnorable() ->build(), ]; @@ -113,7 +112,7 @@ private function findErrorsForNode(Node $node, string $namespace, array &$usedNa } /** - * @param UseUse[] $uses + * @param Node\UseItem[] $uses * @param array $usedNames * @return list */ @@ -132,7 +131,7 @@ private function findErrorsInUses(array $uses, string $useGroupPrefix, string $l $use->getAlias()->toString(), )) ->identifier('use.nameInUse') - ->line($use->getLine()) + ->line($use->getStartLine()) ->nonIgnorable() ->build(); continue; @@ -142,7 +141,7 @@ private function findErrorsInUses(array $uses, string $useGroupPrefix, string $l return $errors; } - private function shouldBeIgnored(Use_|GroupUse|UseUse $use): bool + private function shouldBeIgnored(Use_|GroupUse|Node\UseItem $use): bool { return in_array($use->type, [Use_::TYPE_FUNCTION, Use_::TYPE_CONSTANT], true); } diff --git a/src/Rules/PhpDoc/PhpDocLineHelper.php b/src/Rules/PhpDoc/PhpDocLineHelper.php index b008e63470..a7894f762f 100644 --- a/src/Rules/PhpDoc/PhpDocLineHelper.php +++ b/src/Rules/PhpDoc/PhpDocLineHelper.php @@ -19,7 +19,7 @@ public static function detectLine(PhpParserNode $node, PhpDocNode $phpDocNode): $phpDoc = $node->getDocComment(); if ($phpDocTagLine === null || $phpDoc === null) { - return $node->getLine(); + return $node->getStartLine(); } return $phpDoc->getStartLine() + $phpDocTagLine - 1; diff --git a/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php b/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php index 177079ac6c..9b42e1909e 100644 --- a/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php +++ b/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php @@ -57,9 +57,6 @@ public function processNode(Node $node, Scope $scope): array return []; } } - if ($endNode instanceof Node\Stmt\Throw_) { - return []; - } $variant = ParametersAcceptorSelector::selectSingle($inFunction->getVariants()); $parameters = $variant->getParameters(); diff --git a/src/Testing/TypeInferenceTestCase.php b/src/Testing/TypeInferenceTestCase.php index 4194d4f4d3..874b601156 100644 --- a/src/Testing/TypeInferenceTestCase.php +++ b/src/Testing/TypeInferenceTestCase.php @@ -178,7 +178,7 @@ public static function gatherAssertTypes(string $file): array 'Expected type must be a literal string, %s given in %s on line %d.', $expectedType->describe(VerbosityLevel::precise()), $relativePathHelper->getRelativePath($file), - $node->getLine(), + $node->getStartLine(), )); } $actualType = $scope->getType($node->getArgs()[1]->value); @@ -190,7 +190,7 @@ public static function gatherAssertTypes(string $file): array 'Expected type must be a literal string, %s given in %s on line %d.', $expectedType->describe(VerbosityLevel::precise()), $relativePathHelper->getRelativePath($file), - $node->getLine(), + $node->getStartLine(), )); } diff --git a/src/Type/FileTypeMapper.php b/src/Type/FileTypeMapper.php index a0af548147..9a14e3aec4 100644 --- a/src/Type/FileTypeMapper.php +++ b/src/Type/FileTypeMapper.php @@ -482,10 +482,6 @@ function (Node $node) use ($fileName, $lookForTrait, $phpDocNodeMap, &$traitFoun $functionName = $functionStack[count($functionStack) - 1] ?? null; $nameScopeKey = $this->getNameScopeKey($originalClassFileName, $className, $lookForTrait, $functionName); - if ($namespace === '') { - throw new ShouldNotHappenException('Namespace cannot be empty.'); - } - if ($node instanceof Node\Stmt\ClassLike || $node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Stmt\Function_) { if (array_key_exists($nameScopeKey, $phpDocNodeMap)) { $phpDocNode = $phpDocNodeMap[$nameScopeKey]; From a1ad4238ea5ae5cab1355d4b81b78490d70e978b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 13:56:51 +0200 Subject: [PATCH 40/47] Remove deprecated rule NoopRule --- conf/config.level4.neon | 7 -- src/Rules/DeadCode/NoopRule.php | 73 --------------- tests/PHPStan/Rules/DeadCode/NoopRuleTest.php | 93 ------------------- 3 files changed, 173 deletions(-) delete mode 100644 src/Rules/DeadCode/NoopRule.php delete mode 100644 tests/PHPStan/Rules/DeadCode/NoopRuleTest.php diff --git a/conf/config.level4.neon b/conf/config.level4.neon index 8f3ecc86bc..421cafcd9e 100644 --- a/conf/config.level4.neon +++ b/conf/config.level4.neon @@ -96,13 +96,6 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\DeadCode\NoopRule - arguments: - better: %featureToggles.betterNoop% - tags: - - phpstan.rules.rule - - class: PHPStan\Rules\DeadCode\CallToConstructorStatementWithoutImpurePointsRule diff --git a/src/Rules/DeadCode/NoopRule.php b/src/Rules/DeadCode/NoopRule.php deleted file mode 100644 index ff0d6eb8e7..0000000000 --- a/src/Rules/DeadCode/NoopRule.php +++ /dev/null @@ -1,73 +0,0 @@ - - */ -final class NoopRule implements Rule -{ - - public function __construct(private ExprPrinter $exprPrinter, private bool $better) - { - } - - public function getNodeType(): string - { - return Node\Stmt\Expression::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if ($this->better) { - // disabled in bleeding edge - return []; - } - $originalExpr = $node->expr; - $expr = $originalExpr; - if ( - $expr instanceof Node\Expr\Cast - || $expr instanceof Node\Expr\UnaryMinus - || $expr instanceof Node\Expr\UnaryPlus - || $expr instanceof Node\Expr\ErrorSuppress - ) { - $expr = $expr->expr; - } - - if (!$this->isNoopExpr($expr)) { - return []; - } - - return [ - RuleErrorBuilder::message(sprintf( - 'Expression "%s" on a separate line does not do anything.', - $this->exprPrinter->printExpr($originalExpr), - ))->line($expr->getStartLine()) - ->identifier('expr.resultUnused') - ->build(), - ]; - } - - public function isNoopExpr(Node\Expr $expr): bool - { - return $expr instanceof Node\Expr\Variable - || $expr instanceof Node\Expr\PropertyFetch - || $expr instanceof Node\Expr\StaticPropertyFetch - || $expr instanceof Node\Expr\NullsafePropertyFetch - || $expr instanceof Node\Expr\ArrayDimFetch - || $expr instanceof Node\Scalar - || $expr instanceof Node\Expr\Isset_ - || $expr instanceof Node\Expr\Empty_ - || $expr instanceof Node\Expr\ConstFetch - || $expr instanceof Node\Expr\ClassConstFetch; - } - -} diff --git a/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php deleted file mode 100644 index edffaa5b9a..0000000000 --- a/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -class NoopRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new NoopRule(new ExprPrinter(new Printer()), false); - } - - public function testRule(): void - { - $this->analyse([__DIR__ . '/data/noop.php'], [ - [ - 'Expression "$arr" on a separate line does not do anything.', - 9, - ], - [ - 'Expression "$arr[\'test\']" on a separate line does not do anything.', - 10, - ], - [ - 'Expression "$foo::$test" on a separate line does not do anything.', - 11, - ], - [ - 'Expression "$foo->test" on a separate line does not do anything.', - 12, - ], - [ - 'Expression "\'foo\'" on a separate line does not do anything.', - 14, - ], - [ - 'Expression "1" on a separate line does not do anything.', - 15, - ], - [ - 'Expression "@\'foo\'" on a separate line does not do anything.', - 17, - ], - [ - 'Expression "+1" on a separate line does not do anything.', - 18, - ], - [ - 'Expression "-1" on a separate line does not do anything.', - 19, - ], - [ - 'Expression "isset($test)" on a separate line does not do anything.', - 25, - ], - [ - 'Expression "empty($test)" on a separate line does not do anything.', - 26, - ], - [ - 'Expression "true" on a separate line does not do anything.', - 27, - ], - [ - 'Expression "\DeadCodeNoop\Foo::TEST" on a separate line does not do anything.', - 28, - ], - [ - 'Expression "(string) 1" on a separate line does not do anything.', - 30, - ], - ]); - } - - public function testNullsafe(): void - { - $this->analyse([__DIR__ . '/data/nullsafe-property-fetch-noop.php'], [ - [ - 'Expression "$ref?->name" on a separate line does not do anything.', - 10, - ], - ]); - } - -} From 29345c286888cc6a0563c5cda8c453c7e496e32b Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 14:01:09 +0200 Subject: [PATCH 41/47] Update BetterReflection --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 64c143fd28..e4e61cd532 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "nette/utils": "^3.2.5", "nikic/php-parser": "^5.1.0", "ondram/ci-detector": "^3.4.0", - "ondrejmirtes/better-reflection": "6.42.0.3", + "ondrejmirtes/better-reflection": "6.42.0.6", "phpstan/php-8-stubs": "0.3.101", "phpstan/phpdoc-parser": "1.30.0", "psr/http-message": "^1.1", diff --git a/composer.lock b/composer.lock index 6ef0c6b966..0aba247c22 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b0a75f027cffe40f37c639ade2ee9361", + "content-hash": "bba4725ca58df1d370b5aa291335076d", "packages": [ { "name": "clue/ndjson-react", @@ -2179,16 +2179,16 @@ }, { "name": "ondrejmirtes/better-reflection", - "version": "6.42.0.3", + "version": "6.42.0.6", "source": { "type": "git", "url": "https://github.com/ondrejmirtes/BetterReflection.git", - "reference": "bdb626a5e2fb52bfe3fec1d367a9c72e48550954" + "reference": "955eefa555a862d35c298c69042a176bb39f88e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/bdb626a5e2fb52bfe3fec1d367a9c72e48550954", - "reference": "bdb626a5e2fb52bfe3fec1d367a9c72e48550954", + "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/955eefa555a862d35c298c69042a176bb39f88e2", + "reference": "955eefa555a862d35c298c69042a176bb39f88e2", "shasum": "" }, "require": { @@ -2244,9 +2244,9 @@ ], "description": "Better Reflection - an improved code reflection API", "support": { - "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.42.0.3" + "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.42.0.6" }, - "time": "2024-09-04T11:06:34+00:00" + "time": "2024-09-04T11:59:59+00:00" }, { "name": "phpstan/php-8-stubs", From 0dcb5dcd0e7c9ffdb7f746ab6db57ab7fdbe72d5 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 14:07:14 +0200 Subject: [PATCH 42/47] Fix --- src/Parser/StandaloneThrowExprVisitor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parser/StandaloneThrowExprVisitor.php b/src/Parser/StandaloneThrowExprVisitor.php index 772a3a1c43..386c903281 100644 --- a/src/Parser/StandaloneThrowExprVisitor.php +++ b/src/Parser/StandaloneThrowExprVisitor.php @@ -10,7 +10,7 @@ final class StandaloneThrowExprVisitor extends NodeVisitorAbstract public const ATTRIBUTE_NAME = 'standaloneThrowExpr'; - public function enterNode(Node $node) + public function enterNode(Node $node): ?Node\Stmt\Expression { if (!$node instanceof Node\Stmt\Expression) { return null; From 88560b6fd2df30d60625767061fda87c48af354d Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 14:07:39 +0200 Subject: [PATCH 43/47] Remove deprecated rule ImplodeFunctionRule --- conf/config.level5.neon | 6 -- src/Rules/Functions/ImplodeFunctionRule.php | 84 ------------------- .../Functions/ImplodeFunctionRuleTest.php | 61 -------------- 3 files changed, 151 deletions(-) delete mode 100644 src/Rules/Functions/ImplodeFunctionRule.php delete mode 100644 tests/PHPStan/Rules/Functions/ImplodeFunctionRuleTest.php diff --git a/conf/config.level5.neon b/conf/config.level5.neon index 184cee83b8..470689b7c2 100644 --- a/conf/config.level5.neon +++ b/conf/config.level5.neon @@ -42,12 +42,6 @@ services: - class: PHPStan\Rules\Functions\CallUserFuncRule - - - class: PHPStan\Rules\Functions\ImplodeFunctionRule - arguments: - disabled: %featureToggles.checkParameterCastableToStringFunctions% - tags: - - phpstan.rules.rule - class: PHPStan\Rules\Functions\ParameterCastableToStringRule - diff --git a/src/Rules/Functions/ImplodeFunctionRule.php b/src/Rules/Functions/ImplodeFunctionRule.php deleted file mode 100644 index 93ade0dafc..0000000000 --- a/src/Rules/Functions/ImplodeFunctionRule.php +++ /dev/null @@ -1,84 +0,0 @@ - - */ -final class ImplodeFunctionRule implements Rule -{ - - public function __construct( - private ReflectionProvider $reflectionProvider, - private RuleLevelHelper $ruleLevelHelper, - private bool $disabled, - ) - { - } - - public function getNodeType(): string - { - return FuncCall::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if ($this->disabled) { - return []; - } - - if (!($node->name instanceof Node\Name)) { - return []; - } - - $functionName = $this->reflectionProvider->resolveFunctionName($node->name, $scope); - if (!in_array($functionName, ['implode', 'join'], true)) { - return []; - } - - $args = $node->getArgs(); - if (count($args) === 1) { - $arrayArg = $args[0]->value; - $paramNo = 1; - } elseif (count($args) === 2) { - $arrayArg = $args[1]->value; - $paramNo = 2; - } else { - return []; - } - - $typeResult = $this->ruleLevelHelper->findTypeToCheck( - $scope, - $arrayArg, - '', - static fn (Type $type): bool => !$type->getIterableValueType()->toString() instanceof ErrorType, - ); - - if ($typeResult->getType() instanceof ErrorType - || !$typeResult->getType()->getIterableValueType()->toString() instanceof ErrorType) { - return []; - } - - return [ - RuleErrorBuilder::message( - sprintf('Parameter #%d $array of function %s expects array, %s given.', $paramNo, $functionName, $typeResult->getType()->describe(VerbosityLevel::typeOnly())), - )->identifier('argument.type')->build(), - ]; - } - -} diff --git a/tests/PHPStan/Rules/Functions/ImplodeFunctionRuleTest.php b/tests/PHPStan/Rules/Functions/ImplodeFunctionRuleTest.php deleted file mode 100644 index 44755df63d..0000000000 --- a/tests/PHPStan/Rules/Functions/ImplodeFunctionRuleTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - */ -class ImplodeFunctionRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - $broker = $this->createReflectionProvider(); - return new ImplodeFunctionRule($broker, new RuleLevelHelper($broker, true, false, true, false, false, true, false), false); - } - - public function testFile(): void - { - $this->analyse([__DIR__ . '/data/implode.php'], [ - [ - 'Parameter #2 $array of function implode expects array, array|string> given.', - 9, - ], - [ - 'Parameter #1 $array of function implode expects array, array> given.', - 11, - ], - [ - 'Parameter #1 $array of function implode expects array, array> given.', - 12, - ], - [ - 'Parameter #1 $array of function implode expects array, array> given.', - 13, - ], - [ - 'Parameter #2 $array of function implode expects array, array> given.', - 15, - ], - [ - 'Parameter #2 $array of function join expects array, array> given.', - 16, - ], - ]); - } - - public function testBug6000(): void - { - $this->analyse([__DIR__ . '/../Arrays/data/bug-6000.php'], []); - } - - public function testBug8467a(): void - { - $this->analyse([__DIR__ . '/../Arrays/data/bug-8467a.php'], []); - } - -} From 069d6e98074677aacdd8c7f1e780889795dc0de9 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 14:16:04 +0200 Subject: [PATCH 44/47] Fix tests --- .../Functions/ArrowFunctionReturnTypeRuleTest.php | 13 ++++++++++++- ...ingClassesInArrowFunctionTypehintsRuleTest.php | 9 ++++++++- .../data/arrow-function-never-return.php | 15 +++++++++++++++ .../data/arrow-functions-return-type.php | 12 ------------ .../Rules/Playground/FunctionNeverRuleTest.php | 5 +++++ .../Rules/Playground/MethodNeverRuleTest.php | 5 +++++ 6 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php index bf46cd56a6..8e530c62aa 100644 --- a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php @@ -39,9 +39,20 @@ public function testRule(): void 'Anonymous function should return int but returns string.', 14, ], + + ]); + } + + public function testRuleNever(): void + { + if (PHP_VERSION_ID < 80100) { + self::markTestSkipped('Test requires PHP 8.1.'); + } + + $this->analyse([__DIR__ . '/data/arrow-function-never-return.php'], [ [ 'Anonymous function should never return but return statement found.', - 44, + 12, ], ]); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php index 2417944d1a..e670804dcd 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php @@ -289,7 +289,14 @@ public function testIntersectionTypes(int $phpVersion, array $errors): void public function testNever(): void { $errors = []; - if (PHP_VERSION_ID < 80200) { + if (PHP_VERSION_ID < 80100) { + $errors = [ + [ + 'Anonymous function has invalid return type ArrowFunctionNever\never.', + 6, + ], + ]; + } elseif (PHP_VERSION_ID < 80200) { $errors = [ [ 'Never return type in arrow function is supported only on PHP 8.2 and later.', diff --git a/tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php b/tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php new file mode 100644 index 0000000000..5a9641fb06 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php @@ -0,0 +1,15 @@ += 8.1 + +namespace ArrowFunctionNeverReturn; + +class Baz +{ + + public function doFoo(): void + { + $f = fn () => throw new \Exception(); + $g = fn (): never => throw new \Exception(); + $g = fn (): never => 1; + } + +} diff --git a/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php b/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php index 552bf901c6..4a18708fba 100644 --- a/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php +++ b/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php @@ -33,15 +33,3 @@ public function doBar(): void } static fn (int $value): iterable => yield $value; - -class Baz -{ - - public function doFoo(): void - { - $f = fn () => throw new \Exception(); - $g = fn (): never => throw new \Exception(); - $g = fn (): never => 1; - } - -} diff --git a/tests/PHPStan/Rules/Playground/FunctionNeverRuleTest.php b/tests/PHPStan/Rules/Playground/FunctionNeverRuleTest.php index a75b82f714..2f580113f5 100644 --- a/tests/PHPStan/Rules/Playground/FunctionNeverRuleTest.php +++ b/tests/PHPStan/Rules/Playground/FunctionNeverRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -18,6 +19,10 @@ protected function getRule(): Rule public function testRule(): void { + if (PHP_VERSION_ID < 80100) { + self::markTestSkipped('Test requires PHP 8.1 or greater.'); + } + $this->analyse([__DIR__ . '/data/function-never.php'], [ [ 'Function FunctionNever\doBar() always throws an exception, it should have return type "never".', diff --git a/tests/PHPStan/Rules/Playground/MethodNeverRuleTest.php b/tests/PHPStan/Rules/Playground/MethodNeverRuleTest.php index 583c6a5a5f..83e315479d 100644 --- a/tests/PHPStan/Rules/Playground/MethodNeverRuleTest.php +++ b/tests/PHPStan/Rules/Playground/MethodNeverRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -18,6 +19,10 @@ protected function getRule(): Rule public function testRule(): void { + if (PHP_VERSION_ID < 80100) { + self::markTestSkipped('Test requires PHP 8.1 or greater.'); + } + $this->analyse([__DIR__ . '/data/method-never.php'], [ [ 'Method MethodNever\Foo::doBar() always throws an exception, it should have return type "never".', From 02fab888ca7fafa28aa878bdccf1f2d9e9f8cec7 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 14:40:27 +0200 Subject: [PATCH 45/47] Skip `mixed` tests on PHP < 8.0 --- ...namicReturnTypeExtensionTypeInferenceTest.php | 2 +- .../Analyser/LegacyNodeScopeResolverTest.php | 2 +- tests/PHPStan/Analyser/nsrt/abs.php | 4 +++- tests/PHPStan/Analyser/nsrt/array-key-exists.php | 2 +- .../PHPStan/Analyser/nsrt/assert-conditional.php | 2 +- tests/PHPStan/Analyser/nsrt/assert-docblock.php | 2 +- tests/PHPStan/Analyser/nsrt/assert-empty.php | 2 +- .../PHPStan/Analyser/nsrt/assert-inheritance.php | 2 +- .../PHPStan/Analyser/nsrt/assert-intersected.php | 2 +- tests/PHPStan/Analyser/nsrt/assert-invariant.php | 4 +++- tests/PHPStan/Analyser/nsrt/bug-10037.php | 4 +++- tests/PHPStan/Analyser/nsrt/bug-10254.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-10473.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-6293.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-7141.php | 4 +++- tests/PHPStan/Analyser/nsrt/bug-7788.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-7944.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-8249.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-8803.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-9062.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-9086.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-9341.php | 4 +++- tests/PHPStan/Analyser/nsrt/bug-9472.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-9764.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-9867.php | 2 +- tests/PHPStan/Analyser/nsrt/class-implements.php | 2 +- .../nsrt/conditional-types-inference.php | 2 +- tests/PHPStan/Analyser/nsrt/ctype-digit.php | 4 +++- tests/PHPStan/Analyser/nsrt/enum_exists.php | 2 +- tests/PHPStan/Analyser/nsrt/falsy-isset.php | 2 +- .../PHPStan/Analyser/nsrt/filter-input-array.php | 4 +++- tests/PHPStan/Analyser/nsrt/filter-var-array.php | 2 +- .../PHPStan/Analyser/nsrt/generic-callables.php | 2 +- .../Analyser/nsrt/generic-method-tags.php | 2 +- tests/PHPStan/Analyser/nsrt/key-exists.php | 2 +- tests/PHPStan/Analyser/nsrt/mixed-typehint.php | 2 +- tests/PHPStan/Analyser/nsrt/offset-access.php | 2 +- tests/PHPStan/Reflection/MixedTypeTest.php | 5 +++++ .../Rules/Arrays/IterableInForeachRuleTest.php | 4 ++++ .../NonexistentOffsetInArrayDimFetchRuleTest.php | 4 ++++ .../Arrays/UnpackIterableInArrayRuleTest.php | 4 ++++ tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php | 4 ++++ .../ExistingClassInInstanceOfRuleTest.php | 5 +++++ .../ImpossibleCheckTypeFunctionCallRuleTest.php | 16 ++++++++++++++++ .../ImpossibleCheckTypeMethodCallRuleTest.php | 5 +++++ .../CallToFunctionParametersRuleTest.php | 12 ++++++++++++ ...ngClassesInArrowFunctionTypehintsRuleTest.php | 4 ++++ ...ExistingClassesInClosureTypehintsRuleTest.php | 4 ++++ .../Rules/Functions/ReturnTypeRuleTest.php | 4 ++++ .../Rules/Methods/CallMethodsRuleTest.php | 12 ++++++++++++ .../Rules/Methods/CallStaticMethodsRuleTest.php | 4 ++++ .../ExistingClassesInTypehintsRuleTest.php | 12 ++++++++++++ .../IncompatibleDefaultParameterTypeRuleTest.php | 5 +++++ .../Rules/Methods/OverridingMethodRuleTest.php | 4 ++++ .../Rules/Missing/MissingReturnRuleTest.php | 8 ++++++++ .../Operators/InvalidBinaryOperationRuleTest.php | 4 ++++ .../Operators/InvalidIncDecOperationRuleTest.php | 5 +++++ .../Operators/InvalidUnaryOperationRuleTest.php | 5 +++++ 58 files changed, 181 insertions(+), 37 deletions(-) diff --git a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php index 59ebef356e..c76ca0ebca 100644 --- a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php +++ b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php @@ -14,10 +14,10 @@ public function dataAsserts(): iterable if (PHP_VERSION_ID >= 80000) { yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-types-named-args.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-getsingle-conditional.php'); } yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-compound-types.php'); - yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-getsingle-conditional.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7344.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7391b.php'); } diff --git a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php index 1d17f9ee48..f75730744d 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -6431,7 +6431,7 @@ public function dataMisleadingTypes(): array '$foo->misleadingIntReturnType()', ], [ - 'mixed', + PHP_VERSION_ID >= 80000 ? 'mixed' : 'MisleadingTypes\mixed', '$foo->misleadingMixedReturnType()', ], ]; diff --git a/tests/PHPStan/Analyser/nsrt/abs.php b/tests/PHPStan/Analyser/nsrt/abs.php index eb644eb4bd..506f436c02 100644 --- a/tests/PHPStan/Analyser/nsrt/abs.php +++ b/tests/PHPStan/Analyser/nsrt/abs.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Abs; diff --git a/tests/PHPStan/Analyser/nsrt/array-key-exists.php b/tests/PHPStan/Analyser/nsrt/array-key-exists.php index ed6f552d15..17e49019c7 100644 --- a/tests/PHPStan/Analyser/nsrt/array-key-exists.php +++ b/tests/PHPStan/Analyser/nsrt/array-key-exists.php @@ -1,4 +1,4 @@ -= 8.0 namespace ArrayKeyExistsExtension; diff --git a/tests/PHPStan/Analyser/nsrt/assert-conditional.php b/tests/PHPStan/Analyser/nsrt/assert-conditional.php index 4e52490066..4a8567a2db 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-conditional.php +++ b/tests/PHPStan/Analyser/nsrt/assert-conditional.php @@ -1,4 +1,4 @@ -= 8.0 namespace AssertConditional; diff --git a/tests/PHPStan/Analyser/nsrt/assert-docblock.php b/tests/PHPStan/Analyser/nsrt/assert-docblock.php index 1b094a1cd7..b6391d651a 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-docblock.php +++ b/tests/PHPStan/Analyser/nsrt/assert-docblock.php @@ -1,4 +1,4 @@ -= 8.0 namespace AssertDocblock; diff --git a/tests/PHPStan/Analyser/nsrt/assert-empty.php b/tests/PHPStan/Analyser/nsrt/assert-empty.php index 12176791a3..73f15aade7 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-empty.php +++ b/tests/PHPStan/Analyser/nsrt/assert-empty.php @@ -1,4 +1,4 @@ -= 8.0 namespace AssertEmpty; diff --git a/tests/PHPStan/Analyser/nsrt/assert-inheritance.php b/tests/PHPStan/Analyser/nsrt/assert-inheritance.php index b9b362172e..ffc9552321 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-inheritance.php +++ b/tests/PHPStan/Analyser/nsrt/assert-inheritance.php @@ -1,4 +1,4 @@ -= 8.0 namespace AssertInheritance; diff --git a/tests/PHPStan/Analyser/nsrt/assert-intersected.php b/tests/PHPStan/Analyser/nsrt/assert-intersected.php index a39ffe1436..17aa63957a 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-intersected.php +++ b/tests/PHPStan/Analyser/nsrt/assert-intersected.php @@ -1,4 +1,4 @@ -= 8.0 namespace AssertIntersected; diff --git a/tests/PHPStan/Analyser/nsrt/assert-invariant.php b/tests/PHPStan/Analyser/nsrt/assert-invariant.php index b7368f06e9..4efe160b18 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-invariant.php +++ b/tests/PHPStan/Analyser/nsrt/assert-invariant.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace AssertInvariant; diff --git a/tests/PHPStan/Analyser/nsrt/bug-10037.php b/tests/PHPStan/Analyser/nsrt/bug-10037.php index 58adb961c1..56c49c331b 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10037.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10037.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Bug10037; diff --git a/tests/PHPStan/Analyser/nsrt/bug-10254.php b/tests/PHPStan/Analyser/nsrt/bug-10254.php index 3299015ca0..a16ed81f04 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10254.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10254.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug10254; diff --git a/tests/PHPStan/Analyser/nsrt/bug-10473.php b/tests/PHPStan/Analyser/nsrt/bug-10473.php index d07a7f6804..bad001bea0 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10473.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10473.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug10473; diff --git a/tests/PHPStan/Analyser/nsrt/bug-6293.php b/tests/PHPStan/Analyser/nsrt/bug-6293.php index 0a5c8548be..993f7b470e 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-6293.php +++ b/tests/PHPStan/Analyser/nsrt/bug-6293.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug6239; diff --git a/tests/PHPStan/Analyser/nsrt/bug-7141.php b/tests/PHPStan/Analyser/nsrt/bug-7141.php index 277b00d9e6..2cf34a5733 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7141.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7141.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Bug7141; diff --git a/tests/PHPStan/Analyser/nsrt/bug-7788.php b/tests/PHPStan/Analyser/nsrt/bug-7788.php index 944d10e7e4..fa5c6a73af 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7788.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7788.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug7788; diff --git a/tests/PHPStan/Analyser/nsrt/bug-7944.php b/tests/PHPStan/Analyser/nsrt/bug-7944.php index 737ab3dcb8..0d219b40b3 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7944.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7944.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug7944; diff --git a/tests/PHPStan/Analyser/nsrt/bug-8249.php b/tests/PHPStan/Analyser/nsrt/bug-8249.php index 960126723d..46964dc0ad 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-8249.php +++ b/tests/PHPStan/Analyser/nsrt/bug-8249.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug8249; diff --git a/tests/PHPStan/Analyser/nsrt/bug-8803.php b/tests/PHPStan/Analyser/nsrt/bug-8803.php index a1d9ad568b..88af4df14d 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-8803.php +++ b/tests/PHPStan/Analyser/nsrt/bug-8803.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug8803; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9062.php b/tests/PHPStan/Analyser/nsrt/bug-9062.php index a4c8cc6251..7280c8634c 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9062.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9062.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug9062; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9086.php b/tests/PHPStan/Analyser/nsrt/bug-9086.php index db0110f2f4..e099f4eec1 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9086.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9086.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug9086; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9341.php b/tests/PHPStan/Analyser/nsrt/bug-9341.php index 2c1a90f5bd..3265c4a7b0 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9341.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9341.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Bug9341; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9472.php b/tests/PHPStan/Analyser/nsrt/bug-9472.php index 923c0534e6..e81f67b7ea 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9472.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9472.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug9472; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9764.php b/tests/PHPStan/Analyser/nsrt/bug-9764.php index 15807d0b1e..f24b810fe8 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9764.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9764.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug9764; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9867.php b/tests/PHPStan/Analyser/nsrt/bug-9867.php index 7c677aa8d6..6ab9515b87 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9867.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9867.php @@ -1,4 +1,4 @@ -= 8.0 declare(strict_types=1); diff --git a/tests/PHPStan/Analyser/nsrt/class-implements.php b/tests/PHPStan/Analyser/nsrt/class-implements.php index acd6a616ae..316c8e8ed4 100644 --- a/tests/PHPStan/Analyser/nsrt/class-implements.php +++ b/tests/PHPStan/Analyser/nsrt/class-implements.php @@ -1,4 +1,4 @@ -= 8.0 namespace ClassImplements; diff --git a/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php b/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php index 55335c6e2e..89bfa50a22 100644 --- a/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php +++ b/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php @@ -1,4 +1,4 @@ -= 8.0 namespace ConditionalTypesInference; diff --git a/tests/PHPStan/Analyser/nsrt/ctype-digit.php b/tests/PHPStan/Analyser/nsrt/ctype-digit.php index 835ba4fdcc..00a803d52d 100644 --- a/tests/PHPStan/Analyser/nsrt/ctype-digit.php +++ b/tests/PHPStan/Analyser/nsrt/ctype-digit.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types=1); namespace CtypeDigit; diff --git a/tests/PHPStan/Analyser/nsrt/enum_exists.php b/tests/PHPStan/Analyser/nsrt/enum_exists.php index 33f1200924..37809016ad 100644 --- a/tests/PHPStan/Analyser/nsrt/enum_exists.php +++ b/tests/PHPStan/Analyser/nsrt/enum_exists.php @@ -1,4 +1,4 @@ -= 8.0 namespace EnumExists; diff --git a/tests/PHPStan/Analyser/nsrt/falsy-isset.php b/tests/PHPStan/Analyser/nsrt/falsy-isset.php index bce229826a..eb11c5254d 100644 --- a/tests/PHPStan/Analyser/nsrt/falsy-isset.php +++ b/tests/PHPStan/Analyser/nsrt/falsy-isset.php @@ -1,4 +1,4 @@ -= 8.0 namespace FalsyIsset; diff --git a/tests/PHPStan/Analyser/nsrt/filter-input-array.php b/tests/PHPStan/Analyser/nsrt/filter-input-array.php index 706a300680..d773c237f8 100644 --- a/tests/PHPStan/Analyser/nsrt/filter-input-array.php +++ b/tests/PHPStan/Analyser/nsrt/filter-input-array.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types=1); namespace FilterVarArray; diff --git a/tests/PHPStan/Analyser/nsrt/filter-var-array.php b/tests/PHPStan/Analyser/nsrt/filter-var-array.php index 52261b0e8a..38db914722 100644 --- a/tests/PHPStan/Analyser/nsrt/filter-var-array.php +++ b/tests/PHPStan/Analyser/nsrt/filter-var-array.php @@ -1,4 +1,4 @@ -= 8.0 namespace FilterVarArray; diff --git a/tests/PHPStan/Analyser/nsrt/generic-callables.php b/tests/PHPStan/Analyser/nsrt/generic-callables.php index 94bb3238a2..9fde822894 100644 --- a/tests/PHPStan/Analyser/nsrt/generic-callables.php +++ b/tests/PHPStan/Analyser/nsrt/generic-callables.php @@ -1,4 +1,4 @@ -= 8.0 namespace GenericCallables; diff --git a/tests/PHPStan/Analyser/nsrt/generic-method-tags.php b/tests/PHPStan/Analyser/nsrt/generic-method-tags.php index 92fdfaef5c..0aab6ea591 100644 --- a/tests/PHPStan/Analyser/nsrt/generic-method-tags.php +++ b/tests/PHPStan/Analyser/nsrt/generic-method-tags.php @@ -1,4 +1,4 @@ -= 8.0 namespace GenericMethodTags; diff --git a/tests/PHPStan/Analyser/nsrt/key-exists.php b/tests/PHPStan/Analyser/nsrt/key-exists.php index 11c2ed6a2a..0c98f24b2b 100644 --- a/tests/PHPStan/Analyser/nsrt/key-exists.php +++ b/tests/PHPStan/Analyser/nsrt/key-exists.php @@ -1,4 +1,4 @@ -= 8.0 namespace KeyExists; diff --git a/tests/PHPStan/Analyser/nsrt/mixed-typehint.php b/tests/PHPStan/Analyser/nsrt/mixed-typehint.php index 8d7ce4ad16..5b3c17cbb1 100644 --- a/tests/PHPStan/Analyser/nsrt/mixed-typehint.php +++ b/tests/PHPStan/Analyser/nsrt/mixed-typehint.php @@ -1,4 +1,4 @@ -= 8.0 namespace MixedTypehint; diff --git a/tests/PHPStan/Analyser/nsrt/offset-access.php b/tests/PHPStan/Analyser/nsrt/offset-access.php index 505557b452..593dd799ab 100644 --- a/tests/PHPStan/Analyser/nsrt/offset-access.php +++ b/tests/PHPStan/Analyser/nsrt/offset-access.php @@ -1,4 +1,4 @@ -= 8.0 namespace OffsetAccess; diff --git a/tests/PHPStan/Reflection/MixedTypeTest.php b/tests/PHPStan/Reflection/MixedTypeTest.php index f6c511df33..869f3c2bf8 100644 --- a/tests/PHPStan/Reflection/MixedTypeTest.php +++ b/tests/PHPStan/Reflection/MixedTypeTest.php @@ -6,12 +6,17 @@ use PhpParser\Node\Name; use PHPStan\Testing\PHPStanTestCase; use PHPStan\Type\MixedType; +use const PHP_VERSION_ID; class MixedTypeTest extends PHPStanTestCase { public function testMixedType(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $reflectionProvider = $this->createReflectionProvider(); $class = $reflectionProvider->getClass(Foo::class); $propertyType = $class->getNativeProperty('fooProp')->getNativeType(); diff --git a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php index dbb64b29ca..31407e99be 100644 --- a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php @@ -135,6 +135,10 @@ public function dataMixed(): array */ public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = $checkExplicitMixed; $this->checkImplicitMixed = $checkImplicitMixed; $this->analyse([__DIR__ . '/data/foreach-mixed.php'], $errors); diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php index ffc6aa26d5..bde2d1100e 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -762,6 +762,10 @@ public function testBug10926(): void public function testMixed(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = true; $this->checkImplicitMixed = true; $this->analyse([__DIR__ . '/data/offset-access-mixed.php'], [ diff --git a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php index 32d4900686..c7de4bc7bf 100644 --- a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php @@ -107,6 +107,10 @@ public function dataMixed(): array */ public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = $checkExplicitMixed; $this->checkImplicitMixed = $checkImplicitMixed; $this->analyse([__DIR__ . '/data/unpack-mixed.php'], $errors); diff --git a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php index 5734b47928..bc7cd35acb 100644 --- a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php +++ b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php @@ -163,6 +163,10 @@ public function dataMixed(): array */ public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkImplicitMixed = $checkImplicitMixed; $this->checkExplicitMixed = $checkExplicitMixed; $this->analyse([__DIR__ . '/data/mixed-cast.php'], $errors); diff --git a/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php index 4018d2ca62..0e6d0b066f 100644 --- a/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php @@ -7,6 +7,7 @@ use PHPStan\Rules\ClassNameCheck; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -67,6 +68,10 @@ public function testClassExists(): void public function testBug7720(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-7720.php'], [ [ 'Instanceof between mixed and trait Bug7720\FooBar will always evaluate to false.', diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index 88d9315d84..38d61a57dd 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -46,6 +46,10 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testImpossibleCheckTypeFunctionCall(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse( @@ -274,6 +278,10 @@ public function testBug7898(): void public function testImpossibleCheckTypeFunctionCallWithoutAlwaysTrue(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkAlwaysTrueCheckTypeFunctionCall = false; $this->treatPhpDocTypesAsCertain = true; $this->analyse( @@ -610,6 +618,10 @@ public function testBug7079(): void public function testConditionalTypesInference(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/conditional-types-inference.php'], [ @@ -645,6 +657,10 @@ public function testBug6697(): void public function testBug6443(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6443.php'], []); diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php index 7a697e6ffa..6504b21a6a 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -199,6 +200,10 @@ public function testReportPhpDoc(): void public function testBug8169(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-8169.php'], [ [ diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index d49987e3c5..174f8ece4a 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -1417,6 +1417,10 @@ public function testBug2508(): void public function testBug6175(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-6175.php'], []); } @@ -1600,6 +1604,10 @@ public function testBug9580(): void public function testBug7283(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-7283.php'], []); } @@ -1670,6 +1678,10 @@ public function testParamClosureThis(): void public function testBug10297(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-10297.php'], []); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php index e670804dcd..a409df4391 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php @@ -243,6 +243,10 @@ public function dataRequiredParameterAfterOptional(): array */ public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->phpVersionId = $phpVersionId; $this->analyse([__DIR__ . '/data/required-parameter-after-optional-arrow.php'], $errors); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php index 86f8725573..9b1c1c329d 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php @@ -287,6 +287,10 @@ public function dataRequiredParameterAfterOptional(): array */ public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->phpVersionId = $phpVersionId; $this->analyse([__DIR__ . '/data/required-parameter-after-optional-closures.php'], $errors); } diff --git a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php index f16d288869..53476ec81b 100644 --- a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php @@ -257,6 +257,10 @@ public function testBug8683(): void public function testBug7984(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = true; $this->checkNullables = true; $this->analyse([__DIR__ . '/data/bug-7984.php'], []); diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 3f29976a12..b5565f4d40 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -1595,6 +1595,10 @@ public function dataExplicitMixed(): array */ public function testExplicitMixed(bool $checkExplicitMixed, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkThisOnly = false; $this->checkNullables = true; $this->checkUnionTypes = true; @@ -2708,6 +2712,10 @@ public function testBug1517(): void public function testBug7593(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkThisOnly = false; $this->checkNullables = true; $this->checkUnionTypes = true; @@ -3088,6 +3096,10 @@ public function testObjectShapes(): void public function testBug9951(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkThisOnly = false; $this->checkNullables = true; $this->checkUnionTypes = true; diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index 27718dc9c7..d46969bdf3 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -758,6 +758,10 @@ public function dataMixed(): array */ public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkThisOnly = false; $this->checkExplicitMixed = $checkExplicitMixed; $this->checkImplicitMixed = $checkImplicitMixed; diff --git a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php index df40cbac04..07ea2260ee 100644 --- a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php @@ -362,6 +362,10 @@ public function dataRequiredParameterAfterOptional(): array */ public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->phpVersionId = $phpVersionId; $this->analyse([__DIR__ . '/data/required-parameter-after-optional.php'], $errors); } @@ -459,6 +463,10 @@ public function testTrueTypehint(): void public function testConditionalReturnType(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/conditional-return-type.php'], [ [ 'Template type T of method MethodConditionalReturnType\Container::notGet() is not referenced in a parameter.', @@ -474,6 +482,10 @@ public function testBug7519(): void public function testTemplateInParamOut(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/param-out.php'], [ [ 'Template type T of method ParamOutTemplate\FooBar::uselessLocalTemplate() is not referenced in a parameter.', diff --git a/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php b/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php index e55eb6eede..0f6d5b81f1 100644 --- a/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -75,6 +76,10 @@ public function testDefaultValueForPromotedProperty(): void public function testBug10956(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-10956.php'], []); } diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index 826586689a..75f9465e74 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -238,6 +238,10 @@ public function testParameterContravariance( array $expectedErrors, ): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->phpVersionId = $phpVersion; $this->analyse([$file], $expectedErrors); } diff --git a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php index ad9fc94be5..533ad774eb 100644 --- a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php +++ b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php @@ -265,6 +265,10 @@ public function dataCheckPhpDocMissingReturn(): array */ public function testCheckPhpDocMissingReturn(bool $checkPhpDocMissingReturn, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixedMissingReturn = true; $this->checkPhpDocMissingReturn = $checkPhpDocMissingReturn; $this->analyse([__DIR__ . '/data/check-phpdoc-missing-return.php'], $errors); @@ -287,6 +291,10 @@ public function dataModelMixin(): array */ public function testModelMixin(bool $checkExplicitMixedMissingReturn): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixedMissingReturn = $checkExplicitMixedMissingReturn; $this->checkPhpDocMissingReturn = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/model-mixin.php'], [ diff --git a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php index 41c947e937..190b83798b 100644 --- a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php @@ -306,6 +306,10 @@ public function testBug5309(): void public function testBinaryMixed(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = true; $this->checkImplicitMixed = true; $this->analyse([__DIR__ . '/data/invalid-binary-mixed.php'], [ diff --git a/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php index 5042bb336c..a70d03a6e7 100644 --- a/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php @@ -5,6 +5,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -69,6 +70,10 @@ public function testRule(): void public function testMixed(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = true; $this->checkImplicitMixed = true; $this->analyse([__DIR__ . '/data/invalid-inc-dec-mixed.php'], [ diff --git a/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php index 2475fa3a80..ddc41ed337 100644 --- a/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php @@ -5,6 +5,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -96,6 +97,10 @@ public function testRule(): void public function testMixed(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkImplicitMixed = true; $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/invalid-unary-mixed.php'], [ From 3e3b0518a84a2175cc4f259a6a63e568cdf671c4 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 15:01:24 +0200 Subject: [PATCH 46/47] Fix lint --- build/composer-dependency-analyser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/composer-dependency-analyser.php b/build/composer-dependency-analyser.php index 723a3ece2e..7502680e13 100644 --- a/build/composer-dependency-analyser.php +++ b/build/composer-dependency-analyser.php @@ -33,7 +33,7 @@ ) ->ignoreErrorsOnPackage('phpunit/phpunit', [ErrorType::DEV_DEPENDENCY_IN_PROD]) // prepared test tooling ->ignoreErrorsOnPackage('jetbrains/phpstorm-stubs', [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV]) // there is no direct usage, but we need newer version then required by ondrejmirtes/BetterReflection - ->ignoreErrorsOnPath(__DIR__ . '/../tests', [ErrorType::UNKNOWN_CLASS, ErrorType::UNKNOWN_FUNCTION]) // to be able to test invalid symbols + ->ignoreErrorsOnPath(__DIR__ . '/../tests', [ErrorType::UNKNOWN_CLASS, ErrorType::UNKNOWN_FUNCTION, ErrorType::SHADOW_DEPENDENCY]) // to be able to test invalid symbols ->ignoreUnknownClasses([ 'JetBrains\PhpStorm\Pure', // not present on composer's classmap 'PHPStan\ExtensionInstaller\GeneratedConfig', // generated From 6cfeb235fb75e881b888083744bf652b86a13e58 Mon Sep 17 00:00:00 2001 From: Ondrej Mirtes Date: Wed, 4 Sep 2024 15:08:50 +0200 Subject: [PATCH 47/47] Skip more `mixed` tests --- .../Analyser/AnalyserIntegrationTest.php | 12 +++++++ tests/PHPStan/Analyser/nsrt/bug-10131.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-7607.php | 4 ++- tests/PHPStan/Analyser/nsrt/bug-7685.php | 2 +- tests/PHPStan/Analyser/nsrt/bug-9105.php | 2 +- .../nsrt/falsey-ternary-certainty.php | 2 +- .../PHPStan/Analyser/nsrt/in_array_loose.php | 2 +- .../ImpossibleCheckTypeMethodCallRuleTest.php | 6 ++-- .../Rules/Comparison/data/bug-8169.php | 4 ++- .../ExistingClassesInTypehintsRuleTest.php | 12 +++++++ .../ExistingClassesInTypehintsRuleTest.php | 31 +++++++++++++++++++ .../Rules/Methods/ReturnTypeRuleTest.php | 31 +++++++++++++++++++ .../data/method-misleading-mixed-return.php | 21 +++++++++++++ .../Rules/Methods/data/returnTypes.php | 4 +-- .../NullsafePropertyFetchRuleTest.php | 4 +++ 15 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index b84ff5feb0..e3a3997bf3 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -827,6 +827,10 @@ public function testBug7094(): void public function testOffsetAccess(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $errors = $this->runAnalyse(__DIR__ . '/nsrt/offset-access.php'); $this->assertCount(1, $errors); $this->assertSame('PHPDoc tag @return contains unresolvable type.', $errors[0]->getMessage()); @@ -1063,6 +1067,10 @@ public function testBug8376(): void public function testAssertDocblock(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $errors = $this->runAnalyse(__DIR__ . '/nsrt/assert-docblock.php'); $this->assertCount(4, $errors); $this->assertSame('Call to method AssertDocblock\A::testInt() with string will always evaluate to false.', $errors[0]->getMessage()); @@ -1396,6 +1404,10 @@ public function testBug11147(): void public function testBug11283(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $errors = $this->runAnalyse(__DIR__ . '/data/bug-11283.php'); $this->assertNoErrors($errors); } diff --git a/tests/PHPStan/Analyser/nsrt/bug-10131.php b/tests/PHPStan/Analyser/nsrt/bug-10131.php index d78066e232..11088d2e44 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10131.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10131.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug10131; diff --git a/tests/PHPStan/Analyser/nsrt/bug-7607.php b/tests/PHPStan/Analyser/nsrt/bug-7607.php index b88d6e5c02..e8d6aa5911 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7607.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7607.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Bug7607; diff --git a/tests/PHPStan/Analyser/nsrt/bug-7685.php b/tests/PHPStan/Analyser/nsrt/bug-7685.php index 580ad7f33f..e5674250b4 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7685.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7685.php @@ -1,4 +1,4 @@ -= 8.0 namespace bug7685; diff --git a/tests/PHPStan/Analyser/nsrt/bug-9105.php b/tests/PHPStan/Analyser/nsrt/bug-9105.php index 956d53f055..296baba23d 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9105.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9105.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug9105; diff --git a/tests/PHPStan/Analyser/nsrt/falsey-ternary-certainty.php b/tests/PHPStan/Analyser/nsrt/falsey-ternary-certainty.php index 01045e25f9..cc831b87a4 100644 --- a/tests/PHPStan/Analyser/nsrt/falsey-ternary-certainty.php +++ b/tests/PHPStan/Analyser/nsrt/falsey-ternary-certainty.php @@ -1,4 +1,4 @@ -= 8.0 namespace FalseyTernaryCertainty; diff --git a/tests/PHPStan/Analyser/nsrt/in_array_loose.php b/tests/PHPStan/Analyser/nsrt/in_array_loose.php index 4600ae0a13..78d2899b8c 100644 --- a/tests/PHPStan/Analyser/nsrt/in_array_loose.php +++ b/tests/PHPStan/Analyser/nsrt/in_array_loose.php @@ -1,4 +1,4 @@ -= 8.0 namespace InArrayLoose; diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php index 6504b21a6a..29f63a6bf2 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php @@ -208,15 +208,15 @@ public function testBug8169(): void $this->analyse([__DIR__ . '/data/bug-8169.php'], [ [ 'Call to method Bug8169\HelloWorld::assertString() with string will always evaluate to true.', - 19, + 21, ], [ 'Call to method Bug8169\HelloWorld::assertString() with string will always evaluate to true.', - 26, + 28, ], [ 'Call to method Bug8169\HelloWorld::assertString() with int will always evaluate to false.', - 33, + 35, ], ]); } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-8169.php b/tests/PHPStan/Rules/Comparison/data/bug-8169.php index a6c4d33025..e3ee4aa5a5 100644 --- a/tests/PHPStan/Rules/Comparison/data/bug-8169.php +++ b/tests/PHPStan/Rules/Comparison/data/bug-8169.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace Bug8169; diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index 056740ed99..06957666f5 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -368,6 +368,10 @@ public function dataRequiredParameterAfterOptional(): array */ public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->phpVersionId = $phpVersionId; $this->analyse([__DIR__ . '/data/required-parameter-after-optional.php'], $errors); } @@ -439,6 +443,10 @@ public function testTrueTypehint(): void public function testConditionalReturnType(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/conditional-return-type.php'], [ [ 'Template type T of function FunctionConditionalReturnType\notGet() is not referenced in a parameter.', @@ -449,6 +457,10 @@ public function testConditionalReturnType(): void public function testTemplateInParamOut(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/param-out.php'], [ [ 'Template type S of function ParamOutTemplate\uselessGeneric() is not referenced in a parameter.', diff --git a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php index 07ea2260ee..f4a561e097 100644 --- a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php @@ -437,6 +437,25 @@ public function testTrueTypehint(): void { if (PHP_VERSION_ID >= 80200) { $errors = []; + } elseif (PHP_VERSION_ID >= 80000) { + $errors = [ + [ + 'Parameter $v of method NativeTrueType\Truthy::foo() has invalid type NativeTrueType\true.', + 10, + ], + [ + 'Method NativeTrueType\Truthy::foo() has invalid return type NativeTrueType\true.', + 10, + ], + [ + 'Parameter $trueUnion of method NativeTrueType\Truthy::trueUnion() has invalid type NativeTrueType\true.', + 14, + ], + [ + 'Method NativeTrueType\Truthy::trueUnionReturn() has invalid return type NativeTrueType\true.', + 31, + ], + ]; } else { $errors = [ [ @@ -447,14 +466,26 @@ public function testTrueTypehint(): void 'Method NativeTrueType\Truthy::foo() has invalid return type NativeTrueType\true.', 10, ], + [ + "Method NativeTrueType\Truthy::trueUnion() uses native union types but they're supported only on PHP 8.0 and later.", + 14, + ], [ 'Parameter $trueUnion of method NativeTrueType\Truthy::trueUnion() has invalid type NativeTrueType\true.', 14, ], + [ + 'Parameter $trueUnion of method NativeTrueType\Truthy::trueUnion() has invalid type NativeTrueType\null.', + 14, + ], [ 'Method NativeTrueType\Truthy::trueUnionReturn() has invalid return type NativeTrueType\true.', 31, ], + [ + 'Method NativeTrueType\Truthy::trueUnionReturn() has invalid return type NativeTrueType\null.', + 31, + ], ]; } diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 6303bdcdc4..f080bd4be8 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -283,8 +283,31 @@ public function testReturnTypeRule(): void ]); } + public function testMisleadingMixedType(): void + { + if (PHP_VERSION_ID >= 80000) { + $errors = []; + } else { + $errors = [ + [ + 'Method MethodMisleadingMixedReturn\Foo::misleadingMixedReturnType() should return MethodMisleadingMixedReturn\mixed but returns int.', + 11, + ], + [ + 'Method MethodMisleadingMixedReturn\Foo::misleadingMixedReturnType() should return MethodMisleadingMixedReturn\mixed but returns true.', + 14, + ], + ]; + } + $this->analyse([__DIR__ . '/data/method-misleading-mixed-return.php'], $errors); + } + public function testMisleadingTypehintsInClassWithoutNamespace(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/misleadingTypehints.php'], [ [ 'Method FooWithoutNamespace::misleadingBoolReturnType() should return boolean but returns true.', @@ -522,6 +545,10 @@ public function testBug2573(): void public function testBug4603(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-4603.php'], []); } @@ -774,6 +801,10 @@ public function testBug6358(): void public function testBug8071(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/bug-8071.php'], [ [ diff --git a/tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php b/tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php new file mode 100644 index 0000000000..e7c1b2141a --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php @@ -0,0 +1,21 @@ +analyse([__DIR__ . '/../../Analyser/nsrt/bug-9105.php'], []); }