diff --git a/.github/workflows/apiref.yml b/.github/workflows/apiref.yml index 9375c12fc2..24ba44284b 100644 --- a/.github/workflows/apiref.yml +++ b/.github/workflows/apiref.yml @@ -6,13 +6,16 @@ on: workflow_dispatch: push: branches: - - "2.0.x" + - "2.1.x" paths: - 'src/**' - 'composer.lock' - 'apigen/**' - '.github/workflows/apiref.yml' +env: + COMPOSER_ROOT_VERSION: "2.1.x-dev" + concurrency: group: apigen-${{ github.ref }} # will be canceled on subsequent pushes in branch cancel-in-progress: true diff --git a/.github/workflows/backward-compatibility.yml b/.github/workflows/backward-compatibility.yml index 51e52a365e..52d4cc8cc6 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 06213ad052..ab5f7c28d8 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 8084523280..33a3db908b 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 fd975528a3..e586a82aa2 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' @@ -34,7 +34,7 @@ jobs: with: repository: phpstan/phpstan path: phpstan-dist - ref: 1.12.x + ref: 2.0.x - name: "Get info" id: info @@ -98,14 +98,14 @@ jobs: - name: "Composer dump" run: "composer install --no-interaction --no-progress" env: - COMPOSER_ROOT_VERSION: "1.12.x-dev" + COMPOSER_ROOT_VERSION: "2.0.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" + COMPOSER_ROOT_VERSION: "2.0.x-dev" - name: "Re-sign PHAR" run: "php compiler/build/resign.php tmp/phpstan.phar" diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 4b90be1ec3..96505cbf9c 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/**' @@ -23,36 +23,6 @@ concurrency: cancel-in-progress: true jobs: - result-cache-php-parser-e2e: - name: "Result cache PHP-Parser E2E test" - - runs-on: ${{ matrix.operating-system }} - timeout-minutes: 60 - - strategy: - fail-fast: false - matrix: - operating-system: [ubuntu-latest, windows-latest] - - steps: - - name: "Checkout" - uses: actions/checkout@v4 - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "8.1" - extensions: mbstring - ini-values: memory_limit=256M - - - name: "Install dependencies" - run: "composer install --no-interaction --no-progress" - - - name: "Tests" - run: | - git clone https://github.com/nikic/PHP-Parser.git tests/e2e/PHP-Parser && git -C tests/e2e/PHP-Parser checkout v3.1.5 && composer install --working-dir tests/e2e/PHP-Parser && vendor/bin/phpunit tests/e2e/ResultCacheEndToEndTest.php - result-cache-e2e-tests: name: "Result cache E2E tests" runs-on: ubuntu-latest @@ -167,17 +137,18 @@ jobs: ../../bin/phpstan -vvv - script: | cd e2e/env-parameter - export PHPSTAN_SCOPE_CLASS=MyTestScope - ACTUAL=$(../../bin/phpstan dump-parameters -c phpstan.neon --json -l 9 | jq --raw-output '.scopeClass') - [[ "$ACTUAL" == "MyTestScope" ]]; + export PHPSTAN_RESULT_CACHE_PATH=/some/path + ACTUAL=$(../../bin/phpstan dump-parameters -c phpstan.neon --json -l 9 | jq --raw-output '.resultCachePath') + [[ "$ACTUAL" == "/some/path" ]]; - script: | cd e2e/result-cache-8 composer install ../../bin/phpstan echo -en '\n' >> build/CustomRule.php - OUTPUT=$(../../bin/phpstan 2>&1) - grep 'Result cache might not behave correctly' <<< "$OUTPUT" - grep 'ResultCache8E2E\\CustomRule' <<< "$OUTPUT" + OUTPUT=$(../../bin/phpstan analyze 2>&1 || true) + echo "$OUTPUT" + ../bashunit -a contains 'Result cache might not behave correctly' "$OUTPUT" + ../bashunit -a contains 'ResultCache8E2E\CustomRule' "$OUTPUT" - script: | cd e2e/env-int-key env 1=1 ../../bin/phpstan analyse test.php @@ -189,49 +160,52 @@ jobs: cd e2e/trait-caching ../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/ patch -b data/TraitOne.php < TraitOne.patch - OUTPUT=$(../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/ || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/") echo "$OUTPUT" - ../bashunit -a line_count 1 "$OUTPUT" + ../bashunit -a line_count 2 "$OUTPUT" + ../bashunit -a matches "Note: Using configuration file .+phpstan.neon." "$OUTPUT" ../bashunit -a contains 'Method TraitsCachingIssue\TestClassUsingTrait::doBar() should return stdClass but returns Exception.' "$OUTPUT" - script: | cd e2e/trait-caching ../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/ patch -b data/TraitTwo.php < TraitTwo.patch - OUTPUT=$(../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/ || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/") echo "$OUTPUT" - ../bashunit -a line_count 1 "$OUTPUT" + ../bashunit -a line_count 2 "$OUTPUT" + ../bashunit -a matches "Note: Using configuration file .+phpstan.neon." "$OUTPUT" ../bashunit -a contains 'Method class@anonymous/TestClassUsingTrait.php:20::doBar() should return stdClass but returns Exception.' "$OUTPUT" - script: | cd e2e/trait-caching ../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/ patch -b data/TraitOne.php < TraitOne.patch patch -b data/TraitTwo.php < TraitTwo.patch - OUTPUT=$(../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/ || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyze --no-progress --level 8 --error-format raw data/") echo "$OUTPUT" - ../bashunit -a line_count 2 "$OUTPUT" + ../bashunit -a line_count 3 "$OUTPUT" + ../bashunit -a matches "Note: Using configuration file .+phpstan.neon." "$OUTPUT" ../bashunit -a contains 'Method TraitsCachingIssue\TestClassUsingTrait::doBar() should return stdClass but returns Exception.' "$OUTPUT" ../bashunit -a contains 'Method class@anonymous/TestClassUsingTrait.php:20::doBar() should return stdClass but returns Exception.' "$OUTPUT" - script: | cd e2e/bad-exclude-paths - OUTPUT=$(../../bin/phpstan analyse -c ignore.neon 2>&1 || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c ignore.neon") echo "$OUTPUT" ../bashunit -a contains 'Invalid entry in ignoreErrors' "$OUTPUT" ../bashunit -a contains 'tests is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT" - script: | cd e2e/bad-exclude-paths - OUTPUT=$(../../bin/phpstan analyse -c phpneon.php 2>&1 || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c phpneon.php") echo "$OUTPUT" ../bashunit -a contains 'Invalid entry in ignoreErrors' "$OUTPUT" ../bashunit -a contains 'src/test.php is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT" - script: | cd e2e/bad-exclude-paths - OUTPUT=$(../../bin/phpstan analyse -c excludePaths.neon 2>&1 || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c excludePaths.neon") echo "$OUTPUT" ../bashunit -a contains 'Invalid entry in excludePaths' "$OUTPUT" ../bashunit -a contains 'tests is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT" - script: | cd e2e/bad-exclude-paths - OUTPUT=$(../../bin/phpstan analyse -c phpneon2.php 2>&1 || true) + OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan analyse -c phpneon2.php") echo "$OUTPUT" ../bashunit -a contains 'Invalid entry in excludePaths' "$OUTPUT" ../bashunit -a contains 'src/test.php is neither a directory, nor a file path, nor a fnmatch pattern.' "$OUTPUT" @@ -279,7 +253,7 @@ jobs: run: "patch src/Analyser/Error.php < e2e/PHPStanErrorPatch.patch" - name: "Install bashunit" - run: "curl -s https://bashunit.typeddevs.com/install.sh | bash -s e2e/ 0.17.0" + run: "curl -s https://bashunit.typeddevs.com/install.sh | bash -s e2e/ 0.18.0" - name: "Test" run: "${{ matrix.script }}" @@ -322,6 +296,52 @@ jobs: - script: | cd e2e/bug-11819 ../../bin/phpstan + - script: | + cd e2e/composer-and-phpstan-version-config + composer install --ignore-platform-reqs + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-max-version + composer install + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-min-max-version + composer install + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-min-open-end-version + composer install + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-min-version-v5 + composer install --ignore-platform-reqs + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-min-version-v7 + composer install --ignore-platform-reqs + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-min-version + composer install + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-no-versions + composer install + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-version-config-invalid + OUTPUT=$(../bashunit -a exit_code "1" ../../bin/phpstan) + echo "$OUTPUT" + ../bashunit -a contains 'Invalid configuration' "$OUTPUT" + ../bashunit -a contains 'Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.' "$OUTPUT" + - script: | + cd e2e/composer-version-config-patch + composer install --ignore-platform-reqs + ../../bin/phpstan analyze test.php --level=0 + - script: | + cd e2e/composer-version-config + composer install + ../../bin/phpstan analyze test.php --level=0 steps: - name: "Checkout" @@ -338,5 +358,8 @@ jobs: - name: "Install dependencies" run: "composer install --no-interaction --no-progress" + - name: "Install bashunit" + run: "curl -s https://bashunit.typeddevs.com/install.sh | bash -s e2e/ 0.18.0" + - name: "Test" run: ${{ matrix.script }} diff --git a/.github/workflows/issue-bot.yml b/.github/workflows/issue-bot.yml index eca615b3ce..3165350af2 100644 --- a/.github/workflows/issue-bot.yml +++ b/.github/workflows/issue-bot.yml @@ -11,7 +11,7 @@ on: - 'changelog-generator/**' push: branches: - - "2.0.x" + - "2.1.x" paths-ignore: - 'compiler/**' - 'apigen/**' @@ -106,9 +106,6 @@ jobs: attempt_limit: 5 attempt_delay: 1000 - - name: "Add level 10 config file" - run: "cp issue-bot/config.level10.neon conf/" - - name: "Run PHPStan" working-directory: "issue-bot" timeout-minutes: 5 @@ -167,7 +164,7 @@ jobs: - name: "Evaluate results - push" working-directory: "issue-bot" - if: "github.repository_owner == 'phpstan' && github.ref == 'refs/heads/2.0.x'" + if: "github.repository_owner == 'phpstan' && github.ref == 'refs/heads/2.1.x'" env: GITHUB_PAT: ${{ secrets.PHPSTAN_BOT_TOKEN }} PHPSTAN_SRC_COMMIT_BEFORE: ${{ github.event.before }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index afc5c0db7c..86ee004f07 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" concurrency: group: lint-${{ github.head_ref || github.run_id }} # will be canceled on subsequent pushes in pull requests but not branches @@ -22,8 +22,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" @@ -118,7 +116,7 @@ jobs: uses: "shivammathur/setup-php@v2" with: coverage: "none" - php-version: "8.3" + php-version: "8.4" - name: "Install dependencies" run: "composer install --no-interaction --no-progress" diff --git a/.github/workflows/phar.yml b/.github/workflows/phar.yml index f94cc44244..adea89e232 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 @@ -77,14 +77,14 @@ jobs: - name: "Composer dump" run: "composer install --no-interaction --no-progress" env: - COMPOSER_ROOT_VERSION: "1.12.x-dev" + COMPOSER_ROOT_VERSION: "2.0.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" + COMPOSER_ROOT_VERSION: "2.0.x-dev" - name: "Re-sign PHAR" run: "php compiler/build/resign.php tmp/phpstan.phar" @@ -104,34 +104,33 @@ jobs: - name: "Delete checksum PHAR" run: "rm tmp/phpstan.phar" -# -# integration-tests: -# if: github.event_name == 'pull_request' -# needs: compiler-tests -# uses: phpstan/phpstan/.github/workflows/integration-tests.yml@1.12.x -# with: -# ref: 1.12.x -# phar-checksum: ${{needs.compiler-tests.outputs.checksum}} + integration-tests: + if: github.event_name == 'pull_request' + needs: compiler-tests + uses: phpstan/phpstan/.github/workflows/integration-tests.yml@2.0.x + with: + ref: 2.0.x + phar-checksum: ${{needs.compiler-tests.outputs.checksum}} extension-tests: if: github.event_name == 'pull_request' needs: compiler-tests - uses: phpstan/phpstan/.github/workflows/extension-tests.yml@1.12.x + uses: phpstan/phpstan/.github/workflows/extension-tests.yml@2.0.x with: - ref: 1.12.x + ref: 2.0.x phar-checksum: ${{needs.compiler-tests.outputs.checksum}} other-tests: if: github.event_name == 'pull_request' needs: compiler-tests - uses: phpstan/phpstan/.github/workflows/other-tests.yml@1.12.x + uses: phpstan/phpstan/.github/workflows/other-tests.yml@2.0.x with: - ref: 1.12.x + ref: 2.0.x phar-checksum: ${{needs.compiler-tests.outputs.checksum}} commit: name: "Commit PHAR" - if: "github.repository_owner == 'phpstan' && (github.ref == 'refs/heads/1.12.x' || startsWith(github.ref, 'refs/tags/'))" + if: "github.repository_owner == 'phpstan' && (github.ref == 'refs/heads/2.0.x' || startsWith(github.ref, 'refs/tags/'))" needs: compiler-tests runs-on: "ubuntu-latest" timeout-minutes: 60 @@ -153,7 +152,7 @@ jobs: repository: phpstan/phpstan path: phpstan-dist token: ${{ secrets.PHPSTAN_BOT_TOKEN }} - ref: 1.12.x + ref: 2.0.x - 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..34ef71bb83 100644 --- a/.github/workflows/pr-base-on-previous-branch.yml +++ b/.github/workflows/pr-base-on-previous-branch.yml @@ -7,7 +7,7 @@ on: types: - opened branches: - - '2.0.x' + - '2.2.x' jobs: @@ -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.2.x. PHPStan 2.2 is not going to be released for months. If your code is relevant on 2.1.x and you want it to be released sooner, please rebase your pull request and change its target to 2.1.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 b4a0ac5fd5..ca9f6bd246 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/**' @@ -64,7 +64,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.3" - "7.4" - "8.0" - "8.1" diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index 81d852e90b..b7f4249e8b 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 e8b9e1ec39..161309d17c 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/**' @@ -28,8 +28,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.2" - - "7.3" - "7.4" - "8.0" - "8.1" @@ -58,18 +56,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" @@ -104,9 +96,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 292f8ccf27..97cf5b30da 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/**' @@ -32,7 +32,6 @@ jobs: fail-fast: false matrix: php-version: - - "7.3" - "7.4" - "8.0" - "8.1" @@ -63,10 +62,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" @@ -159,46 +154,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" diff --git a/.github/workflows/update-phpstorm-stubs.yml b/.github/workflows/update-phpstorm-stubs.yml index c559efc208..396be1c0be 100644 --- a/.github/workflows/update-phpstorm-stubs.yml +++ b/.github/workflows/update-phpstorm-stubs.yml @@ -16,7 +16,7 @@ jobs: - name: "Checkout" uses: actions/checkout@v4 with: - ref: 1.12.x + ref: 2.1.x fetch-depth: '0' token: ${{ secrets.PHPSTAN_BOT_TOKEN }} - name: "Install PHP" diff --git a/Makefile b/Makefile index 11807088ca..d8566bfdb0 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,18 @@ lint: --exclude tests/PHPStan/Rules/Classes/data/extends-readonly-class.php \ --exclude tests/PHPStan/Rules/Classes/data/instantiation-promoted-properties.php \ --exclude tests/PHPStan/Rules/Classes/data/bug-11592.php \ + --exclude tests/PHPStan/Rules/Properties/data/property-hooks-bodies-in-interface.php \ + --exclude tests/PHPStan/Rules/Properties/data/property-hooks-in-interface.php \ + --exclude tests/PHPStan/Rules/Properties/data/property-hooks-visibility-in-interface.php \ + --exclude tests/PHPStan/Rules/Properties/data/abstract-hooked-properties-in-class.php \ + --exclude tests/PHPStan/Rules/Properties/data/abstract-hooked-properties-with-bodies.php \ + --exclude tests/PHPStan/Rules/Properties/data/abstract-non-hooked-properties-in-abstract-class.php \ + --exclude tests/PHPStan/Rules/Properties/data/non-abstract-hooked-properties-in-abstract-class.php \ + --exclude tests/PHPStan/Rules/Properties/data/non-abstract-hooked-properties-in-class.php \ + --exclude tests/PHPStan/Rules/Properties/data/hooked-properties-in-class.php \ + --exclude tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php \ + --exclude tests/PHPStan/Rules/Classes/data/bug-12281.php \ + --exclude tests/PHPStan/Rules/Traits/data/bug-12281.php \ src tests cs: diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 0000000000..1b76768ec4 --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,338 @@ +Upgrading from PHPStan 1.x to 2.0 +================================= + +## PHP version requirements + +PHPStan now requires PHP 7.4 or newer to run. + +## Upgrading guide for end users + +The best way to get ready for upgrade to PHPStan 2.0 is to update to the **latest PHPStan 1.12 release** +and enable [**Bleeding Edge**](https://phpstan.org/blog/what-is-bleeding-edge). This will enable the new rules and behaviours that 2.0 turns on for all users. + +Also make sure to install and enable [`phpstan/phpstan-deprecation-rules`](https://github.com/phpstan/phpstan-deprecation-rules). + +Once you get to a green build with no deprecations showed on latest PHPStan 1.12.x with Bleeding Edge enabled, you can update all your related PHPStan dependencies to 2.0 in `composer.json`: + +```json +"require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-doctrine": "^2.0", + "phpstan/phpstan-nette": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpstan/phpstan-symfony": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", + ... +} +``` + +Don't forget to update [3rd party PHPStan extensions](https://phpstan.org/user-guide/extension-library) as well. + +After changing your `composer.json`, run `composer update 'phpstan/*' -W`. + +It's up to you whether you go through the new reported errors or if you just put them all to the [baseline](https://phpstan.org/user-guide/baseline) ;) Everyone who's on PHPStan 1.12 should be able to upgrade to PHPStan 2.0. + +### Noteworthy changes to code analysis + +* [**Enhancements in handling parameters passed by reference**](https://phpstan.org/blog/enhancements-in-handling-parameters-passed-by-reference) +* [**Validate inline PHPDoc `@var` tag type**](https://phpstan.org/blog/phpstan-1-10-comes-with-lie-detector#validate-inline-phpdoc-%40var-tag-type) +* [**List type enforced**](https://phpstan.org/blog/phpstan-1-9-0-with-phpdoc-asserts-list-type#list-type) +* **Always `true` conditions always reported**: previously reported only with phpstan-strict-rules, this is now always reported. + +### Removed option `checkMissingIterableValueType` + +It's strongly recommended to add the missing array typehints. + +If you want to continue ignoring missing typehints from arrays, add `missingType.iterableValue` error identifier to your `ignoreErrors`: + +```neon +parameters: + ignoreErrors: + - + identifier: missingType.iterableValue +``` + +### Removed option `checkGenericClassInNonGenericObjectType` + +It's strongly recommended to add the missing generic typehints. + +If you want to continue ignoring missing typehints from generics, add `missingType.generics` error identifier to your `ignoreErrors`: + +```neon +parameters: + ignoreErrors: + - + identifier: missingType.generics +``` + +### Removed `checkAlwaysTrue*` options + +These options have been removed because PHPStan now always behaves as if these were set to `true`: + +* `checkAlwaysTrueCheckTypeFunctionCall` +* `checkAlwaysTrueInstanceof` +* `checkAlwaysTrueStrictComparison` +* `checkAlwaysTrueLooseComparison` + +### Removed option `excludes_analyse` + +It has been replaced with [`excludePaths`](https://phpstan.org/user-guide/ignoring-errors#excluding-whole-files). + +### Paths in `excludePaths` and `ignoreErrors` have to be a valid file path or a fnmatch pattern + +If you are excluding a file path that might not exist but you still want to have it in `excludePaths`, append `(?)`: + +```neon +parameters: + excludePaths: + - tests/*/data/* + - src/broken + - node_modules (?) # optional path, might not exist +``` + +If you have the same situation in `ignoreErrors` (ignoring an error in a path that might not exist), use `reportUnmatchedIgnoredErrors: false`. + +```neon +parameters: + reportUnmatchedIgnoredErrors: false +``` + +Appending `(?)` in `ignoreErrors` is not supported. + +### Changes in 1st party PHPStan extensions + +* [phpstan-doctrine](https://github.com/phpstan/phpstan-doctrine) + * Removed config parameter `searchOtherMethodsForQueryBuilderBeginning` (extension now behaves as when this was set to `true`) + * Removed config parameter `queryBuilderFastAlgorithm` (extension now behaves as when this was set to `false`) +* [phpstan-symfony](https://github.com/phpstan/phpstan-symfony) + * Removed legacy options with `_` in the name + * `container_xml_path` -> use `containerXmlPath` + * `constant_hassers` -> use `constantHassers` + * `console_application_loader` -> use `consoleApplicationLoader` + +### Minor backward compatibility breaks + +* Removed unused config parameter `cache.nodesByFileCountMax` +* Removed unused config parameter `memoryLimitFile` +* Removed unused feature toggle `disableRuntimeReflectionProvider` +* Removed unused config parameter `staticReflectionClassNamePatterns` +* Remove `fixerTmpDir` config parameter, use `pro.tmpDir` instead +* Remove `tempResultCachePath` config parameter, use `resultCachePath` instead +* `additionalConfigFiles` config parameter must be a list + +## Upgrading guide for extension developers + +> [!NOTE] +> Please switch to PHPStan 2.0 in a new major version of your extension. It's not feasible to try to support both PHPStan 1.x and PHPStan 2.x with the same extension code. +> +> You can definitely get closer to supporting PHPStan 2.0 without increasing major version by solving reported deprecations and other issues by analysing your extension code with PHPStan & phpstan-deprecation-rules & Bleeding Edge, but the final leap and solving backward incompatibilities should be done by requiring `"phpstan/phpstan": "^2.0"` in your `composer.json`, and releasing a new major version. + +### PHPStan now uses nikic/php-parser v5 + +See [UPGRADING](https://github.com/nikic/PHP-Parser/blob/master/UPGRADE-5.0.md) guide for PHP-Parser. + +The most notable change is how `throw` statement is represented. Previously, `throw` statements like `throw $e;` were represented using the `Stmt\Throw_` class, while uses inside other expressions (such as `$x ?? throw $e`) used the `Expr\Throw_` class. + +Now, `throw $e;` is represented as a `Stmt\Expression` that contains an `Expr\Throw_`. The +`Stmt\Throw_` class has been removed. + +### PHPStan now uses phpstan/phpdoc-parser v2 + +See [UPGRADING](https://github.com/phpstan/phpdoc-parser/blob/2.0.x/UPGRADING.md) guide for phpstan/phpdoc-parser. + +### Returning plain strings as errors no longer supported, use RuleErrorBuilder + +Identifiers are also required in custom rules. + +Learn more: [Using RuleErrorBuilder to enrich reported errors in custom rules](https://phpstan.org/blog/using-rule-error-builder) + +**Before**: + +```php +return ['My error']; +``` + +**After**: + +```php +return [ + RuleErrorBuilder::message('My error') + ->identifier('my.error') + ->build(), +]; +``` + +### Deprecate various `instanceof *Type` in favour of new methods on `Type` interface + +Learn more: [Why Is instanceof *Type Wrong and Getting Deprecated?](https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated) + +### Removed deprecated `ParametersAcceptorSelector::selectSingle()` + +Use [`ParametersAcceptorSelector::selectFromArgs()`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ParametersAcceptorSelector.html#_selectFromArgs) instead. It should be used in most places where `selectSingle()` was previously used, like dynamic return type extensions. + +**Before**: + +```php +$defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); +``` + +**After**: + +```php +$defaultReturnType = ParametersAcceptorSelector::selectFromArgs( + $scope, + $functionCall->getArgs(), + $functionReflection->getVariants() +)->getReturnType(); +``` + +If you're analysing function or method body itself and you're using one of the following methods, ask for `getParameters()` and `getReturnType()` directly on the reflection object: + +* [InClassMethodNode::getMethodReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.InClassMethodNode.html) +* [InFunctionNode::getFunctionReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.InFunctionNode.html) +* [FunctionReturnStatementsNode::getFunctionReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.FunctionReturnStatementsNode.html) +* [MethodReturnStatementsNode::getMethodReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.MethodReturnStatementsNode.html) +* [Scope::getFunction()](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.Scope.html#_getFunction) + +**Before**: + +```php +$function = $node->getFunctionReflection(); +$returnType = ParametersAcceptorSelector::selectSingle($function->getVariants())->getReturnType(); +``` + +**After**: + +```php +$returnType = $node->getFunctionReflection()->getReturnType(); +``` + +### Changed `TypeSpecifier::create()` and `SpecifiedTypes` constructor parameters + +[`PHPStan\Analyser\TypeSpecifier::create()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.TypeSpecifier.html#_create) now accepts (all parameters are required): + +* `Expr $expr` +* `Type $type` +* `TypeSpecifierContext $context` +* `Scope $scope` + +If you want to change `$overwrite` or `$rootExpr` (previous parameters also used to be accepted by this method), call `setAlwaysOverwriteTypes()` and `setRootExpr()` on [`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) (object returned by `TypeSpecifier::create()`). These methods return a new object (SpecifiedTypes is immutable). + +[`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) constructor now accepts: + +* `array $sureTypes` +* `array $sureNotTypes` + +If you want to change `$overwrite` or `$rootExpr` (previous parameters also used to be accepted by the constructor), call `setAlwaysOverwriteTypes()` and `setRootExpr()`. These methods return a new object (SpecifiedTypes is immutable). + +### `ConstantArrayType` no longer extends `ArrayType` + +`Type::getArrays()` now returns `list`. + +Using `$type instanceof ArrayType` is [being deprecated anyway](https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated) so the impact of this change should be minimal. + +### Changed `TypeSpecifier::specifyTypesInCondition()` + +This method now longer accepts `Expr $rootExpr`. If you want to change it, call `setRootExpr()` on [`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) (object returned by `TypeSpecifier::specifyTypesInCondition()`). `setRootExpr()` method returns a new object (SpecifiedTypes is immutable). + +### Node attributes `parent`, `previous`, `next` are no longer available + +Learn more: https://phpstan.org/blog/preprocessing-ast-for-custom-rules + +### Removed config parameter `scopeClass` + +As a replacement you can implement [`PHPStan\Type\ExpressionTypeResolverExtension`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.ExpressionTypeResolverExtension.html) interface instead and register it as a service. + +### Removed `PHPStan\Broker\Broker` + +Use [`PHPStan\Reflection\ReflectionProvider`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ReflectionProvider.html) instead. + +`BrokerAwareExtension` was also removed. Ask for `ReflectionProvider` in the extension constructor instead. + +Instead of `PHPStanTestCase::createBroker()`, call `PHPStanTestCase::createReflectionProvider()`. + +### List type is enabled for everyone + +Removed static methods from `AccessoryArrayListType` class: + +* `isListTypeEnabled()` +* `setListTypeEnabled()` +* `intersectWith()` + +Instead of `AccessoryArrayListType::intersectWith($type)`, do `TypeCombinator::intersect($type, new AccessoryArrayListType())`. + +### Minor backward compatibility breaks + +* Classes that were previously `@final` were made `final` +* Parameter `$callableParameters` of [`MutatingScope::enterAnonymousFunction()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.MutatingScope.html#_enterAnonymousFunction) and [`enterArrowFunction()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.MutatingScope.html#_enterArrowFunction) made required +* Parameter `StatementContext $context` of [`NodeScopeResolver::processStmtNodes()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.NodeScopeResolver.html#_processStmtNodes) made required +* ClassPropertiesNode - remove `$extensions` parameter from [`getUninitializedProperties()`](https://apiref.phpstan.org/2.0.x/PHPStan.Node.ClassPropertiesNode.html#_getUninitializedProperties) +* `Type::getSmallerType()`, `Type::getSmallerOrEqualType()`, `Type::getGreaterType()`, `Type::getGreaterOrEqualType()`, `Type::isSmallerThan()`, `Type::isSmallerThanOrEqual()` now require [`PhpVersion`](https://apiref.phpstan.org/2.0.x/PHPStan.Php.PhpVersion.html) as argument. +* `CompoundType::isGreaterThan()`, `CompoundType::isGreaterThanOrEqual()` now require [`PhpVersion`](https://apiref.phpstan.org/2.0.x/PHPStan.Php.PhpVersion.html) as argument. +* Removed `ReflectionProvider::supportsAnonymousClasses()` (all reflection providers support anonymous classes) +* Remove `ArrayType::generalizeKeys()` +* Remove `ArrayType::count()`, use `Type::getArraySize()` instead +* Remove `ArrayType::castToArrayKeyType()`, `Type::toArrayKey()` instead +* Remove `UnionType::pickTypes()`, use `pickFromTypes()` instead +* Remove `RegexArrayShapeMatcher::matchType()`, use `matchExpr()` instead +* Remove unused `PHPStanTestCase::$useStaticReflectionProvider` +* Remove `PHPStanTestCase::getReflectors()`, use `getReflector()` instead +* Remove `ClassReflection::getFileNameWithPhpDocs()`, use `getFileName()` instead +* Remove `AnalysisResult::getInternalErrors()`, use `getInternalErrorObjects()` instead +* Remove `ConstantReflection::getValue()`, use `getValueExpr()` instead. To get `Type` from `Expr`, use `Scope::getType()` or `InitializerExprTypeResolver::getType()` +* Remove `PropertyTag::getType()`, use `getReadableType()` / `getWritableType()` instead +* Remove `GenericTypeVariableResolver`, use [`Type::getTemplateType()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getTemplateType) instead +* Rename `Type::isClassStringType()` to `Type::isClassString()` +* Remove `Scope::isSpecified()`, use `hasExpressionType()` instead +* Remove `ConstantArrayType::isEmpty()`, use `isIterableAtLeastOnce()->no()` instead +* Remove `ConstantArrayType::getNextAutoIndex()` +* Removed methods from `ConstantArrayType` - `getFirst*Type` and `getLast*Type` + * Use `getFirstIterable*Type` and `getLastIterable*Type` instead +* Remove `ConstantArrayType::generalizeToArray()` +* Remove `ConstantArrayType::findTypeAndMethodName()`, use `findTypeAndMethodNames()` instead +* Remove `ConstantArrayType::removeLast()`, use [`Type::popArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_popArray) instead +* Remove `ConstantArrayType::removeFirst()`, use [`Type::shiftArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_shiftArray) instead +* Remove `ConstantArrayType::reverse()`, use [`Type::reverseArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_reverseArray) instead +* Remove `ConstantArrayType::chunk()`, use [`Type::chunkArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_chunkArray) instead +* Remove `ConstantArrayType::slice()`, use [`Type::sliceArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_sliceArray) instead +* Made `TypeUtils` thinner by removing methods: + * Remove `TypeUtils::getArrays()` and `getAnyArrays()`, use [`Type::getArrays()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getArrays) instead + * Remove `TypeUtils::getConstantArrays()` and `getOldConstantArrays()`, use [`Type::getConstantArrays()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantArrays) instead + * Remove `TypeUtils::getConstantStrings()`, use [`Type::getConstantStrings()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantStrings) instead + * Remove `TypeUtils::getConstantTypes()` and `getAnyConstantTypes()`, use [`Type::isConstantValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantValue) or [`Type::generalize()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_generalize) + * Remove `TypeUtils::generalizeType()`, use [`Type::generalize()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_generalize) instead + * Remove `TypeUtils::getDirectClassNames()`, use [`Type::getObjectClassNames()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getObjectClassNames) instead + * Remove `TypeUtils::getConstantScalars()`, use [`Type::isConstantScalarValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantScalarValue) or [`Type::getConstantScalarTypes()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantScalarTypes) instead + * Remove `TypeUtils::getEnumCaseObjects()`, use [`Type::getEnumCases()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getEnumCases) instead + * Remove `TypeUtils::containsCallable()`, use [`Type::isCallable()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isCallable) instead +* Removed `Scope::doNotTreatPhpDocTypesAsCertain()`, use `getNativeType()` instead +* Parameter `$isList` in `ConstantArrayType` constructor can only be `TrinaryLogic`, no longer `bool` +* Parameter `$nextAutoIndexes` in `ConstantArrayType` constructor can only be `non-empty-list`, no longer `int` +* Remove `ConstantType` interface, use [`Type::isConstantValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantValue) instead +* `acceptsNamedArguments()` in `FunctionReflection`, `ExtendedMethodReflection` and `CallableParametersAcceptor` interfaces returns `TrinaryLogic` instead of `bool` +* Remove `FunctionReflection::isFinal()` +* [`Type::getProperty()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getProperty) now returns [`ExtendedPropertyReflection`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ExtendedPropertyReflection.html) +* Remove `__set_state()` on objects that should not be serialized in cache +* Parameter `$selfClass` of [`TypehintHelper::decideTypeFromReflection()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.TypehintHelper.html#_decideTypeFromReflection) no longer accepts `string` +* `LevelsTestCase::dataTopics()` data provider made static +* `PHPStan\Node\Printer\Printer` no longer autowired as `PhpParser\PrettyPrinter\Standard`, use `PHPStan\Node\Printer\Printer` in the typehint +* Remove `Type::acceptsWithReason()`, `Type:accepts()` return type changed from `TrinaryLogic` to [`AcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html) +* Remove `CompoundType::isAcceptedWithReasonBy()`, `CompoundType::isAcceptedBy()` return type changed from `TrinaryLogic` to [`AcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html) +Remove `Type::isSuperTypeOfWithReason()`, `Type:isSuperTypeOf()` return type changed from `TrinaryLogic` to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html) +* Remove `CompoundType::isSubTypeOfWithReasonBy()`, `CompoundType::isSubTypeOf()` return type changed from `TrinaryLogic` to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html) +* Remove `TemplateType::isValidVarianceWithReason()`, changed `TemplateType::isValidVariance()` return type to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html) +* `RuleLevelHelper::accepts()` return type changed from `bool` to [`RuleLevelHelperAcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html) +* Changes around `ClassConstantReflection` + * Class `ClassConstantReflection` removed from BC promise, renamed to `RealClassConstantReflection` + * Interface `ConstantReflection` renamed to `ClassConstantReflection` + * Added more methods around PHPDoc types and native types to the (new) `ClassConstantReflection` + * Interface `GlobalConstantReflection` renamed to `ConstantReflection` +* Renamed interfaces and classes from `*WithPhpDocs` to `Extended*` + * `ParametersAcceptorWithPhpDocs` -> `ExtendedParametersAcceptor` + * `ParameterReflectionWithPhpDocs` -> `ExtendedParameterReflection` + * `FunctionVariantWithPhpDocs` -> `ExtendedFunctionVariant` +* `ClassPropertyNode::getNativeType()` return type changed from AST node to `Type|null` +* Class `PHPStan\Node\ClassMethod` (accessible from `ClassMethodsNode`) is no longer an AST node + * Call `PHPStan\Node\ClassMethod::getNode()` to access the original AST node diff --git a/bin/generate-function-metadata.php b/bin/generate-function-metadata.php index f6f5131a53..97737499a5 100755 --- a/bin/generate-function-metadata.php +++ b/bin/generate-function-metadata.php @@ -16,7 +16,7 @@ (function (): void { require_once __DIR__ . '/../vendor/autoload.php'; - $parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7); + $parser = (new ParserFactory())->createForNewestSupportedVersion(); $finder = new Finder(); $finder->in(__DIR__ . '/../vendor/jetbrains/phpstorm-stubs')->files()->name('*.php'); diff --git a/bin/make-optional-parameters-required.php b/bin/make-optional-parameters-required.php new file mode 100755 index 0000000000..5d2dd308c0 --- /dev/null +++ b/bin/make-optional-parameters-required.php @@ -0,0 +1,51 @@ +#!/usr/bin/env php +createForHostVersion(); + $traverser = new NodeTraverser(new CloningVisitor()); + $printer = new Standard(); + $finder = new Finder(); + $finder->followLinks(); + + $removeParamDefaultTraverser = new NodeTraverser(new class () extends NodeVisitorAbstract { + + public function enterNode(Node $node) + { + if (!$node instanceof Node\Param) { + return null; + } + + $node->default = null; + + return $node; + } + + }); + foreach ($finder->files()->name('*.php')->in($dir) as $fileInfo) { + $oldStmts = $parser->parse(file_get_contents($fileInfo->getPathname())); + $oldTokens = $parser->getTokens(); + + $newStmts = $traverser->traverse($oldStmts); + $newStmts = $removeParamDefaultTraverser->traverse($newStmts); + + $newCode = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens); + file_put_contents($fileInfo->getPathname(), $newCode); + } +})(); diff --git a/bin/phpstan b/bin/phpstan index 03a1a8aad7..119af4377c 100755 --- a/bin/phpstan +++ b/bin/phpstan @@ -13,15 +13,6 @@ use Symfony\Component\Console\Helper\ProgressBar; (function () { error_reporting(E_ALL & ~E_DEPRECATED); ini_set('display_errors', 'stderr'); - if (version_compare(PHP_VERSION, '7.4.0', '<')) { - // PHP earlier than 7.4.x with OpCache triggers a bug when we intercept - // custom autoloaders' reads to discover file paths. See PHPStan #4881. - ini_set('opcache.enable', 'Off'); - } - - if (PHP_VERSION_ID < 70300) { - gc_disable(); // performance boost - } define('__PHPSTAN_RUNNING__', true); @@ -45,8 +36,6 @@ use Symfony\Component\Console\Helper\ProgressBar; || !array_key_exists('a4a119a56e50fbb293281d9a48007e0e', $composerAutoloadFiles) || !array_key_exists('0e6d7bf4a5811bfa5cf40c5ccd6fae6a', $composerAutoloadFiles) || !array_key_exists('e69f7f6ee287b969198c3c9d6777bd38', $composerAutoloadFiles) - || !array_key_exists('0d59ee240a4cd96ddbb4ff164fccea4d', $composerAutoloadFiles) - || !array_key_exists('b686b8e46447868025a15ce5d0cb2634', $composerAutoloadFiles) || !array_key_exists('8825ede83f2f289127722d4e842cf7e8', $composerAutoloadFiles) || !array_key_exists('23c18046f52bef3eea034657bafda50f', $composerAutoloadFiles) ) { @@ -69,12 +58,6 @@ use Symfony\Component\Console\Helper\ProgressBar; // vendor/symfony/polyfill-intl-normalizer/bootstrap.php 'e69f7f6ee287b969198c3c9d6777bd38' => true, - // vendor/symfony/polyfill-php73/bootstrap.php - '0d59ee240a4cd96ddbb4ff164fccea4d' => true, - - // vendor/symfony/polyfill-php74/bootstrap.php - 'b686b8e46447868025a15ce5d0cb2634' => true, - // vendor/symfony/polyfill-intl-grapheme/bootstrap.php '8825ede83f2f289127722d4e842cf7e8' => true, diff --git a/src/Internal/ContainerDynamicReturnTypeExtension.php b/build/PHPStan/Build/ContainerDynamicReturnTypeExtension.php similarity index 98% rename from src/Internal/ContainerDynamicReturnTypeExtension.php rename to build/PHPStan/Build/ContainerDynamicReturnTypeExtension.php index 0fc017e67f..8e43bd2d47 100644 --- a/src/Internal/ContainerDynamicReturnTypeExtension.php +++ b/build/PHPStan/Build/ContainerDynamicReturnTypeExtension.php @@ -1,6 +1,6 @@ getName(), [ FunctionVariant::class, - FunctionVariantWithPhpDocs::class, + ExtendedFunctionVariant::class, DummyParameter::class, PhpFunctionFromParserNodeReflection::class, ], true)) { diff --git a/build/baseline-lt-7.3.neon b/build/baseline-lt-7.3.neon deleted file mode 100644 index aab4991158..0000000000 --- a/build/baseline-lt-7.3.neon +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - ignoreErrors: [] diff --git a/build/collision-detector.json b/build/collision-detector.json index 21228704f5..12de9af1d3 100644 --- a/build/collision-detector.json +++ b/build/collision-detector.json @@ -12,5 +12,5 @@ "../tests/notAutoloaded", "../tests/PHPStan/Rules/Functions/data/define-bug-3349.php", "../tests/PHPStan/Levels/data/stubs/function.php" - ] + ] } diff --git a/build/composer-dependency-analyser.php b/build/composer-dependency-analyser.php index 723a3ece2e..79dc694253 100644 --- a/build/composer-dependency-analyser.php +++ b/build/composer-dependency-analyser.php @@ -9,8 +9,6 @@ 'symfony/polyfill-intl-grapheme', 'symfony/polyfill-intl-normalizer', 'symfony/polyfill-mbstring', - 'symfony/polyfill-php73', - 'symfony/polyfill-php74', 'symfony/polyfill-php80', 'symfony/polyfill-php81', ]; @@ -33,7 +31,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 diff --git a/build/deprecated-8.4.neon b/build/deprecated-8.4.neon new file mode 100644 index 0000000000..6b3bd6db5e --- /dev/null +++ b/build/deprecated-8.4.neon @@ -0,0 +1,7 @@ +parameters: + ignoreErrors: + - + message: '#^Use of constant E_STRICT is deprecated\.$#' + identifier: constant.deprecated + count: 1 + path: ../src/Analyser/FileAnalyser.php diff --git a/build/enum-adapter-errors.neon b/build/enum-adapter-errors.neon deleted file mode 100644 index d78223e40c..0000000000 --- a/build/enum-adapter-errors.neon +++ /dev/null @@ -1,151 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Call to method getAttributes\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 2 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getBackingType\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getValueExpression\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnumBackedCase\\.$#" - count: 2 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getCase\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getCases\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getConstructor\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getDocComment\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 2 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getFileName\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getName\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getParentClass\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 4 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method getTraits\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method hasCase\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method implementsInterface\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isAbstract\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isBacked\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 2 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isEnum\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isFinal\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isInterface\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 2 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isInternal\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isReadOnly\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isSubclassOf\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Call to method isTrait\\(\\) on an unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum not found\\.$#" - count: 4 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnumBackedCase not found\\.$#" - count: 2 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Method PHPStan\\\\Reflection\\\\ClassReflection\\:\\:getNativeReflection\\(\\) has invalid return type PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Parameter \\$class of method PHPStan\\\\Reflection\\\\ClassReflection\\:\\:collectTraits\\(\\) has invalid type PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Parameter \\$reflection of method PHPStan\\\\Reflection\\\\ClassReflection\\:\\:__construct\\(\\) has invalid type PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Property PHPStan\\\\Reflection\\\\ClassReflection\\:\\:\\$reflection has unknown class PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum as its type\\.$#" - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: '#^PHPDoc tag @phpstan\-assert\-if\-true for \$this\-\>reflection contains unknown class PHPStan\\BetterReflection\\Reflection\\Adapter\\ReflectionEnum\.$#' - count: 1 - path: ../src/Reflection/ClassReflection.php - - - - message: "#^Method PHPStan\\\\Reflection\\\\Php\\\\BuiltinMethodReflection\\:\\:getDeclaringClass\\(\\) has invalid return type PHPStan\\\\BetterReflection\\\\Reflection\\\\Adapter\\\\ReflectionEnum\\.$#" - count: 1 - path: ../src/Reflection/Php/BuiltinMethodReflection.php diff --git a/build/ignore-by-php-version.neon.php b/build/ignore-by-php-version.neon.php index 62de0070e5..c250ea9eec 100644 --- a/build/ignore-by-php-version.neon.php +++ b/build/ignore-by-php-version.neon.php @@ -1,11 +1,6 @@ = 80000) { $includes[] = __DIR__ . '/baseline-8.0.neon'; } @@ -20,10 +15,6 @@ $includes[] = __DIR__ . '/ignore-gte-php7.4-errors.neon'; } -if (PHP_VERSION_ID < 70400) { - $includes[] = __DIR__ . '/enum-adapter-errors.neon'; -} - if (PHP_VERSION_ID < 80000) { $includes[] = __DIR__ . '/more-enum-adapter-errors.neon'; } @@ -38,6 +29,10 @@ $includes[] = __DIR__ . '/datetime-php-83.neon'; } +if (PHP_VERSION_ID >= 80400) { + $includes[] = __DIR__ . '/deprecated-8.4.neon'; +} + $config = []; $config['includes'] = $includes; diff --git a/build/phpstan.neon b/build/phpstan.neon index 95526db694..1b1bf800f9 100644 --- a/build/phpstan.neon +++ b/build/phpstan.neon @@ -89,7 +89,6 @@ parameters: message: "#^Parameter \\#1 (?:\\$argument|\\$objectOrClass) of class ReflectionClass constructor expects class\\-string\\\\|PHPStan\\\\ExtensionInstaller\\\\GeneratedConfig, string given\\.$#" count: 1 path: ../src/Diagnose/PHPStanDiagnoseExtension.php - - '#^Parameter \#1 \$offsetType of class PHPStan\\Type\\Accessory\\HasOffsetType constructor expects PHPStan\\Type\\Constant\\ConstantIntegerType\|PHPStan\\Type\\Constant\\ConstantStringType#' - '#^Short ternary operator is not allowed#' reportStaticMethodSignatures: true tmpDir: %rootDir%/tmp @@ -108,6 +107,6 @@ services: tags: - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Internal\ContainerDynamicReturnTypeExtension + class: PHPStan\Build\ContainerDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension diff --git a/changelog-generator/phpstan.neon b/changelog-generator/phpstan.neon index d187d34c96..a1fee9d3a7 100644 --- a/changelog-generator/phpstan.neon +++ b/changelog-generator/phpstan.neon @@ -11,4 +11,6 @@ parameters: paths: - src - run.php - checkGenericClassInNonGenericObjectType: false + ignoreErrors: + - + identifier: missingType.generics diff --git a/compiler/build/scoper.inc.php b/compiler/build/scoper.inc.php index ba198a0c91..0d0008d341 100644 --- a/compiler/build/scoper.inc.php +++ b/compiler/build/scoper.inc.php @@ -20,8 +20,6 @@ '../../vendor/symfony/polyfill-php81', '../../vendor/symfony/polyfill-mbstring', '../../vendor/symfony/polyfill-intl-normalizer', - '../../vendor/symfony/polyfill-php73', - '../../vendor/symfony/polyfill-php74', '../../vendor/symfony/polyfill-intl-grapheme', ]) as $file) { if ($file->getPathName() === '../../vendor/jetbrains/phpstorm-stubs/PhpStormStubsMap.php') { @@ -218,6 +216,33 @@ function (string $filePath, string $prefix, string $content): string { return str_replace(sprintf('use %s\\PhpParser;', $prefix), 'use PhpParser;', $content); }, + function (string $filePath, string $prefix, string $content): string { + if (!str_starts_with($filePath, 'vendor/nikic/php-parser/lib')) { + return $content; + } + + return str_replace([ + sprintf('\\%s', $prefix), + sprintf('\\\\%s', $prefix), + ], '', $content); + }, + function (string $filePath, string $prefix, string $content): string { + if (!str_starts_with($filePath, 'vendor/ondrejmirtes/better-reflection')) { + return $content; + } + + return str_replace(sprintf('%s\\PropertyHookType', $prefix), 'PropertyHookType', $content); + }, + function (string $filePath, string $prefix, string $content): string { + if ( + $filePath !== 'vendor/nette/utils/src/Utils/Strings.php' + && $filePath !== 'vendor/nette/utils/src/Utils/Arrays.php' + ) { + return $content; + } + + return str_replace('#[\\JetBrains\\PhpStorm\\Language(\'RegExp\')] ', '', $content); + }, function (string $filePath, string $prefix, string $content): string { if ($filePath !== 'vendor/fidry/cpu-core-counter/src/Finder/WindowsRegistryLogicalFinder.php') { return $content; @@ -234,8 +259,6 @@ function (string $filePath, string $prefix, string $content): string { 'Symfony\Polyfill\Php81', 'Symfony\Polyfill\Mbstring', 'Symfony\Polyfill\Intl\Normalizer', - 'Symfony\Polyfill\Php73', - 'Symfony\Polyfill\Php74', 'Symfony\Polyfill\Intl\Grapheme', ], 'expose-global-functions' => false, diff --git a/compiler/src/Console/PrepareCommand.php b/compiler/src/Console/PrepareCommand.php index f7f2b6cdf6..9dbc3e3192 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; @@ -62,9 +63,9 @@ private function fixComposerJson(string $buildDir): void { $json = json_decode($this->filesystem->read($buildDir . '/composer.json'), true); - unset($json['replace']); + unset($json['replace']['phpstan/phpstan']); $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/'; @@ -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"; } diff --git a/composer.json b/composer.json index 9aac57806f..30dfc158c3 100644 --- a/composer.json +++ b/composer.json @@ -15,18 +15,18 @@ "hoa/compiler": "3.17.08.08", "hoa/exception": "^1.0", "hoa/file": "1.17.07.11", - "jetbrains/phpstorm-stubs": "dev-master#56f6b9e55f5885e651553843a1aaf9ec9c586c04", + "jetbrains/phpstorm-stubs": "dev-master#0e82bdfe850c71857ee4ee3501ed82a9fc5d043c", "nette/bootstrap": "^3.0", "nette/di": "^3.1.4", - "nette/neon": "3.3.3", + "nette/neon": "3.3.4", "nette/php-generator": "3.6.9", "nette/schema": "^1.2.2", "nette/utils": "^3.2.5", - "nikic/php-parser": "^4.19.4", + "nikic/php-parser": "^5.3.0", "ondram/ci-detector": "^3.4.0", - "ondrejmirtes/better-reflection": "6.25.0.21", - "phpstan/php-8-stubs": "0.3.111", - "phpstan/phpdoc-parser": "1.33.0", + "ondrejmirtes/better-reflection": "6.49.0.0", + "phpstan/php-8-stubs": "0.4.9", + "phpstan/phpdoc-parser": "2.0.0", "psr/http-message": "^1.1", "react/async": "^3", "react/child-process": "^0.7", @@ -41,8 +41,6 @@ "symfony/polyfill-intl-grapheme": "^1.23", "symfony/polyfill-intl-normalizer": "^1.23", "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php73": "^1.23", - "symfony/polyfill-php74": "^1.23", "symfony/polyfill-php80": "^1.23", "symfony/polyfill-php81": "^1.27", "symfony/process": "^5.4.3", @@ -50,19 +48,19 @@ "symfony/string": "^5.4.3" }, "replace": { - "phpstan/phpstan": "1.12.x" + "phpstan/phpstan": "2.0.x", + "symfony/polyfill-php73": "*" }, "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", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "^9.5.4", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-nette": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", "shipmonk/composer-dependency-analyser": "^1.5", "shipmonk/name-collision-detector": "^2.0" }, @@ -120,10 +118,6 @@ "nette/di": [ "patches/DependencyChecker.patch" ], - "nette/neon": [ - "patches/NetteNeonStringNode.patch", - "patches/NeonParser.patch" - ], "react/http": [ "patches/Sender.patch" ] diff --git a/composer.lock b/composer.lock index 7a215f2f76..731974732a 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": "07b46dce51ea41c025511b9415b3274c", + "content-hash": "7887860dff8af8b2ff60352d573b1aba", "packages": [ { "name": "clue/ndjson-react", @@ -1442,19 +1442,19 @@ "source": { "type": "git", "url": "https://github.com/JetBrains/phpstorm-stubs.git", - "reference": "56f6b9e55f5885e651553843a1aaf9ec9c586c04" + "reference": "0e82bdfe850c71857ee4ee3501ed82a9fc5d043c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JetBrains/phpstorm-stubs/zipball/56f6b9e55f5885e651553843a1aaf9ec9c586c04", - "reference": "56f6b9e55f5885e651553843a1aaf9ec9c586c04", + "url": "https://api.github.com/repos/JetBrains/phpstorm-stubs/zipball/0e82bdfe850c71857ee4ee3501ed82a9fc5d043c", + "reference": "0e82bdfe850c71857ee4ee3501ed82a9fc5d043c", "shasum": "" }, "require-dev": { - "friendsofphp/php-cs-fixer": "v3.61.1", - "nikic/php-parser": "v5.1.0", - "phpdocumentor/reflection-docblock": "5.4.1", - "phpunit/phpunit": "11.3.0" + "friendsofphp/php-cs-fixer": "v3.64.0", + "nikic/php-parser": "v5.3.1", + "phpdocumentor/reflection-docblock": "5.6.0", + "phpunit/phpunit": "11.4.3" }, "default-branch": true, "type": "library", @@ -1482,7 +1482,7 @@ "support": { "source": "https://github.com/JetBrains/phpstorm-stubs/tree/master" }, - "time": "2024-09-01T14:35:14+00:00" + "time": "2024-12-14T08:03:12+00:00" }, { "name": "nette/bootstrap", @@ -1706,21 +1706,21 @@ }, { "name": "nette/neon", - "version": "v3.3.3", + "version": "v3.3.4", "source": { "type": "git", "url": "https://github.com/nette/neon.git", - "reference": "22e384da162fab42961d48eb06c06d3ad0c11b95" + "reference": "bb88bf3a54dd21bf4dbddb5cd525d7b0c61b7cda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/neon/zipball/22e384da162fab42961d48eb06c06d3ad0c11b95", - "reference": "22e384da162fab42961d48eb06c06d3ad0c11b95", + "url": "https://api.github.com/repos/nette/neon/zipball/bb88bf3a54dd21bf4dbddb5cd525d7b0c61b7cda", + "reference": "bb88bf3a54dd21bf4dbddb5cd525d7b0c61b7cda", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=7.1" + "php": "7.1 - 8.4" }, "require-dev": { "nette/tester": "^2.0", @@ -1768,9 +1768,9 @@ ], "support": { "issues": "https://github.com/nette/neon/issues", - "source": "https://github.com/nette/neon/tree/v3.3.3" + "source": "https://github.com/nette/neon/tree/v3.3.4" }, - "time": "2022-03-10T02:04:26+00:00" + "time": "2024-10-04T22:17:24+00:00" }, { "name": "nette/php-generator", @@ -1971,25 +1971,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" @@ -2050,31 +2051,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.4", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", - "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.1" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -2082,7 +2085,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2106,9 +2109,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-09-29T15:01:53+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "ondram/ci-detector", @@ -2184,23 +2187,23 @@ }, { "name": "ondrejmirtes/better-reflection", - "version": "6.25.0.21", + "version": "6.49.0.0", "source": { "type": "git", "url": "https://github.com/ondrejmirtes/BetterReflection.git", - "reference": "c1bcfaa130718e4004ab8260bed4bfe96a46dc02" + "reference": "11abb6b4c9c8b29ee2730a3307ebae77b17fa94d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/c1bcfaa130718e4004ab8260bed4bfe96a46dc02", - "reference": "c1bcfaa130718e4004ab8260bed4bfe96a46dc02", + "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/11abb6b4c9c8b29ee2730a3307ebae77b17fa94d", + "reference": "11abb6b4c9c8b29ee2730a3307ebae77b17fa94d", "shasum": "" }, "require": { "ext-json": "*", - "jetbrains/phpstorm-stubs": "dev-master#217ed9356d07ef89109d3cd7d8c5df10aab4b0d4", - "nikic/php-parser": "^4.18.0", - "php": "^7.2 || ^8.0" + "jetbrains/phpstorm-stubs": "dev-master#b61d4a5f40c3940be440d85355fef4e2416b8527", + "nikic/php-parser": "^5.3.1", + "php": "^7.4 || ^8.0" }, "conflict": { "thecodingmachine/safe": "<1.1.3" @@ -2209,9 +2212,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.5.1", + "rector/rector": "1.2.10" }, "suggest": { "composer/composer": "Required to use the ComposerSourceLocator" @@ -2250,22 +2252,22 @@ ], "description": "Better Reflection - an improved code reflection API", "support": { - "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.25.0.21" + "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.49.0.0" }, - "time": "2024-10-12T09:29:10+00:00" + "time": "2024-12-20T19:27:15+00:00" }, { "name": "phpstan/php-8-stubs", - "version": "0.3.111", + "version": "0.4.9", "source": { "type": "git", "url": "https://github.com/phpstan/php-8-stubs.git", - "reference": "0013252145df5d84112764d4ea57ed1c6f074018" + "reference": "1857c330fea6e795af1f7435ed02a18652e7dd8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/php-8-stubs/zipball/0013252145df5d84112764d4ea57ed1c6f074018", - "reference": "0013252145df5d84112764d4ea57ed1c6f074018", + "url": "https://api.github.com/repos/phpstan/php-8-stubs/zipball/1857c330fea6e795af1f7435ed02a18652e7dd8c", + "reference": "1857c330fea6e795af1f7435ed02a18652e7dd8c", "shasum": "" }, "type": "library", @@ -2282,36 +2284,36 @@ "description": "PHP stubs extracted from php-src", "support": { "issues": "https://github.com/phpstan/php-8-stubs/issues", - "source": "https://github.com/phpstan/php-8-stubs/tree/0.3.111" + "source": "https://github.com/phpstan/php-8-stubs/tree/0.4.9" }, - "time": "2024-09-29T00:21:10+00:00" + "time": "2024-12-02T00:21:59+00:00" }, { "name": "phpstan/phpdoc-parser", - "version": "1.33.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + "reference": "c00d78fb6b29658347f9d37ebe104bffadf36299" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", - "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/c00d78fb6b29658347f9d37ebe104bffadf36299", + "reference": "c00d78fb6b29658347f9d37ebe104bffadf36299", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^5.3.0", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", "symfony/process": "^5.2" }, "type": "library", @@ -2329,9 +2331,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.0" }, - "time": "2024-10-13T11:25:22+00:00" + "time": "2024-10-13T11:29:49+00:00" }, { "name": "psr/container", @@ -3176,16 +3178,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": { @@ -3255,7 +3257,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.41" + "source": "https://github.com/symfony/console/tree/v5.4.43" }, "funding": [ { @@ -3271,7 +3273,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T07:48:55+00:00" + "time": "2024-08-13T16:31:56+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3342,16 +3344,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": { @@ -3385,7 +3387,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": [ { @@ -3401,7 +3403,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2024-08-13T14:03:51+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3721,159 +3723,6 @@ ], "time": "2024-06-19T12:30:46+00:00" }, - { - "name": "symfony/polyfill-php73", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "ec444d3f3f6505bb28d11afa41e75faadebc10a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/ec444d3f3f6505bb28d11afa41e75faadebc10a1", - "reference": "ec444d3f3f6505bb28d11afa41e75faadebc10a1", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - }, - { - "name": "symfony/polyfill-php74", - "version": "v1.30.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php74.git", - "reference": "37f1d1a2fb3ebc494f9f9b0f7e92064b43332321" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php74/zipball/37f1d1a2fb3ebc494f9f9b0f7e92064b43332321", - "reference": "37f1d1a2fb3ebc494f9f9b0f7e92064b43332321", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php74\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.4+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php74/tree/v1.30.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-05-31T15:07:36+00:00" - }, { "name": "symfony/polyfill-php80", "version": "v1.30.0", @@ -4177,16 +4026,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": { @@ -4243,7 +4092,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.41" + "source": "https://github.com/symfony/string/tree/v5.4.43" }, "funding": [ { @@ -4259,7 +4108,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:20:55+00:00" + "time": "2024-08-01T10:24:28+00:00" } ], "packages-dev": [ @@ -4406,30 +4255,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": { @@ -4456,7 +4305,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": [ { @@ -4472,7 +4321,7 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "jean85/pretty-package-versions", @@ -4535,16 +4384,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": { @@ -4552,11 +4401,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", @@ -4582,7 +4432,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": [ { @@ -4590,34 +4440,34 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2024-06-12T14:39:25+00:00" }, { "name": "ondrejmirtes/simple-downgrader", - "version": "1.0.2", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/ondrejmirtes/simple-downgrader.git", - "reference": "832aaae53dcfe358f63180494de8734244773d46" + "reference": "fb8b7833034f0396d5e4518ed090e3d099b7d9bc" }, "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/fb8b7833034f0396d5e4518ed090e3d099b7d9bc", + "reference": "fb8b7833034f0396d5e4518ed090e3d099b7d9bc", "shasum": "" }, "require": { "nette/utils": "^3.2.5", - "nikic/php-parser": "^4.18", - "php": "^7.2|^8.0", - "phpstan/phpdoc-parser": "^1.24.5", + "nikic/php-parser": "^5.3.0", + "php": "^7.4|^8.0", + "phpstan/phpdoc-parser": "^2.0", "symfony/console": "^5.4", "symfony/finder": "^5.4" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.3", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^8.5.36" + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^9.6" }, "bin": [ "bin/simple-downgrade" @@ -4637,26 +4487,27 @@ "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.0.0" }, - "time": "2024-02-12T19:22:32+00:00" + "time": "2024-10-09T14:55:47+00:00" }, { "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", @@ -4697,9 +4548,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", @@ -4815,26 +4672,26 @@ }, { "name": "phpstan/phpstan-deprecation-rules", - "version": "1.2.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", - "reference": "fa8cce7720fa782899a0aa97b6a41225d1bb7b26" + "reference": "81833b5787e2e8f451b31218875e29e4ed600ab2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/fa8cce7720fa782899a0aa97b6a41225d1bb7b26", - "reference": "fa8cce7720fa782899a0aa97b6a41225d1bb7b26", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/81833b5787e2e8f451b31218875e29e4ed600ab2", + "reference": "81833b5787e2e8f451b31218875e29e4ed600ab2", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -4856,27 +4713,27 @@ "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "support": { "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", - "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.2.0" + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/2.0.0" }, - "time": "2024-04-20T06:39:48+00:00" + "time": "2024-10-26T16:04:11+00:00" }, { "name": "phpstan/phpstan-nette", - "version": "1.3.8", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-nette.git", - "reference": "bc74b8b208b47f163fe55708fcf1a0333247fa79" + "reference": "cacb6983bbdf44d5c3a7222e5ca74f61f8531806" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-nette/zipball/bc74b8b208b47f163fe55708fcf1a0333247fa79", - "reference": "bc74b8b208b47f163fe55708fcf1a0333247fa79", + "url": "https://api.github.com/repos/phpstan/phpstan-nette/zipball/cacb6983bbdf44d5c3a7222e5ca74f61f8531806", + "reference": "cacb6983bbdf44d5c3a7222e5ca74f61f8531806", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" }, "conflict": { "nette/application": "<2.3.0", @@ -4888,13 +4745,13 @@ }, "require-dev": { "nette/application": "^3.0", + "nette/di": "^3.1.10", "nette/forms": "^3.0", "nette/utils": "^2.3.0 || ^3.0.0", - "nikic/php-parser": "^4.13.2", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "~9.5.28" + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -4917,36 +4774,35 @@ "description": "Nette Framework class reflection extension for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-nette/issues", - "source": "https://github.com/phpstan/phpstan-nette/tree/1.3.8" + "source": "https://github.com/phpstan/phpstan-nette/tree/2.0.0" }, - "time": "2024-08-25T12:11:12+00:00" + "time": "2024-10-26T16:03:48+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.4.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11" + "reference": "3cc855474263ad6220dfa49167cbea34ca1dd300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/3cc855474263ad6220dfa49167cbea34ca1dd300", + "reference": "3cc855474263ad6220dfa49167cbea34ca1dd300", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" }, "conflict": { "phpunit/phpunit": "<7.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -4969,34 +4825,33 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.0" }, - "time": "2024-04-20T06:39:00+00:00" + "time": "2024-10-14T03:16:27+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.6.0", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "363f921dd8441777d4fc137deb99beb486c77df1" + "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1", - "reference": "363f921dd8441777d4fc137deb99beb486c77df1", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", + "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-deprecation-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -5018,41 +4873,41 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.0" }, - "time": "2024-04-20T06:37:51+00:00" + "time": "2024-10-26T16:04:33+00:00" }, { "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", @@ -5061,7 +4916,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -5090,7 +4945,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": [ { @@ -5098,7 +4953,7 @@ "type": "github" } ], - "time": "2023-12-22T06:47:57+00:00" + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5343,50 +5198,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" @@ -5394,7 +5249,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -5425,7 +5280,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": [ { @@ -5435,22 +5291,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": { @@ -5485,7 +5345,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": [ { @@ -5493,7 +5353,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -5608,16 +5468,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": { @@ -5670,7 +5530,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": [ { @@ -5678,7 +5538,7 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { "name": "sebastian/complexity", @@ -5739,16 +5599,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": { @@ -5793,7 +5653,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": [ { @@ -5801,7 +5661,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", @@ -5868,16 +5728,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": { @@ -5933,7 +5793,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": [ { @@ -5941,20 +5801,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": { @@ -5997,7 +5857,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": [ { @@ -6005,7 +5865,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", @@ -6178,16 +6038,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": { @@ -6226,10 +6086,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": [ { @@ -6237,20 +6097,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": { @@ -6262,7 +6122,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -6283,8 +6143,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": [ { @@ -6292,20 +6151,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": { @@ -6317,7 +6176,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -6340,7 +6199,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": [ { @@ -6348,7 +6207,7 @@ "type": "github" } ], - "time": "2022-03-15T09:54:48+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -6529,16 +6388,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": { @@ -6567,7 +6426,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": [ { @@ -6575,7 +6434,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2024-03-03T12:36:25+00:00" } ], "aliases": [], diff --git a/conf/bleedingEdge.neon b/conf/bleedingEdge.neon index 8fb6e4da6a..76dd0d8904 100644 --- a/conf/bleedingEdge.neon +++ b/conf/bleedingEdge.neon @@ -1,67 +1,7 @@ parameters: featureToggles: bleedingEdge: true + checkParameterCastableToNumberFunctions: true skipCheckGenericClasses!: [] - explicitMixedInUnknownGenericNew: true - explicitMixedForGlobalVariables: true - explicitMixedViaIsArray: true - arrayFilter: true - arrayUnpacking: true - arrayValues: true - nodeConnectingVisitorCompatibility: false - nodeConnectingVisitorRule: true - disableCheckMissingIterableValueType: true - strictUnnecessaryNullsafePropertyFetch: true - looseComparison: true - consistentConstructor: true - checkUnresolvableParameterTypes: true - readOnlyByPhpDoc: true - phpDocParserRequireWhitespaceBeforeDescription: true - phpDocParserIncludeLines: true - enableIgnoreErrorsWithinPhpDocs: true - runtimeReflectionRules: true - notAnalysedTrait: true - curlSetOptTypes: true - listType: true - abstractTraitMethod: true - missingMagicSerializationRule: true - nullContextForVoidReturningFunctions: true - unescapeStrings: true - alwaysCheckTooWideReturnTypeFinalMethods: true - duplicateStubs: true - logicalXor: true - betterNoop: true - invarianceComposition: true - alwaysTrueAlwaysReported: true - disableUnreachableBranchesRules: true - varTagType: true - closureDefaultParameterTypeRule: true - newRuleLevelHelper: true - instanceofType: true - paramOutVariance: true - allInvalidPhpDocs: true - strictStaticMethodTemplateTypeVariance: true - propertyVariance: true - genericPrototypeMessage: true stricterFunctionMap: true - invalidPhpDocTagLine: true - detectDeadTypeInMultiCatch: true - zeroFiles: true - projectServicesNotInAnalysedPaths: true - callUserFunc: true - finalByPhpDoc: true - magicConstantOutOfContext: true - paramOutType: true - pure: true - checkParameterCastableToStringFunctions: true - uselessReturnValue: true - printfArrayParameters: true - preciseMissingReturn: true - validatePregQuote: true - noImplicitWildcard: true - tooWidePropertyType: true - explicitThrow: true - absentTypeChecks: true - requireFileExists: true - stubFiles: - - ../stubs/bleedingEdge/Rule.stub + reportPreciseLineForUnusedFunctionParameter: true diff --git a/conf/config.level0.neon b/conf/config.level0.neon index 15f1048b86..c84cf8f5f7 100644 --- a/conf/config.level0.neon +++ b/conf/config.level0.neon @@ -2,41 +2,14 @@ parameters: customRulesetUsed: false conditionalTags: - PHPStan\Rules\Api\NodeConnectingVisitorAttributesRule: - phpstan.rules.rule: %featureToggles.nodeConnectingVisitorRule% - PHPStan\Rules\Properties\MissingReadOnlyByPhpDocPropertyAssignRule: - phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc% - PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule: - phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc% PHPStan\Rules\Properties\UninitializedPropertyRule: phpstan.rules.rule: %checkUninitializedProperties% - PHPStan\Rules\Methods\ConsistentConstructorRule: - phpstan.rules.rule: %featureToggles.consistentConstructor% - PHPStan\Rules\Api\ApiClassConstFetchRule: - phpstan.rules.rule: %featureToggles.runtimeReflectionRules% - PHPStan\Rules\Api\ApiInstanceofRule: - phpstan.rules.rule: %featureToggles.runtimeReflectionRules% - PHPStan\Rules\Api\RuntimeReflectionFunctionRule: - phpstan.rules.rule: %featureToggles.runtimeReflectionRules% - PHPStan\Rules\Api\RuntimeReflectionInstantiationRule: - phpstan.rules.rule: %featureToggles.runtimeReflectionRules% - PHPStan\Rules\Methods\MissingMagicSerializationMethodsRule: - phpstan.rules.rule: %featureToggles.missingMagicSerializationRule% - PHPStan\Rules\Constants\MagicConstantContextRule: - phpstan.rules.rule: %featureToggles.magicConstantOutOfContext% - PHPStan\Rules\Functions\UselessFunctionReturnValueRule: - phpstan.rules.rule: %featureToggles.uselessReturnValue% - PHPStan\Rules\Functions\PrintfArrayParametersRule: - phpstan.rules.rule: %featureToggles.printfArrayParameters% - PHPStan\Rules\Regexp\RegularExpressionQuotingRule: - phpstan.rules.rule: %featureToggles.validatePregQuote% - PHPStan\Rules\Keywords\RequireFileExistsRule: - phpstan.rules.rule: %featureToggles.requireFileExists% - PHPStan\Rules\Classes\LocalTypeTraitUseAliasesRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% rules: + - PHPStan\Rules\Api\ApiInstanceofRule + - PHPStan\Rules\Api\ApiInstanceofTypeRule - PHPStan\Rules\Api\ApiInstantiationRule + - PHPStan\Rules\Api\ApiClassConstFetchRule - PHPStan\Rules\Api\ApiClassExtendsRule - PHPStan\Rules\Api\ApiClassImplementsRule - PHPStan\Rules\Api\ApiInterfaceExtendsRule @@ -44,9 +17,12 @@ rules: - PHPStan\Rules\Api\ApiStaticCallRule - PHPStan\Rules\Api\ApiTraitUseRule - PHPStan\Rules\Api\GetTemplateTypeRule + - PHPStan\Rules\Api\NodeConnectingVisitorAttributesRule + - PHPStan\Rules\Api\OldPhpParser4ClassRule - PHPStan\Rules\Api\PhpStanNamespaceIn3rdPartyPackageRule + - PHPStan\Rules\Api\RuntimeReflectionInstantiationRule + - PHPStan\Rules\Api\RuntimeReflectionFunctionRule - PHPStan\Rules\Arrays\DuplicateKeysInLiteralArraysRule - - PHPStan\Rules\Arrays\EmptyArrayItemRule - PHPStan\Rules\Arrays\OffsetAccessWithoutDimForReadingRule - PHPStan\Rules\Cast\UnsetCastRule - PHPStan\Rules\Classes\AllowedSubTypesRule @@ -63,6 +39,7 @@ rules: - PHPStan\Rules\Classes\InstantiationCallableRule - PHPStan\Rules\Classes\InvalidPromotedPropertiesRule - PHPStan\Rules\Classes\LocalTypeAliasesRule + - PHPStan\Rules\Classes\LocalTypeTraitUseAliasesRule - PHPStan\Rules\Classes\LocalTypeTraitAliasesRule - PHPStan\Rules\Classes\NewStaticRule - PHPStan\Rules\Classes\NonClassAttributeClassRule @@ -71,6 +48,7 @@ rules: - PHPStan\Rules\Constants\ClassAsClassConstantRule - PHPStan\Rules\Constants\DynamicClassConstantFetchRule - PHPStan\Rules\Constants\FinalConstantRule + - PHPStan\Rules\Constants\MagicConstantContextRule - PHPStan\Rules\Constants\NativeTypedClassConstantRule - PHPStan\Rules\EnumCases\EnumCaseAttributesRule - PHPStan\Rules\Exceptions\NoncapturingCatchRule @@ -87,6 +65,7 @@ rules: - PHPStan\Rules\Functions\InnerFunctionRule - PHPStan\Rules\Functions\InvalidLexicalVariablesInClosureUseRule - PHPStan\Rules\Functions\ParamAttributesRule + - PHPStan\Rules\Functions\PrintfArrayParametersRule - PHPStan\Rules\Functions\PrintfParametersRule - PHPStan\Rules\Functions\RedefinedParametersRule - PHPStan\Rules\Functions\ReturnNullsafeByRefRule @@ -98,47 +77,38 @@ rules: - PHPStan\Rules\Methods\AbstractPrivateMethodRule - PHPStan\Rules\Methods\CallMethodsRule - PHPStan\Rules\Methods\CallStaticMethodsRule + - PHPStan\Rules\Methods\ConsistentConstructorRule - PHPStan\Rules\Methods\ConstructorReturnTypeRule - PHPStan\Rules\Methods\ExistingClassesInTypehintsRule - PHPStan\Rules\Methods\FinalPrivateMethodRule - PHPStan\Rules\Methods\MethodCallableRule - PHPStan\Rules\Methods\MethodVisibilityInInterfaceRule + - PHPStan\Rules\Methods\MissingMagicSerializationMethodsRule - PHPStan\Rules\Methods\MissingMethodImplementationRule - PHPStan\Rules\Methods\MethodAttributesRule - PHPStan\Rules\Methods\StaticMethodCallableRule - PHPStan\Rules\Names\UsedNamesRule - PHPStan\Rules\Operators\InvalidAssignVarRule + - PHPStan\Rules\Operators\InvalidIncDecOperationRule - PHPStan\Rules\Properties\AccessPropertiesInAssignRule - PHPStan\Rules\Properties\AccessStaticPropertiesInAssignRule - PHPStan\Rules\Properties\InvalidCallablePropertyTypeRule - PHPStan\Rules\Properties\MissingReadOnlyPropertyAssignRule + - PHPStan\Rules\Properties\MissingReadOnlyByPhpDocPropertyAssignRule - PHPStan\Rules\Properties\PropertiesInInterfaceRule - PHPStan\Rules\Properties\PropertyAttributesRule + - PHPStan\Rules\Properties\PropertyInClassRule - PHPStan\Rules\Properties\ReadOnlyPropertyRule + - PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule + - PHPStan\Rules\Regexp\RegularExpressionPatternRule - PHPStan\Rules\Traits\ConflictingTraitConstantsRule - PHPStan\Rules\Traits\ConstantsInTraitsRule + - PHPStan\Rules\Traits\TraitAttributesRule - PHPStan\Rules\Types\InvalidTypesInUnionRule - PHPStan\Rules\Variables\UnsetRule - PHPStan\Rules\Whitespace\FileWhitespaceRule services: - - - class: PHPStan\Rules\Api\ApiClassConstFetchRule - - - class: PHPStan\Rules\Api\ApiInstanceofRule - - - class: PHPStan\Rules\Api\ApiInstanceofTypeRule - arguments: - enabled: %featureToggles.instanceofType% - deprecationRulesInstalled: %deprecationRulesInstalled% - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\Api\NodeConnectingVisitorAttributesRule - - - class: PHPStan\Rules\Api\RuntimeReflectionFunctionRule - - - class: PHPStan\Rules\Api\RuntimeReflectionInstantiationRule - class: PHPStan\Rules\Classes\ExistingClassInClassExtendsRule tags: @@ -151,9 +121,6 @@ services: arguments: checkClassCaseSensitivity: %checkClassCaseSensitivity% - - - class: PHPStan\Rules\Classes\LocalTypeTraitUseAliasesRule - - class: PHPStan\Rules\Exceptions\CaughtExceptionExistenceRule tags: @@ -179,14 +146,10 @@ services: class: PHPStan\Rules\Methods\OverridingMethodRule arguments: checkPhpDocMethodSignatures: %checkPhpDocMethodSignatures% - genericPrototypeMessage: %featureToggles.genericPrototypeMessage% - finalByPhpDoc: %featureToggles.finalByPhpDoc% checkMissingOverrideMethodAttribute: %checkMissingOverrideMethodAttribute% tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Methods\ConsistentConstructorRule - class: PHPStan\Rules\Missing\MissingReturnRule @@ -210,14 +173,6 @@ services: arguments: checkFunctionNameCase: %checkFunctionNameCase% - - - class: PHPStan\Rules\Operators\InvalidIncDecOperationRule - tags: - - phpstan.rules.rule - arguments: - bleedingEdge: %featureToggles.bleedingEdge% - checkThisOnly: %checkThisOnly% - - class: PHPStan\Rules\Properties\AccessPropertiesRule tags: @@ -247,9 +202,6 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Properties\MissingReadOnlyByPhpDocPropertyAssignRule - - class: PHPStan\Rules\Properties\OverridingPropertyRule arguments: @@ -258,9 +210,6 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyRule - - class: PHPStan\Rules\Properties\UninitializedPropertyRule @@ -293,31 +242,14 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Regexp\RegularExpressionPatternRule - tags: - - phpstan.rules.rule - - class: PHPStan\Reflection\ConstructorsHelper arguments: additionalConstructors: %additionalConstructors% - - - class: PHPStan\Rules\Methods\MissingMagicSerializationMethodsRule - - - - class: PHPStan\Rules\Constants\MagicConstantContextRule - - - - class: PHPStan\Rules\Functions\UselessFunctionReturnValueRule - - - - class: PHPStan\Rules\Functions\PrintfArrayParametersRule - - - - class: PHPStan\Rules\Regexp\RegularExpressionQuotingRule - class: PHPStan\Rules\Keywords\RequireFileExistsRule arguments: currentWorkingDirectory: %currentWorkingDirectory% + tags: + - phpstan.rules.rule diff --git a/issue-bot/config.level10.neon b/conf/config.level10.neon similarity index 100% rename from issue-bot/config.level10.neon rename to conf/config.level10.neon diff --git a/conf/config.level2.neon b/conf/config.level2.neon index 1399394032..2d547cb94e 100644 --- a/conf/config.level2.neon +++ b/conf/config.level2.neon @@ -12,9 +12,19 @@ rules: - PHPStan\Rules\Cast\InvalidPartOfEncapsedStringRule - PHPStan\Rules\Cast\PrintRule - PHPStan\Rules\Classes\AccessPrivateConstantThroughStaticRule + - PHPStan\Rules\Classes\MethodTagRule + - PHPStan\Rules\Classes\MethodTagTraitRule + - PHPStan\Rules\Classes\MethodTagTraitUseRule + - PHPStan\Rules\Classes\PropertyTagRule + - PHPStan\Rules\Classes\PropertyTagTraitRule + - PHPStan\Rules\Classes\PropertyTagTraitUseRule + - PHPStan\Rules\Classes\MixinTraitRule + - PHPStan\Rules\Classes\MixinTraitUseRule - PHPStan\Rules\Comparison\UsageOfVoidMatchExpressionRule - PHPStan\Rules\Constants\ValueAssignedToClassConstantRule - PHPStan\Rules\Functions\IncompatibleDefaultParameterTypeRule + - PHPStan\Rules\Functions\IncompatibleArrowFunctionDefaultParameterTypeRule + - PHPStan\Rules\Functions\IncompatibleClosureDefaultParameterTypeRule - PHPStan\Rules\Generics\ClassAncestorsRule - PHPStan\Rules\Generics\ClassTemplateTypeRule - PHPStan\Rules\Generics\EnumAncestorsRule @@ -25,12 +35,16 @@ rules: - PHPStan\Rules\Generics\InterfaceTemplateTypeRule - PHPStan\Rules\Generics\MethodTemplateTypeRule - PHPStan\Rules\Generics\MethodTagTemplateTypeRule + - PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule - PHPStan\Rules\Generics\MethodSignatureVarianceRule + - PHPStan\Rules\Generics\PropertyVarianceRule - PHPStan\Rules\Generics\TraitTemplateTypeRule - PHPStan\Rules\Generics\UsedTraitsRule - PHPStan\Rules\Methods\CallPrivateMethodThroughStaticRule - PHPStan\Rules\Methods\IncompatibleDefaultParameterTypeRule + - PHPStan\Rules\Operators\InvalidBinaryOperationRule - PHPStan\Rules\Operators\InvalidComparisonOperationRule + - PHPStan\Rules\Operators\InvalidUnaryOperationRule - PHPStan\Rules\PhpDoc\FunctionConditionalReturnTypeRule - PHPStan\Rules\PhpDoc\MethodConditionalReturnTypeRule - PHPStan\Rules\PhpDoc\FunctionAssertRule @@ -41,48 +55,16 @@ rules: - PHPStan\Rules\PhpDoc\IncompatiblePropertyPhpDocTypeRule - PHPStan\Rules\PhpDoc\InvalidThrowsPhpDocValueRule - PHPStan\Rules\PhpDoc\IncompatibleParamImmediatelyInvokedCallableRule + - PHPStan\Rules\PhpDoc\VarTagChangedExpressionTypeRule + - PHPStan\Rules\PhpDoc\WrongVariableNameInVarTagRule - PHPStan\Rules\Properties\AccessPrivatePropertyThroughStaticRule - PHPStan\Rules\Classes\RequireImplementsRule - PHPStan\Rules\Classes\RequireExtendsRule - PHPStan\Rules\PhpDoc\RequireImplementsDefinitionClassRule - PHPStan\Rules\PhpDoc\RequireExtendsDefinitionClassRule - PHPStan\Rules\PhpDoc\RequireExtendsDefinitionTraitRule - -conditionalTags: - PHPStan\Rules\Classes\MethodTagRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\MethodTagTraitRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\MethodTagTraitUseRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\MixinTraitRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\MixinTraitUseRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\PropertyTagRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\PropertyTagTraitRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Classes\PropertyTagTraitUseRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Functions\IncompatibleArrowFunctionDefaultParameterTypeRule: - phpstan.rules.rule: %featureToggles.closureDefaultParameterTypeRule% - PHPStan\Rules\Functions\IncompatibleClosureDefaultParameterTypeRule: - phpstan.rules.rule: %featureToggles.closureDefaultParameterTypeRule% - PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - PHPStan\Rules\Methods\IllegalConstructorMethodCallRule: - phpstan.rules.rule: %featureToggles.illegalConstructorMethodCall% - PHPStan\Rules\Methods\IllegalConstructorStaticCallRule: - phpstan.rules.rule: %featureToggles.illegalConstructorMethodCall% - PHPStan\Rules\PhpDoc\VarTagChangedExpressionTypeRule: - phpstan.rules.rule: %featureToggles.varTagType% - PHPStan\Rules\Generics\PropertyVarianceRule: - phpstan.rules.rule: %featureToggles.propertyVariance% - PHPStan\Rules\Pure\PureFunctionRule: - phpstan.rules.rule: %featureToggles.pure% - PHPStan\Rules\Pure\PureMethodRule: - phpstan.rules.rule: %featureToggles.pure% + - PHPStan\Rules\Pure\PureFunctionRule + - PHPStan\Rules\Pure\PureMethodRule services: - @@ -90,30 +72,6 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Classes\MixinTraitRule - - - - class: PHPStan\Rules\Classes\MixinTraitUseRule - - - - class: PHPStan\Rules\Classes\MethodTagRule - - - - class: PHPStan\Rules\Classes\MethodTagTraitRule - - - - class: PHPStan\Rules\Classes\MethodTagTraitUseRule - - - - class: PHPStan\Rules\Classes\PropertyTagRule - - - - class: PHPStan\Rules\Classes\PropertyTagTraitRule - - - - class: PHPStan\Rules\Classes\PropertyTagTraitUseRule - - class: PHPStan\Rules\PhpDoc\RequireExtendsCheck arguments: @@ -126,10 +84,6 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Functions\IncompatibleArrowFunctionDefaultParameterTypeRule - - - class: PHPStan\Rules\Functions\IncompatibleClosureDefaultParameterTypeRule - class: PHPStan\Rules\Functions\CallCallablesRule arguments: @@ -137,17 +91,8 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule - - - class: PHPStan\Rules\Methods\IllegalConstructorMethodCallRule - - - class: PHPStan\Rules\Methods\IllegalConstructorStaticCallRule - class: PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule - arguments: - checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs% - invalidPhpDocTagLine: %featureToggles.invalidPhpDocTagLine% tags: - phpstan.rules.rule - @@ -159,36 +104,5 @@ services: - phpstan.rules.rule - class: PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule - arguments: - checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs% - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\PhpDoc\VarTagChangedExpressionTypeRule - - - class: PHPStan\Rules\PhpDoc\WrongVariableNameInVarTagRule - arguments: - checkTypeAgainstNativeType: %featureToggles.varTagType% - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\Generics\PropertyVarianceRule - arguments: - readOnlyByPhpDoc: %featureToggles.readOnlyByPhpDoc% - - - class: PHPStan\Rules\Pure\PureFunctionRule - - - - class: PHPStan\Rules\Pure\PureMethodRule - - - class: PHPStan\Rules\Operators\InvalidBinaryOperationRule - arguments: - bleedingEdge: %featureToggles.bleedingEdge% - tags: - - phpstan.rules.rule - - - class: PHPStan\Rules\Operators\InvalidUnaryOperationRule - arguments: - bleedingEdge: %featureToggles.bleedingEdge% tags: - phpstan.rules.rule diff --git a/conf/config.level3.neon b/conf/config.level3.neon index 5540500714..250d545f15 100644 --- a/conf/config.level3.neon +++ b/conf/config.level3.neon @@ -1,20 +1,9 @@ includes: - config.level2.neon -conditionalTags: - PHPStan\Rules\Arrays\ArrayUnpackingRule: - phpstan.rules.rule: %featureToggles.arrayUnpacking% - PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRefRule: - phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc% - PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRule: - phpstan.rules.rule: %featureToggles.readOnlyByPhpDoc% - PHPStan\Rules\Variables\ParameterOutAssignedTypeRule: - phpstan.rules.rule: %featureToggles.paramOutType% - PHPStan\Rules\Variables\ParameterOutExecutionEndTypeRule: - phpstan.rules.rule: %featureToggles.paramOutType% - rules: - PHPStan\Rules\Arrays\ArrayDestructuringRule + - PHPStan\Rules\Arrays\ArrayUnpackingRule - PHPStan\Rules\Arrays\IterableInForeachRule - PHPStan\Rules\Arrays\OffsetAccessAssignmentRule - PHPStan\Rules\Arrays\OffsetAccessAssignOpRule @@ -28,9 +17,12 @@ rules: - PHPStan\Rules\Methods\ReturnTypeRule - PHPStan\Rules\Properties\DefaultValueTypesAssignedToPropertiesRule - PHPStan\Rules\Properties\ReadOnlyPropertyAssignRule + - PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRule - PHPStan\Rules\Properties\ReadOnlyPropertyAssignRefRule + - PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRefRule - PHPStan\Rules\Properties\TypesAssignedToPropertiesRule - - PHPStan\Rules\Variables\ThrowTypeRule + - PHPStan\Rules\Variables\ParameterOutAssignedTypeRule + - PHPStan\Rules\Variables\ParameterOutExecutionEndTypeRule - PHPStan\Rules\Variables\VariableCloningRule parameters: @@ -87,18 +79,3 @@ services: reportMaybes: %reportMaybes% tags: - phpstan.rules.rule - - - - class: PHPStan\Rules\Arrays\ArrayUnpackingRule - - - - class: PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRefRule - - - - class: PHPStan\Rules\Properties\ReadOnlyByPhpDocPropertyAssignRule - - - - class: PHPStan\Rules\Variables\ParameterOutAssignedTypeRule - - - - class: PHPStan\Rules\Variables\ParameterOutExecutionEndTypeRule diff --git a/conf/config.level4.neon b/conf/config.level4.neon index 7d4441fcf9..bda46632c2 100644 --- a/conf/config.level4.neon +++ b/conf/config.level4.neon @@ -3,59 +3,34 @@ includes: rules: - PHPStan\Rules\Arrays\DeadForeachRule + - PHPStan\Rules\DeadCode\CallToConstructorStatementWithoutImpurePointsRule + - PHPStan\Rules\DeadCode\CallToFunctionStatementWithoutImpurePointsRule + - PHPStan\Rules\DeadCode\CallToMethodStatementWithoutImpurePointsRule + - PHPStan\Rules\DeadCode\CallToStaticMethodStatementWithoutImpurePointsRule + - PHPStan\Rules\DeadCode\NoopRule - PHPStan\Rules\DeadCode\UnreachableStatementRule - PHPStan\Rules\DeadCode\UnusedPrivateConstantRule - PHPStan\Rules\DeadCode\UnusedPrivateMethodRule - PHPStan\Rules\Exceptions\OverwrittenExitPointByFinallyRule - PHPStan\Rules\Functions\CallToFunctionStatementWithoutSideEffectsRule + - PHPStan\Rules\Functions\UselessFunctionReturnValueRule + - PHPStan\Rules\Methods\CallToConstructorStatementWithoutSideEffectsRule - PHPStan\Rules\Methods\CallToMethodStatementWithoutSideEffectsRule - PHPStan\Rules\Methods\CallToStaticMethodStatementWithoutSideEffectsRule - PHPStan\Rules\Methods\NullsafeMethodCallRule - PHPStan\Rules\TooWideTypehints\TooWideArrowFunctionReturnTypehintRule - PHPStan\Rules\TooWideTypehints\TooWideClosureReturnTypehintRule - PHPStan\Rules\TooWideTypehints\TooWideFunctionReturnTypehintRule + - PHPStan\Rules\TooWideTypehints\TooWideFunctionParameterOutTypeRule + - PHPStan\Rules\TooWideTypehints\TooWideMethodParameterOutTypeRule + - PHPStan\Rules\TooWideTypehints\TooWidePropertyTypeRule + - PHPStan\Rules\Traits\NotAnalysedTraitRule conditionalTags: - PHPStan\Rules\Comparison\ConstantLooseComparisonRule: - phpstan.rules.rule: %featureToggles.looseComparison% - PHPStan\Rules\Traits\TraitDeclarationCollector: - phpstan.collector: %featureToggles.notAnalysedTrait% - PHPStan\Rules\Traits\TraitUseCollector: - phpstan.collector: %featureToggles.notAnalysedTrait% - PHPStan\Rules\Traits\NotAnalysedTraitRule: - phpstan.rules.rule: %featureToggles.notAnalysedTrait% - PHPStan\Rules\Comparison\LogicalXorConstantConditionRule: - phpstan.rules.rule: %featureToggles.logicalXor% - PHPStan\Rules\DeadCode\BetterNoopRule: - phpstan.rules.rule: %featureToggles.betterNoop% - PHPStan\Rules\TooWideTypehints\TooWideFunctionParameterOutTypeRule: - phpstan.rules.rule: %featureToggles.paramOutType% - PHPStan\Rules\TooWideTypehints\TooWideMethodParameterOutTypeRule: - phpstan.rules.rule: %featureToggles.paramOutType% - PHPStan\Rules\DeadCode\CallToConstructorStatementWithoutImpurePointsRule: - phpstan.rules.rule: %featureToggles.pure% - PHPStan\Rules\DeadCode\PossiblyPureNewCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\DeadCode\ConstructorWithoutImpurePointsCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\DeadCode\CallToFunctionStatementWithoutImpurePointsRule: - phpstan.rules.rule: %featureToggles.pure% - PHPStan\Rules\DeadCode\PossiblyPureFuncCallCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\DeadCode\FunctionWithoutImpurePointsCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\DeadCode\CallToMethodStatementWithoutImpurePointsRule: - phpstan.rules.rule: %featureToggles.pure% - PHPStan\Rules\DeadCode\PossiblyPureMethodCallCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\DeadCode\MethodWithoutImpurePointsCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\DeadCode\CallToStaticMethodStatementWithoutImpurePointsRule: - phpstan.rules.rule: %featureToggles.pure% - PHPStan\Rules\DeadCode\PossiblyPureStaticCallCollector: - phpstan.collector: %featureToggles.pure% - PHPStan\Rules\TooWideTypehints\TooWidePropertyTypeRule: - phpstan.rules.rule: %featureToggles.tooWidePropertyType% + PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule: + phpstan.rules.rule: %exceptions.check.tooWideThrowType% + PHPStan\Rules\Exceptions\TooWideMethodThrowTypeRule: + phpstan.rules.rule: %exceptions.check.tooWideThrowType% parameters: checkAdvancedIsset: true @@ -64,7 +39,6 @@ services: - class: PHPStan\Rules\Classes\ImpossibleInstanceOfRule arguments: - checkAlwaysTrueInstanceof: %checkAlwaysTrueInstanceof% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% @@ -75,7 +49,6 @@ services: class: PHPStan\Rules\Comparison\BooleanAndConstantConditionRule arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - bleedingEdge: %featureToggles.bleedingEdge% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% tags: @@ -85,7 +58,6 @@ services: class: PHPStan\Rules\Comparison\BooleanOrConstantConditionRule arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - bleedingEdge: %featureToggles.bleedingEdge% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% tags: @@ -100,45 +72,40 @@ services: tags: - phpstan.rules.rule - - - class: PHPStan\Rules\DeadCode\NoopRule - arguments: - better: %featureToggles.betterNoop% - tags: - - phpstan.rules.rule - - - - class: PHPStan\Rules\DeadCode\CallToConstructorStatementWithoutImpurePointsRule - - class: PHPStan\Rules\DeadCode\ConstructorWithoutImpurePointsCollector + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\PossiblyPureNewCollector - - - - class: PHPStan\Rules\DeadCode\CallToFunctionStatementWithoutImpurePointsRule + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\FunctionWithoutImpurePointsCollector + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\PossiblyPureFuncCallCollector - - - - class: PHPStan\Rules\DeadCode\CallToMethodStatementWithoutImpurePointsRule + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\MethodWithoutImpurePointsCollector + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\PossiblyPureMethodCallCollector - - - - class: PHPStan\Rules\DeadCode\CallToStaticMethodStatementWithoutImpurePointsRule + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\PossiblyPureStaticCallCollector + tags: + - phpstan.collector - class: PHPStan\Rules\DeadCode\UnusedPrivatePropertyRule @@ -177,7 +144,6 @@ services: - class: PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRule arguments: - checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% @@ -187,7 +153,6 @@ services: - class: PHPStan\Rules\Comparison\ImpossibleCheckTypeMethodCallRule arguments: - checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% @@ -197,7 +162,6 @@ services: - class: PHPStan\Rules\Comparison\ImpossibleCheckTypeStaticMethodCallRule arguments: - checkAlwaysTrueCheckTypeFunctionCall: %checkAlwaysTrueCheckTypeFunctionCall% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% @@ -210,15 +174,12 @@ services: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% - - - - class: PHPStan\Rules\DeadCode\BetterNoopRule + tags: + - phpstan.rules.rule - class: PHPStan\Rules\Comparison\MatchExpressionRule arguments: - checkAlwaysTrueStrictComparison: %checkAlwaysTrueStrictComparison% - disableUnreachable: %featureToggles.disableUnreachableBranchesRules% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% tags: @@ -235,7 +196,6 @@ services: - class: PHPStan\Rules\Comparison\StrictComparisonOfDifferentTypesRule arguments: - checkAlwaysTrueStrictComparison: %checkAlwaysTrueStrictComparison% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% @@ -245,33 +205,16 @@ services: - class: PHPStan\Rules\Comparison\ConstantLooseComparisonRule arguments: - checkAlwaysTrueLooseComparison: %checkAlwaysTrueLooseComparison% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% reportAlwaysTrueInLastCondition: %reportAlwaysTrueInLastCondition% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% - - - - class: PHPStan\Rules\Comparison\TernaryOperatorConstantConditionRule - arguments: - treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% tags: - phpstan.rules.rule - - class: PHPStan\Rules\Comparison\UnreachableIfBranchesRule - arguments: - treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - disable: %featureToggles.disableUnreachableBranchesRules% - treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% - tags: - - phpstan.rules.rule - - - - class: PHPStan\Rules\Comparison\UnreachableTernaryElseBranchRule + class: PHPStan\Rules\Comparison\TernaryOperatorConstantConditionRule arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - disable: %featureToggles.disableUnreachableBranchesRules% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% tags: - phpstan.rules.rule @@ -293,17 +236,15 @@ services: - phpstan.rules.rule - - class: PHPStan\Rules\Methods\CallToConstructorStatementWithoutSideEffectsRule - arguments: - reportNoConstructor: %featureToggles.pure% - tags: - - phpstan.rules.rule + class: PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule + + - + class: PHPStan\Rules\Exceptions\TooWideMethodThrowTypeRule - class: PHPStan\Rules\TooWideTypehints\TooWideMethodReturnTypehintRule arguments: checkProtectedAndPublicMethods: %checkTooWideReturnTypesInProtectedAndPublicMethods% - alwaysCheckFinal: %featureToggles.alwaysCheckTooWideReturnTypeFinalMethods% tags: - phpstan.rules.rule @@ -314,12 +255,13 @@ services: - class: PHPStan\Rules\Traits\TraitDeclarationCollector + tags: + - phpstan.collector - class: PHPStan\Rules\Traits\TraitUseCollector - - - - class: PHPStan\Rules\Traits\NotAnalysedTraitRule + tags: + - phpstan.collector - class: PHPStan\Rules\Exceptions\CatchWithUnthrownExceptionRule @@ -328,12 +270,3 @@ services: reportUncheckedExceptionDeadCatch: %exceptions.reportUncheckedExceptionDeadCatch% tags: - phpstan.rules.rule - - - - class: PHPStan\Rules\TooWideTypehints\TooWideFunctionParameterOutTypeRule - - - - class: PHPStan\Rules\TooWideTypehints\TooWideMethodParameterOutTypeRule - - - - class: PHPStan\Rules\TooWideTypehints\TooWidePropertyTypeRule diff --git a/conf/config.level5.neon b/conf/config.level5.neon index 7b4f758f44..fd3835fbf1 100644 --- a/conf/config.level5.neon +++ b/conf/config.level5.neon @@ -6,21 +6,16 @@ parameters: checkArgumentsPassedByReference: true conditionalTags: - PHPStan\Rules\Functions\ArrayFilterRule: - phpstan.rules.rule: %featureToggles.arrayFilter% - PHPStan\Rules\Functions\ArrayValuesRule: - phpstan.rules.rule: %featureToggles.arrayValues% - PHPStan\Rules\Functions\CallUserFuncRule: - phpstan.rules.rule: %featureToggles.callUserFunc% - PHPStan\Rules\Functions\ParameterCastableToStringRule: - phpstan.rules.rule: %featureToggles.checkParameterCastableToStringFunctions% - PHPStan\Rules\Functions\ImplodeParameterCastableToStringRule: - phpstan.rules.rule: %featureToggles.checkParameterCastableToStringFunctions% - PHPStan\Rules\Functions\SortParameterCastableToStringRule: - phpstan.rules.rule: %featureToggles.checkParameterCastableToStringFunctions% + PHPStan\Rules\Functions\ParameterCastableToNumberRule: + phpstan.rules.rule: %featureToggles.checkParameterCastableToNumberFunctions% rules: - PHPStan\Rules\DateTimeInstantiationRule + - PHPStan\Rules\Functions\CallUserFuncRule + - PHPStan\Rules\Functions\ParameterCastableToStringRule + - PHPStan\Rules\Functions\ImplodeParameterCastableToStringRule + - PHPStan\Rules\Functions\SortParameterCastableToStringRule + - PHPStan\Rules\Regexp\RegularExpressionQuotingRule services: - @@ -35,24 +30,15 @@ services: arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% + tags: + - phpstan.rules.rule - class: PHPStan\Rules\Functions\ArrayValuesRule arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% - - - - class: PHPStan\Rules\Functions\CallUserFuncRule - - - class: PHPStan\Rules\Functions\ImplodeFunctionRule - arguments: - disabled: %featureToggles.checkParameterCastableToStringFunctions% tags: - phpstan.rules.rule - - class: PHPStan\Rules\Functions\ParameterCastableToStringRule - - - class: PHPStan\Rules\Functions\ImplodeParameterCastableToStringRule - - - class: PHPStan\Rules\Functions\SortParameterCastableToStringRule + class: PHPStan\Rules\Functions\ParameterCastableToNumberRule diff --git a/conf/config.level6.neon b/conf/config.level6.neon index 1029bcdba0..25214e97dd 100644 --- a/conf/config.level6.neon +++ b/conf/config.level6.neon @@ -2,35 +2,14 @@ includes: - config.level5.neon parameters: - checkGenericClassInNonGenericObjectType: true - checkMissingIterableValueType: true checkMissingVarTagTypehint: true checkMissingTypehints: true rules: - PHPStan\Rules\Constants\MissingClassConstantTypehintRule + - PHPStan\Rules\Functions\MissingFunctionParameterTypehintRule - PHPStan\Rules\Functions\MissingFunctionReturnTypehintRule + - PHPStan\Rules\Methods\MissingMethodParameterTypehintRule - PHPStan\Rules\Methods\MissingMethodReturnTypehintRule + - PHPStan\Rules\Methods\MissingMethodSelfOutTypeRule - PHPStan\Rules\Properties\MissingPropertyTypehintRule - -conditionalTags: - PHPStan\Rules\Methods\MissingMethodSelfOutTypeRule: - phpstan.rules.rule: %featureToggles.absentTypeChecks% - -services: - - - class: PHPStan\Rules\Functions\MissingFunctionParameterTypehintRule - arguments: - paramOut: %featureToggles.paramOutType% - tags: - - phpstan.rules.rule - - - - class: PHPStan\Rules\Methods\MissingMethodParameterTypehintRule - arguments: - paramOut: %featureToggles.paramOutType% - tags: - - phpstan.rules.rule - - - - class: PHPStan\Rules\Methods\MissingMethodSelfOutTypeRule diff --git a/conf/config.levelmax.neon b/conf/config.levelmax.neon index da48578fe3..ce4c43f2f7 100644 --- a/conf/config.levelmax.neon +++ b/conf/config.levelmax.neon @@ -1,2 +1,2 @@ includes: - - config.level9.neon + - config.level10.neon diff --git a/conf/config.neon b/conf/config.neon index 19b6388858..d77e889531 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -7,8 +7,7 @@ parameters: - ../stubs/runtime/ReflectionAttribute.php - ../stubs/runtime/Attribute.php - ../stubs/runtime/ReflectionIntersectionType.php - excludes_analyse: [] - excludePaths: null + excludePaths: [] level: null paths: [] exceptions: @@ -20,101 +19,23 @@ parameters: checkedExceptionClasses: [] check: missingCheckedExceptionInThrows: false - tooWideThrowType: false + tooWideThrowType: true featureToggles: bleedingEdge: false - disableRuntimeReflectionProvider: true - skipCheckGenericClasses: - - DatePeriod - - CallbackFilterIterator - - FilterIterator - - RecursiveCallbackFilterIterator - - AppendIterator - - NoRewindIterator - - LimitIterator - - InfiniteIterator - - CachingIterator - - RegexIterator - - ReflectionEnum - explicitMixedInUnknownGenericNew: false - explicitMixedForGlobalVariables: false - explicitMixedViaIsArray: false - arrayFilter: false - arrayUnpacking: false - arrayValues: false - nodeConnectingVisitorCompatibility: true - nodeConnectingVisitorRule: false - illegalConstructorMethodCall: false - disableCheckMissingIterableValueType: false - strictUnnecessaryNullsafePropertyFetch: false - looseComparison: false - consistentConstructor: false - checkUnresolvableParameterTypes: false - readOnlyByPhpDoc: false - phpDocParserRequireWhitespaceBeforeDescription: false - phpDocParserIncludeLines: false - enableIgnoreErrorsWithinPhpDocs: false - runtimeReflectionRules: false - notAnalysedTrait: false - curlSetOptTypes: false - listType: false - abstractTraitMethod: false - missingMagicSerializationRule: false - nullContextForVoidReturningFunctions: false - unescapeStrings: false - alwaysCheckTooWideReturnTypeFinalMethods: false - duplicateStubs: false - logicalXor: false - betterNoop: false - invarianceComposition: false - alwaysTrueAlwaysReported: false - disableUnreachableBranchesRules: false - varTagType: false - closureDefaultParameterTypeRule: false - newRuleLevelHelper: false - instanceofType: false - paramOutVariance: false - allInvalidPhpDocs: false - strictStaticMethodTemplateTypeVariance: false - propertyVariance: false - genericPrototypeMessage: false + checkParameterCastableToNumberFunctions: false + skipCheckGenericClasses: [] stricterFunctionMap: false - invalidPhpDocTagLine: false - detectDeadTypeInMultiCatch: false - zeroFiles: false - projectServicesNotInAnalysedPaths: false - callUserFunc: false - finalByPhpDoc: false - magicConstantOutOfContext: false - paramOutType: false - pure: false - checkParameterCastableToStringFunctions: false - uselessReturnValue: false - printfArrayParameters: false - preciseMissingReturn: false - validatePregQuote: false - noImplicitWildcard: false - requireFileExists: false - narrowPregMatches: true - tooWidePropertyType: false - explicitThrow: false - absentTypeChecks: false + reportPreciseLineForUnusedFunctionParameter: false fileExtensions: - php checkAdvancedIsset: false - checkAlwaysTrueCheckTypeFunctionCall: %featureToggles.alwaysTrueAlwaysReported% - checkAlwaysTrueInstanceof: %featureToggles.alwaysTrueAlwaysReported% - checkAlwaysTrueStrictComparison: %featureToggles.alwaysTrueAlwaysReported% - checkAlwaysTrueLooseComparison: %featureToggles.alwaysTrueAlwaysReported% reportAlwaysTrueInLastCondition: false checkClassCaseSensitivity: false checkExplicitMixed: false checkImplicitMixed: false checkFunctionArgumentTypes: false checkFunctionNameCase: false - checkGenericClassInNonGenericObjectType: false checkInternalClassCaseSensitivity: false - checkMissingIterableValueType: false checkMissingCallableSignature: false checkMissingVarTagTypehint: false checkArgumentsPassedByReference: false @@ -131,6 +52,7 @@ parameters: checkTooWideReturnTypesInProtectedAndPublicMethods: false checkUninitializedProperties: false checkDynamicProperties: false + strictRulesInstalled: false deprecationRulesInstalled: false inferPrivatePropertyTypeFromConstructor: false reportMaybes: false @@ -154,9 +76,9 @@ parameters: phpVersion: null polluteScopeWithLoopInitialAssignments: true polluteScopeWithAlwaysIterableForeach: true + polluteScopeWithBlock: true propertyAlwaysWrittenTags: [] propertyAlwaysReadTags: [] - fixerTmpDir: %pro.tmpDir% #unused additionalConstructors: [] treatPhpDocTypesAsCertain: true usePathConstantsAsConstantString: false @@ -169,10 +91,8 @@ parameters: ignoreErrors: [] internalErrorsCountLimit: 50 cache: - nodesByFileCountMax: 1024 nodesByStringCountMax: 256 reportUnmatchedIgnoredErrors: true - scopeClass: PHPStan\Analyser\MutatingScope typeAliases: [] universalObjectCratesClasses: - stdClass @@ -201,13 +121,11 @@ parameters: - ../stubs/arrayFunctions.stub - ../stubs/core.stub - ../stubs/typeCheckingFunctions.stub + - ../stubs/Countable.stub earlyTerminatingMethodCalls: [] earlyTerminatingFunctionCalls: [] - memoryLimitFile: %tmpDir%/.memory_limit - tempResultCachePath: %tmpDir%/resultCaches resultCachePath: %tmpDir%/resultCache.php resultCacheChecksProjectExtensionFilesDependencies: false - staticReflectionClassNamePatterns: [] dynamicConstantNames: - ICONV_IMPL - LIBXML_VERSION @@ -291,16 +209,6 @@ conditionalTags: phpstan.rules.rule: %exceptions.check.missingCheckedExceptionInThrows% PHPStan\Rules\Exceptions\MissingCheckedExceptionInMethodThrowsRule: phpstan.rules.rule: %exceptions.check.missingCheckedExceptionInThrows% - PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule: - phpstan.rules.rule: %exceptions.check.tooWideThrowType% - PHPStan\Rules\Exceptions\TooWideMethodThrowTypeRule: - phpstan.rules.rule: %exceptions.check.tooWideThrowType% - PhpParser\NodeVisitor\NodeConnectingVisitor: - phpstan.parser.richParserNodeVisitor: %featureToggles.nodeConnectingVisitorCompatibility% - PHPStan\Parser\CurlSetOptArgVisitor: - phpstan.parser.richParserNodeVisitor: %featureToggles.curlSetOptTypes% - PHPStan\Parser\TypeTraverserInstanceofVisitor: - phpstan.parser.richParserNodeVisitor: %featureToggles.instanceofType% services: - @@ -357,9 +265,8 @@ services: - class: PHPStan\Parser\CurlSetOptArgVisitor - - - - class: PHPStan\Parser\TypeTraverserInstanceofVisitor + tags: + - phpstan.parser.richParserNodeVisitor - class: PHPStan\Parser\ArrowFunctionArgVisitor @@ -381,6 +288,11 @@ services: tags: - phpstan.parser.richParserNodeVisitor + - + class: PHPStan\Parser\StandaloneThrowExprVisitor + tags: + - phpstan.parser.richParserNodeVisitor + - class: PHPStan\Parser\TryCatchTypeVisitor tags: @@ -392,13 +304,27 @@ services: - phpstan.parser.richParserNodeVisitor - - class: PhpParser\NodeVisitor\NodeConnectingVisitor + class: PHPStan\Parser\TypeTraverserInstanceofVisitor + tags: + - phpstan.parser.richParserNodeVisitor + + - + class: PHPStan\Parser\VariadicMethodsVisitor + tags: + - phpstan.parser.richParserNodeVisitor + + - + class: PHPStan\Parser\VariadicFunctionsVisitor + tags: + - phpstan.parser.richParserNodeVisitor - class: PHPStan\Node\Printer\ExprPrinter - class: PHPStan\Node\Printer\Printer + autowired: + - PHPStan\Node\Printer\Printer - class: PHPStan\Broker\AnonymousClassNameHelper @@ -416,37 +342,35 @@ services: - class: PHPStan\Php\PhpVersionFactoryFactory arguments: - versionId: %phpVersion% + phpVersion: %phpVersion% composerAutoloaderProjectPaths: %composerAutoloaderProjectPaths% + - + class: PHPStan\Php\ComposerPhpVersionFactory + arguments: + composerAutoloaderProjectPaths: %composerAutoloaderProjectPaths% + + - + class: PHPStan\PhpDocParser\ParserConfig + arguments: + usedAttributes: + lines: true + - class: PHPStan\PhpDocParser\Lexer\Lexer - class: PHPStan\PhpDocParser\Parser\TypeParser - arguments: - quoteAwareConstExprString: %featureToggles.unescapeStrings% - class: PHPStan\PhpDocParser\Parser\ConstExprParser - factory: @PHPStan\PhpDoc\ConstExprParserFactory::create() - class: PHPStan\PhpDocParser\Parser\PhpDocParser - arguments: - requireWhitespaceBeforeDescription: %featureToggles.phpDocParserRequireWhitespaceBeforeDescription% - preserveTypeAliasesWithInvalidTypes: true - usedAttributes: - lines: %featureToggles.phpDocParserIncludeLines% - class: PHPStan\PhpDocParser\Printer\Printer - - - class: PHPStan\PhpDoc\ConstExprParserFactory - arguments: - unescapeStrings: %featureToggles.unescapeStrings% - - class: PHPStan\PhpDoc\PhpDocInheritanceResolver @@ -471,15 +395,6 @@ services: - class: PHPStan\PhpDoc\StubValidator - arguments: - duplicateStubs: %featureToggles.duplicateStubs% - - - - class: PHPStan\PhpDoc\CountableStubFilesExtension - arguments: - bleedingEdge: %featureToggles.bleedingEdge% - tags: - - phpstan.stubFilesExtension - class: PHPStan\PhpDoc\SocketSelectStubFilesExtension @@ -536,8 +451,6 @@ services: - class: PHPStan\Analyser\LazyInternalScopeFactory - arguments: - scopeClass: %scopeClass% autowired: - PHPStan\Analyser\InternalScopeFactory @@ -551,15 +464,12 @@ services: reflector: @nodeScopeResolverReflector polluteScopeWithLoopInitialAssignments: %polluteScopeWithLoopInitialAssignments% polluteScopeWithAlwaysIterableForeach: %polluteScopeWithAlwaysIterableForeach% + polluteScopeWithBlock: %polluteScopeWithBlock% earlyTerminatingMethodCalls: %earlyTerminatingMethodCalls% earlyTerminatingFunctionCalls: %earlyTerminatingFunctionCalls% implicitThrows: %exceptions.implicitThrows% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - detectDeadTypeInMultiCatch: %featureToggles.detectDeadTypeInMultiCatch% universalObjectCratesClasses: %universalObjectCratesClasses% - paramOutType: %featureToggles.paramOutType% - preciseMissingReturn: %featureToggles.preciseMissingReturn% - explicitThrow: %featureToggles.explicitThrow% - class: PHPStan\Analyser\ConstantResolver @@ -696,13 +606,10 @@ services: - class: PHPStan\File\FileExcluderFactory arguments: - obsoleteExcludesAnalyse: %excludes_analyse% excludePaths: %excludePaths% - implement: PHPStan\File\FileExcluderRawFactory - arguments: - noImplicitWildcard: %featureToggles.noImplicitWildcard% fileExcluderAnalyse: class: PHPStan\File\FileExcluder @@ -759,9 +666,6 @@ services: tags: - phpstan.diagnoseExtension - - - class: PHPStan\Parser\FunctionCallStatementFinder - - class: PHPStan\Process\CpuCoreCounter @@ -809,6 +713,25 @@ services: - class: PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedSingleFileSourceLocatorRepository + - + class: PHPStan\Reflection\BetterReflection\Type\AdapterReflectionEnumCaseDynamicReturnTypeExtension + arguments: + class: PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumBackedCase + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + + - + class: PHPStan\Reflection\BetterReflection\Type\AdapterReflectionEnumCaseDynamicReturnTypeExtension + arguments: + class: PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumUnitCase + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + + - + class: PHPStan\Reflection\BetterReflection\Type\AdapterReflectionEnumDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - class: PHPStan\Reflection\RequireExtension\RequireExtendsMethodsClassReflectionExtension @@ -912,7 +835,6 @@ services: class: PHPStan\Rules\Arrays\NonexistentOffsetInArrayDimFetchCheck arguments: reportMaybes: %reportMaybes% - bleedingEdge: %featureToggles.bleedingEdge% reportPossiblyNonexistentGeneralArrayOffset: %reportPossiblyNonexistentGeneralArrayOffset% reportPossiblyNonexistentConstantArrayOffset: %reportPossiblyNonexistentConstantArrayOffset% @@ -933,7 +855,6 @@ services: globalTypeAliases: %typeAliases% checkMissingTypehints: %checkMissingTypehints% checkClassCaseSensitivity: %checkClassCaseSensitivity% - absentTypeChecks: %featureToggles.absentTypeChecks% - class: PHPStan\Rules\Classes\MethodTagCheck @@ -945,7 +866,6 @@ services: class: PHPStan\Rules\Classes\MixinCheck arguments: checkClassCaseSensitivity: %checkClassCaseSensitivity% - absentTypeChecks: %featureToggles.absentTypeChecks% checkMissingTypehints: %checkMissingTypehints% - @@ -958,14 +878,12 @@ services: class: PHPStan\Rules\Comparison\ConstantConditionRuleHelper arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - looseComparisonRuleEnabled: %featureToggles.looseComparison% - class: PHPStan\Rules\Comparison\ImpossibleCheckTypeHelper arguments: universalObjectCratesClasses: %universalObjectCratesClasses% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - nullContextForVoidReturningFunctions: %featureToggles.nullContextForVoidReturningFunctions% - class: PHPStan\Rules\Exceptions\DefaultExceptionTypeResolver @@ -988,14 +906,10 @@ services: arguments: exceptionTypeResolver: @exceptionTypeResolver - - - class: PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule - - - - class: PHPStan\Rules\Exceptions\TooWideMethodThrowTypeRule - - class: PHPStan\Rules\Exceptions\TooWideThrowTypeCheck + arguments: + implicitThrows: %exceptions.implicitThrows% - class: PHPStan\Rules\FunctionCallParametersCheck @@ -1004,14 +918,12 @@ services: checkArgumentsPassedByReference: %checkArgumentsPassedByReference% checkExtraArguments: %checkExtraArguments% checkMissingTypehints: %checkMissingTypehints% - checkUnresolvableParameterTypes: %featureToggles.checkUnresolvableParameterTypes% - class: PHPStan\Rules\FunctionDefinitionCheck arguments: checkClassCaseSensitivity: %checkClassCaseSensitivity% checkThisOnly: %checkThisOnly% - absentTypeChecks: %featureToggles.absentTypeChecks% - class: PHPStan\Rules\FunctionReturnTypeCheck @@ -1024,9 +936,8 @@ services: - class: PHPStan\Rules\Generics\GenericAncestorsCheck arguments: - checkGenericClassInNonGenericObjectType: %checkGenericClassInNonGenericObjectType% skipCheckGenericClasses: %featureToggles.skipCheckGenericClasses% - absentTypeChecks: %featureToggles.absentTypeChecks% + checkMissingTypehints: %checkMissingTypehints% - class: PHPStan\Rules\Generics\GenericObjectTypeCheck @@ -1041,16 +952,12 @@ services: - class: PHPStan\Rules\Generics\VarianceCheck - arguments: - checkParamOutVariance: %featureToggles.paramOutVariance% - strictStaticVariance: %featureToggles.strictStaticMethodTemplateTypeVariance% - class: PHPStan\Rules\IssetCheck arguments: checkAdvancedIsset: %checkAdvancedIsset% treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% - strictUnnecessaryNullsafePropertyFetch: %featureToggles.strictUnnecessaryNullsafePropertyFetch% - class: PHPStan\Rules\Methods\MethodCallCheck @@ -1070,19 +977,13 @@ services: arguments: reportMaybes: %reportMaybesInMethodSignatures% reportStatic: %reportStaticMethodSignatures% - abstractTraitMethod: %featureToggles.abstractTraitMethod% - class: PHPStan\Rules\Methods\MethodParameterComparisonHelper - arguments: - genericPrototypeMessage: %featureToggles.genericPrototypeMessage% - class: PHPStan\Rules\MissingTypehintCheck arguments: - checkMissingIterableValueType: %checkMissingIterableValueType% - disableCheckMissingIterableValueType: %featureToggles.disableCheckMissingIterableValueType% - checkGenericClassInNonGenericObjectType: %checkGenericClassInNonGenericObjectType% checkMissingCallableSignature: %checkMissingCallableSignature% skipCheckGenericClasses: %featureToggles.skipCheckGenericClasses% @@ -1103,7 +1004,6 @@ services: arguments: checkMissingTypehints: %checkMissingTypehints% checkClassCaseSensitivity: %checkClassCaseSensitivity% - absentTypeChecks: %featureToggles.absentTypeChecks% - class: PHPStan\Rules\PhpDoc\UnresolvableTypeHelper @@ -1140,11 +1040,12 @@ services: checkUnionTypes: %checkUnionTypes% checkExplicitMixed: %checkExplicitMixed% checkImplicitMixed: %checkImplicitMixed% - newRuleLevelHelper: %featureToggles.newRuleLevelHelper% checkBenevolentUnionTypes: %checkBenevolentUnionTypes% - class: PHPStan\Rules\UnusedFunctionParametersCheck + arguments: + reportExactLine: %featureToggles.reportPreciseLineForUnusedFunctionParameter% - class: PHPStan\Rules\TooWideTypehints\TooWideParameterOutTypeCheck @@ -1154,6 +1055,12 @@ services: arguments: phpParser: @defaultAnalysisParser + stubFileTypeMapper: + class: PHPStan\Type\FileTypeMapper + arguments: + phpParser: @stubParser + autowired: false + - class: PHPStan\Type\TypeAliasResolver factory: PHPStan\Type\UsefulTypeAliasResolver @@ -1383,13 +1290,18 @@ services: - phpstan.broker.dynamicFunctionReturnTypeExtension - - class: PHPStan\Type\Php\ConstantHelper + class: PHPStan\Type\Php\ConstantHelper - class: PHPStan\Type\Php\CountFunctionReturnTypeExtension tags: - phpstan.broker.dynamicFunctionReturnTypeExtension + - + class: PHPStan\Type\Php\CountCharsFunctionDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicFunctionReturnTypeExtension + - class: PHPStan\Type\Php\CountFunctionTypeSpecifyingExtension tags: @@ -1791,6 +1703,8 @@ services: - class: PHPStan\Type\Php\VersionCompareFunctionDynamicReturnTypeExtension + arguments: + configPhpVersion: %phpVersion% tags: - phpstan.broker.dynamicFunctionReturnTypeExtension @@ -1858,8 +1772,6 @@ services: class: PHPStan\Type\Php\IsArrayFunctionTypeSpecifyingExtension tags: - phpstan.typeSpecifier.functionTypeSpecifyingExtension - arguments: - explicitMixed: %featureToggles.explicitMixedViaIsArray% - class: PHPStan\Type\Php\IsCallableFunctionTypeSpecifyingExtension @@ -1904,7 +1816,6 @@ services: arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% universalObjectCratesClasses: %universalObjectCratesClasses% - nullContextForVoidReturningFunctions: %featureToggles.nullContextForVoidReturningFunctions% tags: - phpstan.broker.dynamicFunctionReturnTypeExtension @@ -2037,15 +1948,6 @@ services: parentDirectory: %currentWorkingDirectory% autowired: false - broker: - class: PHPStan\Broker\Broker - factory: @brokerFactory::create - autowired: - - PHPStan\Broker\Broker - - brokerFactory: - class: PHPStan\Broker\BrokerFactory - cacheStorage: class: PHPStan\Cache\FileCacheStorage arguments: @@ -2056,8 +1958,6 @@ services: class: PHPStan\Parser\RichParser arguments: parser: @currentPhpVersionPhpParser - lexer: @currentPhpVersionLexer - enableIgnoreErrorsWithinPhpDocs: %featureToggles.enableIgnoreErrorsWithinPhpDocs% autowired: no currentPhpVersionSimpleParser: @@ -2091,7 +1991,11 @@ services: autowired: false currentPhpVersionPhpParser: - class: PhpParser\Parser\Php7 + factory: @currentPhpVersionPhpParserFactory::create() + autowired: false + + currentPhpVersionPhpParserFactory: + class: PHPStan\Parser\PhpParserFactory arguments: lexer: @currentPhpVersionLexer autowired: false @@ -2104,7 +2008,8 @@ services: stubPhpDocProvider: class: PHPStan\PhpDoc\StubPhpDocProvider arguments: - parser: @defaultAnalysisParser + parser: @stubParser + fileTypeMapper: @stubFileTypeMapper # Reflection providers @@ -2134,27 +2039,6 @@ services: reflector: @originalBetterReflectionReflector autowired: false - # deprecated - betterReflectionClassReflector: - class: PHPStan\BetterReflection\Reflector\ClassReflector - arguments: - sourceLocator: @betterReflectionSourceLocator - autowired: false - - # deprecated - betterReflectionFunctionReflector: - class: PHPStan\BetterReflection\Reflector\FunctionReflector - arguments: - sourceLocator: @betterReflectionSourceLocator - autowired: false - - # deprecated - betterReflectionConstantReflector: - class: PHPStan\BetterReflection\Reflector\ConstantReflector - arguments: - sourceLocator: @betterReflectionSourceLocator - autowired: false - nodeScopeResolverReflector: factory: @betterReflectionReflector autowired: false @@ -2207,7 +2091,7 @@ services: autowired: false php8PhpParser: - class: PhpParser\Parser\Php7 + class: PhpParser\Parser\Php8 arguments: lexer: @php8Lexer autowired: false @@ -2226,11 +2110,25 @@ services: php8Parser: @php8Parser autowired: false + freshStubParser: + class: PHPStan\Parser\StubParser + arguments: + parser: @php8PhpParser + autowired: false + + stubParser: + class: PHPStan\Parser\CachedParser + arguments: + originalParser: @freshStubParser + cachedNodesByStringCountMax: %cache.nodesByStringCountMax% + autowired: false + phpstanDiagnoseExtension: class: PHPStan\Diagnose\PHPStanDiagnoseExtension arguments: composerAutoloaderProjectPaths: %composerAutoloaderProjectPaths% allConfigFiles: %allConfigFiles% + configPhpVersion: %phpVersion% autowired: false # Error formatters diff --git a/conf/config.stubValidator.neon b/conf/config.stubValidator.neon index 1645698a92..52eac72312 100644 --- a/conf/config.stubValidator.neon +++ b/conf/config.stubValidator.neon @@ -1,8 +1,6 @@ parameters: checkThisOnly: false checkClassCaseSensitivity: true - checkGenericClassInNonGenericObjectType: true - checkMissingIterableValueType: true checkMissingTypehints: true checkMissingCallableSignature: false __validate: false @@ -13,7 +11,10 @@ services: arguments: php8Parser: @php8PhpParser - nodeScopeResolverClassReflector: + defaultAnalysisParser!: + factory: @stubParser + + nodeScopeResolverReflector: factory: @stubReflector stubBetterReflectionProvider: @@ -38,3 +39,11 @@ services: factory: @stubBetterReflectionProvider autowired: - PHPStan\Reflection\ReflectionProvider + + currentPhpVersionLexer: + factory: @php8Lexer + autowired: false + + currentPhpVersionPhpParser: + factory: @php8PhpParser + autowired: false diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index d3359c6867..f7328f7863 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -1,7 +1,6 @@ parametersSchema: bootstrapFiles: listOf(string()) - excludes_analyse: listOf(string()) - excludePaths: schema(anyOf( + excludePaths: anyOf( structure([ analyse: listOf(string()), ]), @@ -12,7 +11,7 @@ parametersSchema: analyse: listOf(string()), analyseAndScan: listOf(string()) ]) - ), nullable()) + ) level: schema(anyOf(int(), string()), nullable()) paths: listOf(string()) exceptions: structure([ @@ -29,87 +28,20 @@ parametersSchema: ]) featureToggles: structure([ bleedingEdge: bool(), - disableRuntimeReflectionProvider: bool(), + checkParameterCastableToNumberFunctions: bool(), skipCheckGenericClasses: listOf(string()), - explicitMixedInUnknownGenericNew: bool(), - explicitMixedForGlobalVariables: bool(), - explicitMixedViaIsArray: bool(), - arrayFilter: bool(), - arrayUnpacking: bool(), - arrayValues: bool(), - nodeConnectingVisitorCompatibility: bool(), - nodeConnectingVisitorRule: bool(), - illegalConstructorMethodCall: bool(), - disableCheckMissingIterableValueType: bool(), - strictUnnecessaryNullsafePropertyFetch: bool(), - looseComparison: bool(), - consistentConstructor: bool() - checkUnresolvableParameterTypes: bool() - readOnlyByPhpDoc: bool() - phpDocParserRequireWhitespaceBeforeDescription: bool() - phpDocParserIncludeLines: bool() - enableIgnoreErrorsWithinPhpDocs: bool() - runtimeReflectionRules: bool() - notAnalysedTrait: bool() - curlSetOptTypes: bool() - listType: bool() - abstractTraitMethod: bool() - missingMagicSerializationRule: bool() - nullContextForVoidReturningFunctions: bool() - unescapeStrings: bool() - alwaysCheckTooWideReturnTypeFinalMethods: bool() - duplicateStubs: bool() - logicalXor: bool() - betterNoop: bool() - invarianceComposition: bool() - alwaysTrueAlwaysReported: bool() - disableUnreachableBranchesRules: bool() - varTagType: bool() - closureDefaultParameterTypeRule: bool() - newRuleLevelHelper: bool() - instanceofType: bool() - paramOutVariance: bool() - allInvalidPhpDocs: bool() - strictStaticMethodTemplateTypeVariance: bool() - propertyVariance: bool() - genericPrototypeMessage: bool() stricterFunctionMap: bool() - invalidPhpDocTagLine: bool() - detectDeadTypeInMultiCatch: bool() - zeroFiles: bool() - projectServicesNotInAnalysedPaths: bool() - callUserFunc: bool() - finalByPhpDoc: bool() - magicConstantOutOfContext: bool() - paramOutType: bool() - pure: bool() - checkParameterCastableToStringFunctions: bool() - uselessReturnValue: bool() - printfArrayParameters: bool() - preciseMissingReturn: bool() - validatePregQuote: bool() - noImplicitWildcard: bool() - narrowPregMatches: bool() - tooWidePropertyType: bool() - explicitThrow: bool() - absentTypeChecks: bool() - requireFileExists: bool() + reportPreciseLineForUnusedFunctionParameter: bool() ]) fileExtensions: listOf(string()) checkAdvancedIsset: bool() - checkAlwaysTrueCheckTypeFunctionCall: bool() - checkAlwaysTrueInstanceof: bool() - checkAlwaysTrueStrictComparison: bool() - checkAlwaysTrueLooseComparison: bool() reportAlwaysTrueInLastCondition: bool() checkClassCaseSensitivity: bool() checkExplicitMixed: bool() checkImplicitMixed: bool() checkFunctionArgumentTypes: bool() checkFunctionNameCase: bool() - checkGenericClassInNonGenericObjectType: bool() checkInternalClassCaseSensitivity: bool() - checkMissingIterableValueType: bool() checkMissingCallableSignature: bool() checkMissingVarTagTypehint: bool() checkArgumentsPassedByReference: bool() @@ -126,6 +58,7 @@ parametersSchema: checkTooWideReturnTypesInProtectedAndPublicMethods: bool() checkUninitializedProperties: bool() checkDynamicProperties: bool() + strictRulesInstalled: bool() deprecationRulesInstalled: bool() inferPrivatePropertyTypeFromConstructor: bool() @@ -149,9 +82,16 @@ parametersSchema: minimumNumberOfJobsPerProcess: int(), buffer: int() ]) - phpVersion: schema(anyOf(schema(int(), min(70100), max(80499))), nullable()) + phpVersion: schema(anyOf( + schema(int(), min(70100), max(80499)), + structure([ + min: schema(int(), min(70100), max(80499)), + max: schema(int(), min(70100), max(80499)) + ]) + ), nullable()) polluteScopeWithLoopInitialAssignments: bool() polluteScopeWithAlwaysIterableForeach: bool() + polluteScopeWithBlock: bool() propertyAlwaysWrittenTags: listOf(string()) propertyAlwaysReadTags: listOf(string()) additionalConstructors: listOf(string()) @@ -198,21 +138,16 @@ parametersSchema: ) internalErrorsCountLimit: int() cache: structure([ - nodesByFileCountMax: int() nodesByStringCountMax: int() ]) reportUnmatchedIgnoredErrors: bool() - scopeClass: string() typeAliases: arrayOf(string()) universalObjectCratesClasses: listOf(string()) stubFiles: listOf(string()) earlyTerminatingMethodCalls: arrayOf(listOf(string())) earlyTerminatingFunctionCalls: listOf(string()) - memoryLimitFile: string() - tempResultCachePath: string() resultCachePath: string() resultCacheChecksProjectExtensionFilesDependencies: bool() - staticReflectionClassNamePatterns: listOf(string()) dynamicConstantNames: listOf(string()) customRulesetUsed: schema(bool(), nullable()) rootDir: string() @@ -222,7 +157,6 @@ parametersSchema: mixinExcludeClasses: listOf(string()) scanFiles: listOf(string()) scanDirectories: listOf(string()) - fixerTmpDir: string() #unused editorUrl: schema(string(), nullable()) editorUrlTitle: schema(string(), nullable()) errorFormat: schema(string(), nullable()) @@ -243,7 +177,7 @@ parametersSchema: __validate: bool() # internal parameters only for DerivativeContainerFactory - additionalConfigFiles: arrayOf(string()) + additionalConfigFiles: listOf(string()) generateBaselineFile: schema(string(), nullable()) analysedPaths: listOf(string()) allConfigFiles: listOf(string()) diff --git a/e2e/bug-9622-trait/baseline-1.neon b/e2e/bug-9622-trait/baseline-1.neon index 1548dbca10..caa24d89e8 100644 --- a/e2e/bug-9622-trait/baseline-1.neon +++ b/e2e/bug-9622-trait/baseline-1.neon @@ -1,6 +1,6 @@ parameters: ignoreErrors: - - message: "#^Offset 'foo' does not exist on array\\{foo\\?\\: int\\}\\.$#" + message: "#^Offset 'foo' might not exist on array\\{foo\\?\\: int\\}\\.$#" count: 1 path: src/UsesBar.php diff --git a/e2e/bug-9622/baseline-1.neon b/e2e/bug-9622/baseline-1.neon index a7df787390..0ae88bf65b 100644 --- a/e2e/bug-9622/baseline-1.neon +++ b/e2e/bug-9622/baseline-1.neon @@ -1,6 +1,6 @@ parameters: ignoreErrors: - - message: "#^Offset 'foo' does not exist on array\\{foo\\?\\: int\\}\\.$#" + message: "#^Offset 'foo' might not exist on array\\{foo\\?\\: int\\}\\.$#" count: 1 path: src/Bar.php diff --git a/e2e/composer-and-phpstan-version-config/.gitignore b/e2e/composer-and-phpstan-version-config/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-and-phpstan-version-config/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-and-phpstan-version-config/composer.json b/e2e/composer-and-phpstan-version-config/composer.json new file mode 100644 index 0000000000..8fe9570814 --- /dev/null +++ b/e2e/composer-and-phpstan-version-config/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "^7.0" + } +} diff --git a/e2e/composer-and-phpstan-version-config/phpstan.neon b/e2e/composer-and-phpstan-version-config/phpstan.neon new file mode 100644 index 0000000000..003e5e1484 --- /dev/null +++ b/e2e/composer-and-phpstan-version-config/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + phpVersion: + min: 80103 + max: 80304 diff --git a/e2e/composer-and-phpstan-version-config/test.php b/e2e/composer-and-phpstan-version-config/test.php new file mode 100644 index 0000000000..a9afaa4b65 --- /dev/null +++ b/e2e/composer-and-phpstan-version-config/test.php @@ -0,0 +1,11 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<1, 3>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); + +\PHPStan\Testing\assertType('1', version_compare(PHP_VERSION, '7.0.0')); +\PHPStan\Testing\assertType('false', version_compare(PHP_VERSION, '7.0.0', '<')); +\PHPStan\Testing\assertType('true', version_compare(PHP_VERSION, '7.0.0', '>')); diff --git a/e2e/composer-max-version/.gitignore b/e2e/composer-max-version/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-max-version/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-max-version/composer.json b/e2e/composer-max-version/composer.json new file mode 100644 index 0000000000..4d4ca141ef --- /dev/null +++ b/e2e/composer-max-version/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "<=8.3" + } +} diff --git a/e2e/composer-max-version/test.php b/e2e/composer-max-version/test.php new file mode 100644 index 0000000000..038f559122 --- /dev/null +++ b/e2e/composer-max-version/test.php @@ -0,0 +1,10 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('int<5, 8>', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); + +\PHPStan\Testing\assertType('-1|0|1', version_compare(PHP_VERSION, '7.0.0')); +\PHPStan\Testing\assertType('bool', version_compare(PHP_VERSION, '7.0.0', '<')); +\PHPStan\Testing\assertType('bool', version_compare(PHP_VERSION, '7.0.0', '>')); diff --git a/e2e/composer-min-max-version/.gitignore b/e2e/composer-min-max-version/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-min-max-version/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-min-max-version/composer.json b/e2e/composer-min-max-version/composer.json new file mode 100644 index 0000000000..869fd2ce42 --- /dev/null +++ b/e2e/composer-min-max-version/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": ">=8.1, <=8.2.99" + } +} diff --git a/e2e/composer-min-max-version/test.php b/e2e/composer-min-max-version/test.php new file mode 100644 index 0000000000..28d770f3bb --- /dev/null +++ b/e2e/composer-min-max-version/test.php @@ -0,0 +1,10 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<1, 2>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); + +\PHPStan\Testing\assertType('1', version_compare(PHP_VERSION, '7.0.0')); +\PHPStan\Testing\assertType('false', version_compare(PHP_VERSION, '7.0.0', '<')); +\PHPStan\Testing\assertType('true', version_compare(PHP_VERSION, '7.0.0', '>')); diff --git a/e2e/composer-min-open-end-version/.gitignore b/e2e/composer-min-open-end-version/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-min-open-end-version/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-min-open-end-version/composer.json b/e2e/composer-min-open-end-version/composer.json new file mode 100644 index 0000000000..b6303c6b77 --- /dev/null +++ b/e2e/composer-min-open-end-version/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": ">= 8.1" + } +} diff --git a/e2e/composer-min-open-end-version/test.php b/e2e/composer-min-open-end-version/test.php new file mode 100644 index 0000000000..d4d06a34eb --- /dev/null +++ b/e2e/composer-min-open-end-version/test.php @@ -0,0 +1,6 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<1, 4>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-min-version-v5/.gitignore b/e2e/composer-min-version-v5/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-min-version-v5/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-min-version-v5/composer.json b/e2e/composer-min-version-v5/composer.json new file mode 100644 index 0000000000..b73464d219 --- /dev/null +++ b/e2e/composer-min-version-v5/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "^5.6" + } +} diff --git a/e2e/composer-min-version-v5/test.php b/e2e/composer-min-version-v5/test.php new file mode 100644 index 0000000000..2f652079a6 --- /dev/null +++ b/e2e/composer-min-version-v5/test.php @@ -0,0 +1,6 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('5', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('6', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, 99>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-min-version-v7/.gitignore b/e2e/composer-min-version-v7/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-min-version-v7/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-min-version-v7/composer.json b/e2e/composer-min-version-v7/composer.json new file mode 100644 index 0000000000..9f9b263871 --- /dev/null +++ b/e2e/composer-min-version-v7/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "^7" + } +} diff --git a/e2e/composer-min-version-v7/test.php b/e2e/composer-min-version-v7/test.php new file mode 100644 index 0000000000..e8876bd78f --- /dev/null +++ b/e2e/composer-min-version-v7/test.php @@ -0,0 +1,6 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('7', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<0, 4>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-min-version/.gitignore b/e2e/composer-min-version/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-min-version/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-min-version/composer.json b/e2e/composer-min-version/composer.json new file mode 100644 index 0000000000..9be64619f1 --- /dev/null +++ b/e2e/composer-min-version/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "^8.1" + } +} diff --git a/e2e/composer-min-version/test.php b/e2e/composer-min-version/test.php new file mode 100644 index 0000000000..d4d06a34eb --- /dev/null +++ b/e2e/composer-min-version/test.php @@ -0,0 +1,6 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<1, 4>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-no-versions/.gitignore b/e2e/composer-no-versions/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-no-versions/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-no-versions/composer.json b/e2e/composer-no-versions/composer.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/e2e/composer-no-versions/composer.json @@ -0,0 +1,2 @@ +{ +} diff --git a/e2e/composer-no-versions/test.php b/e2e/composer-no-versions/test.php new file mode 100644 index 0000000000..28c8a3183b --- /dev/null +++ b/e2e/composer-no-versions/test.php @@ -0,0 +1,6 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('int<5, 8>', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-version-config-invalid/phpstan.neon b/e2e/composer-version-config-invalid/phpstan.neon new file mode 100644 index 0000000000..96977def5f --- /dev/null +++ b/e2e/composer-version-config-invalid/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + phpVersion: + min: 80303 + max: 80104 + diff --git a/e2e/composer-version-config-patch/.gitignore b/e2e/composer-version-config-patch/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-version-config-patch/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-version-config-patch/composer.json b/e2e/composer-version-config-patch/composer.json new file mode 100644 index 0000000000..d6103988c8 --- /dev/null +++ b/e2e/composer-version-config-patch/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": ">=8.0.2, <8.0.15" + } +} diff --git a/e2e/composer-version-config-patch/test.php b/e2e/composer-version-config-patch/test.php new file mode 100644 index 0000000000..3f201eadab --- /dev/null +++ b/e2e/composer-version-config-patch/test.php @@ -0,0 +1,7 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('0', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<2, 15>', PHP_RELEASE_VERSION); diff --git a/e2e/composer-version-config/.gitignore b/e2e/composer-version-config/.gitignore new file mode 100644 index 0000000000..3a9875b460 --- /dev/null +++ b/e2e/composer-version-config/.gitignore @@ -0,0 +1,2 @@ +/vendor/ +composer.lock diff --git a/e2e/composer-version-config/composer.json b/e2e/composer-version-config/composer.json new file mode 100644 index 0000000000..2da0adaf1c --- /dev/null +++ b/e2e/composer-version-config/composer.json @@ -0,0 +1,5 @@ +{ + "require": { + "php": "^8.0" + } +} diff --git a/e2e/composer-version-config/phpstan.neon b/e2e/composer-version-config/phpstan.neon new file mode 100644 index 0000000000..003e5e1484 --- /dev/null +++ b/e2e/composer-version-config/phpstan.neon @@ -0,0 +1,4 @@ +parameters: + phpVersion: + min: 80103 + max: 80304 diff --git a/e2e/composer-version-config/test.php b/e2e/composer-version-config/test.php new file mode 100644 index 0000000000..a9afaa4b65 --- /dev/null +++ b/e2e/composer-version-config/test.php @@ -0,0 +1,11 @@ +', PHP_VERSION_ID); +\PHPStan\Testing\assertType('8', PHP_MAJOR_VERSION); +\PHPStan\Testing\assertType('int<1, 3>', PHP_MINOR_VERSION); +\PHPStan\Testing\assertType('int<0, max>', PHP_RELEASE_VERSION); + +\PHPStan\Testing\assertType('1', version_compare(PHP_VERSION, '7.0.0')); +\PHPStan\Testing\assertType('false', version_compare(PHP_VERSION, '7.0.0', '<')); +\PHPStan\Testing\assertType('true', version_compare(PHP_VERSION, '7.0.0', '>')); diff --git a/e2e/discussion-11362/phpstan.neon b/e2e/discussion-11362/phpstan.neon index d9a4bd0ab3..2e6178c1a7 100644 --- a/e2e/discussion-11362/phpstan.neon +++ b/e2e/discussion-11362/phpstan.neon @@ -1,7 +1,5 @@ parameters: excludePaths: - analyseAndScan: - - .git analyse: - vendor diff --git a/e2e/env-parameter/phpstan.neon b/e2e/env-parameter/phpstan.neon index 9287016809..b92bf25f4a 100644 --- a/e2e/env-parameter/phpstan.neon +++ b/e2e/env-parameter/phpstan.neon @@ -1,2 +1,2 @@ parameters: - scopeClass: %env.PHPSTAN_SCOPE_CLASS% + resultCachePath: %env.PHPSTAN_RESULT_CACHE_PATH% diff --git a/e2e/result-cache-5/phpstan.neon b/e2e/result-cache-5/phpstan.neon index ddbf4c2114..7c3f71ae98 100644 --- a/e2e/result-cache-5/phpstan.neon +++ b/e2e/result-cache-5/phpstan.neon @@ -5,3 +5,7 @@ parameters: level: 8 paths: - src + ignoreErrors: + - + identifier: instanceof.alwaysTrue + reportUnmatched: false diff --git a/e2e/result-cache-7/phpstan.neon b/e2e/result-cache-7/phpstan.neon index ddbf4c2114..66c19c7166 100644 --- a/e2e/result-cache-7/phpstan.neon +++ b/e2e/result-cache-7/phpstan.neon @@ -5,3 +5,6 @@ parameters: level: 8 paths: - src + ignoreErrors: + - + identifier: trait.unused diff --git a/issue-bot/composer.json b/issue-bot/composer.json index 92ec4ec6e8..1d35a96375 100644 --- a/issue-bot/composer.json +++ b/issue-bot/composer.json @@ -7,7 +7,7 @@ "league/commonmark": "^2.3", "nette/neon": "^3.3", "nette/utils": "^3.2", - "phpstan/phpstan-strict-rules": "1.6.x-dev", + "phpstan/phpstan-strict-rules": "^2.0", "symfony/console": "^6.1", "symfony/finder": "^6.1" }, diff --git a/issue-bot/composer.lock b/issue-bot/composer.lock index 2af3d80b5f..b4abdf4947 100644 --- a/issue-bot/composer.lock +++ b/issue-bot/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": "fa15712157441e401f9e8107ea219d0e", + "content-hash": "6a526cc8f4e310c4a649c65001b30782", "packages": [ { "name": "clue/stream-filter", @@ -1403,25 +1403,24 @@ }, { "name": "phpstan/phpstan", - "version": "1.11.x-dev", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "7a2e524c7bdc18295d62b0ed598cec1166da80ab" + "reference": "72115ab2bf1e40af1f9b238938d493ba7f3221e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/7a2e524c7bdc18295d62b0ed598cec1166da80ab", - "reference": "7a2e524c7bdc18295d62b0ed598cec1166da80ab", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/72115ab2bf1e40af1f9b238938d493ba7f3221e7", + "reference": "72115ab2bf1e40af1f9b238938d493ba7f3221e7", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" }, - "default-branch": true, "bin": [ "phpstan", "phpstan.phar" @@ -1458,34 +1457,32 @@ "type": "github" } ], - "time": "2024-04-19T14:55:18+00:00" + "time": "2024-11-11T07:06:55+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.6.x-dev", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "c7b4d283fbffd23b9405c01d1f68124739d698f6" + "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/c7b4d283fbffd23b9405c01d1f68124739d698f6", - "reference": "c7b4d283fbffd23b9405c01d1f68124739d698f6", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", + "reference": "a4a6a08bd4a461e516b9c3b8fdbf0f1883b34158", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-deprecation-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" }, - "default-branch": true, "type": "phpstan-extension", "extra": { "phpstan": { @@ -1506,9 +1503,9 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.x" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.0" }, - "time": "2024-04-19T14:52:46+00:00" + "time": "2024-10-26T16:04:33+00:00" }, { "name": "psr/cache", @@ -4472,14 +4469,12 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": { - "phpstan/phpstan-strict-rules": 20 - }, + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.3" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/patches/NeonParser.patch b/patches/NeonParser.patch deleted file mode 100644 index 9ff7a2b3de..0000000000 --- a/patches/NeonParser.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- src/Neon/Parser.php 2022-03-10 03:04:26 -+++ src/Neon/Parser.php 2024-08-26 21:57:02 -@@ -236,7 +236,7 @@ - } - - -- private function injectPos(Node $node, int $start = null, int $end = null): Node -+ private function injectPos(Node $node, ?int $start = null, ?int $end = null): Node - { - $node->startTokenPos = $start ?? $this->tokens->getPos(); - $node->startLine = $this->posToLine[$node->startTokenPos]; diff --git a/patches/NetteNeonStringNode.patch b/patches/NetteNeonStringNode.patch deleted file mode 100644 index ff7332693f..0000000000 --- a/patches/NetteNeonStringNode.patch +++ /dev/null @@ -1,40 +0,0 @@ ---- src/Neon/Node/StringNode.php 2022-03-10 03:04:26 -+++ src/Neon/Node/StringNode.php 2024-08-26 14:53:45 -@@ -79,27 +79,18 @@ - - public function toString(): string - { -- if (strpos($this->value, "\n") === false) { -- return "'" . str_replace("'", "''", $this->value) . "'"; -+ $res = json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); -+ if ($res === false) { -+ throw new Nette\Neon\Exception('Invalid UTF-8 sequence: ' . $this->value); -+ } - -- } elseif (preg_match('~\n[\t ]+\'{3}~', $this->value)) { -- $s = json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); -- $s = preg_replace_callback( -- '#[^\\\\]|\\\\(.)#s', -- function ($m) { -- return ['n' => "\n", 't' => "\t", '"' => '"'][$m[1] ?? ''] ?? $m[0]; -- }, -- substr($s, 1, -1) -- ); -- $s = str_replace('"""', '""\"', $s); -- $delim = '"""'; -- -- } else { -- $s = $this->value; -- $delim = "'''"; -+ if (strpos($this->value, "\n") !== false) { -+ $res = preg_replace_callback('#[^\\\\]|\\\\(.)#s', function ($m) { -+ return ['n' => "\n\t", 't' => "\t", '"' => '"'][$m[1] ?? ''] ?? $m[0]; -+ }, $res); -+ $res = '"""' . "\n\t" . substr($res, 1, -1) . "\n" . '"""'; - } - -- $s = preg_replace('#^(?=.)#m', "\t", $s); -- return $delim . "\n" . $s . "\n" . $delim; -+ return $res; - } - } diff --git a/phpcs.xml b/phpcs.xml index 7ec0a21da2..fa9198745f 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,6 +1,7 @@ + diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1662d1fa9a..d3e9a54a9d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,1838 +1,1984 @@ parameters: ignoreErrors: - - message: "#^Method PHPStan\\\\Analyser\\\\AnalyserResultFinalizer\\:\\:finalize\\(\\) throws checked exception Throwable but it's missing from the PHPDoc @throws tag\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 - path: src/Analyser/AnalyserResultFinalizer.php + path: build/PHPStan/Build/ContainerDynamicReturnTypeExtension.php - - message: "#^Function is_a\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Method PHPStan\\Analyser\\AnalyserResultFinalizer\:\:finalize\(\) throws checked exception Throwable but it''s missing from the PHPDoc @throws tag\.$#' + identifier: missingType.checkedException count: 1 - path: src/Analyser/DirectInternalScopeFactory.php + path: src/Analyser/AnalyserResultFinalizer.php - - message: "#^Cannot assign offset 'realCount' to array\\|string\\.$#" + message: '#^Cannot assign offset ''realCount'' to array\\|string\.$#' + identifier: offsetAssign.dimType count: 1 path: src/Analyser/Ignore/IgnoredErrorHelperResult.php - - message: "#^Function is_a\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" - count: 1 - path: src/Analyser/LazyInternalScopeFactory.php - - - - message: """ - #^Call to deprecated method getAnyArrays\\(\\) of class PHPStan\\\\Type\\\\TypeUtils\\: - Use PHPStan\\\\Type\\\\Type\\:\\:getArrays\\(\\) instead\\.$# - """ - count: 2 - path: src/Analyser/MutatingScope.php - - - - message: "#^Casting to string something that's already string\\.$#" + message: '#^Casting to string something that''s already string\.$#' + identifier: cast.useless count: 3 path: src/Analyser/MutatingScope.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Analyser/MutatingScope.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Analyser/MutatingScope.php - - message: "#^Only numeric types are allowed in pre\\-increment, float\\|int\\|string\\|null given\\.$#" + message: '#^Only numeric types are allowed in pre\-increment, float\|int\|string\|null given\.$#' + identifier: preInc.nonNumeric count: 1 path: src/Analyser/MutatingScope.php - - message: """ - #^Call to deprecated method doNotTreatPhpDocTypesAsCertain\\(\\) of class PHPStan\\\\Analyser\\\\MutatingScope\\: - Use getNativeType\\(\\)$# - """ - count: 1 - path: src/Analyser/NodeScopeResolver.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 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\\Function_\|PhpParser\\Node\\Stmt\\Interface_\|PhpParser\\Node\\Stmt\\Trait_, PhpParser\\Node\\Stmt\\ClassLike given\.$#' + identifier: argument.type count: 1 path: src/Analyser/NodeScopeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Analyser/RicherScopeGetTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Analyser/TypeSpecifier.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 5 path: src/Analyser/TypeSpecifier.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Analyser/TypeSpecifier.php - - message: "#^Template type TNodeType is declared as covariant, but occurs in contravariant position in parameter node of method PHPStan\\\\Collectors\\\\Collector\\:\\:processNode\\(\\)\\.$#" + message: '#^Template type TNodeType is declared as covariant, but occurs in contravariant position in parameter node of method PHPStan\\Collectors\\Collector\:\:processNode\(\)\.$#' + identifier: generics.variance count: 1 path: src/Collectors/Collector.php - - message: "#^Method PHPStan\\\\Collectors\\\\Registry\\:\\:__construct\\(\\) has parameter \\$collectors with generic interface PHPStan\\\\Collectors\\\\Collector but does not specify its types\\: TNodeType, TValue$#" + message: '#^Method PHPStan\\Collectors\\Registry\:\:__construct\(\) has parameter \$collectors with generic interface PHPStan\\Collectors\\Collector but does not specify its types\: TNodeType, TValue$#' + identifier: missingType.generics count: 1 path: src/Collectors/Registry.php - - message: "#^Property PHPStan\\\\Collectors\\\\Registry\\:\\:\\$cache with generic interface PHPStan\\\\Collectors\\\\Collector does not specify its types\\: TNodeType, TValue$#" + message: '#^Property PHPStan\\Collectors\\Registry\:\:\$cache with generic interface PHPStan\\Collectors\\Collector does not specify its types\: TNodeType, TValue$#' + identifier: missingType.generics count: 1 path: src/Collectors/Registry.php - - message: "#^Property PHPStan\\\\Collectors\\\\Registry\\:\\:\\$collectors with generic interface PHPStan\\\\Collectors\\\\Collector does not specify its types\\: TNodeType, TValue$#" + message: '#^Property PHPStan\\Collectors\\Registry\:\:\$collectors with generic interface PHPStan\\Collectors\\Collector does not specify its types\: TNodeType, TValue$#' + identifier: missingType.generics count: 1 path: src/Collectors/Registry.php - - message: "#^Anonymous function has an unused use \\$container\\.$#" + message: '#^Anonymous function has an unused use \$container\.$#' + identifier: closure.unusedUse count: 1 path: src/Command/CommandHelper.php - - message: "#^Parameter \\#1 \\$path of function dirname expects string, string\\|false given\\.$#" + message: '#^Parameter \#1 \$path of function dirname expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: src/Command/CommandHelper.php - - message: "#^Static property PHPStan\\\\Command\\\\CommandHelper\\:\\:\\$reservedMemory is never read, only written\\.$#" + message: '#^Static property PHPStan\\Command\\CommandHelper\:\:\$reservedMemory is never read, only written\.$#' + identifier: property.onlyWritten count: 1 path: src/Command/CommandHelper.php - - message: "#^Parameter \\#1 \\$headers \\(array\\\\) of method PHPStan\\\\Command\\\\ErrorsConsoleStyle\\:\\:table\\(\\) should be contravariant with parameter \\$headers \\(array\\) of method Symfony\\\\Component\\\\Console\\\\Style\\\\StyleInterface\\:\\:table\\(\\)$#" + message: '#^Parameter \#1 \$headers \(array\\) of method PHPStan\\Command\\ErrorsConsoleStyle\:\:table\(\) should be contravariant with parameter \$headers \(array\) of method Symfony\\Component\\Console\\Style\\StyleInterface\:\:table\(\)$#' + identifier: method.childParameterType count: 1 path: src/Command/ErrorsConsoleStyle.php - - message: "#^Parameter \\#1 \\$headers \\(array\\\\) of method PHPStan\\\\Command\\\\ErrorsConsoleStyle\\:\\:table\\(\\) should be contravariant with parameter \\$headers \\(array\\) of method Symfony\\\\Component\\\\Console\\\\Style\\\\SymfonyStyle\\:\\:table\\(\\)$#" + message: '#^Parameter \#1 \$headers \(array\\) of method PHPStan\\Command\\ErrorsConsoleStyle\:\:table\(\) should be contravariant with parameter \$headers \(array\) of method Symfony\\Component\\Console\\Style\\SymfonyStyle\:\:table\(\)$#' + identifier: method.childParameterType count: 1 path: src/Command/ErrorsConsoleStyle.php - - message: "#^Parameter \\#2 \\$rows \\(array\\\\>\\) of method PHPStan\\\\Command\\\\ErrorsConsoleStyle\\:\\:table\\(\\) should be contravariant with parameter \\$rows \\(array\\) of method Symfony\\\\Component\\\\Console\\\\Style\\\\StyleInterface\\:\\:table\\(\\)$#" + message: '#^Parameter \#2 \$rows \(array\\>\) of method PHPStan\\Command\\ErrorsConsoleStyle\:\:table\(\) should be contravariant with parameter \$rows \(array\) of method Symfony\\Component\\Console\\Style\\StyleInterface\:\:table\(\)$#' + identifier: method.childParameterType count: 1 path: src/Command/ErrorsConsoleStyle.php - - message: "#^Parameter \\#2 \\$rows \\(array\\\\>\\) of method PHPStan\\\\Command\\\\ErrorsConsoleStyle\\:\\:table\\(\\) should be contravariant with parameter \\$rows \\(array\\) of method Symfony\\\\Component\\\\Console\\\\Style\\\\SymfonyStyle\\:\\:table\\(\\)$#" + message: '#^Parameter \#2 \$rows \(array\\>\) of method PHPStan\\Command\\ErrorsConsoleStyle\:\:table\(\) should be contravariant with parameter \$rows \(array\) of method Symfony\\Component\\Console\\Style\\SymfonyStyle\:\:table\(\)$#' + identifier: method.childParameterType count: 1 path: src/Command/ErrorsConsoleStyle.php - - message: "#^Variable method call on Nette\\\\Schema\\\\Elements\\\\AnyOf\\|Nette\\\\Schema\\\\Elements\\\\Structure\\|Nette\\\\Schema\\\\Elements\\\\Type\\.$#" + message: '#^Variable method call on Nette\\Schema\\Elements\\AnyOf\|Nette\\Schema\\Elements\\Structure\|Nette\\Schema\\Elements\\Type\.$#' + identifier: method.dynamicName count: 1 path: src/DependencyInjection/ContainerFactory.php - - message: "#^Variable static method call on Nette\\\\Schema\\\\Expect\\.$#" + message: '#^Variable static method call on Nette\\Schema\\Expect\.$#' + identifier: staticMethod.dynamicName count: 1 path: src/DependencyInjection/ContainerFactory.php - - message: "#^Fetching class constant PREVENT_MERGING of deprecated class Nette\\\\DI\\\\Config\\\\Helpers\\.$#" + message: '#^Fetching class constant PREVENT_MERGING of deprecated class Nette\\DI\\Config\\Helpers\.$#' + identifier: classConstant.deprecatedClass count: 1 path: src/DependencyInjection/NeonAdapter.php - - message: "#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Diagnose/PHPStanDiagnoseExtension.php - - message: "#^Parameter \\#1 \\$path of function dirname expects string, string\\|false given\\.$#" + message: '#^Parameter \#1 \$path of function dirname expects string, string\|false given\.$#' + identifier: argument.type count: 1 path: src/Diagnose/PHPStanDiagnoseExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" - count: 1 - path: src/Internal/ContainerDynamicReturnTypeExtension.php - - - - message: "#^Variable method call on PHPStan\\\\Reflection\\\\ClassReflection\\.$#" + message: '#^Variable method call on PHPStan\\Reflection\\ClassReflection\.$#' + identifier: method.dynamicName count: 2 path: src/PhpDoc/PhpDocBlock.php - - message: "#^Variable static method call on PHPStan\\\\PhpDoc\\\\PhpDocBlock\\.$#" + message: '#^Variable static method call on PHPStan\\PhpDoc\\PhpDocBlock\.$#' + identifier: staticMethod.dynamicName count: 1 path: src/PhpDoc/PhpDocBlock.php - - message: "#^Call to function method_exists\\(\\) with PHPStan\\\\PhpDocParser\\\\Ast\\\\PhpDoc\\\\PhpDocNode and 'getParamOutTypeTagV…' will always evaluate to true\\.$#" - count: 1 - path: src/PhpDoc/PhpDocNodeResolver.php - - - - message: "#^Call to function method_exists\\(\\) with PHPStan\\\\PhpDocParser\\\\Ast\\\\PhpDoc\\\\PhpDocNode and 'getSelfOutTypeTagVa…' will always evaluate to true\\.$#" - count: 1 - path: src/PhpDoc/PhpDocNodeResolver.php - - - - message: "#^Property PHPStan\\\\PhpDocParser\\\\Ast\\\\PhpDoc\\\\AssertTagMethodValueNode\\:\\:\\$isEquality \\(bool\\) on left side of \\?\\? is not nullable\\.$#" - count: 1 - path: src/PhpDoc/PhpDocNodeResolver.php - - - - message: "#^Property PHPStan\\\\PhpDocParser\\\\Ast\\\\PhpDoc\\\\AssertTagPropertyValueNode\\:\\:\\$isEquality \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + message: '#^Call to function method_exists\(\) with PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode and ''getParamOutTypeTagV…'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/PhpDoc/PhpDocNodeResolver.php - - message: "#^Property PHPStan\\\\PhpDocParser\\\\Ast\\\\PhpDoc\\\\AssertTagValueNode\\:\\:\\$isEquality \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + message: '#^Call to function method_exists\(\) with PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode and ''getSelfOutTypeTagVa…'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/PhpDoc/PhpDocNodeResolver.php - - message: "#^Method PHPStan\\\\PhpDoc\\\\ResolvedPhpDocBlock\\:\\:getNameScope\\(\\) should return PHPStan\\\\Analyser\\\\NameScope but returns PHPStan\\\\Analyser\\\\NameScope\\|null\\.$#" + message: '#^Method PHPStan\\PhpDoc\\ResolvedPhpDocBlock\:\:getNameScope\(\) should return PHPStan\\Analyser\\NameScope but returns PHPStan\\Analyser\\NameScope\|null\.$#' + identifier: return.type count: 1 path: src/PhpDoc/ResolvedPhpDocBlock.php - - message: """ - #^Call to deprecated method getInstance\\(\\) of class PHPStan\\\\Broker\\\\Broker\\: - Use PHPStan\\\\Reflection\\\\ReflectionProviderStaticAccessor instead$# - """ + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 - path: src/PhpDoc/StubValidator.php + path: src/PhpDoc/TypeNodeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\CallableType is error\-prone and deprecated\. Use Type\:\:isCallable\(\) and Type\:\:getCallableParametersAcceptors\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/PhpDoc/TypeNodeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\CallableType is error\\-prone and deprecated\\. Use Type\\:\\:isCallable\\(\\) and Type\\:\\:getCallableParametersAcceptors\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/PhpDoc/TypeNodeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IterableType is error\\-prone and deprecated\\. Use Type\\:\\:isIterable\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/PhpDoc/TypeNodeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" - count: 2 + message: '#^Doing instanceof PHPStan\\Type\\IterableType is error\-prone and deprecated\. Use Type\:\:isIterable\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 1 path: src/PhpDoc/TypeNodeResolver.php - - message: "#^Property PHPStan\\\\PhpDocParser\\\\Ast\\\\Type\\\\CallableTypeNode\\:\\:\\$templateTypes \\(array\\\\) on left side of \\?\\? is not nullable\\.$#" - count: 1 + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 2 path: src/PhpDoc/TypeNodeResolver.php - - message: "#^Dead catch \\- PHPStan\\\\BetterReflection\\\\Identifier\\\\Exception\\\\InvalidIdentifierName is never thrown in the try block\\.$#" + message: '#^Dead catch \- PHPStan\\BetterReflection\\Identifier\\Exception\\InvalidIdentifierName is never thrown in the try block\.$#' + identifier: catch.neverThrown count: 3 path: src/Reflection/BetterReflection/BetterReflectionProvider.php - - message: "#^Dead catch \\- PHPStan\\\\BetterReflection\\\\NodeCompiler\\\\Exception\\\\UnableToCompileNode is never thrown in the try block\\.$#" + message: '#^Dead catch \- PHPStan\\BetterReflection\\NodeCompiler\\Exception\\UnableToCompileNode is never thrown in the try block\.$#' + identifier: catch.neverThrown count: 1 path: src/Reflection/BetterReflection/BetterReflectionProvider.php - - message: "#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php - - message: "#^Creating new ReflectionFunction is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Creating new ReflectionFunction is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 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\\Function_\|PhpParser\\Node\\Stmt\\Interface_\|PhpParser\\Node\\Stmt\\Trait_, PhpParser\\Node\\Stmt\\ClassLike given\.$#' + identifier: argument.type count: 1 path: src/Reflection/BetterReflection/SourceLocator/AutoloadSourceLocator.php - - message: "#^Method PHPStan\\\\Reflection\\\\BetterReflection\\\\SourceLocator\\\\FileReadTrapStreamWrapper\\:\\:invokeWithRealFileStreamWrapper\\(\\) has parameter \\$cb with no signature specified for callable\\.$#" + message: '#^Method PHPStan\\Reflection\\BetterReflection\\SourceLocator\\FileReadTrapStreamWrapper\:\:invokeWithRealFileStreamWrapper\(\) has parameter \$cb with no signature specified for callable\.$#' + identifier: missingType.callable count: 1 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\\.$#" - 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\\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\.$#' + identifier: argument.type 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\\Function_\|PhpParser\\Node\\Stmt\\Interface_\|PhpParser\\Node\\Stmt\\Trait_, PhpParser\\Node\\Stmt\\ClassLike given\.$#' + identifier: argument.type count: 2 path: src/Reflection/BetterReflection/SourceLocator/OptimizedSingleFileSourceLocator.php - - message: "#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Reflection/BetterReflection/SourceLocator/ReflectionClassSourceLocator.php - - message: "#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Reflection/BetterReflection/SourceLocator/RewriteClassAliasSourceLocator.php - - message: "#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Creating new ReflectionClass is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Reflection/BetterReflection/SourceLocator/SkipClassAliasSourceLocator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Reflection/ClassReflection.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Reflection/ClassReflection.php - - message: "#^Method PHPStan\\\\Reflection\\\\ClassReflection\\:\\:getCacheKey\\(\\) should return string but returns string\\|null\\.$#" + message: '#^Method PHPStan\\Reflection\\ClassReflection\:\:getCacheKey\(\) should return string but returns string\|null\.$#' + identifier: return.type count: 1 path: src/Reflection/ClassReflection.php - - message: "#^Binary operation \"&\" between bool\\|float\\|int\\|string\\|null and bool\\|float\\|int\\|string\\|null results in an error\\.$#" + message: '#^Binary operation "&" between bool\|float\|int\|string\|null and bool\|float\|int\|string\|null results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Binary operation \"\\*\" between bool\\|float\\|int\\|string\\|null and bool\\|float\\|int\\|string\\|null results in an error\\.$#" + message: '#^Binary operation "\*" between bool\|float\|int\|string\|null and bool\|float\|int\|string\|null results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Binary operation \"\\+\" between bool\\|float\\|int\\|string\\|null and bool\\|float\\|int\\|string\\|null results in an error\\.$#" + message: '#^Binary operation "\+" between bool\|float\|int\|string\|null and bool\|float\|int\|string\|null results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Binary operation \"\\-\" between bool\\|float\\|int\\|string\\|null and bool\\|float\\|int\\|string\\|null results in an error\\.$#" + message: '#^Binary operation "\-" between bool\|float\|int\|string\|null and bool\|float\|int\|string\|null results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Binary operation \"\\^\" between bool\\|float\\|int\\|string\\|null and bool\\|float\\|int\\|string\\|null results in an error\\.$#" + message: '#^Binary operation "\^" between bool\|float\|int\|string\|null and bool\|float\|int\|string\|null results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Binary operation \"\\|\" between bool\\|float\\|int\\|string\\|null and bool\\|float\\|int\\|string\\|null results in an error\\.$#" + message: '#^Binary operation "\|" between bool\|float\|int\|string\|null and bool\|float\|int\|string\|null results in an error\.$#' + identifier: binaryOp.invalid count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 22 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 10 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^PHPDoc tag @var with type float\\|int is not subtype of native type int\\.$#" + message: '#^PHPDoc tag @var with type float\|int is not subtype of native type int\.$#' + identifier: varTag.nativeType count: 1 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^PHPDoc tag @var with type float\\|int is not subtype of type int\\.$#" + message: '#^PHPDoc tag @var with type float\|int is not subtype of type int\.$#' + identifier: varTag.type count: 4 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^PHPDoc tag @var with type float\\|int\\|null is not subtype of type int\\|null\\.$#" + message: '#^PHPDoc tag @var with type float\|int\|null is not subtype of type int\|null\.$#' + identifier: varTag.type count: 6 path: src/Reflection/InitializerExprTypeResolver.php - - message: "#^Creating new PHPStan\\\\Php8StubsMap is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Creating new PHPStan\\Php8StubsMap is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.constructor count: 1 path: src/Reflection/SignatureMap/Php8SignatureMapProvider.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Api/NodeConnectingVisitorAttributesRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Arrays/DuplicateKeysInLiteralArraysRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Classes/ImpossibleInstanceOfRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Classes/RequireExtendsRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Classes/RequireImplementsRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 6 path: src/Rules/Comparison/BooleanAndConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/BooleanNotConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 6 path: src/Rules/Comparison/BooleanOrConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/ConstantLooseComparisonRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/DoWhileLoopConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/ElseIfConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/IfConstantConditionRule.php - - message: """ - #^Call to deprecated method doNotTreatPhpDocTypesAsCertain\\(\\) of interface PHPStan\\\\Analyser\\\\Scope\\: - Use getNativeType\\(\\)$# - """ - count: 1 - path: src/Rules/Comparison/ImpossibleCheckTypeHelper.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/ImpossibleCheckTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/ImpossibleCheckTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Rules/Comparison/ImpossibleCheckTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) or Type\\:\\:getObjectClassReflections\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\TypeWithClassName is error\-prone and deprecated\. Use Type\:\:getObjectClassNames\(\) or Type\:\:getObjectClassReflections\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Comparison/ImpossibleCheckTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Rules/Comparison/LogicalXorConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Rules/Comparison/MatchExpressionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/NumberComparisonOperatorsConstantConditionRule.php - - message: """ - #^Call to deprecated method doNotTreatPhpDocTypesAsCertain\\(\\) of interface PHPStan\\\\Analyser\\\\Scope\\: - Use getNativeType\\(\\)$# - """ + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" - count: 2 - path: src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/Comparison/TernaryOperatorConstantConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" - count: 1 - path: src/Rules/Comparison/UnreachableIfBranchesRule.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" - count: 1 - path: src/Rules/Comparison/UnreachableTernaryElseBranchRule.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Comparison/WhileLoopAlwaysFalseConditionRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php - - message: "#^Function class_implements\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Function class_implements\(\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Rules/DirectRegistry.php - - message: "#^Function class_parents\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Function class_parents\(\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Rules/DirectRegistry.php - - message: "#^Method PHPStan\\\\Rules\\\\DirectRegistry\\:\\:__construct\\(\\) has parameter \\$rules with generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" + message: '#^Method PHPStan\\Rules\\DirectRegistry\:\:__construct\(\) has parameter \$rules with generic interface PHPStan\\Rules\\Rule but does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: src/Rules/DirectRegistry.php - - message: "#^Property PHPStan\\\\Rules\\\\DirectRegistry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Property PHPStan\\Rules\\DirectRegistry\:\:\$cache with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: src/Rules/DirectRegistry.php - - message: "#^Property PHPStan\\\\Rules\\\\DirectRegistry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Property PHPStan\\Rules\\DirectRegistry\:\:\$rules with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: src/Rules/DirectRegistry.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Generics/GenericAncestorsCheck.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Generics/TemplateTypeCheck.php - - message: "#^Function class_implements\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Function class_implements\(\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Rules/LazyRegistry.php - - message: "#^Function class_parents\\(\\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\\. Use objects retrieved from ReflectionProvider instead\\.$#" + message: '#^Function class_parents\(\) is a runtime reflection concept that might not work in PHPStan because it uses fully static reflection engine\. Use objects retrieved from ReflectionProvider instead\.$#' + identifier: phpstanApi.runtimeReflection count: 1 path: src/Rules/LazyRegistry.php - - message: "#^Method PHPStan\\\\Rules\\\\LazyRegistry\\:\\:getRulesFromContainer\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Method PHPStan\\Rules\\LazyRegistry\:\:getRulesFromContainer\(\) return type with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: src/Rules/LazyRegistry.php - - message: "#^Property PHPStan\\\\Rules\\\\LazyRegistry\\:\\:\\$cache with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Property PHPStan\\Rules\\LazyRegistry\:\:\$cache with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: src/Rules/LazyRegistry.php - - message: "#^Property PHPStan\\\\Rules\\\\LazyRegistry\\:\\:\\$rules with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Property PHPStan\\Rules\\LazyRegistry\:\:\$rules with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: src/Rules/LazyRegistry.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 1 + path: src/Rules/Methods/MethodParameterComparisonHelper.php + + - + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Methods/MethodParameterComparisonHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IterableType is error\\-prone and deprecated\\. Use Type\\:\\:isIterable\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IterableType is error\-prone and deprecated\. Use Type\:\:isIterable\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Methods/MethodParameterComparisonHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/Methods/StaticMethodCallCheck.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/PhpDoc/RequireExtendsCheck.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/PhpDoc/RequireImplementsDefinitionTraitRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/PhpDoc/VarTagTypeRuleHelper.php - - message: "#^Access to an undefined property T of PHPStan\\\\Rules\\\\RuleError\\:\\:\\$tip\\.$#" + message: '#^Access to an undefined property T of PHPStan\\Rules\\RuleError\:\:\$tip\.$#' + identifier: property.notFound count: 2 path: src/Rules/RuleErrorBuilder.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Rules/RuleLevelHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\NullType is error\\-prone and deprecated\\. Use Type\\:\\:isNull\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Rules/RuleLevelHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" - count: 2 - path: src/Rules/RuleLevelHelper.php + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 1 + path: src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectWithoutClassType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 - path: src/Rules/RuleLevelHelper.php + path: src/Rules/UnusedFunctionParametersCheck.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 - path: src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php + path: src/Rules/Variables/CompactVariablesRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 - path: src/Rules/UnusedFunctionParametersCheck.php + path: src/Rules/Variables/CompactVariablesRule.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: ''' + #^Call to deprecated method assertFileNotExists\(\) of class PHPUnit\\Framework\\Assert\: + https\://github\.com/sebastianbergmann/phpunit/issues/4077$# + ''' + identifier: staticMethod.deprecated count: 1 - path: src/Rules/Variables/CompactVariablesRule.php + path: src/Testing/LevelsTestCase.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Call to function method_exists\(\) with ''PHPUnit\\\\Framework\\\\TestCase'' and ''assertFileDoesNotEx…'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 - path: src/Rules/Variables/CompactVariablesRule.php + path: src/Testing/LevelsTestCase.php - - message: "#^Anonymous function has an unused use \\$container\\.$#" + message: '#^Anonymous function has an unused use \$container\.$#' + identifier: closure.unusedUse count: 1 path: src/Testing/PHPStanTestCase.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Testing/TypeInferenceTestCase.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryArrayListType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryLiteralStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryLowercaseStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryNonEmptyStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryNonEmptyStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryNonFalsyStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryNumericStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryNumericStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/AccessoryUppercaseStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/HasMethodType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/HasOffsetType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Accessory/HasOffsetValueType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Accessory/HasOffsetValueType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/HasOffsetValueType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/HasPropertyType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/NonEmptyArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Accessory/OversizedArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/ArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" - count: 1 + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 2 path: src/Type/ArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/ArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/ArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\BooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isBoolean\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\BooleanType is error\-prone and deprecated\. Use Type\:\:isBoolean\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/BooleanType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/BooleanType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\CallableType is error\\-prone and deprecated\\. Use Type\\:\\:isCallable\\(\\) and Type\\:\\:getCallableParametersAcceptors\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\CallableType is error\-prone and deprecated\. Use Type\:\:isCallable\(\) and Type\:\:getCallableParametersAcceptors\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/CallableType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/CallableType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/ClosureType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Constant/ConstantArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" - count: 10 + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 5 path: src/Type/Constant/ConstantArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" - count: 3 + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 2 path: src/Type/Constant/ConstantArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Constant/ConstantArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Constant/ConstantArrayTypeBuilder.php - - message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Type is always PHPStan\\\\Type\\\\Constant\\\\ConstantIntegerType\\|PHPStan\\\\Type\\\\Constant\\\\ConstantStringType but it's error\\-prone and dangerous\\.$#" + message: '#^PHPDoc tag @var assumes the expression with type PHPStan\\Type\\Type is always PHPStan\\Type\\Constant\\ConstantIntegerType\|PHPStan\\Type\\Constant\\ConstantStringType but it''s error\-prone and dangerous\.$#' + identifier: phpstanApi.varTagAssumption count: 2 path: src/Type/Constant/ConstantArrayTypeBuilder.php - - message: "#^PHPDoc tag @var with type float\\|int is not subtype of native type int\\.$#" + message: '#^PHPDoc tag @var with type float\|int is not subtype of native type int\.$#' + identifier: varTag.nativeType count: 2 path: src/Type/Constant/ConstantArrayTypeBuilder.php - - message: "#^PHPDoc tag @var with type float\\|int is not subtype of type int\\.$#" + message: '#^PHPDoc tag @var with type float\|int is not subtype of type int\.$#' + identifier: varTag.type count: 1 path: src/Type/Constant/ConstantArrayTypeBuilder.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\BooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isBoolean\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\BooleanType is error\-prone and deprecated\. Use Type\:\:isBoolean\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantBooleanType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Constant/ConstantBooleanType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Constant/ConstantBooleanType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Constant/ConstantFloatType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\FloatType is error\\-prone and deprecated\\. Use Type\\:\\:isFloat\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\FloatType is error\-prone and deprecated\. Use Type\:\:isFloat\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantFloatType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Constant/ConstantIntegerType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntegerType is error\\-prone and deprecated\\. Use Type\\:\\:isInteger\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntegerType is error\-prone and deprecated\. Use Type\:\:isInteger\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantIntegerType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Constant/ConstantStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Constant/ConstantStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\StringType is error\\-prone and deprecated\\. Use Type\\:\\:isString\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\StringType is error\-prone and deprecated\. Use Type\:\:isString\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/ConstantStringType.php - - message: "#^PHPDoc tag @var with type int\\|string is not subtype of type string\\.$#" + message: '#^PHPDoc tag @var with type int\|string is not subtype of type string\.$#' + identifier: varTag.type count: 1 path: src/Type/Constant/ConstantStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Constant/OversizedArrayBuilder.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Enum\\\\EnumCaseObjectType is error\\-prone and deprecated\\. Use Type\\:\\:getEnumCases\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Enum\\EnumCaseObjectType is error\-prone and deprecated\. Use Type\:\:getEnumCases\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Enum/EnumCaseObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/ExponentiateHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/FileTypeMapper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\FloatType is error\\-prone and deprecated\\. Use Type\\:\\:isFloat\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\FloatType is error\-prone and deprecated\. Use Type\:\:isFloat\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/FloatType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/GenericClassStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Generic/GenericClassStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Generic/GenericClassStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/GenericClassStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\StringType is error\\-prone and deprecated\\. Use Type\\:\\:isString\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\StringType is error\-prone and deprecated\. Use Type\:\:isString\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Generic/GenericClassStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/GenericObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/GenericObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/GenericObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) or Type\\:\\:getObjectClassReflections\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\TypeWithClassName is error\-prone and deprecated\. Use Type\:\:getObjectClassNames\(\) or Type\:\:getObjectClassReflections\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Generic/GenericObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateBenevolentUnionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateBooleanType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateConstantArrayType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateConstantIntegerType.php - - message: "#^Method PHPStan\\\\Type\\\\Generic\\\\TemplateConstantIntegerType\\:\\:toPhpDocNode\\(\\) should return PHPStan\\\\PhpDocParser\\\\Ast\\\\Type\\\\ConstTypeNode but returns PHPStan\\\\PhpDocParser\\\\Ast\\\\Type\\\\IdentifierTypeNode\\.$#" + message: '#^Method PHPStan\\Type\\Generic\\TemplateConstantIntegerType\:\:toPhpDocNode\(\) should return PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode but returns PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode\.$#' + identifier: return.type count: 1 path: src/Type/Generic/TemplateConstantIntegerType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateConstantStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateFloatType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateGenericObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateIntegerType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateIntersectionType.php - - message: "#^Instanceof between PHPStan\\\\Type\\\\Type and PHPStan\\\\Type\\\\IntersectionType will always evaluate to false\\.$#" + message: '#^Instanceof between PHPStan\\Type\\Type and PHPStan\\Type\\IntersectionType will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse count: 2 path: src/Type/Generic/TemplateIntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateKeyOfType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Generic/TemplateMixedType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateObjectShapeType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateObjectWithoutClassType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Generic/TemplateStrictMixedType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateStringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\BooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isBoolean\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\BooleanType is error\-prone and deprecated\. Use Type\:\:isBoolean\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\FloatType is error\\-prone and deprecated\\. Use Type\\:\\:isFloat\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\FloatType is error\-prone and deprecated\. Use Type\:\:isFloat\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntegerType is error\\-prone and deprecated\\. Use Type\\:\\:isInteger\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntegerType is error\-prone and deprecated\. Use Type\:\:isInteger\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectShapeType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) and Type\\:\\:hasProperty\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectShapeType is error\-prone and deprecated\. Use Type\:\:isObject\(\) and Type\:\:hasProperty\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectWithoutClassType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectWithoutClassType is error\-prone and deprecated\. Use Type\:\:isObject\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\StringType is error\\-prone and deprecated\\. Use Type\\:\\:isString\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\StringType is error\-prone and deprecated\. Use Type\:\:isString\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Generic/TemplateTypeFactory.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/Generic/TemplateUnionType.php - - message: "#^Instanceof between PHPStan\\\\Type\\\\Type and PHPStan\\\\Type\\\\UnionType will always evaluate to false\\.$#" + message: '#^Instanceof between PHPStan\\Type\\Type and PHPStan\\Type\\UnionType will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse count: 2 path: src/Type/Generic/TemplateUnionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/IntegerRangeType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntegerType is error\\-prone and deprecated\\. Use Type\\:\\:isInteger\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntegerType is error\-prone and deprecated\. Use Type\:\:isInteger\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/IntegerRangeType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/IntegerRangeType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntegerType is error\\-prone and deprecated\\. Use Type\\:\\:isInteger\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntegerType is error\-prone and deprecated\. Use Type\:\:isInteger\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/IntegerType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Accessory\\\\AccessoryType is error\\-prone and deprecated\\. Use methods on PHPStan\\\\Type\\\\Type instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Accessory\\AccessoryType is error\-prone and deprecated\. Use methods on PHPStan\\Type\\Type instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/IntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" - count: 1 + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 4 path: src/Type/IntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\BooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isBoolean\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\BooleanType is error\-prone and deprecated\. Use Type\:\:isBoolean\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/IntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\CallableType is error\\-prone and deprecated\\. Use Type\\:\\:isCallable\\(\\) and Type\\:\\:getCallableParametersAcceptors\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\CallableType is error\-prone and deprecated\. Use Type\:\:isCallable\(\) and Type\:\:getCallableParametersAcceptors\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/IntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 3 + path: src/Type/IntersectionType.php + + - + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/IntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/IntersectionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/IterableType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IterableType is error\\-prone and deprecated\\. Use Type\\:\\:isIterable\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IterableType is error\-prone and deprecated\. Use Type\:\:isIterable\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/IterableType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/NullType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\NullType is error\\-prone and deprecated\\. Use Type\\:\\:isNull\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\NullType is error\-prone and deprecated\. Use Type\:\:isNull\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/NullType.php - - message: """ - #^Call to deprecated method getInstance\\(\\) of class PHPStan\\\\Broker\\\\Broker\\: - Use PHPStan\\\\Reflection\\\\ReflectionProviderStaticAccessor instead$# - """ - count: 2 - path: src/Type/ObjectShapeType.php - - - - message: """ - #^Call to deprecated method getUniversalObjectCratesClasses\\(\\) of class PHPStan\\\\Broker\\\\Broker\\: - Inject %%universalObjectCratesClasses%% parameter instead\\.$# - """ - count: 2 - path: src/Type/ObjectShapeType.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/ObjectShapeType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectShapeType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) and Type\\:\\:hasProperty\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectShapeType is error\-prone and deprecated\. Use Type\:\:isObject\(\) and Type\:\:hasProperty\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/ObjectShapeType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectWithoutClassType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectWithoutClassType is error\-prone and deprecated\. Use Type\:\:isObject\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/ObjectShapeType.php - - message: """ - #^Call to deprecated method getInstance\\(\\) of class PHPStan\\\\Broker\\\\Broker\\: - Use PHPStan\\\\Reflection\\\\ReflectionProviderStaticAccessor instead$# - """ - count: 1 - path: src/Type/ObjectType.php - - - - message: """ - #^Call to deprecated method getUniversalObjectCratesClasses\\(\\) of class PHPStan\\\\Broker\\\\Broker\\: - Inject %%universalObjectCratesClasses%% parameter instead\\.$# - """ + message: '#^Doing instanceof PHPStan\\Type\\Enum\\EnumCaseObjectType is error\-prone and deprecated\. Use Type\:\:getEnumCases\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/ObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Enum\\\\EnumCaseObjectType is error\\-prone and deprecated\\. Use Type\\:\\:getEnumCases\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericObjectType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/ObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericObjectType is error\\-prone and deprecated\\.$#" - count: 1 - path: src/Type/ObjectType.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" - count: 6 + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 3 path: src/Type/ObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectWithoutClassType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectWithoutClassType is error\-prone and deprecated\. Use Type\:\:isObject\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/ObjectType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectShapeType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) and Type\\:\\:hasProperty\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectShapeType is error\-prone and deprecated\. Use Type\:\:isObject\(\) and Type\:\:hasProperty\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/ObjectWithoutClassType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectWithoutClassType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectWithoutClassType is error\-prone and deprecated\. Use Type\:\:isObject\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/ObjectWithoutClassType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ArrayCombineFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ArraySearchFunctionDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 16 path: src/Type/Php/BcMathStringOrNullReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/CompactFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/CompactFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/DefineConstantTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/DefinedConstantTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) or Type\\:\\:getObjectClassReflections\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\TypeWithClassName is error\-prone and deprecated\. Use Type\:\:getObjectClassNames\(\) or Type\:\:getObjectClassReflections\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/DsMapDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/FilterFunctionReturnTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/FilterFunctionReturnTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ImplodeFunctionReturnTypeExtension.php - - message: """ - #^Call to deprecated method getConstantScalars\\(\\) of class PHPStan\\\\Type\\\\TypeUtils\\: - Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\)$# - """ - count: 2 - path: src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php - - - - message: """ - #^Call to deprecated method getEnumCaseObjects\\(\\) of class PHPStan\\\\Type\\\\TypeUtils\\: - Use Type\\:\\:getEnumCases\\(\\)$# - """ - count: 2 - path: src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/IsAFunctionTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/JsonThrowOnErrorDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/LtrimFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/MbStrlenFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/MbSubstituteCharacterDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/MethodExistsTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/Php/MinMaxFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantValue\\(\\) or Type\\:\\:generalize\\(\\) instead\\.$#" - count: 1 - path: src/Type/Php/MinMaxFunctionReturnTypeExtension.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/MinMaxFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/NumberFormatFunctionDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/NumberFormatFunctionDynamicReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/PropertyExistsTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/Php/RangeFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ReflectionMethodConstructorThrowTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/ReflectionMethodConstructorThrowTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/SscanfFunctionDynamicReturnTypeExtension.php - - message: "#^Cannot access offset int\\<0, max\\> on \\(float\\|int\\)\\.$#" + message: '#^Cannot access offset int\<0, max\> on \(float\|int\)\.$#' + identifier: offsetAccess.nonOffsetAccessible count: 2 path: src/Type/Php/StrIncrementDecrementFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/StrRepeatFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/Php/StrlenFunctionReturnTypeExtension.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) or Type\\:\\:getObjectClassNames\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectType is error\-prone and deprecated\. Use Type\:\:isObject\(\) or Type\:\:getObjectClassNames\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/StaticType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectWithoutClassType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectWithoutClassType is error\-prone and deprecated\. Use Type\:\:isObject\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/StaticType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/StringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\StringType is error\\-prone and deprecated\\. Use Type\\:\\:isString\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\StringType is error\-prone and deprecated\. Use Type\:\:isString\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/StringType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Accessory\\\\AccessoryType is error\\-prone and deprecated\\. Use methods on PHPStan\\\\Type\\\\Type instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Accessory\\AccessoryType is error\-prone and deprecated\. Use methods on PHPStan\\Type\\Type instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 5 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\BooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isBoolean\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\BooleanType is error\-prone and deprecated\. Use Type\:\:isBoolean\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\CallableType is error\\-prone and deprecated\\. Use Type\\:\\:isCallable\\(\\) and Type\\:\\:getCallableParametersAcceptors\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\CallableType is error\-prone and deprecated\. Use Type\:\:isCallable\(\) and Type\:\:getCallableParametersAcceptors\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" - count: 10 + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 14 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 5 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\FloatType is error\\-prone and deprecated\\. Use Type\\:\\:isFloat\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\FloatType is error\-prone and deprecated\. Use Type\:\:isFloat\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntegerType is error\\-prone and deprecated\\. Use Type\\:\\:isInteger\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntegerType is error\-prone and deprecated\. Use Type\:\:isInteger\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IterableType is error\\-prone and deprecated\\. Use Type\\:\\:isIterable\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IterableType is error\-prone and deprecated\. Use Type\:\:isIterable\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 8 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\NullType is error\\-prone and deprecated\\. Use Type\\:\\:isNull\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\NullType is error\-prone and deprecated\. Use Type\:\:isNull\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ObjectShapeType is error\\-prone and deprecated\\. Use Type\\:\\:isObject\\(\\) and Type\\:\\:hasProperty\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ObjectShapeType is error\-prone and deprecated\. Use Type\:\:isObject\(\) and Type\:\:hasProperty\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\StringType is error\\-prone and deprecated\\. Use Type\\:\\:isString\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\StringType is error\-prone and deprecated\. Use Type\:\:isString\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypeCombinator.php - - message: "#^Instanceof between PHPStan\\\\Type\\\\Constant\\\\ConstantIntegerType and PHPStan\\\\Type\\\\Constant\\\\ConstantIntegerType will always evaluate to true\\.$#" + message: '#^Instanceof between PHPStan\\Type\\Constant\\ConstantIntegerType and PHPStan\\Type\\Constant\\ConstantIntegerType will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue count: 1 path: src/Type/TypeCombinator.php - - message: "#^Result of \\|\\| is always true\\.$#" + message: '#^Result of \|\| is always true\.$#' + identifier: booleanOr.alwaysTrue count: 1 path: src/Type/TypeCombinator.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" - count: 3 - path: src/Type/TypeUtils.php - - - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantArrayType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantArrays\\(\\) instead\\.$#" - count: 5 + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 2 path: src/Type/TypeUtils.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" - count: 5 + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType + count: 3 path: src/Type/TypeUtils.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\TypeWithClassName is error\\-prone and deprecated\\. Use Type\\:\\:getObjectClassNames\\(\\) or Type\\:\\:getObjectClassReflections\\(\\) instead\\.$#" - count: 1 - path: src/Type/TypeUtils.php + message: '#^Doing instanceof PHPStan\\Type\\ArrayType is error\-prone and deprecated\. Use Type\:\:isArray\(\) or Type\:\:getArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType + count: 3 + path: src/Type/TypehintHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ArrayType is error\\-prone and deprecated\\. Use Type\\:\\:isArray\\(\\) or Type\\:\\:getArrays\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantArrayType is error\-prone and deprecated\. Use Type\:\:getConstantArrays\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/TypehintHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IterableType is error\\-prone and deprecated\\. Use Type\\:\\:isIterable\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IterableType is error\-prone and deprecated\. Use Type\:\:isIterable\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/TypehintHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\CallableType is error\\-prone and deprecated\\. Use Type\\:\\:isCallable\\(\\) and Type\\:\\:getCallableParametersAcceptors\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\CallableType is error\-prone and deprecated\. Use Type\:\:isCallable\(\) and Type\:\:getCallableParametersAcceptors\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Generic\\\\GenericClassStringType is error\\-prone and deprecated\\. Use Type\\:\\:isClassStringType\\(\\) and Type\\:\\:getClassStringObjectType\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Generic\\GenericClassStringType is error\-prone and deprecated\. Use Type\:\:isClassStringType\(\) and Type\:\:getClassStringObjectType\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/UnionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntersectionType is error\\-prone and deprecated\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntersectionType is error\-prone and deprecated\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IterableType is error\\-prone and deprecated\\. Use Type\\:\\:isIterable\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IterableType is error\-prone and deprecated\. Use Type\:\:isIterable\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 1 path: src/Type/UnionType.php - - message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Type is always PHPStan\\\\Type\\\\BooleanType but it's error\\-prone and dangerous\\.$#" + message: '#^PHPDoc tag @var assumes the expression with type PHPStan\\Type\\Type is always PHPStan\\Type\\BooleanType but it''s error\-prone and dangerous\.$#' + identifier: phpstanApi.varTagAssumption count: 1 path: src/Type/UnionType.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Accessory\\\\AccessoryType is error\\-prone and deprecated\\. Use methods on PHPStan\\\\Type\\\\Type instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Accessory\\AccessoryType is error\-prone and deprecated\. Use methods on PHPStan\\Type\\Type instead\.$#' + identifier: phpstanApi.instanceofType count: 3 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\CallableType is error\\-prone and deprecated\\. Use Type\\:\\:isCallable\\(\\) and Type\\:\\:getCallableParametersAcceptors\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\CallableType is error\-prone and deprecated\. Use Type\:\:isCallable\(\) and Type\:\:getCallableParametersAcceptors\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\ConstantScalarType is error\\-prone and deprecated\\. Use Type\\:\\:isConstantScalarValue\\(\\) or Type\\:\\:getConstantScalarTypes\\(\\) or Type\\:\\:getConstantScalarValues\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\ConstantScalarType is error\-prone and deprecated\. Use Type\:\:isConstantScalarValue\(\) or Type\:\:getConstantScalarTypes\(\) or Type\:\:getConstantScalarValues\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 4 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantBooleanType is error\\-prone and deprecated\\. Use Type\\:\\:isTrue\\(\\) or Type\\:\\:isFalse\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantBooleanType is error\-prone and deprecated\. Use Type\:\:isTrue\(\) or Type\:\:isFalse\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\Constant\\\\ConstantStringType is error\\-prone and deprecated\\. Use Type\\:\\:getConstantStrings\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\IntegerType is error\\-prone and deprecated\\. Use Type\\:\\:isInteger\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\IntegerType is error\-prone and deprecated\. Use Type\:\:isInteger\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\NullType is error\\-prone and deprecated\\. Use Type\\:\\:isNull\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\NullType is error\-prone and deprecated\. Use Type\:\:isNull\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/UnionTypeHelper.php - - message: "#^Doing instanceof PHPStan\\\\Type\\\\VoidType is error\\-prone and deprecated\\. Use Type\\:\\:isVoid\\(\\) instead\\.$#" + message: '#^Doing instanceof PHPStan\\Type\\VoidType is error\-prone and deprecated\. Use Type\:\:isVoid\(\) instead\.$#' + identifier: phpstanApi.instanceofType count: 2 path: src/Type/VoidType.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable count: 1 path: tests/PHPStan/Analyser/AnalyserTest.php - - message: "#^Class PHPStan\\\\Analyser\\\\AnonymousClassNameRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" + message: '#^Class PHPStan\\Analyser\\AnonymousClassNameRuleTest extends generic class PHPStan\\Testing\\RuleTestCase but does not specify its types\: TRule$#' + identifier: missingType.generics count: 1 path: tests/PHPStan/Analyser/AnonymousClassNameRuleTest.php - - message: "#^Method PHPStan\\\\Analyser\\\\AnonymousClassNameRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Method PHPStan\\Analyser\\AnonymousClassNameRuleTest\:\:getRule\(\) return type with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: tests/PHPStan/Analyser/AnonymousClassNameRuleTest.php - - message: "#^Class PHPStan\\\\Analyser\\\\EvaluationOrderTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" + message: '#^Class PHPStan\\Analyser\\EvaluationOrderTest extends generic class PHPStan\\Testing\\RuleTestCase but does not specify its types\: TRule$#' + identifier: missingType.generics count: 1 path: tests/PHPStan/Analyser/EvaluationOrderTest.php - - message: "#^Method PHPStan\\\\Analyser\\\\EvaluationOrderTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Method PHPStan\\Analyser\\EvaluationOrderTest\:\:getRule\(\) return type with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: tests/PHPStan/Analyser/EvaluationOrderTest.php - - message: "#^Constant SOME_CONSTANT_IN_AUTOLOAD_FILE not found\\.$#" + message: '#^Constant SOME_CONSTANT_IN_AUTOLOAD_FILE not found\.$#' + identifier: constant.notFound count: 1 path: tests/PHPStan/Command/AnalyseCommandTest.php - - message: "#^Class PHPStan\\\\Node\\\\FileNodeTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" + message: '#^Class PHPStan\\Node\\FileNodeTest extends generic class PHPStan\\Testing\\RuleTestCase but does not specify its types\: TRule$#' + identifier: missingType.generics count: 1 path: tests/PHPStan/Node/FileNodeTest.php - - message: "#^Method PHPStan\\\\Node\\\\FileNodeTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" + message: '#^Method PHPStan\\Node\\FileNodeTest\:\:getRule\(\) return type with generic interface PHPStan\\Rules\\Rule does not specify its types\: TNodeType$#' + identifier: missingType.generics count: 1 path: tests/PHPStan/Node/FileNodeTest.php - - message: "#^PHPDoc tag @var with type string is not subtype of type class\\-string\\.$#" + message: '#^PHPDoc tag @var with type string is not subtype of type class\-string\.$#' + identifier: varTag.type count: 1 path: tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php - - message: "#^Creating new PHPStan\\\\Php8StubsMap is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Creating new PHPStan\\Php8StubsMap is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.constructor count: 1 path: tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php - - message: "#^Creating new PHPStan\\\\Php8StubsMap is not covered by backward compatibility promise\\. The class might change in a minor PHPStan version\\.$#" + message: '#^Creating new PHPStan\\Php8StubsMap is not covered by backward compatibility promise\. The class might change in a minor PHPStan version\.$#' + identifier: phpstanApi.constructor count: 1 path: tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php - - message: """ - #^Instantiation of deprecated class PHPStan\\\\Rules\\\\Arrays\\\\AppendedArrayItemTypeRule\\: - Replaced by PHPStan\\\\Rules\\\\Properties\\\\TypesAssignedToPropertiesRule$# - """ - count: 1 - path: tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php - - - - message: """ - #^Return type of method PHPStan\\\\Rules\\\\Arrays\\\\AppendedArrayItemTypeRuleTest\\:\\:getRule\\(\\) has typehint with deprecated class PHPStan\\\\Rules\\\\Arrays\\\\AppendedArrayItemTypeRule\\: - Replaced by PHPStan\\\\Rules\\\\Properties\\\\TypesAssignedToPropertiesRule$# - """ - count: 1 - path: tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php - - - - message: """ - #^Instantiation of deprecated class PHPStan\\\\Rules\\\\Arrays\\\\AppendedArrayKeyTypeRule\\: - Replaced by PHPStan\\\\Rules\\\\Properties\\\\TypesAssignedToPropertiesRule$# - """ - count: 1 - path: tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php - - - - message: """ - #^Return type of method PHPStan\\\\Rules\\\\Arrays\\\\AppendedArrayKeyTypeRuleTest\\:\\:getRule\\(\\) has typehint with deprecated class PHPStan\\\\Rules\\\\Arrays\\\\AppendedArrayKeyTypeRule\\: - Replaced by PHPStan\\\\Rules\\\\Properties\\\\TypesAssignedToPropertiesRule$# - """ - 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\\.$#" + 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\.$#' + identifier: phpstanApi.varTagAssumption count: 1 path: tests/PHPStan/Type/IterableTypeTest.php diff --git a/resources/functionMap.php b/resources/functionMap.php index 1b8e4c28a4..bf078bc8a0 100644 --- a/resources/functionMap.php +++ b/resources/functionMap.php @@ -209,7 +209,7 @@ 'APCIterator::valid' => ['bool'], 'apcu_add' => ['bool', 'key'=>'string', 'var'=>'', 'ttl='=>'int'], 'apcu_add\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], -'apcu_cache_info' => ['array', 'limited='=>'bool'], +'apcu_cache_info' => ['__benevolent|false>', 'limited='=>'bool'], 'apcu_cas' => ['bool', 'key'=>'string', 'old'=>'int', 'new'=>'int'], 'apcu_clear_cache' => ['bool'], 'apcu_dec' => ['int', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool', 'ttl='=>'int'], @@ -220,7 +220,7 @@ 'apcu_exists\'1' => ['array', 'keys'=>'string[]'], 'apcu_fetch' => ['mixed', 'key'=>'string|string[]', '&w_success='=>'bool'], 'apcu_inc' => ['int', 'key'=>'string', 'step='=>'int', '&w_success='=>'bool', 'ttl='=>'int'], -'apcu_sma_info' => ['array', 'limited='=>'bool'], +'apcu_sma_info' => ['__benevolent', 'limited='=>'bool'], 'apcu_store' => ['bool', 'key'=>'string', 'var='=>'', 'ttl='=>'int'], 'apcu_store\'1' => ['array', 'values'=>'array', 'unused='=>'', 'ttl='=>'int'], 'APCuIterator::__construct' => ['void', 'search='=>'string|string[]|null', 'format='=>'int', 'chunk_size='=>'int', 'list='=>'int'], @@ -417,11 +417,11 @@ 'bbcode_parse' => ['string', 'bbcode_container'=>'resource', 'to_parse'=>'string'], 'bbcode_set_arg_parser' => ['bool', 'bbcode_container'=>'resource', 'bbcode_arg_parser'=>'resource'], 'bbcode_set_flags' => ['bool', 'bbcode_container'=>'resource', 'flags'=>'int', 'mode='=>'int'], -'bcadd' => ['numeric-string', 'left_operand'=>'string', 'right_operand'=>'string', 'scale='=>'int'], -'bccomp' => ['int', 'left_operand'=>'string', 'right_operand'=>'string', 'scale='=>'int'], -'bcdiv' => ['numeric-string|null', 'left_operand'=>'string', 'right_operand'=>'string', 'scale='=>'int'], -'bcmod' => ['numeric-string|null', 'left_operand'=>'string', 'right_operand'=>'string', 'scale='=>'int'], -'bcmul' => ['numeric-string', 'left_operand'=>'string', 'right_operand'=>'string', 'scale='=>'int'], +'bcadd' => ['numeric-string', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], +'bccomp' => ['0|1|-1', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], +'bcdiv' => ['numeric-string|null', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], +'bcmod' => ['numeric-string|null', 'left_operand'=>'string', 'right_operand'=>'numeric-string', 'scale='=>'int'], +'bcmul' => ['numeric-string', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], 'bcompiler_load' => ['bool', 'filename'=>'string'], 'bcompiler_load_exe' => ['bool', 'filename'=>'string'], 'bcompiler_parse_class' => ['bool', 'class'=>'string', 'callback'=>'string'], @@ -435,11 +435,11 @@ 'bcompiler_write_functions_from_file' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], 'bcompiler_write_header' => ['bool', 'filehandle'=>'resource', 'write_ver='=>'string'], 'bcompiler_write_included_filename' => ['bool', 'filehandle'=>'resource', 'filename'=>'string'], -'bcpow' => ['numeric-string', 'base'=>'string', 'exponent'=>'string', 'scale='=>'int'], -'bcpowmod' => ['numeric-string|null', 'base'=>'string', 'exponent'=>'string', 'modulus'=>'string', 'scale='=>'int'], +'bcpow' => ['numeric-string', 'base'=>'numeric-string', 'exponent'=>'numeric-string', 'scale='=>'int'], +'bcpowmod' => ['numeric-string|null', 'base'=>'numeric-string', 'exponent'=>'numeric-string', 'modulus'=>'string', 'scale='=>'int'], 'bcscale' => ['int', 'scale='=>'int'], -'bcsqrt' => ['numeric-string', 'operand'=>'string', 'scale='=>'int'], -'bcsub' => ['numeric-string', 'left_operand'=>'string', 'right_operand'=>'string', 'scale='=>'int'], +'bcsqrt' => ['numeric-string', 'operand'=>'numeric-string', 'scale='=>'int'], +'bcsub' => ['numeric-string', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], 'bin2hex' => ['string', 'data'=>'string'], 'bind_textdomain_codeset' => ['string|false', 'domain'=>'string', 'codeset'=>'string'], 'bindec' => ['float|int', 'binary_number'=>'string'], @@ -994,8 +994,8 @@ 'closelog' => ['bool'], 'Closure::__construct' => ['void'], 'Closure::__invoke' => ['', '...args='=>''], -'Closure::bind' => ['__benevolent', 'old'=>'Closure', 'to'=>'?object', 'scope='=>'object|string|null'], -'Closure::bindTo' => ['__benevolent', 'new'=>'?object', 'newscope='=>'object|string|null'], +'Closure::bind' => ['__benevolent', 'old'=>'Closure', 'to'=>'?object', 'scope='=>'object|class-string|\'static\'|null'], +'Closure::bindTo' => ['__benevolent', 'new'=>'?object', 'newscope='=>'object|class-string|\'static\'|null'], 'Closure::call' => ['', 'to'=>'object', '...parameters='=>''], 'Closure::fromCallable' => ['Closure', 'callable'=>'callable'], 'clusterObj::convertToString' => ['string'], @@ -1363,7 +1363,7 @@ 'Couchbase\WildcardSearchQuery::jsonSerialize' => ['array'], 'Couchbase\zlibCompress' => ['string', 'data'=>'string'], 'Couchbase\zlibDecompress' => ['string', 'data'=>'string'], -'count' => ['0|positive-int', 'var'=>'Countable|array', 'mode='=>'int'], +'count' => ['0|positive-int', 'var'=>'Countable|array', 'mode='=>'0|1'], 'count_chars' => ['mixed', 'input'=>'string', 'mode='=>'0|1|2|3|4'], 'Countable::count' => ['0|positive-int'], 'crack_check' => ['bool', 'dictionary'=>'', 'password'=>'string'], @@ -2334,7 +2334,7 @@ 'Error::getTraceAsString' => ['string'], 'error_clear_last' => ['void'], 'error_get_last' => ['?array{type:int,message:string,file:string,line:int}'], -'error_log' => ['bool', 'message'=>'string', 'message_type='=>'int', 'destination='=>'string', 'extra_headers='=>'string'], +'error_log' => ['bool', 'message'=>'string', 'message_type='=>'0|1|2|3|4', 'destination='=>'string', 'extra_headers='=>'string'], 'error_reporting' => ['int', 'new_error_level='=>'int'], 'ErrorException::__clone' => ['void'], 'ErrorException::__construct' => ['void', 'message='=>'string', 'code='=>'int', 'severity='=>'int', 'filename='=>'string', 'lineno='=>'int', 'previous='=>'(?Throwable)|(?ErrorException)'], @@ -2637,7 +2637,7 @@ 'explode' => ['list|false', 'separator'=>'string', 'str'=>'string', 'limit='=>'int'], 'expm1' => ['float', 'number'=>'float'], 'extension_loaded' => ['bool', 'extension_name'=>'string'], -'extract' => ['0|positive-int', 'array'=>'array', 'flags='=>'int', 'prefix='=>'string|null'], +'extract' => ['0|positive-int', 'array'=>'array', 'flags='=>'EXTR_OVERWRITE|EXTR_SKIP|EXTR_PREFIX_SAME|EXTR_PREFIX_ALL|EXTR_PREFIX_INVALID|EXTR_IF_EXISTS|EXTR_PREFIX_IF_EXISTS|EXTR_REFS', 'prefix='=>'string|null'], 'ezmlm_hash' => ['int', 'addr'=>'string'], 'fam_cancel_monitor' => ['bool', 'fam'=>'resource', 'fam_monitor'=>'resource'], 'fam_close' => ['void', 'fam'=>'resource'], @@ -2935,7 +2935,7 @@ 'fgetcsv' => ['list|array{0: null}|false|null', 'fp'=>'resource', 'length='=>'0|positive-int|null', 'delimiter='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'fgets' => ['string|false', 'fp'=>'resource', 'length='=>'0|positive-int'], 'fgetss' => ['string|false', 'fp'=>'resource', 'length='=>'0|positive-int', 'allowable_tags='=>'string'], -'file' => ['list|false', 'filename'=>'string', 'flags='=>'int', 'context='=>'resource'], +'file' => ['list|false', 'filename'=>'string', 'flags='=>'int-mask', 'context='=>'resource'], 'file_exists' => ['bool', 'filename'=>'string'], 'file_get_contents' => ['string|false', 'filename'=>'string', 'use_include_path='=>'bool', 'context='=>'?resource', 'offset='=>'int', 'maxlen='=>'0|positive-int'], 'file_put_contents' => ['0|positive-int|false', 'file'=>'string', 'data'=>'mixed', 'flags='=>'int', 'context='=>'?resource'], @@ -2988,7 +2988,7 @@ 'finfo_open' => ['resource|false', 'options='=>'int', 'arg='=>'string'], 'finfo_set_flags' => ['bool', 'finfo'=>'resource', 'options'=>'int'], 'floatval' => ['float', 'var'=>'scalar|array|resource|null'], -'flock' => ['bool', 'fp'=>'resource', 'operation'=>'int', '&w_wouldblock='=>'int'], +'flock' => ['bool', 'fp'=>'resource', 'operation'=>'int-mask', '&w_wouldblock='=>'0|1'], 'floor' => ['__benevolent', 'number'=>'float'], 'flush' => ['void'], 'fmod' => ['float', 'x'=>'float', 'y'=>'float'], @@ -3011,7 +3011,7 @@ 'ftell' => ['int|false', 'fp'=>'resource'], 'ftok' => ['int', 'pathname'=>'string', 'proj'=>'string'], 'ftp_alloc' => ['bool', 'stream'=>'resource', 'size'=>'int', '&w_response='=>'string'], -'ftp_append' => ['bool', 'ftp'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'int'], +'ftp_append' => ['bool', 'ftp'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY'], 'ftp_cdup' => ['bool', 'stream'=>'resource'], 'ftp_chdir' => ['bool', 'stream'=>'resource', 'directory'=>'string'], 'ftp_chmod' => ['int|false', 'stream'=>'resource', 'mode'=>'int', 'filename'=>'string'], @@ -3019,22 +3019,22 @@ 'ftp_connect' => ['resource|false', 'host'=>'string', 'port='=>'int', 'timeout='=>'int'], 'ftp_delete' => ['bool', 'stream'=>'resource', 'file'=>'string'], 'ftp_exec' => ['bool', 'stream'=>'resource', 'command'=>'string'], -'ftp_fget' => ['bool', 'stream'=>'resource', 'fp'=>'resource', 'remote_file'=>'string', 'mode='=>'int', 'resumepos='=>'int'], -'ftp_fput' => ['bool', 'stream'=>'resource', 'remote_file'=>'string', 'fp'=>'resource', 'mode='=>'int', 'startpos='=>'int'], -'ftp_get' => ['bool', 'stream'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'mode='=>'int', 'resume_pos='=>'int'], +'ftp_fget' => ['bool', 'stream'=>'resource', 'fp'=>'resource', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resumepos='=>'int'], +'ftp_fput' => ['bool', 'stream'=>'resource', 'remote_file'=>'string', 'fp'=>'resource', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], +'ftp_get' => ['bool', 'stream'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resume_pos='=>'int'], 'ftp_get_option' => ['mixed', 'stream'=>'resource', 'option'=>'int'], 'ftp_login' => ['bool', 'stream'=>'resource', 'username'=>'string', 'password'=>'string'], 'ftp_mdtm' => ['int', 'stream'=>'resource', 'filename'=>'string'], 'ftp_mkdir' => ['string|false', 'stream'=>'resource', 'directory'=>'string'], 'ftp_mlsd' => ['array|false', 'ftp_stream'=>'resource', 'directory'=>'string'], 'ftp_nb_continue' => ['int', 'stream'=>'resource'], -'ftp_nb_fget' => ['int', 'stream'=>'resource', 'fp'=>'resource', 'remote_file'=>'string', 'mode='=>'int', 'resumepos='=>'int'], -'ftp_nb_fput' => ['int', 'stream'=>'resource', 'remote_file'=>'string', 'fp'=>'resource', 'mode='=>'int', 'startpos='=>'int'], -'ftp_nb_get' => ['int|false', 'stream'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'mode='=>'int', 'resume_pos='=>'int'], -'ftp_nb_put' => ['int|false', 'stream'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'int', 'startpos='=>'int'], +'ftp_nb_fget' => ['int', 'stream'=>'resource', 'fp'=>'resource', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resumepos='=>'int'], +'ftp_nb_fput' => ['int', 'stream'=>'resource', 'remote_file'=>'string', 'fp'=>'resource', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], +'ftp_nb_get' => ['int|false', 'stream'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resume_pos='=>'int'], +'ftp_nb_put' => ['int|false', 'stream'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], 'ftp_nlist' => ['array|false', 'stream'=>'resource', 'directory'=>'string'], 'ftp_pasv' => ['bool', 'stream'=>'resource', 'pasv'=>'bool'], -'ftp_put' => ['bool', 'stream'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'int', 'startpos='=>'int'], +'ftp_put' => ['bool', 'stream'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], 'ftp_pwd' => ['string|false', 'stream'=>'resource'], 'ftp_raw' => ['array', 'stream'=>'resource', 'command'=>'string'], 'ftp_rawlist' => ['array|false', 'stream'=>'resource', 'directory'=>'string', 'recursive='=>'bool'], @@ -3957,8 +3957,8 @@ 'HRTime\StopWatch::start' => ['void'], 'HRTime\StopWatch::stop' => ['void'], 'html_entity_decode' => ['string', 'string'=>'string', 'quote_style='=>'int', 'encoding='=>'string'], -'htmlentities' => ['string', 'string'=>'string', 'quote_style='=>'int', 'encoding='=>'string', 'double_encode='=>'bool'], -'htmlspecialchars' => ['string', 'string'=>'string', 'quote_style='=>'int', 'encoding='=>'string', 'double_encode='=>'bool'], +'htmlentities' => ['string', 'string'=>'string', 'quote_style='=>'int', 'encoding='=>'string|null', 'double_encode='=>'bool'], +'htmlspecialchars' => ['string', 'string'=>'string', 'quote_style='=>'int', 'encoding='=>'string|null', 'double_encode='=>'bool'], 'htmlspecialchars_decode' => ['string', 'string'=>'string', 'quote_style='=>'int'], 'http\Env\Request::__construct' => ['void'], 'http\Env\Request::getCookie' => ['mixed', 'name='=>'string', 'type='=>'mixed', 'defval='=>'mixed', 'delete='=>'bool|false'], @@ -4542,19 +4542,19 @@ 'imagebmp' => ['bool', 'image'=>'resource', 'to='=>'string|resource|null', 'compressed='=>'bool'], 'imagechar' => ['bool', 'im'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'c'=>'string', 'col'=>'int'], 'imagecharup' => ['bool', 'im'=>'resource', 'font'=>'int', 'x'=>'int', 'y'=>'int', 'c'=>'string', 'col'=>'int'], -'imagecolorallocate' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], -'imagecolorallocatealpha' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], +'imagecolorallocate' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], +'imagecolorallocatealpha' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], 'imagecolorat' => ['int<0, max>|false', 'im'=>'resource', 'x'=>'int', 'y'=>'int'], -'imagecolorclosest' => ['int<0, max>', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], -'imagecolorclosestalpha' => ['int<0, max>', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], -'imagecolorclosesthwb' => ['int<0, max>', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], +'imagecolorclosest' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], +'imagecolorclosestalpha' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], +'imagecolorclosesthwb' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], 'imagecolordeallocate' => ['bool', 'im'=>'resource', 'index'=>'int'], -'imagecolorexact' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], -'imagecolorexactalpha' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], +'imagecolorexact' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], +'imagecolorexactalpha' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], 'imagecolormatch' => ['bool', 'im1'=>'resource', 'im2'=>'resource'], -'imagecolorresolve' => ['int<0, max>', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], -'imagecolorresolvealpha' => ['int<0, max>', 'im'=>'resource', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha'=>'int'], -'imagecolorset' => ['void', 'im'=>'resource', 'col'=>'int', 'red'=>'int', 'green'=>'int', 'blue'=>'int', 'alpha='=>'int'], +'imagecolorresolve' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], +'imagecolorresolvealpha' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], +'imagecolorset' => ['void', 'im'=>'resource', 'col'=>'int', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha='=>'int<0, 127>'], 'imagecolorsforindex' => ['array{red: int<0, 255>, green: int<0, 255>, blue: int<0, 255>, alpha: int<0, 127>}', 'im'=>'resource', 'col'=>'int'], 'imagecolorstotal' => ['int<0, 256>', 'im'=>'resource'], 'imagecolortransparent' => ['int', 'im'=>'resource', 'col='=>'int'], @@ -4564,7 +4564,7 @@ 'imagecopymergegray' => ['bool', 'src_im'=>'resource', 'dst_im'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'src_w'=>'int', 'src_h'=>'int', 'pct'=>'int'], 'imagecopyresampled' => ['bool', 'dst_im'=>'resource', 'src_im'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_w'=>'int', 'dst_h'=>'int', 'src_w'=>'int', 'src_h'=>'int'], 'imagecopyresized' => ['bool', 'dst_im'=>'resource', 'src_im'=>'resource', 'dst_x'=>'int', 'dst_y'=>'int', 'src_x'=>'int', 'src_y'=>'int', 'dst_w'=>'int', 'dst_h'=>'int', 'src_w'=>'int', 'src_h'=>'int'], -'imagecreate' => ['__benevolent', 'x_size'=>'int', 'y_size'=>'int'], +'imagecreate' => ['__benevolent', 'x_size'=>'int<1, max>', 'y_size'=>'int<1, max>'], 'imagecreatefrombmp' => ['resource|false', 'filename'=>'string'], 'imagecreatefromgd' => ['resource|false', 'filename'=>'string'], 'imagecreatefromgd2' => ['resource|false', 'filename'=>'string'], @@ -4577,7 +4577,7 @@ 'imagecreatefromwebp' => ['resource|false', 'filename'=>'string'], 'imagecreatefromxbm' => ['resource|false', 'filename'=>'string'], 'imagecreatefromxpm' => ['resource|false', 'filename'=>'string'], -'imagecreatetruecolor' => ['__benevolent', 'x_size'=>'int', 'y_size'=>'int'], +'imagecreatetruecolor' => ['__benevolent', 'x_size'=>'int<1, max>', 'y_size'=>'int<1, max>'], 'imagecrop' => ['resource|false', 'im'=>'resource', 'rect'=>'array'], 'imagecropauto' => ['resource|false', 'im'=>'resource', 'mode='=>'int', 'threshold='=>'float', 'color='=>'int'], 'imagedashedline' => ['bool', 'im'=>'resource', 'x1'=>'int', 'y1'=>'int', 'x2'=>'int', 'y2'=>'int', 'col'=>'int'], @@ -4648,25 +4648,25 @@ 'imagexbm' => ['bool', 'im'=>'resource', 'filename='=>'string|resource|null', 'foreground='=>'int'], 'Imagick::__construct' => ['void', 'files='=>''], 'Imagick::__toString' => ['string'], -'Imagick::adaptiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], +'Imagick::adaptiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::adaptiveResizeImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'bestfit='=>'bool'], -'Imagick::adaptiveSharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], +'Imagick::adaptiveSharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::adaptiveThresholdImage' => ['bool', 'width'=>'int', 'height'=>'int', 'offset'=>'int'], 'Imagick::addImage' => ['bool', 'source'=>'imagick'], -'Imagick::addNoiseImage' => ['bool', 'noise_type'=>'int', 'channel='=>'int'], +'Imagick::addNoiseImage' => ['bool', 'noise_type'=>'Imagick::NOISE_*', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::affineTransformImage' => ['bool', 'matrix'=>'imagickdraw'], 'Imagick::animateImages' => ['bool', 'x_server'=>'string'], 'Imagick::annotateImage' => ['bool', 'draw_settings'=>'imagickdraw', 'x'=>'float', 'y'=>'float', 'angle'=>'float', 'text'=>'string'], 'Imagick::appendImages' => ['Imagick', 'stack'=>'bool'], -'Imagick::autoGammaImage' => ['bool', 'channel='=>'int'], -'Imagick::autoLevelImage' => ['bool', 'channel='=>'int'], +'Imagick::autoGammaImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::autoLevelImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::autoOrient' => ['bool'], 'Imagick::averageImages' => ['Imagick'], 'Imagick::blackThresholdImage' => ['bool', 'threshold'=>'mixed'], 'Imagick::blueShiftImage' => ['bool', 'factor='=>'float'], -'Imagick::blurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], +'Imagick::blurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::borderImage' => ['bool', 'bordercolor'=>'mixed', 'width'=>'int', 'height'=>'int'], -'Imagick::brightnessContrastImage' => ['bool', 'brightness'=>'float', 'contrast'=>'float', 'channel='=>'int'], +'Imagick::brightnessContrastImage' => ['bool', 'brightness'=>'float', 'contrast'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::charcoalImage' => ['bool', 'radius'=>'float', 'sigma'=>'float'], 'Imagick::chopImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::clampImage' => ['bool', 'channel='=>'int'], @@ -4680,16 +4680,16 @@ 'Imagick::colorFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int'], 'Imagick::colorizeImage' => ['bool', 'colorize'=>'mixed', 'opacity'=>'mixed'], 'Imagick::colorMatrixImage' => ['bool', 'color_matrix'=>'array'], -'Imagick::combineImages' => ['Imagick', 'channeltype'=>'int'], +'Imagick::combineImages' => ['Imagick', 'channeltype'=>'Imagick::CHANNEL_*'], 'Imagick::commentImage' => ['bool', 'comment'=>'string'], -'Imagick::compareImageChannels' => ['array{Imagick,float}', 'image'=>'imagick', 'channeltype'=>'int', 'metrictype'=>'int'], -'Imagick::compareImageLayers' => ['Imagick', 'method'=>'int'], -'Imagick::compareImages' => ['array{Imagick,float}', 'compare'=>'imagick', 'metric'=>'int'], -'Imagick::compositeImage' => ['bool', 'composite_object'=>'imagick', 'composite'=>'int', 'x'=>'int', 'y'=>'int', 'channel='=>'int'], +'Imagick::compareImageChannels' => ['array{Imagick,float}', 'image'=>'imagick', 'channeltype'=>'Imagick::CHANNEL_*', 'metrictype'=>'Imagick::METRIC_*'], +'Imagick::compareImageLayers' => ['Imagick', 'method'=>'Imagick::LAYERMETHOD_*'], +'Imagick::compareImages' => ['array{Imagick,float}', 'compare'=>'imagick', 'metric'=>'Imagick::METRIC_*'], +'Imagick::compositeImage' => ['bool', 'composite_object'=>'imagick', 'composite'=>'Imagick::COMPOSITE_*', 'x'=>'int', 'y'=>'int', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::compositeImageGravity' => ['bool', 'imagick'=>'Imagick', 'COMPOSITE_CONSTANT'=>'int', 'GRAVITY_CONSTANT'=>'int'], 'Imagick::contrastImage' => ['bool', 'sharpen'=>'bool'], -'Imagick::contrastStretchImage' => ['bool', 'black_point'=>'float', 'white_point'=>'float', 'channel='=>'int'], -'Imagick::convolveImage' => ['bool', 'kernel'=>'array', 'channel='=>'int'], +'Imagick::contrastStretchImage' => ['bool', 'black_point'=>'float', 'white_point'=>'float', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::convolveImage' => ['bool', 'kernel'=>'array', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::count' => ['0|positive-int', 'mode='=>'int'], 'Imagick::cropImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::cropThumbnailImage' => ['bool', 'width'=>'int', 'height'=>'int', 'legacy='=>'bool'], @@ -4704,28 +4704,28 @@ 'Imagick::destroy' => ['bool'], 'Imagick::displayImage' => ['bool', 'servername'=>'string'], 'Imagick::displayImages' => ['bool', 'servername'=>'string'], -'Imagick::distortImage' => ['bool', 'method'=>'int', 'arguments'=>'array', 'bestfit'=>'bool'], +'Imagick::distortImage' => ['bool', 'method'=>'Imagick::DISTORTION_*', 'arguments'=>'array', 'bestfit'=>'bool'], 'Imagick::drawImage' => ['bool', 'draw'=>'imagickdraw'], 'Imagick::edgeImage' => ['bool', 'radius'=>'float'], 'Imagick::embossImage' => ['bool', 'radius'=>'float', 'sigma'=>'float'], 'Imagick::encipherImage' => ['bool', 'passphrase'=>'string'], 'Imagick::enhanceImage' => ['bool'], 'Imagick::equalizeImage' => ['bool'], -'Imagick::evaluateImage' => ['bool', 'op'=>'int', 'constant'=>'float', 'channel='=>'int'], +'Imagick::evaluateImage' => ['bool', 'op'=>'Imagick::EVALUATE_*', 'constant'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::evaluateImages' => ['bool', 'EVALUATE_CONSTANT'=>'int'], -'Imagick::exportImagePixels' => ['list', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'int'], +'Imagick::exportImagePixels' => ['list', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'Imagick::PIXEL_*'], 'Imagick::extentImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::filter' => ['bool', 'ImagickKernel'=>'ImagickKernel', 'CHANNEL='=>'int'], 'Imagick::flattenImages' => ['Imagick'], 'Imagick::flipImage' => ['bool'], -'Imagick::floodFillPaintImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'target'=>'mixed', 'x'=>'int', 'y'=>'int', 'invert'=>'bool', 'channel='=>'int'], +'Imagick::floodFillPaintImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'target'=>'mixed', 'x'=>'int', 'y'=>'int', 'invert'=>'bool', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::flopImage' => ['bool'], 'Imagick::forwardFourierTransformimage' => ['bool', 'magnitude'=>'bool'], 'Imagick::frameImage' => ['bool', 'matte_color'=>'mixed', 'width'=>'int', 'height'=>'int', 'inner_bevel'=>'int', 'outer_bevel'=>'int'], -'Imagick::functionImage' => ['bool', 'function'=>'int', 'arguments'=>'array', 'channel='=>'int'], -'Imagick::fxImage' => ['Imagick', 'expression'=>'string', 'channel='=>'int'], -'Imagick::gammaImage' => ['bool', 'gamma'=>'float', 'channel='=>'int'], -'Imagick::gaussianBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], +'Imagick::functionImage' => ['bool', 'function'=>'Imagick::FUNCTION_*', 'arguments'=>'array', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::fxImage' => ['Imagick', 'expression'=>'string', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::gammaImage' => ['bool', 'gamma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::gaussianBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::getColorspace' => ['Imagick::COLORSPACE_*'], 'Imagick::getCompression' => ['Imagick::COMPRESSION_*'], 'Imagick::getCompressionQuality' => ['int'], @@ -4746,13 +4746,13 @@ 'Imagick::getImageBlob' => ['string'], 'Imagick::getImageBluePrimary' => ['array{x:float,y:float}'], 'Imagick::getImageBorderColor' => ['ImagickPixel'], -'Imagick::getImageChannelDepth' => ['int', 'channel'=>'int'], -'Imagick::getImageChannelDistortion' => ['float', 'reference'=>'imagick', 'channel'=>'int', 'metric'=>'int'], -'Imagick::getImageChannelDistortions' => ['float', 'reference'=>'imagick', 'metric'=>'int', 'channel='=>'int'], -'Imagick::getImageChannelExtrema' => ['array{minima:0|positive-int,maxima:0|positive-int}', 'channel'=>'int'], -'Imagick::getImageChannelKurtosis' => ['array{kurtosis:float,skewness:float}', 'channel='=>'int'], -'Imagick::getImageChannelMean' => ['array{mean:float,standardDeviation:float}', 'channel'=>'int'], -'Imagick::getImageChannelRange' => ['array{minima:float,maxima:float}', 'channel'=>'int'], +'Imagick::getImageChannelDepth' => ['int', 'channel'=>'Imagick::CHANNEL_*'], +'Imagick::getImageChannelDistortion' => ['float', 'reference'=>'imagick', 'channel'=>'Imagick::CHANNEL_*', 'metric'=>'Imagick::METRIC_*'], +'Imagick::getImageChannelDistortions' => ['float', 'reference'=>'imagick', 'metric'=>'Imagick::METRIC_*', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::getImageChannelExtrema' => ['array{minima:0|positive-int,maxima:0|positive-int}', 'channel'=>'Imagick::CHANNEL_*'], +'Imagick::getImageChannelKurtosis' => ['array{kurtosis:float,skewness:float}', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::getImageChannelMean' => ['array{mean:float,standardDeviation:float}', 'channel'=>'Imagick::CHANNEL_*'], +'Imagick::getImageChannelRange' => ['array{minima:float,maxima:float}', 'channel'=>'Imagick::CHANNEL_*'], 'Imagick::getImageChannelStatistics' => ['array{mean:float,minima:float,maxima:float,standardDeviation:float,depth:int}'], 'Imagick::getImageClipMask' => ['Imagick'], 'Imagick::getImageColormapColor' => ['ImagickPixel', 'index'=>'int'], @@ -4764,7 +4764,7 @@ 'Imagick::getImageDelay' => ['int'], 'Imagick::getImageDepth' => ['int'], 'Imagick::getImageDispose' => ['Imagick::DISPOSE_*'], -'Imagick::getImageDistortion' => ['float', 'reference'=>'magickwand', 'metric'=>'int'], +'Imagick::getImageDistortion' => ['float', 'reference'=>'magickwand', 'metric'=>'Imagick::METRIC_*'], 'Imagick::getImageExtrema' => ['array{min:0|positive-int,max:0|positive-int}'], 'Imagick::getImageFilename' => ['string'], 'Imagick::getImageFormat' => ['string'], @@ -4819,8 +4819,8 @@ 'Imagick::getQuantumRange' => ['array{quantumRangeLong:0|positive-int,quantumRangeString:numeric-string}'], 'Imagick::getRegistry' => ['string', 'key'=>'string'], 'Imagick::getReleaseDate' => ['string'], -'Imagick::getResource' => ['int', 'type'=>'int'], -'Imagick::getResourceLimit' => ['int', 'type'=>'int'], +'Imagick::getResource' => ['int', 'type'=>'Imagick::RESOURCETYPE_*'], +'Imagick::getResourceLimit' => ['int', 'type'=>'Imagick::RESOURCETYPE_*'], 'Imagick::getSamplingFactors' => ['list'], 'Imagick::getSize' => ['array{columns:0|positive-int,rows:0|positive-int}'], 'Imagick::getSizeOffset' => ['int'], @@ -4832,11 +4832,11 @@ 'Imagick::identifyImage' => ['array{imageName:string,mimetype:string,format:string,units:string,colorSpace:string,type:string,compression:string,fileSize:string,geometry:array{width:0|positive-int,height:0|positive-int},resolution:array{x:float,y:float},signature:string}', 'appendrawoutput='=>'bool'], 'Imagick::identifyImageType' => ['int'], 'Imagick::implodeImage' => ['bool', 'radius'=>'float'], -'Imagick::importImagePixels' => ['bool', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'int', 'pixels'=>'array'], +'Imagick::importImagePixels' => ['bool', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'Imagick::PIXEL_*', 'pixels'=>'array'], 'Imagick::inverseFourierTransformImage' => ['bool', 'complement'=>'Imagick', 'magnitude'=>'bool'], 'Imagick::key' => ['int|string'], 'Imagick::labelImage' => ['bool', 'label'=>'string'], -'Imagick::levelImage' => ['bool', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'int'], +'Imagick::levelImage' => ['bool', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::linearStretchImage' => ['bool', 'blackpoint'=>'float', 'whitepoint'=>'float'], 'Imagick::liquidRescaleImage' => ['bool', 'width'=>'int', 'height'=>'int', 'delta_x'=>'float', 'rigidity'=>'float'], 'Imagick::listRegistry' => ['array'], @@ -4845,26 +4845,26 @@ 'Imagick::mapImage' => ['bool', 'map'=>'imagick', 'dither'=>'bool'], 'Imagick::matteFloodfillImage' => ['bool', 'alpha'=>'float', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int'], 'Imagick::medianFilterImage' => ['bool', 'radius'=>'float'], -'Imagick::mergeImageLayers' => ['Imagick', 'layer_method'=>'int'], +'Imagick::mergeImageLayers' => ['Imagick', 'layer_method'=>'Imagick::LAYERMETHOD_*'], 'Imagick::minifyImage' => ['bool'], 'Imagick::modulateImage' => ['bool', 'brightness'=>'float', 'saturation'=>'float', 'hue'=>'float'], -'Imagick::montageImage' => ['Imagick', 'draw'=>'imagickdraw', 'tile_geometry'=>'string', 'thumbnail_geometry'=>'string', 'mode'=>'int', 'frame'=>'string'], +'Imagick::montageImage' => ['Imagick', 'draw'=>'imagickdraw', 'tile_geometry'=>'string', 'thumbnail_geometry'=>'string', 'mode'=>'Imagick::MONTAGEMODE_*', 'frame'=>'string'], 'Imagick::morphImages' => ['Imagick', 'number_frames'=>'int'], -'Imagick::morphology' => ['bool', 'morphologyMethod'=>'int', 'iterations'=>'int', 'ImagickKernel'=>'ImagickKernel', 'channel='=>'int'], +'Imagick::morphology' => ['bool', 'morphologyMethod'=>'Imagick::MORPHOLOGY_*', 'iterations'=>'int', 'ImagickKernel'=>'ImagickKernel', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::mosaicImages' => ['Imagick'], -'Imagick::motionBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float', 'channel='=>'int'], -'Imagick::negateImage' => ['bool', 'gray'=>'bool', 'channel='=>'int'], +'Imagick::motionBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::negateImage' => ['bool', 'gray'=>'bool', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::newImage' => ['bool', 'cols'=>'int', 'rows'=>'int', 'background'=>'mixed', 'format='=>'string'], 'Imagick::newPseudoImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'pseudostring'=>'string'], 'Imagick::next' => ['void'], 'Imagick::nextImage' => ['bool'], -'Imagick::normalizeImage' => ['bool', 'channel='=>'int'], +'Imagick::normalizeImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::oilPaintImage' => ['bool', 'radius'=>'float'], -'Imagick::opaquePaintImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'invert'=>'bool', 'channel='=>'int'], +'Imagick::opaquePaintImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'invert'=>'bool', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::optimizeImageLayers' => ['bool'], -'Imagick::orderedPosterizeImage' => ['bool', 'threshold_map'=>'string', 'channel='=>'int'], -'Imagick::paintFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int', 'channel='=>'int'], -'Imagick::paintOpaqueImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'channel='=>'int'], +'Imagick::orderedPosterizeImage' => ['bool', 'threshold_map'=>'string', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::paintFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::paintOpaqueImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::paintTransparentImage' => ['bool', 'target'=>'mixed', 'alpha'=>'float', 'fuzz'=>'float'], 'Imagick::pingImage' => ['bool', 'filename'=>'string'], 'Imagick::pingImageBlob' => ['bool', 'image'=>'string'], @@ -4879,16 +4879,16 @@ 'Imagick::queryFontMetrics' => ['array{characterWidth:float,characterHeight:float,ascender:float,descender:float,textWidth:float,textHeight:float,maxHorizontalAdvance:float,boundingBox:array{x1:float,x2:float,y1:float,y2:float},originX:float,originY:float}', 'properties'=>'imagickdraw', 'text'=>'string', 'multiline='=>'bool'], 'Imagick::queryFonts' => ['list', 'pattern='=>'string'], 'Imagick::queryFormats' => ['list', 'pattern='=>'string'], -'Imagick::radialBlurImage' => ['bool', 'angle'=>'float', 'channel='=>'int'], +'Imagick::radialBlurImage' => ['bool', 'angle'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::raiseImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int', 'raise'=>'bool'], -'Imagick::randomThresholdImage' => ['bool', 'low'=>'float', 'high'=>'float', 'channel='=>'int'], +'Imagick::randomThresholdImage' => ['bool', 'low'=>'float', 'high'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::readImage' => ['bool', 'filename'=>'string'], 'Imagick::readImageBlob' => ['bool', 'image'=>'string', 'filename='=>'string'], 'Imagick::readImageFile' => ['bool', 'filehandle'=>'resource', 'filename='=>'string'], 'Imagick::readImages' => ['Imagick', 'filenames'=>'string'], 'Imagick::recolorImage' => ['bool', 'matrix'=>'array'], 'Imagick::reduceNoiseImage' => ['bool', 'radius'=>'float'], -'Imagick::remapImage' => ['bool', 'replacement'=>'imagick', 'dither'=>'int'], +'Imagick::remapImage' => ['bool', 'replacement'=>'imagick', 'dither'=>'Imagick::DITHERMETHOD_*'], 'Imagick::removeImage' => ['bool'], 'Imagick::removeImageProfile' => ['string', 'name'=>'string'], 'Imagick::render' => ['bool'], @@ -4899,28 +4899,28 @@ 'Imagick::rewind' => ['void'], 'Imagick::rollImage' => ['bool', 'x'=>'int', 'y'=>'int'], 'Imagick::rotateImage' => ['bool', 'background'=>'mixed', 'degrees'=>'float'], -'Imagick::rotationalBlurImage' => ['bool', 'float'=>'string', 'channel='=>'int'], +'Imagick::rotationalBlurImage' => ['bool', 'float'=>'string', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::roundCorners' => ['bool', 'x_rounding'=>'float', 'y_rounding'=>'float', 'stroke_width='=>'float', 'displace='=>'float', 'size_correction='=>'float'], 'Imagick::roundCornersImage' => ['bool', 'x_rounding'=>'', 'y_rounding'=>'', 'stroke_width='=>'', 'displace='=>'', 'size_correction='=>''], 'Imagick::sampleImage' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::scaleImage' => ['bool', 'cols'=>'int', 'rows'=>'int', 'bestfit='=>'bool', 'legacy='=>'bool'], -'Imagick::segmentImage' => ['bool', 'colorspace'=>'int', 'cluster_threshold'=>'float', 'smooth_threshold'=>'float', 'verbose='=>'bool'], -'Imagick::selectiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'threshold'=>'float', 'channel='=>'int'], -'Imagick::separateImageChannel' => ['bool', 'channel'=>'int'], +'Imagick::segmentImage' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*', 'cluster_threshold'=>'float', 'smooth_threshold'=>'float', 'verbose='=>'bool'], +'Imagick::selectiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'threshold'=>'float', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::separateImageChannel' => ['bool', 'channel'=>'Imagick::CHANNEL_*'], 'Imagick::sepiaToneImage' => ['bool', 'threshold'=>'float'], 'Imagick::setAntiAlias' => ['int', 'antialias'=>'bool'], 'Imagick::setBackgroundColor' => ['bool', 'background'=>'mixed'], -'Imagick::setColorspace' => ['bool', 'colorspace'=>'int'], -'Imagick::setCompression' => ['bool', 'compression'=>'int'], +'Imagick::setColorspace' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*'], +'Imagick::setCompression' => ['bool', 'compression'=>'Imagick::COMPRESSION_*'], 'Imagick::setCompressionQuality' => ['bool', 'quality'=>'int'], 'Imagick::setFilename' => ['bool', 'filename'=>'string'], 'Imagick::setFirstIterator' => ['bool'], 'Imagick::setFont' => ['bool', 'font'=>'string'], 'Imagick::setFormat' => ['bool', 'format'=>'string'], -'Imagick::setGravity' => ['bool', 'gravity'=>'int'], +'Imagick::setGravity' => ['bool', 'gravity'=>'Imagick::GRAVITY_*'], 'Imagick::setImage' => ['bool', 'replace'=>'imagick'], 'Imagick::setImageAlpha' => ['bool', 'alpha'=>'float'], -'Imagick::setImageAlphaChannel' => ['bool', 'mode'=>'int'], +'Imagick::setImageAlphaChannel' => ['bool', 'mode'=>'Imagick::ALPHACHANNEL_*'], 'Imagick::setImageArtifact' => ['bool', 'artifact'=>'string', 'value'=>'string'], 'Imagick::setImageAttribute' => ['bool', 'key'=>'string', 'value'=>'string'], 'Imagick::setImageBackgroundColor' => ['bool', 'background'=>'mixed'], @@ -4928,41 +4928,41 @@ 'Imagick::setImageBiasQuantum' => ['void', 'bias'=>'string'], 'Imagick::setImageBluePrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageBorderColor' => ['bool', 'border'=>'mixed'], -'Imagick::setImageChannelDepth' => ['bool', 'channel'=>'int', 'depth'=>'int'], -'Imagick::setImageChannelMask' => ['', 'channel'=>'int'], +'Imagick::setImageChannelDepth' => ['bool', 'channel'=>'Imagick::CHANNEL_*', 'depth'=>'int'], +'Imagick::setImageChannelMask' => ['', 'channel'=>'Imagick::CHANNEL_*'], 'Imagick::setImageClipMask' => ['bool', 'clip_mask'=>'imagick'], 'Imagick::setImageColormapColor' => ['bool', 'index'=>'int', 'color'=>'imagickpixel'], -'Imagick::setImageColorspace' => ['bool', 'colorspace'=>'int'], -'Imagick::setImageCompose' => ['bool', 'compose'=>'int'], -'Imagick::setImageCompression' => ['bool', 'compression'=>'int'], +'Imagick::setImageColorspace' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*'], +'Imagick::setImageCompose' => ['bool', 'compose'=>'Imagick::COMPOSITE_*'], +'Imagick::setImageCompression' => ['bool', 'compression'=>'Imagick::COMPRESSION_*'], 'Imagick::setImageCompressionQuality' => ['bool', 'quality'=>'int'], 'Imagick::setImageDelay' => ['bool', 'delay'=>'int'], 'Imagick::setImageDepth' => ['bool', 'depth'=>'int'], -'Imagick::setImageDispose' => ['bool', 'dispose'=>'int'], +'Imagick::setImageDispose' => ['bool', 'dispose'=>'Imagick::DISPOSE_*'], 'Imagick::setImageExtent' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::setImageFilename' => ['bool', 'filename'=>'string'], 'Imagick::setImageFormat' => ['bool', 'format'=>'string'], 'Imagick::setImageGamma' => ['bool', 'gamma'=>'float'], -'Imagick::setImageGravity' => ['bool', 'gravity'=>'int'], +'Imagick::setImageGravity' => ['bool', 'gravity'=>'Imagick::GRAVITY_*'], 'Imagick::setImageGreenPrimary' => ['bool', 'x'=>'float', 'y'=>'float'], 'Imagick::setImageIndex' => ['bool', 'index'=>'int'], -'Imagick::setImageInterlaceScheme' => ['bool', 'interlace_scheme'=>'int'], -'Imagick::setImageInterpolateMethod' => ['bool', 'method'=>'int'], +'Imagick::setImageInterlaceScheme' => ['bool', 'interlace_scheme'=>'Imagick::INTERLACE_*'], +'Imagick::setImageInterpolateMethod' => ['bool', 'method'=>'Imagick::INTERPOLATE_*'], 'Imagick::setImageIterations' => ['bool', 'iterations'=>'int'], 'Imagick::setImageMatte' => ['bool', 'matte'=>'bool'], 'Imagick::setImageMatteColor' => ['bool', 'matte'=>'mixed'], 'Imagick::setImageOpacity' => ['bool', 'opacity'=>'float'], -'Imagick::setImageOrientation' => ['bool', 'orientation'=>'int'], +'Imagick::setImageOrientation' => ['bool', 'orientation'=>'Imagick::ORIENTATION_*'], 'Imagick::setImagePage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::setImageProfile' => ['bool', 'name'=>'string', 'profile'=>'string'], 'Imagick::setImageProgressMonitor' => ['', 'filename'=>''], 'Imagick::setImageProperty' => ['bool', 'name'=>'string', 'value'=>'string'], 'Imagick::setImageRedPrimary' => ['bool', 'x'=>'float', 'y'=>'float'], -'Imagick::setImageRenderingIntent' => ['bool', 'rendering_intent'=>'int'], +'Imagick::setImageRenderingIntent' => ['bool', 'rendering_intent'=>'Imagick::RENDERINGINTENT_*'], 'Imagick::setImageResolution' => ['bool', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'Imagick::setImageScene' => ['bool', 'scene'=>'int'], 'Imagick::setImageTicksPerSecond' => ['bool', 'ticks_per_second'=>'int'], -'Imagick::setImageType' => ['bool', 'image_type'=>'int'], +'Imagick::setImageType' => ['bool', 'image_type'=>'Imagick::IMGTYPE_*'], 'Imagick::setImageUnits' => ['bool', 'units'=>'int'], 'Imagick::setImageVirtualPixelMethod' => ['bool', 'method'=>'int'], 'Imagick::setImageWhitePoint' => ['bool', 'x'=>'float', 'y'=>'float'], @@ -4979,38 +4979,38 @@ 'Imagick::setSamplingFactors' => ['bool', 'factors'=>'array'], 'Imagick::setSize' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::setSizeOffset' => ['bool', 'columns'=>'int', 'rows'=>'int', 'offset'=>'int'], -'Imagick::setType' => ['bool', 'image_type'=>'int'], +'Imagick::setType' => ['bool', 'image_type'=>'Imagick::IMGTYPE_*'], 'Imagick::shadeImage' => ['bool', 'gray'=>'bool', 'azimuth'=>'float', 'elevation'=>'float'], 'Imagick::shadowImage' => ['bool', 'opacity'=>'float', 'sigma'=>'float', 'x'=>'int', 'y'=>'int'], -'Imagick::sharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'int'], +'Imagick::sharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::shaveImage' => ['bool', 'columns'=>'int', 'rows'=>'int'], 'Imagick::shearImage' => ['bool', 'background'=>'mixed', 'x_shear'=>'float', 'y_shear'=>'float'], -'Imagick::sigmoidalContrastImage' => ['bool', 'sharpen'=>'bool', 'alpha'=>'float', 'beta'=>'float', 'channel='=>'int'], -'Imagick::similarityImage' => ['Imagick', 'imagick'=>'Imagick', '&bestMatch'=>'array', '&similarity'=>'float', 'similarity_threshold'=>'float', 'metric'=>'int'], +'Imagick::sigmoidalContrastImage' => ['bool', 'sharpen'=>'bool', 'alpha'=>'float', 'beta'=>'float', 'channel='=>'Imagick::CHANNEL_*'], +'Imagick::similarityImage' => ['Imagick', 'imagick'=>'Imagick', '&bestMatch'=>'array', '&similarity'=>'float', 'similarity_threshold'=>'float', 'metric'=>'Imagick::METRIC_*'], 'Imagick::sketchImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float'], 'Imagick::smushImages' => ['Imagick', 'stack'=>'bool', 'offset'=>'int'], 'Imagick::solarizeImage' => ['bool', 'threshold'=>'0|positive-int'], -'Imagick::sparseColorImage' => ['bool', 'sparse_method'=>'int', 'arguments'=>'array', 'channel='=>'int'], +'Imagick::sparseColorImage' => ['bool', 'sparse_method'=>'Imagick::SPARSECOLORMETHOD_*', 'arguments'=>'array', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::spliceImage' => ['bool', 'width'=>'int', 'height'=>'int', 'x'=>'int', 'y'=>'int'], 'Imagick::spreadImage' => ['bool', 'radius'=>'float'], -'Imagick::statisticImage' => ['bool', 'type'=>'int', 'width'=>'int', 'height'=>'int', 'channel='=>'int'], +'Imagick::statisticImage' => ['bool', 'type'=>'Imagick::STATISTIC_*', 'width'=>'int', 'height'=>'int', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::steganoImage' => ['Imagick', 'watermark_wand'=>'imagick', 'offset'=>'int'], 'Imagick::stereoImage' => ['bool', 'offset_wand'=>'imagick'], 'Imagick::stripImage' => ['bool'], 'Imagick::subImageMatch' => ['Imagick', 'Imagick'=>'Imagick', '&w_offset='=>'array', '&w_similarity='=>'float'], 'Imagick::swirlImage' => ['bool', 'degrees'=>'float'], 'Imagick::textureImage' => ['Imagick', 'texture_wand'=>'imagick'], -'Imagick::thresholdImage' => ['bool', 'threshold'=>'float', 'channel='=>'int'], +'Imagick::thresholdImage' => ['bool', 'threshold'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::thumbnailImage' => ['bool', 'columns'=>'int', 'rows'=>'int', 'bestfit='=>'bool', 'fill='=>'bool', 'legacy='=>'bool'], 'Imagick::tintImage' => ['bool', 'tint'=>'mixed', 'opacity'=>'mixed'], 'Imagick::transformImage' => ['Imagick', 'crop'=>'string', 'geometry'=>'string'], -'Imagick::transformImageColorspace' => ['bool', 'colorspace'=>'int'], +'Imagick::transformImageColorspace' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*'], 'Imagick::transparentPaintImage' => ['bool', 'target'=>'mixed', 'alpha'=>'float', 'fuzz'=>'float', 'invert'=>'bool'], 'Imagick::transposeImage' => ['bool'], 'Imagick::transverseImage' => ['bool'], 'Imagick::trimImage' => ['bool', 'fuzz'=>'float'], 'Imagick::uniqueImageColors' => ['bool'], -'Imagick::unsharpMaskImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'amount'=>'float', 'threshold'=>'float', 'channel='=>'int'], +'Imagick::unsharpMaskImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'amount'=>'float', 'threshold'=>'float', 'channel='=>'Imagick::CHANNEL_*'], 'Imagick::valid' => ['bool'], 'Imagick::vignetteImage' => ['bool', 'blackpoint'=>'float', 'whitepoint'=>'float', 'x'=>'int', 'y'=>'int'], 'Imagick::waveImage' => ['bool', 'amplitude'=>'float', 'length'=>'float'], @@ -5027,9 +5027,9 @@ 'ImagickDraw::circle' => ['bool', 'ox'=>'float', 'oy'=>'float', 'px'=>'float', 'py'=>'float'], 'ImagickDraw::clear' => ['bool'], 'ImagickDraw::clone' => ['ImagickDraw'], -'ImagickDraw::color' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'int'], +'ImagickDraw::color' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'Imagick::PAINT_*'], 'ImagickDraw::comment' => ['bool', 'comment'=>'string'], -'ImagickDraw::composite' => ['bool', 'compose'=>'int', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float', 'compositewand'=>'imagick'], +'ImagickDraw::composite' => ['bool', 'compose'=>'Imagick::COMPOSITE_*', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float', 'compositewand'=>'imagick'], 'ImagickDraw::destroy' => ['bool'], 'ImagickDraw::ellipse' => ['bool', 'ox'=>'float', 'oy'=>'float', 'rx'=>'float', 'ry'=>'float', 'start'=>'float', 'end'=>'float'], 'ImagickDraw::getBorderColor' => ['ImagickPixel'], @@ -5069,7 +5069,7 @@ 'ImagickDraw::getTextUnderColor' => ['ImagickPixel'], 'ImagickDraw::getVectorGraphics' => ['string'], 'ImagickDraw::line' => ['bool', 'sx'=>'float', 'sy'=>'float', 'ex'=>'float', 'ey'=>'float'], -'ImagickDraw::matte' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'int'], +'ImagickDraw::matte' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'Imagick::PAINT_*'], 'ImagickDraw::pathClose' => ['bool'], 'ImagickDraw::pathCurveToAbsolute' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x2'=>'float', 'y2'=>'float', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::pathCurveToQuadraticBezierAbsolute' => ['bool', 'x1'=>'float', 'y1'=>'float', 'x'=>'float', 'y'=>'float'], @@ -5110,22 +5110,22 @@ 'ImagickDraw::scale' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::setBorderColor' => ['bool', 'color'=>'ImagickPixel|string'], 'ImagickDraw::setClipPath' => ['bool', 'clip_mask'=>'string'], -'ImagickDraw::setClipRule' => ['bool', 'fill_rule'=>'int'], +'ImagickDraw::setClipRule' => ['bool', 'fill_rule'=>'Imagick::FILLRULE_*'], 'ImagickDraw::setClipUnits' => ['bool', 'clip_units'=>'int'], 'ImagickDraw::setDensity' => ['bool', 'density_string'=>'string'], 'ImagickDraw::setFillAlpha' => ['bool', 'opacity'=>'float'], 'ImagickDraw::setFillColor' => ['bool', 'fill_pixel'=>'ImagickPixel|string'], 'ImagickDraw::setFillOpacity' => ['bool', 'fillopacity'=>'float'], 'ImagickDraw::setFillPatternURL' => ['bool', 'fill_url'=>'string'], -'ImagickDraw::setFillRule' => ['bool', 'fill_rule'=>'int'], +'ImagickDraw::setFillRule' => ['bool', 'fill_rule'=>'Imagick::FILLRULE_*'], 'ImagickDraw::setFont' => ['bool', 'font_name'=>'string'], 'ImagickDraw::setFontFamily' => ['bool', 'font_family'=>'string'], 'ImagickDraw::setFontResolution' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickDraw::setFontSize' => ['bool', 'pointsize'=>'float'], -'ImagickDraw::setFontStretch' => ['bool', 'fontstretch'=>'int'], -'ImagickDraw::setFontStyle' => ['bool', 'style'=>'int'], +'ImagickDraw::setFontStretch' => ['bool', 'fontstretch'=>'Imagick::STRETCH_*'], +'ImagickDraw::setFontStyle' => ['bool', 'style'=>'Imagick::STYLE_*'], 'ImagickDraw::setFontWeight' => ['bool', 'font_weight'=>'int'], -'ImagickDraw::setGravity' => ['bool', 'gravity'=>'int'], +'ImagickDraw::setGravity' => ['bool', 'gravity'=>'Imagick::GRAVITY_*'], 'ImagickDraw::setOpacity' => ['void', 'opacity'=>'float'], 'ImagickDraw::setResolution' => ['void', 'x_resolution'=>'float', 'y_resolution'=>'float'], 'ImagickDraw::setStrokeAlpha' => ['bool', 'opacity'=>'float'], @@ -5133,15 +5133,15 @@ 'ImagickDraw::setStrokeColor' => ['bool', 'stroke_pixel'=>'ImagickPixel|string'], 'ImagickDraw::setStrokeDashArray' => ['bool', 'dasharray'=>'array'], 'ImagickDraw::setStrokeDashOffset' => ['bool', 'dash_offset'=>'float'], -'ImagickDraw::setStrokeLineCap' => ['bool', 'linecap'=>'int'], -'ImagickDraw::setStrokeLineJoin' => ['bool', 'linejoin'=>'int'], +'ImagickDraw::setStrokeLineCap' => ['bool', 'linecap'=>'Imagick::LINECAP_*'], +'ImagickDraw::setStrokeLineJoin' => ['bool', 'linejoin'=>'Imagick::LINEJOIN_*'], 'ImagickDraw::setStrokeMiterLimit' => ['bool', 'miterlimit'=>'int'], 'ImagickDraw::setStrokeOpacity' => ['bool', 'stroke_opacity'=>'float'], 'ImagickDraw::setStrokePatternURL' => ['bool', 'stroke_url'=>'string'], 'ImagickDraw::setStrokeWidth' => ['bool', 'stroke_width'=>'float'], -'ImagickDraw::setTextAlignment' => ['bool', 'alignment'=>'int'], +'ImagickDraw::setTextAlignment' => ['bool', 'alignment'=>'Imagick::ALIGN_*'], 'ImagickDraw::setTextAntialias' => ['bool', 'antialias'=>'bool'], -'ImagickDraw::setTextDecoration' => ['bool', 'decoration'=>'int'], +'ImagickDraw::setTextDecoration' => ['bool', 'decoration'=>'Imagick::DECORATION_*'], 'ImagickDraw::setTextDirection' => ['bool', 'direction'=>'int'], 'ImagickDraw::setTextEncoding' => ['bool', 'encoding'=>'string'], 'ImagickDraw::setTextInterlineSpacing' => ['void', 'spacing'=>'float'], @@ -5155,10 +5155,10 @@ 'ImagickDraw::translate' => ['bool', 'x'=>'float', 'y'=>'float'], 'ImagickKernel::addKernel' => ['void', 'ImagickKernel'=>'ImagickKernel'], 'ImagickKernel::addUnityKernel' => ['void'], -'ImagickKernel::fromBuiltin' => ['ImagickKernel', 'kernelType'=>'int', 'kernelString'=>'string'], +'ImagickKernel::fromBuiltin' => ['ImagickKernel', 'kernelType'=>'Imagick::KERNEL_*', 'kernelString'=>'string'], 'ImagickKernel::fromMatrix' => ['ImagickKernel', 'matrix'=>'array', 'origin='=>'array'], 'ImagickKernel::getMatrix' => ['list>'], -'ImagickKernel::scale' => ['void', 'scale'=>'float', 'normalizeFlag'=>'int'], +'ImagickKernel::scale' => ['void', 'scale'=>'float', 'normalizeFlag'=>'Imagick::NORMALIZE_KERNEL_*'], 'ImagickKernel::separate' => ['array'], 'ImagickPixel::__construct' => ['void', 'color='=>'string'], 'ImagickPixel::clear' => ['bool'], @@ -5953,7 +5953,7 @@ 'litespeed_response_headers' => ['array|false'], 'Locale::acceptFromHttp' => ['non-empty-string|false', 'header'=>'string'], 'Locale::canonicalize' => ['non-empty-string|null', 'locale'=>'string'], -'Locale::composeLocale' => ['string|false', 'subtags'=>'array'], +'Locale::composeLocale' => ['string|false', 'subtags'=>'array{language:string, script?:string, region?:string, variant?:array, private?:array, extlang?:array, variant0?:string, variant1?:string, variant2?:string, variant3?:string, variant4?:string, variant5?:string, variant6?:string, variant7?:string, variant8?:string, variant9?:string, variant10?:string, variant11?:string, variant12?:string, variant13?:string, variant14?:string, private0?:string, private1?:string, private2?:string, private3?:string, private4?:string, private5?:string, private6?:string, private7?:string, private8?:string, private9?:string, private10?:string, private11?:string, private12?:string, private13?:string, private14?:string, extlang0?:string, extlang1?:string, extlang2?:string}'], 'Locale::filterMatches' => ['bool|null', 'langtag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'], 'Locale::getAllVariants' => ['array|null', 'locale'=>'string'], 'Locale::getDefault' => ['non-empty-string'], @@ -5971,7 +5971,7 @@ 'Locale::setDefault' => ['bool', 'locale'=>'string'], 'locale_accept_from_http' => ['non-empty-string|false', 'header'=>'string'], 'locale_canonicalize' => ['non-empty-string|null', 'locale'=>'string'], -'locale_compose' => ['string|false', 'subtags'=>'array'], +'locale_compose' => ['string|false', 'subtags'=>'array{language:string, script?:string, region?:string, variant?:array, private?:array, extlang?:array, variant0?:string, variant1?:string, variant2?:string, variant3?:string, variant4?:string, variant5?:string, variant6?:string, variant7?:string, variant8?:string, variant9?:string, variant10?:string, variant11?:string, variant12?:string, variant13?:string, variant14?:string, private0?:string, private1?:string, private2?:string, private3?:string, private4?:string, private5?:string, private6?:string, private7?:string, private8?:string, private9?:string, private10?:string, private11?:string, private12?:string, private13?:string, private14?:string, extlang0?:string, extlang1?:string, extlang2?:string}'], 'locale_filter_matches' => ['bool|null', 'langtag'=>'string', 'locale'=>'string', 'canonicalize='=>'bool'], 'locale_get_all_variants' => ['array|null', 'locale'=>'string'], 'locale_get_default' => ['non-empty-string'], @@ -6142,7 +6142,7 @@ 'mapObj::zoomPoint' => ['int', 'nZoomFactor'=>'int', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj'], 'mapObj::zoomRectangle' => ['int', 'oPixelExt'=>'rectObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj'], 'mapObj::zoomScale' => ['int', 'nScaleDenom'=>'float', 'oPixelPos'=>'pointObj', 'nImageWidth'=>'int', 'nImageHeight'=>'int', 'oGeorefExt'=>'rectObj', 'oMaxGeorefExt'=>'rectObj'], -'max' => ['', '...arg1'=>'array'], +'max' => ['', '...arg1'=>'non-empty-array'], 'max\'1' => ['', 'arg1'=>'', 'arg2'=>'', '...args='=>''], 'maxdb::__construct' => ['void', 'host='=>'string', 'username='=>'string', 'passwd='=>'string', 'dbname='=>'string', 'port='=>'int', 'socket='=>'string'], 'maxdb::affected_rows' => ['int', 'link'=>''], @@ -6318,7 +6318,7 @@ 'mb_decode_mimeheader' => ['string', 'string'=>'string'], 'mb_decode_numericentity' => ['string', 'string'=>'string', 'convmap'=>'array', 'encoding'=>'string'], 'mb_detect_encoding' => ['string|false', 'str'=>'string', 'encoding_list='=>'mixed', 'strict='=>'bool'], -'mb_detect_order' => ['bool|list', 'encoding_list='=>'mixed'], +'mb_detect_order' => ['bool|list', 'encoding_list='=>'non-empty-list|non-falsy-string'], 'mb_encode_mimeheader' => ['string', 'str'=>'string', 'charset='=>'string', 'transfer_encoding='=>'string', 'linefeed='=>'string', 'indent='=>'int'], 'mb_encode_numericentity' => ['string', 'string'=>'string', 'convmap'=>'array', 'encoding='=>'string', 'is_hex='=>'bool'], 'mb_encoding_aliases' => ['list|false', 'encoding'=>'string'], @@ -6514,7 +6514,7 @@ 'mhash_keygen_s2k' => ['string|false', 'hash'=>'int', 'input_password'=>'string', 'salt'=>'string', 'bytes'=>'int'], 'microtime' => ['mixed', 'get_as_float='=>'bool'], 'mime_content_type' => ['string|false', 'filename_or_stream'=>'string|resource'], -'min' => ['', '...arg1'=>'array'], +'min' => ['', '...arg1'=>'non-empty-array'], 'min\'1' => ['', 'arg1'=>'', 'arg2'=>'', '...args='=>''], 'ming_keypress' => ['int', 'char'=>'string'], 'ming_setcubicthreshold' => ['void', 'threshold'=>'int'], @@ -9438,7 +9438,7 @@ 'RecursiveFilterIterator::hasChildren' => ['bool'], 'RecursiveIterator::getChildren' => ['RecursiveIterator'], 'RecursiveIterator::hasChildren' => ['bool'], -'RecursiveIteratorIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'mode='=>'int', 'flags='=>'int'], +'RecursiveIteratorIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'mode='=>'RecursiveIteratorIterator::LEAVES_ONLY|RecursiveIteratorIterator::SELF_FIRST|RecursiveIteratorIterator::CHILD_FIRST', 'flags='=>'0|RecursiveIteratorIterator::CATCH_GET_CHILD'], 'RecursiveIteratorIterator::beginChildren' => ['void'], 'RecursiveIteratorIterator::beginIteration' => ['RecursiveIterator'], 'RecursiveIteratorIterator::callGetChildren' => ['RecursiveIterator'], @@ -10283,7 +10283,7 @@ 'scalebarObj::set' => ['int', 'property_name'=>'string', 'new_value'=>''], 'scalebarObj::setImageColor' => ['int', 'red'=>'int', 'green'=>'int', 'blue'=>'int'], 'scalebarObj::updateFromString' => ['int', 'snippet'=>'string'], -'scandir' => ['list|false', 'dir'=>'string', 'sorting_order='=>'int', 'context='=>'resource'], +'scandir' => ['list|false', 'dir'=>'string', 'sorting_order='=>'SCANDIR_SORT_ASCENDING|SCANDIR_SORT_DESCENDING| SCANDIR_SORT_NONE', 'context='=>'resource'], 'SDO_DAS_ChangeSummary::beginLogging' => [''], 'SDO_DAS_ChangeSummary::endLogging' => [''], 'SDO_DAS_ChangeSummary::getChangedDataObjects' => ['SDO_List'], @@ -11579,7 +11579,7 @@ 'SplFileObject::fgetcsv' => ['list|array{0: null}|false|null', 'delimiter='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::fgets' => ['string'], 'SplFileObject::fgetss' => ['string|false', 'allowable_tags='=>'string'], -'SplFileObject::flock' => ['bool', 'operation'=>'int', '&w_wouldblock='=>'int'], +'SplFileObject::flock' => ['bool', 'operation'=>'int-mask', '&w_wouldblock='=>'0|1'], 'SplFileObject::fpassthru' => ['int'], 'SplFileObject::fputcsv' => ['int|false', 'fields'=>'array', 'delimiter='=>'string', 'enclosure='=>'string', 'escape='=>'string'], 'SplFileObject::fread' => ['string|false', 'length'=>'int'], @@ -12024,8 +12024,8 @@ 'stream_set_timeout' => ['bool', 'stream'=>'resource', 'seconds'=>'int', 'microseconds='=>'int'], 'stream_set_write_buffer' => ['int', 'fp'=>'resource', 'buffer'=>'int'], 'stream_socket_accept' => ['resource|false', 'serverstream'=>'resource', 'timeout='=>'float', '&w_peername='=>'string'], -'stream_socket_client' => ['resource|false', 'remoteaddress'=>'string', '&w_errcode='=>'int', '&w_errstring='=>'string', 'timeout='=>'float', 'flags='=>'int', 'context='=>'resource'], -'stream_socket_enable_crypto' => ['0|bool', 'stream'=>'resource', 'enable'=>'bool', 'cryptokind='=>'int', 'sessionstream='=>'resource'], +'stream_socket_client' => ['resource|false', 'remoteaddress'=>'string', '&w_errcode='=>'int', '&w_errstring='=>'string', 'timeout='=>'float', 'flags='=>'int-mask', 'context='=>'resource'], +'stream_socket_enable_crypto' => ['0|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'STREAM_CRYPTO_METHOD_SSLv2_CLIENT|STREAM_CRYPTO_METHOD_SSLv3_CLIENT|STREAM_CRYPTO_METHOD_SSLv23_CLIENT|STREAM_CRYPTO_METHOD_ANY_CLIENT|STREAM_CRYPTO_METHOD_TLS_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT|STREAM_CRYPTO_METHOD_SSLv2_SERVER|STREAM_CRYPTO_METHOD_SSLv3_SERVER|STREAM_CRYPTO_METHOD_SSLv23_SERVER|STREAM_CRYPTO_METHOD_ANY_SERVER|STREAM_CRYPTO_METHOD_TLS_SERVER|STREAM_CRYPTO_METHOD_TLSv1_0_SERVER|STREAM_CRYPTO_METHOD_TLSv1_1_SERVER|STREAM_CRYPTO_METHOD_TLSv1_2_SERVER|STREAM_CRYPTO_METHOD_TLSv1_3_SERVER', 'session_stream='=>'resource'], 'stream_socket_get_name' => ['string|false', 'stream'=>'resource', 'want_peer'=>'bool'], 'stream_socket_pair' => ['resource[]|false', 'domain'=>'int', 'type'=>'int', 'protocol'=>'int'], 'stream_socket_recvfrom' => ['string|false', 'stream'=>'resource', 'amount'=>'int', 'flags='=>'int', '&w_remote_addr='=>'string'], @@ -13270,7 +13270,7 @@ 'xdebug_get_declared_vars' => ['array'], 'xdebug_get_formatted_function_stack' => [''], 'xdebug_get_function_count' => ['int'], -'xdebug_get_function_stack' => ['array', 'message='=>'string', 'options='=>'int'], +'xdebug_get_function_stack' => ['array', 'options='=>'array{local_vars?: bool, params_as_values?: bool, from_exception?: Throwable}'], 'xdebug_get_headers' => ['array'], 'xdebug_get_monitored_functions' => ['array'], 'xdebug_get_profiler_filename' => ['string'], diff --git a/resources/functionMap_bleedingEdge.php b/resources/functionMap_bleedingEdge.php index 9d26a518b6..92f41e9db0 100644 --- a/resources/functionMap_bleedingEdge.php +++ b/resources/functionMap_bleedingEdge.php @@ -2,157 +2,7 @@ return [ 'new' => [ - 'bcadd' => ['numeric-string', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], - 'bccomp' => ['int', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], - 'bcdiv' => ['numeric-string|null', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], - 'bcmod' => ['numeric-string|null', 'left_operand'=>'string', 'right_operand'=>'numeric-string', 'scale='=>'int'], - 'bcmul' => ['numeric-string', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], - 'bcpow' => ['numeric-string', 'base'=>'numeric-string', 'exponent'=>'numeric-string', 'scale='=>'int'], - 'bcpowmod' => ['numeric-string|null', 'base'=>'numeric-string', 'exponent'=>'numeric-string', 'modulus'=>'string', 'scale='=>'int'], - 'bcsqrt' => ['numeric-string', 'operand'=>'numeric-string', 'scale='=>'int'], - 'bcsub' => ['numeric-string', 'left_operand'=>'numeric-string', 'right_operand'=>'numeric-string', 'scale='=>'int'], - 'Closure::bind' => ['Closure', 'old'=>'Closure', 'to'=>'?object', 'scope='=>'object|class-string|\'static\'|null'], - 'Closure::bindTo' => ['Closure', 'new'=>'?object', 'newscope='=>'object|class-string|\'static\'|null'], - 'error_log' => ['bool', 'message'=>'string', 'message_type='=>'0|1|2|3|4', 'destination='=>'string', 'extra_headers='=>'string'], - 'SplFileObject::flock' => ['bool', 'operation'=>'int-mask', '&w_wouldblock='=>'0|1'], - 'Imagick::adaptiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::adaptiveSharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::addNoiseImage' => ['bool', 'noise_type'=>'Imagick::NOISE_*', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::autoGammaImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::autoLevelImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::blurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::brightnessContrastImage' => ['bool', 'brightness'=>'float', 'contrast'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::clampImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::combineImages' => ['Imagick', 'channeltype'=>'Imagick::CHANNEL_*'], - 'Imagick::compareImageChannels' => ['array{Imagick,float}', 'image'=>'imagick', 'channeltype'=>'Imagick::CHANNEL_*', 'metrictype'=>'Imagick::METRIC_*'], - 'Imagick::compareImageLayers' => ['Imagick', 'method'=>'Imagick::LAYERMETHOD_*'], - 'Imagick::compareImages' => ['array{Imagick,float}', 'compare'=>'imagick', 'metric'=>'Imagick::METRIC_*'], - 'Imagick::compositeImage' => ['bool', 'composite_object'=>'imagick', 'composite'=>'Imagick::COMPOSITE_*', 'x'=>'int', 'y'=>'int', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::contrastStretchImage' => ['bool', 'black_point'=>'float', 'white_point'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::convolveImage' => ['bool', 'kernel'=>'array', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::distortImage' => ['bool', 'method'=>'Imagick::DISTORTION_*', 'arguments'=>'array', 'bestfit'=>'bool'], - 'Imagick::evaluateImage' => ['bool', 'op'=>'Imagick::EVALUATE_*', 'constant'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::exportImagePixels' => ['list', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'Imagick::PIXEL_*'], - 'Imagick::floodFillPaintImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'target'=>'mixed', 'x'=>'int', 'y'=>'int', 'invert'=>'bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::functionImage' => ['bool', 'function'=>'Imagick::FUNCTION_*', 'arguments'=>'array', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::fxImage' => ['Imagick', 'expression'=>'string', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::gammaImage' => ['bool', 'gamma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::gaussianBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::getImageChannelDepth' => ['int', 'channel'=>'Imagick::CHANNEL_*'], - 'Imagick::getImageChannelDistortion' => ['float', 'reference'=>'imagick', 'channel'=>'Imagick::CHANNEL_*', 'metric'=>'Imagick::METRIC_*'], - 'Imagick::getImageChannelDistortions' => ['float', 'reference'=>'imagick', 'metric'=>'Imagick::METRIC_*', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::getImageChannelExtrema' => ['array{minima:0|positive-int,maxima:0|positive-int}', 'channel'=>'Imagick::CHANNEL_*'], - 'Imagick::getImageChannelKurtosis' => ['array{kurtosis:float,skewness:float}', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::getImageChannelMean' => ['array{mean:float,standardDeviation:float}', 'channel'=>'Imagick::CHANNEL_*'], - 'Imagick::getImageChannelRange' => ['array{minima:float,maxima:float}', 'channel'=>'Imagick::CHANNEL_*'], - 'Imagick::getImageDistortion' => ['float', 'reference'=>'magickwand', 'metric'=>'Imagick::METRIC_*'], - 'Imagick::getResource' => ['int', 'type'=>'Imagick::RESOURCETYPE_*'], - 'Imagick::getResourceLimit' => ['int', 'type'=>'Imagick::RESOURCETYPE_*'], - 'Imagick::importImagePixels' => ['bool', 'x'=>'int', 'y'=>'int', 'width'=>'int', 'height'=>'int', 'map'=>'string', 'storage'=>'Imagick::PIXEL_*', 'pixels'=>'array'], - 'Imagick::levelImage' => ['bool', 'blackpoint'=>'float', 'gamma'=>'float', 'whitepoint'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::mergeImageLayers' => ['Imagick', 'layer_method'=>'Imagick::LAYERMETHOD_*'], - 'Imagick::montageImage' => ['Imagick', 'draw'=>'imagickdraw', 'tile_geometry'=>'string', 'thumbnail_geometry'=>'string', 'mode'=>'Imagick::MONTAGEMODE_*', 'frame'=>'string'], - 'Imagick::morphology' => ['bool', 'morphologyMethod'=>'Imagick::MORPHOLOGY_*', 'iterations'=>'int', 'ImagickKernel'=>'ImagickKernel', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::motionBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'angle'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::negateImage' => ['bool', 'gray'=>'bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::normalizeImage' => ['bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::opaquePaintImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'invert'=>'bool', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::orderedPosterizeImage' => ['bool', 'threshold_map'=>'string', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::paintFloodfillImage' => ['bool', 'fill'=>'mixed', 'fuzz'=>'float', 'bordercolor'=>'mixed', 'x'=>'int', 'y'=>'int', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::paintOpaqueImage' => ['bool', 'target'=>'mixed', 'fill'=>'mixed', 'fuzz'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::radialBlurImage' => ['bool', 'angle'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::randomThresholdImage' => ['bool', 'low'=>'float', 'high'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::remapImage' => ['bool', 'replacement'=>'imagick', 'dither'=>'Imagick::DITHERMETHOD_*'], - 'Imagick::rotationalBlurImage' => ['bool', 'float'=>'string', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::segmentImage' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*', 'cluster_threshold'=>'float', 'smooth_threshold'=>'float', 'verbose='=>'bool'], - 'Imagick::selectiveBlurImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'threshold'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::separateImageChannel' => ['bool', 'channel'=>'Imagick::CHANNEL_*'], - 'Imagick::setColorspace' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*'], - 'Imagick::setCompression' => ['bool', 'compression'=>'Imagick::COMPRESSION_*'], - 'Imagick::setGravity' => ['bool', 'gravity'=>'Imagick::GRAVITY_*'], - 'Imagick::setImageAlphaChannel' => ['bool', 'mode'=>'Imagick::ALPHACHANNEL_*'], - 'Imagick::setImageChannelDepth' => ['bool', 'channel'=>'Imagick::CHANNEL_*', 'depth'=>'int'], - 'Imagick::setImageChannelMask' => ['', 'channel'=>'Imagick::CHANNEL_*'], - 'Imagick::setImageClipMask' => ['bool', 'clip_mask'=>'imagick'], - 'Imagick::setImageColormapColor' => ['bool', 'index'=>'int', 'color'=>'imagickpixel'], - 'Imagick::setImageColorspace' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*'], - 'Imagick::setImageCompose' => ['bool', 'compose'=>'Imagick::COMPOSITE_*'], - 'Imagick::setImageCompression' => ['bool', 'compression'=>'Imagick::COMPRESSION_*'], - 'Imagick::setImageDispose' => ['bool', 'dispose'=>'Imagick::DISPOSE_*'], - 'Imagick::setImageGravity' => ['bool', 'gravity'=>'Imagick::GRAVITY_*'], - 'Imagick::setImageInterlaceScheme' => ['bool', 'interlace_scheme'=>'Imagick::INTERLACE_*'], - 'Imagick::setImageInterpolateMethod' => ['bool', 'method'=>'Imagick::INTERPOLATE_*'], - 'Imagick::setImageOrientation' => ['bool', 'orientation'=>'Imagick::ORIENTATION_*'], - 'Imagick::setImageRenderingIntent' => ['bool', 'rendering_intent'=>'Imagick::RENDERINGINTENT_*'], - 'Imagick::setImageType' => ['bool', 'image_type'=>'Imagick::IMGTYPE_*'], - 'Imagick::setType' => ['bool', 'image_type'=>'Imagick::IMGTYPE_*'], - 'Imagick::sharpenImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::sigmoidalContrastImage' => ['bool', 'sharpen'=>'bool', 'alpha'=>'float', 'beta'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::similarityImage' => ['Imagick', 'imagick'=>'Imagick', '&bestMatch'=>'array', '&similarity'=>'float', 'similarity_threshold'=>'float', 'metric'=>'Imagick::METRIC_*'], - 'Imagick::sparseColorImage' => ['bool', 'sparse_method'=>'Imagick::SPARSECOLORMETHOD_*', 'arguments'=>'array', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::statisticImage' => ['bool', 'type'=>'Imagick::STATISTIC_*', 'width'=>'int', 'height'=>'int', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::thresholdImage' => ['bool', 'threshold'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'Imagick::transformImageColorspace' => ['bool', 'colorspace'=>'Imagick::COLORSPACE_*'], - 'Imagick::unsharpMaskImage' => ['bool', 'radius'=>'float', 'sigma'=>'float', 'amount'=>'float', 'threshold'=>'float', 'channel='=>'Imagick::CHANNEL_*'], - 'ImagickDraw::color' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'Imagick::PAINT_*'], - 'ImagickDraw::composite' => ['bool', 'compose'=>'Imagick::COMPOSITE_*', 'x'=>'float', 'y'=>'float', 'width'=>'float', 'height'=>'float', 'compositewand'=>'imagick'], - 'ImagickDraw::getFillRule' => ['Imagick::FILLRULE_*'], - 'ImagickDraw::getFontStretch' => ['Imagick::STRETCH_*'], - 'ImagickDraw::getFontStyle' => ['Imagick::STYLE_*'], - 'ImagickDraw::getGravity' => ['Imagick::GRAVITY_*'], - 'ImagickDraw::getStrokeLineCap' => ['Imagick::LINECAP_*'], - 'ImagickDraw::getStrokeLineJoin' => ['Imagick::LINEJOIN_*'], - 'ImagickDraw::getTextAlignment' => ['Imagick::ALIGN_*'], - 'ImagickDraw::getTextDecoration' => ['Imagick::DECORATION_*'], - 'ImagickDraw::matte' => ['bool', 'x'=>'float', 'y'=>'float', 'paintmethod'=>'Imagick::PAINT_*'], - 'ImagickDraw::setClipRule' => ['bool', 'fill_rule'=>'Imagick::FILLRULE_*'], - 'ImagickDraw::setFillRule' => ['bool', 'fill_rule'=>'Imagick::FILLRULE_*'], - 'ImagickDraw::setFontStretch' => ['bool', 'fontstretch'=>'Imagick::STRETCH_*'], - 'ImagickDraw::setFontStyle' => ['bool', 'style'=>'Imagick::STYLE_*'], - 'ImagickDraw::setGravity' => ['bool', 'gravity'=>'Imagick::GRAVITY_*'], - 'ImagickDraw::setStrokeLineCap' => ['bool', 'linecap'=>'Imagick::LINECAP_*'], - 'ImagickDraw::setStrokeLineJoin' => ['bool', 'linejoin'=>'Imagick::LINEJOIN_*'], - 'ImagickDraw::setTextAlignment' => ['bool', 'alignment'=>'Imagick::ALIGN_*'], - 'ImagickDraw::setTextAntialias' => ['bool', 'antialias'=>'bool'], - 'ImagickDraw::setTextDecoration' => ['bool', 'decoration'=>'Imagick::DECORATION_*'], - 'ImagickKernel::fromBuiltin' => ['ImagickKernel', 'kernelType'=>'Imagick::KERNEL_*', 'kernelString'=>'string'], - 'ImagickKernel::scale' => ['void', 'scale'=>'float', 'normalizeFlag'=>'Imagick::NORMALIZE_KERNEL_*'], - 'imagecolorallocate' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], - 'imagecolorallocatealpha' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], - 'imagecolorclosest' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], - 'imagecolorclosestalpha' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], - 'imagecolorclosesthwb' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], - 'imagecolorexact' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], - 'imagecolorexactalpha' => ['int<0, max>|false', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], - 'imagecolorresolve' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>'], - 'imagecolorresolvealpha' => ['int<0, max>', 'im'=>'resource', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha'=>'int<0, 127>'], - 'imagecolorset' => ['void', 'im'=>'resource', 'col'=>'int', 'red'=>'int<0, 255>', 'green'=>'int<0, 255>', 'blue'=>'int<0, 255>', 'alpha='=>'int<0, 127>'], - 'imagecreate' => ['__benevolent', 'x_size'=>'int<1, max>', 'y_size'=>'int<1, max>'], - 'imagecreatetruecolor' => ['__benevolent', 'x_size'=>'int<1, max>', 'y_size'=>'int<1, max>'], - 'max' => ['', '...arg1'=>'non-empty-array'], - 'mb_detect_order' => ['bool|list', 'encoding_list='=>'non-empty-list|non-falsy-string'], - 'min' => ['', '...arg1'=>'non-empty-array'], - 'file' => ['list|false', 'filename'=>'string', 'flags='=>'int-mask', 'context='=>'resource'], - 'flock' => ['bool', 'fp'=>'resource', 'operation'=>'int-mask', '&w_wouldblock='=>'0|1'], - 'ftp_append' => ['bool', 'ftp'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY'], - 'ftp_fget' => ['bool', 'stream'=>'resource', 'fp'=>'resource', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resumepos='=>'int'], - 'ftp_fput' => ['bool', 'stream'=>'resource', 'remote_file'=>'string', 'fp'=>'resource', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], - 'ftp_get' => ['bool', 'stream'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resume_pos='=>'int'], - 'ftp_nb_fget' => ['int', 'stream'=>'resource', 'fp'=>'resource', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resumepos='=>'int'], - 'ftp_nb_fput' => ['int', 'stream'=>'resource', 'remote_file'=>'string', 'fp'=>'resource', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], - 'ftp_nb_get' => ['int|false', 'stream'=>'resource', 'local_file'=>'string', 'remote_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'resume_pos='=>'int'], - 'ftp_nb_put' => ['int|false', 'stream'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], - 'ftp_put' => ['bool', 'stream'=>'resource', 'remote_file'=>'string', 'local_file'=>'string', 'mode='=>'FTP_ASCII|FTP_BINARY', 'startpos='=>'int'], - 'scandir' => ['list|false', 'dir'=>'string', 'sorting_order='=>'SCANDIR_SORT_ASCENDING|SCANDIR_SORT_DESCENDING| SCANDIR_SORT_NONE', 'context='=>'resource'], - 'stream_socket_client' => ['resource|false', 'remoteaddress'=>'string', '&w_errcode='=>'int', '&w_errstring='=>'string', 'timeout='=>'float', 'flags='=>'int-mask', 'context='=>'resource'], - 'stream_socket_enable_crypto' => ['0|bool', 'stream'=>'resource', 'enable'=>'bool', 'crypto_method='=>'STREAM_CRYPTO_METHOD_SSLv2_CLIENT|STREAM_CRYPTO_METHOD_SSLv3_CLIENT|STREAM_CRYPTO_METHOD_SSLv23_CLIENT|STREAM_CRYPTO_METHOD_ANY_CLIENT|STREAM_CRYPTO_METHOD_TLS_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT|STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT|STREAM_CRYPTO_METHOD_SSLv2_SERVER|STREAM_CRYPTO_METHOD_SSLv3_SERVER|STREAM_CRYPTO_METHOD_SSLv23_SERVER|STREAM_CRYPTO_METHOD_ANY_SERVER|STREAM_CRYPTO_METHOD_TLS_SERVER|STREAM_CRYPTO_METHOD_TLSv1_0_SERVER|STREAM_CRYPTO_METHOD_TLSv1_1_SERVER|STREAM_CRYPTO_METHOD_TLSv1_2_SERVER|STREAM_CRYPTO_METHOD_TLSv1_3_SERVER', 'session_stream='=>'resource'], - 'extract' => ['0|positive-int', 'array'=>'array', 'flags='=>'EXTR_OVERWRITE|EXTR_SKIP|EXTR_PREFIX_SAME|EXTR_PREFIX_ALL|EXTR_PREFIX_INVALID|EXTR_IF_EXISTS|EXTR_PREFIX_IF_EXISTS|EXTR_REFS', 'prefix='=>'string|null'], - 'RecursiveIteratorIterator::__construct' => ['void', 'iterator'=>'RecursiveIterator|IteratorAggregate', 'mode='=>'RecursiveIteratorIterator::LEAVES_ONLY|RecursiveIteratorIterator::SELF_FIRST|RecursiveIteratorIterator::CHILD_FIRST', 'flags='=>'0|RecursiveIteratorIterator::CATCH_GET_CHILD'], - 'Locale::composeLocale' => ['string|false', 'subtags'=>'array{language:string, script?:string, region?:string, variant?:array, private?:array, extlang?:array, variant0?:string, variant1?:string, variant2?:string, variant3?:string, variant4?:string, variant5?:string, variant6?:string, variant7?:string, variant8?:string, variant9?:string, variant10?:string, variant11?:string, variant12?:string, variant13?:string, variant14?:string, private0?:string, private1?:string, private2?:string, private3?:string, private4?:string, private5?:string, private6?:string, private7?:string, private8?:string, private9?:string, private10?:string, private11?:string, private12?:string, private13?:string, private14?:string, extlang0?:string, extlang1?:string, extlang2?:string}'], - 'locale_compose' => ['string|false', 'subtags'=>'array{language:string, script?:string, region?:string, variant?:array, private?:array, extlang?:array, variant0?:string, variant1?:string, variant2?:string, variant3?:string, variant4?:string, variant5?:string, variant6?:string, variant7?:string, variant8?:string, variant9?:string, variant10?:string, variant11?:string, variant12?:string, variant13?:string, variant14?:string, private0?:string, private1?:string, private2?:string, private3?:string, private4?:string, private5?:string, private6?:string, private7?:string, private8?:string, private9?:string, private10?:string, private11?:string, private12?:string, private13?:string, private14?:string, extlang0?:string, extlang1?:string, extlang2?:string}'], - 'count' => ['0|positive-int', 'var'=>'Countable|array', 'mode='=>'0|1'], ], 'old' => [ - - ] + ], ]; diff --git a/resources/functionMap_php80delta.php b/resources/functionMap_php80delta.php index d242a5410a..879dc310e4 100644 --- a/resources/functionMap_php80delta.php +++ b/resources/functionMap_php80delta.php @@ -43,8 +43,12 @@ 'date_time_set' => ['DateTime', 'object'=>'DateTime', 'hour'=>'int', 'minute'=>'int', 'second='=>'int', 'microseconds='=>'int'], 'date_timestamp_set' => ['DateTime', 'object'=>'DateTime', 'unixtimestamp'=>'int'], 'date_timezone_set' => ['DateTime', 'object'=>'DateTime', 'timezone'=>'DateTimeZone'], + 'error_log' => ['bool', 'message'=>'string', 'message_type='=>'0|1|3|4', 'destination='=>'string', 'extra_headers='=>'string'], 'explode' => ['list', 'separator'=>'non-empty-string', 'str'=>'string', 'limit='=>'int'], 'fdiv' => ['float', 'dividend'=>'float', 'divisor'=>'float'], + 'fgetcsv' => ['list|array{0: null}|false', 'fp'=>'resource', 'length='=>'0|positive-int|null', 'delimiter='=>'string', 'enclosure='=>'string', 'escape='=>'string'], + 'filter_input' => ['mixed', 'type'=>'INPUT_GET|INPUT_POST|INPUT_COOKIE|INPUT_SERVER|INPUT_ENV', 'variable_name'=>'string', 'filter='=>'int', 'options='=>'array|int'], + 'filter_input_array' => ['array|false|null', 'type'=>'INPUT_GET|INPUT_POST|INPUT_COOKIE|INPUT_SERVER|INPUT_ENV', 'definition='=>'int|array', 'add_empty='=>'bool'], 'floor' => ['float', 'number'=>'float'], 'forward_static_call_array' => ['mixed', 'function'=>'callable', 'parameters'=>'array'], 'get_debug_type' => ['string', 'var'=>'mixed'], @@ -52,11 +56,11 @@ 'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int'], 'gmmktime' => ['int|false', 'hour'=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'], 'hash' => ['non-falsy-string', 'algo'=>'string', 'data'=>'string', 'raw_output='=>'bool'], - 'hash_hkdf' => ['non-falsy-string', 'algo'=>'string', 'key'=>'string', 'length='=>'int', 'info='=>'string', 'salt='=>'string'], + 'hash_hkdf' => ['non-falsy-string', 'algo'=>'non-falsy-string', 'key'=>'string', 'length='=>'0|positive-int', 'info='=>'string', 'salt='=>'string'], 'hash_hmac' => ['non-empty-string', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'raw_output='=>'bool'], - 'hash_pbkdf2' => ['non-empty-string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'raw_output='=>'bool'], + 'hash_pbkdf2' => ['non-empty-string', 'algo'=>'non-falsy-string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'positive-int', 'length='=>'0|positive-int', 'raw_output='=>'bool'], 'imageaffine' => ['false|object', 'src'=>'resource', 'affine'=>'array', 'clip='=>'array'], - 'imagecreate' => ['__benevolent', 'width'=>'int', 'height'=>'int'], + 'imagecreate' => ['__benevolent', 'width'=>'int<1, max>', 'height'=>'int<1, max>'], 'imagecreatefrombmp' => ['false|object', 'filename'=>'string'], 'imagecreatefromgd' => ['false|object', 'filename'=>'string'], 'imagecreatefromgd2' => ['false|object', 'filename'=>'string'], @@ -69,7 +73,7 @@ 'imagecreatefromwebp' => ['false|object', 'filename'=>'string'], 'imagecreatefromxbm' => ['false|object', 'filename'=>'string'], 'imagecreatefromxpm' => ['false|object', 'filename'=>'string'], - 'imagecreatetruecolor' => ['__benevolent', 'width'=>'int', 'height'=>'int'], + 'imagecreatetruecolor' => ['__benevolent', 'width'=>'int<1, max>', 'height'=>'int<1, max>'], 'imagecrop' => ['false|object', 'im'=>'resource', 'rect'=>'array'], 'imagecropauto' => ['false|object', 'im'=>'resource', 'mode'=>'int', 'threshold'=>'float', 'color'=>'int'], 'imagegetclip' => ['array', 'im'=>'resource'], @@ -80,6 +84,7 @@ 'imagescale' => ['false|object', 'im'=>'resource', 'new_width'=>'int', 'new_height='=>'int', 'method='=>'int'], 'ldap_set_rebind_proc' => ['bool', 'ldap'=>'resource', 'callback'=>'?callable'], 'mb_decode_numericentity' => ['string|false', 'string'=>'string', 'convmap'=>'array', 'encoding='=>'string'], + 'mb_detect_order' => ['bool|list', 'encoding_list='=>'non-empty-list|non-falsy-string|null'], 'mb_encoding_aliases' => ['list', 'encoding'=>'string'], 'mb_str_split' => ['list', 'str'=>'string', 'split_length='=>'positive-int', 'encoding='=>'string'], 'mb_strlen' => ['0|positive-int', 'str'=>'string', 'encoding='=>'string'], diff --git a/resources/functionMap_php80delta_bleedingEdge.php b/resources/functionMap_php80delta_bleedingEdge.php index 82e9b720a8..92f41e9db0 100644 --- a/resources/functionMap_php80delta_bleedingEdge.php +++ b/resources/functionMap_php80delta_bleedingEdge.php @@ -2,16 +2,7 @@ return [ 'new' => [ - 'error_log' => ['bool', 'message'=>'string', 'message_type='=>'0|1|3|4', 'destination='=>'string', 'extra_headers='=>'string'], - 'filter_input' => ['mixed', 'type'=>'INPUT_GET|INPUT_POST|INPUT_COOKIE|INPUT_SERVER|INPUT_ENV', 'variable_name'=>'string', 'filter='=>'int', 'options='=>'array|int'], - 'filter_input_array' => ['array|false|null', 'type'=>'INPUT_GET|INPUT_POST|INPUT_COOKIE|INPUT_SERVER|INPUT_ENV', 'definition='=>'int|array', 'add_empty='=>'bool'], - 'hash_hkdf' => ['non-falsy-string', 'algo'=>'non-falsy-string', 'key'=>'string', 'length='=>'0|positive-int', 'info='=>'string', 'salt='=>'string'], - 'hash_pbkdf2' => ['non-empty-string', 'algo'=>'non-falsy-string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'positive-int', 'length='=>'0|positive-int', 'raw_output='=>'bool'], - 'imagecreate' => ['__benevolent', 'width'=>'int<1, max>', 'height'=>'int<1, max>'], - 'imagecreatetruecolor' => ['__benevolent', 'width'=>'int<1, max>', 'height'=>'int<1, max>'], - 'mb_detect_order' => ['bool|list', 'encoding_list='=>'non-empty-list|non-falsy-string|null'], ], 'old' => [ - - ] + ], ]; diff --git a/resources/functionMetadata.php b/resources/functionMetadata.php index 4ba615393d..0c5c33759a 100644 --- a/resources/functionMetadata.php +++ b/resources/functionMetadata.php @@ -651,7 +651,6 @@ 'StringBackedEnum::tryFrom' => ['hasSideEffects' => false], 'StubTests\\CodeStyle\\BracesOneLineFixer::getDefinition' => ['hasSideEffects' => false], 'StubTests\\Parsers\\ExpectedFunctionArgumentsInfo::__toString' => ['hasSideEffects' => false], - 'StubTests\\Parsers\\Visitors\\CoreStubASTVisitor::__construct' => ['hasSideEffects' => false], 'StubTests\\StubsMetaExpectedArgumentsTest::getClassMemberFqn' => ['hasSideEffects' => false], 'StubTests\\StubsParameterNamesTest::printParameters' => ['hasSideEffects' => false], 'Transliterator::createInverse' => ['hasSideEffects' => false], diff --git a/src/Analyser/ArgumentsNormalizer.php b/src/Analyser/ArgumentsNormalizer.php index 6baa6e0c6b..0b68559b42 100644 --- a/src/Analyser/ArgumentsNormalizer.php +++ b/src/Analyser/ArgumentsNormalizer.php @@ -11,6 +11,7 @@ use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\Constant\ConstantArrayType; use function array_key_exists; use function array_keys; @@ -27,7 +28,7 @@ final class ArgumentsNormalizer public const ORIGINAL_ARG_ATTRIBUTE = 'originalArg'; /** - * @return array{ParametersAcceptor, FuncCall, bool}|null + * @return array{ParametersAcceptor, FuncCall, TrinaryLogic}|null */ public static function reorderCallUserFuncArguments( FuncCall $callUserFuncCall, @@ -73,9 +74,9 @@ public static function reorderCallUserFuncArguments( null, ); - $acceptsNamedArguments = true; + $acceptsNamedArguments = TrinaryLogic::createYes(); foreach ($callableParametersAcceptors as $callableParametersAcceptor) { - $acceptsNamedArguments = $acceptsNamedArguments && $callableParametersAcceptor->acceptsNamedArguments(); + $acceptsNamedArguments = $acceptsNamedArguments->and($callableParametersAcceptor->acceptsNamedArguments()); } return [$parametersAcceptor, new FuncCall( diff --git a/src/Analyser/ConstantResolver.php b/src/Analyser/ConstantResolver.php index b209533fac..846188b985 100644 --- a/src/Analyser/ConstantResolver.php +++ b/src/Analyser/ConstantResolver.php @@ -3,9 +3,12 @@ namespace PHPStan\Analyser; use PhpParser\Node\Name; +use PHPStan\Php\ComposerPhpVersionFactory; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\NamespaceAnswerer; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\ReflectionProvider\ReflectionProviderProvider; +use PHPStan\ShouldNotHappenException; use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\Constant\ConstantIntegerType; @@ -20,6 +23,9 @@ use PHPStan\Type\UnionType; use function array_key_exists; use function in_array; +use function is_array; +use function is_int; +use function max; use function sprintf; use const INF; use const NAN; @@ -33,8 +39,14 @@ final class ConstantResolver /** * @param string[] $dynamicConstantNames + * @param int|array{min: int, max: int}|null $phpVersion */ - public function __construct(private ReflectionProviderProvider $reflectionProviderProvider, private array $dynamicConstantNames) + public function __construct( + private ReflectionProviderProvider $reflectionProviderProvider, + private array $dynamicConstantNames, + private int|array|null $phpVersion, + private ComposerPhpVersionFactory $composerPhpVersionFactory, + ) { } @@ -76,17 +88,69 @@ public function resolvePredefinedConstant(string $resolvedConstantName): ?Type new AccessoryNonFalsyStringType(), ]); } + + $minPhpVersion = null; + $maxPhpVersion = null; + if (in_array($resolvedConstantName, ['PHP_VERSION_ID', 'PHP_MAJOR_VERSION', 'PHP_MINOR_VERSION', 'PHP_RELEASE_VERSION'], true)) { + $minPhpVersion = $this->getMinPhpVersion(); + $maxPhpVersion = $this->getMaxPhpVersion(); + } + if ($resolvedConstantName === 'PHP_MAJOR_VERSION') { - return IntegerRangeType::fromInterval(5, null); + $minMajor = 5; + $maxMajor = null; + + if ($minPhpVersion !== null) { + $minMajor = max($minMajor, $minPhpVersion->getMajorVersionId()); + } + if ($maxPhpVersion !== null) { + $maxMajor = $maxPhpVersion->getMajorVersionId(); + } + + return $this->createInteger($minMajor, $maxMajor); } if ($resolvedConstantName === 'PHP_MINOR_VERSION') { - return IntegerRangeType::fromInterval(0, null); + $minMinor = 0; + $maxMinor = null; + + if ( + $minPhpVersion !== null + && $maxPhpVersion !== null + && $maxPhpVersion->getMajorVersionId() === $minPhpVersion->getMajorVersionId() + ) { + $minMinor = $minPhpVersion->getMinorVersionId(); + $maxMinor = $maxPhpVersion->getMinorVersionId(); + } + + return $this->createInteger($minMinor, $maxMinor); } if ($resolvedConstantName === 'PHP_RELEASE_VERSION') { - return IntegerRangeType::fromInterval(0, null); + $minRelease = 0; + $maxRelease = null; + + if ( + $minPhpVersion !== null + && $maxPhpVersion !== null + && $maxPhpVersion->getMajorVersionId() === $minPhpVersion->getMajorVersionId() + && $maxPhpVersion->getMinorVersionId() === $minPhpVersion->getMinorVersionId() + ) { + $minRelease = $minPhpVersion->getPatchVersionId(); + $maxRelease = $maxPhpVersion->getPatchVersionId(); + } + + return $this->createInteger($minRelease, $maxRelease); } if ($resolvedConstantName === 'PHP_VERSION_ID') { - return IntegerRangeType::fromInterval(50207, null); + $minVersion = 50207; + $maxVersion = null; + if ($minPhpVersion !== null) { + $minVersion = max($minVersion, $minPhpVersion->getVersionId()); + } + if ($maxPhpVersion !== null) { + $maxVersion = $maxPhpVersion->getVersionId(); + } + + return $this->createInteger($minVersion, $maxVersion); } if ($resolvedConstantName === 'PHP_ZTS') { return new UnionType([ @@ -300,6 +364,40 @@ public function resolvePredefinedConstant(string $resolvedConstantName): ?Type return null; } + private function getMinPhpVersion(): ?PhpVersion + { + if (is_int($this->phpVersion)) { + return null; + } + + if (is_array($this->phpVersion)) { + if ($this->phpVersion['max'] < $this->phpVersion['min']) { + throw new ShouldNotHappenException('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.'); + } + + return new PhpVersion($this->phpVersion['min']); + } + + return $this->composerPhpVersionFactory->getMinVersion(); + } + + private function getMaxPhpVersion(): ?PhpVersion + { + if (is_int($this->phpVersion)) { + return null; + } + + if (is_array($this->phpVersion)) { + if ($this->phpVersion['max'] < $this->phpVersion['min']) { + throw new ShouldNotHappenException('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.'); + } + + return new PhpVersion($this->phpVersion['max']); + } + + return $this->composerPhpVersionFactory->getMaxVersion(); + } + public function resolveConstantType(string $constantName, Type $constantType): Type { if ($constantType->isConstantValue()->yes() && in_array($constantName, $this->dynamicConstantNames, true)) { @@ -325,6 +423,14 @@ public function resolveClassConstantType(string $className, string $constantName return $constantType; } + private function createInteger(?int $min, ?int $max): Type + { + if ($min !== null && $min === $max) { + return new ConstantIntegerType($min); + } + return IntegerRangeType::fromInterval($min, $max); + } + private function getReflectionProvider(): ReflectionProvider { return $this->reflectionProviderProvider->getReflectionProvider(); diff --git a/src/Analyser/ConstantResolverFactory.php b/src/Analyser/ConstantResolverFactory.php index 67a98408a0..5ccc516e42 100644 --- a/src/Analyser/ConstantResolverFactory.php +++ b/src/Analyser/ConstantResolverFactory.php @@ -3,6 +3,7 @@ namespace PHPStan\Analyser; use PHPStan\DependencyInjection\Container; +use PHPStan\Php\ComposerPhpVersionFactory; use PHPStan\Reflection\ReflectionProvider\ReflectionProviderProvider; final class ConstantResolverFactory @@ -17,9 +18,13 @@ public function __construct( public function create(): ConstantResolver { + $composerFactory = $this->container->getByType(ComposerPhpVersionFactory::class); + return new ConstantResolver( $this->reflectionProviderProvider, $this->container->getParameter('dynamicConstantNames'), + $this->container->getParameter('phpVersion'), + $composerFactory, ); } diff --git a/src/Analyser/DirectInternalScopeFactory.php b/src/Analyser/DirectInternalScopeFactory.php index cbec53d0d1..74b43d80c9 100644 --- a/src/Analyser/DirectInternalScopeFactory.php +++ b/src/Analyser/DirectInternalScopeFactory.php @@ -12,19 +12,17 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; +use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Properties\PropertyReflectionFinder; -use PHPStan\ShouldNotHappenException; -use function is_a; final class DirectInternalScopeFactory implements InternalScopeFactory { /** - * @param class-string $scopeClass + * @param int|array{min: int, max: int}|null $configPhpVersion */ public function __construct( - private string $scopeClass, private ReflectionProvider $reflectionProvider, private InitializerExprTypeResolver $initializerExprTypeResolver, private DynamicReturnTypeExtensionRegistryProvider $dynamicReturnTypeExtensionRegistryProvider, @@ -36,8 +34,7 @@ public function __construct( private NodeScopeResolver $nodeScopeResolver, private RicherScopeGetTypeHelper $richerScopeGetTypeHelper, private PhpVersion $phpVersion, - private bool $explicitMixedInUnknownGenericNew, - private bool $explicitMixedForGlobalVariables, + private int|array|null $configPhpVersion, private ConstantResolver $constantResolver, ) { @@ -54,7 +51,7 @@ public function __construct( public function create( ScopeContext $context, bool $declareStrictTypes = false, - FunctionReflection|MethodReflection|null $function = null, + PhpFunctionFromParserNodeReflection|null $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], @@ -70,12 +67,7 @@ public function create( bool $nativeTypesPromoted = false, ): MutatingScope { - $scopeClass = $this->scopeClass; - if (!is_a($scopeClass, MutatingScope::class, true)) { - throw new ShouldNotHappenException(); - } - - return new $scopeClass( + return new MutatingScope( $this, $this->reflectionProvider, $this->initializerExprTypeResolver, @@ -90,6 +82,7 @@ public function create( $this->constantResolver, $context, $this->phpVersion, + $this->configPhpVersion, $declareStrictTypes, $function, $namespace, @@ -105,8 +98,6 @@ public function create( $afterExtractCall, $parentScope, $nativeTypesPromoted, - $this->explicitMixedInUnknownGenericNew, - $this->explicitMixedForGlobalVariables, ); } diff --git a/src/Analyser/Error.php b/src/Analyser/Error.php index d92f983a3e..1ad85c60be 100644 --- a/src/Analyser/Error.php +++ b/src/Analyser/Error.php @@ -14,9 +14,8 @@ /** * @api - * @final */ -class Error implements JsonSerializable +final class Error implements JsonSerializable { public const PATTERN_IDENTIFIER = '[a-zA-Z0-9](?:[a-zA-Z0-9\\.]*[a-zA-Z0-9])?'; diff --git a/src/Analyser/FileAnalyser.php b/src/Analyser/FileAnalyser.php index 8d8cf59016..570c637092 100644 --- a/src/Analyser/FileAnalyser.php +++ b/src/Analyser/FileAnalyser.php @@ -31,6 +31,7 @@ use const E_NOTICE; use const E_PARSE; use const E_STRICT; +use const E_USER_DEPRECATED; use const E_USER_ERROR; use const E_USER_NOTICE; use const E_USER_WARNING; @@ -322,7 +323,7 @@ private function collectErrors(array $analysedFiles): void $errorMessage = sprintf('%s: %s', $this->getErrorLabel($errno), $errstr); - $this->allPhpErrors[] = (new Error($errorMessage, $errfile, $errline, true))->withIdentifier('phpstan.php'); + $this->allPhpErrors[] = (new Error($errorMessage, $errfile, $errline, false))->withIdentifier('phpstan.php'); if ($errno === E_DEPRECATED) { return true; @@ -332,7 +333,7 @@ private function collectErrors(array $analysedFiles): void return true; } - $this->filteredPhpErrors[] = (new Error($errorMessage, $errfile, $errline, true))->withIdentifier('phpstan.php'); + $this->filteredPhpErrors[] = (new Error($errorMessage, $errfile, $errline, $errno === E_USER_DEPRECATED))->withIdentifier('phpstan.php'); return true; }); @@ -354,12 +355,16 @@ private function getErrorLabel(int $errno): string return 'Parse error'; case E_NOTICE: return 'Notice'; + case E_DEPRECATED: + return 'Deprecated'; case E_USER_ERROR: return 'User error (E_USER_ERROR)'; case E_USER_WARNING: return 'User warning (E_USER_WARNING)'; case E_USER_NOTICE: return 'User notice (E_USER_NOTICE)'; + case E_USER_DEPRECATED: + return 'Deprecated (E_USER_DEPRECATED)'; case E_STRICT: return 'Strict error (E_STRICT)'; } diff --git a/src/Analyser/Ignore/IgnoredError.php b/src/Analyser/Ignore/IgnoredError.php index e714c93f79..b420ae29ce 100644 --- a/src/Analyser/Ignore/IgnoredError.php +++ b/src/Analyser/Ignore/IgnoredError.php @@ -4,7 +4,6 @@ use Nette\Utils\Strings; use PHPStan\Analyser\Error; -use PHPStan\DependencyInjection\BleedingEdgeToggle; use PHPStan\File\FileExcluder; use PHPStan\File\FileHelper; use PHPStan\ShouldNotHappenException; @@ -86,7 +85,7 @@ public static function shouldIgnore( } if ($path !== null) { - $fileExcluder = new FileExcluder($fileHelper, [$path], BleedingEdgeToggle::isBleedingEdge()); + $fileExcluder = new FileExcluder($fileHelper, [$path]); $isExcluded = $fileExcluder->isExcludedFromAnalysing($error->getFilePath()); if (!$isExcluded && $error->getTraitFilePath() !== null) { return $fileExcluder->isExcludedFromAnalysing($error->getTraitFilePath()); diff --git a/src/Analyser/ImpurePoint.php b/src/Analyser/ImpurePoint.php index d4dc6fe133..20335325a7 100644 --- a/src/Analyser/ImpurePoint.php +++ b/src/Analyser/ImpurePoint.php @@ -8,9 +8,8 @@ /** * @phpstan-type ImpurePointIdentifier = 'echo'|'die'|'exit'|'propertyAssign'|'propertyAssignByRef'|'propertyUnset'|'methodCall'|'new'|'functionCall'|'include'|'require'|'print'|'eval'|'superglobal'|'yield'|'yieldFrom'|'static'|'global'|'betweenPhpTags' * @api - * @final */ -class ImpurePoint +final class ImpurePoint { /** diff --git a/src/Analyser/InternalError.php b/src/Analyser/InternalError.php index d778e89462..371b64cdc3 100644 --- a/src/Analyser/InternalError.php +++ b/src/Analyser/InternalError.php @@ -10,10 +10,9 @@ /** * @api - * @final * @phpstan-type Trace = list */ -class InternalError implements JsonSerializable +final class InternalError implements JsonSerializable { public const STACK_TRACE_METADATA_KEY = 'stackTrace'; diff --git a/src/Analyser/InternalScopeFactory.php b/src/Analyser/InternalScopeFactory.php index fdacebc9ec..6d8608ec18 100644 --- a/src/Analyser/InternalScopeFactory.php +++ b/src/Analyser/InternalScopeFactory.php @@ -6,6 +6,7 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; +use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection; interface InternalScopeFactory { @@ -22,7 +23,7 @@ interface InternalScopeFactory public function create( ScopeContext $context, bool $declareStrictTypes = false, - FunctionReflection|MethodReflection|null $function = null, + PhpFunctionFromParserNodeReflection|null $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], diff --git a/src/Analyser/LazyInternalScopeFactory.php b/src/Analyser/LazyInternalScopeFactory.php index 1e2e938678..ac5b757991 100644 --- a/src/Analyser/LazyInternalScopeFactory.php +++ b/src/Analyser/LazyInternalScopeFactory.php @@ -12,28 +12,17 @@ use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; +use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Properties\PropertyReflectionFinder; -use PHPStan\ShouldNotHappenException; -use function is_a; final class LazyInternalScopeFactory implements InternalScopeFactory { - private bool $explicitMixedInUnknownGenericNew; - - private bool $explicitMixedForGlobalVariables; - - /** - * @param class-string $scopeClass - */ public function __construct( - private string $scopeClass, private Container $container, ) { - $this->explicitMixedInUnknownGenericNew = $this->container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew']; - $this->explicitMixedForGlobalVariables = $this->container->getParameter('featureToggles')['explicitMixedForGlobalVariables']; } /** @@ -47,7 +36,7 @@ public function __construct( public function create( ScopeContext $context, bool $declareStrictTypes = false, - FunctionReflection|MethodReflection|null $function = null, + PhpFunctionFromParserNodeReflection|null $function = null, ?string $namespace = null, array $expressionTypes = [], array $nativeExpressionTypes = [], @@ -63,12 +52,7 @@ public function create( bool $nativeTypesPromoted = false, ): MutatingScope { - $scopeClass = $this->scopeClass; - if (!is_a($scopeClass, MutatingScope::class, true)) { - throw new ShouldNotHappenException(); - } - - return new $scopeClass( + return new MutatingScope( $this, $this->container->getByType(ReflectionProvider::class), $this->container->getByType(InitializerExprTypeResolver::class), @@ -83,6 +67,7 @@ public function create( $this->container->getByType(ConstantResolver::class), $context, $this->container->getByType(PhpVersion::class), + $this->container->getParameter('phpVersion'), $declareStrictTypes, $function, $namespace, @@ -98,8 +83,6 @@ public function create( $afterExtractCall, $parentScope, $nativeTypesPromoted, - $this->explicitMixedInUnknownGenericNew, - $this->explicitMixedForGlobalVariables, ); } diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 52ae676397..e6e9dc15ab 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -21,11 +21,9 @@ 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; use PHPStan\Node\ExecutionEndNode; @@ -49,16 +47,18 @@ use PHPStan\Parser\NewAssignedToPropertyVisitor; use PHPStan\Parser\Parser; use PHPStan\Php\PhpVersion; +use PHPStan\Php\PhpVersions; use PHPStan\PhpDoc\Tag\TemplateTag; use PHPStan\Reflection\Assertions; use PHPStan\Reflection\Callables\CallableParametersAcceptor; use PHPStan\Reflection\Callables\SimpleImpurePoint; use PHPStan\Reflection\Callables\SimpleThrowPoint; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\Dummy\DummyConstructorReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\InitializerExprContext; @@ -68,7 +68,6 @@ use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ParametersAcceptorSelector; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\PassedByReference; use PHPStan\Reflection\Php\DummyParameter; use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection; @@ -145,6 +144,7 @@ use function get_class; use function implode; use function in_array; +use function is_array; use function is_bool; use function is_numeric; use function is_string; @@ -185,6 +185,7 @@ final class MutatingScope implements Scope private static int $resolveClosureTypeDepth = 0; /** + * @param int|array{min: int, max: int}|null $configPhpVersion * @param array $expressionTypes * @param array $conditionalExpressions * @param list $inClosureBindScopeClasses @@ -208,6 +209,7 @@ public function __construct( private ConstantResolver $constantResolver, private ScopeContext $context, private PhpVersion $phpVersion, + private int|array|null $configPhpVersion, private bool $declareStrictTypes = false, private PhpFunctionFromParserNodeReflection|null $function = null, ?string $namespace = null, @@ -223,8 +225,6 @@ public function __construct( private bool $afterExtractCall = false, private ?Scope $parentScope = null, private bool $nativeTypesPromoted = false, - private bool $explicitMixedInUnknownGenericNew = false, - private bool $explicitMixedForGlobalVariables = false, ) { if ($namespace === '') { @@ -528,10 +528,11 @@ public function getVariableType(string $variableName): Type return IntegerRangeType::fromInterval(1, null); } if ($variableName === 'argv') { - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + return TypeCombinator::intersect( new ArrayType(new IntegerType(), new StringType()), new NonEmptyArrayType(), - )); + new AccessoryArrayListType(), + ); } if ($this->canAnyVariableExist()) { return new MixedType(); @@ -539,7 +540,7 @@ public function getVariableType(string $variableName): Type } if ($this->isGlobalVariable($variableName)) { - return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType($this->explicitMixedForGlobalVariables)); + return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true)); } if ($this->hasVariableType($variableName)->no()) { @@ -556,7 +557,7 @@ public function getVariableType(string $variableName): Type /** * @api - * @return array + * @return list */ public function getDefinedVariables(): array { @@ -577,7 +578,7 @@ public function getDefinedVariables(): array /** * @api - * @return array + * @return list */ public function getMaybeDefinedVariables(): array { @@ -609,12 +610,7 @@ public function hasConstant(Name $name): bool return $this->fileHasCompilerHaltStatementCalls(); } - if (!$name->isFullyQualified() && $this->getNamespace() !== null) { - if ($this->hasExpressionType(new ConstFetch(new FullyQualified([$this->getNamespace(), $name->toString()])))->yes()) { - return true; - } - } - if ($this->hasExpressionType(new ConstFetch(new FullyQualified($name->toString())))->yes()) { + if ($this->getGlobalConstantType($name) !== null) { return true; } @@ -772,19 +768,19 @@ private function resolveType(string $exprString, Expr $node): Type } if ($node instanceof Expr\BinaryOp\Smaller) { - return $this->getType($node->left)->isSmallerThan($this->getType($node->right))->toBooleanType(); + return $this->getType($node->left)->isSmallerThan($this->getType($node->right), $this->phpVersion)->toBooleanType(); } if ($node instanceof Expr\BinaryOp\SmallerOrEqual) { - return $this->getType($node->left)->isSmallerThanOrEqual($this->getType($node->right))->toBooleanType(); + return $this->getType($node->left)->isSmallerThanOrEqual($this->getType($node->right), $this->phpVersion)->toBooleanType(); } if ($node instanceof Expr\BinaryOp\Greater) { - return $this->getType($node->right)->isSmallerThan($this->getType($node->left))->toBooleanType(); + return $this->getType($node->right)->isSmallerThan($this->getType($node->left), $this->phpVersion)->toBooleanType(); } if ($node instanceof Expr\BinaryOp\GreaterOrEqual) { - return $this->getType($node->right)->isSmallerThanOrEqual($this->getType($node->left))->toBooleanType(); + return $this->getType($node->right)->isSmallerThanOrEqual($this->getType($node->left), $this->phpVersion)->toBooleanType(); } if ($node instanceof Expr\BinaryOp\Equal) { @@ -1112,20 +1108,20 @@ 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)); - } 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)->toString(); + } if ($resultType === null) { $resultType = $partType; - continue; } @@ -1133,7 +1129,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) { @@ -1345,7 +1341,8 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu $cachedClosureData['impurePoints'], $cachedClosureData['invalidateExpressions'], $cachedClosureData['usedVariables'], - true, + TrinaryLogic::createYes(), + TrinaryLogic::createNo(), ); } if (self::$resolveClosureTypeDepth >= 2) { @@ -1560,7 +1557,8 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu $impurePointsForClosureType, $invalidateExpressions, $usedVariables, - true, + TrinaryLogic::createYes(), + TrinaryLogic::createNo(), ); } elseif ($node instanceof New_) { if ($node->class instanceof Name) { @@ -1691,10 +1689,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) { @@ -1821,7 +1819,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'), @@ -2491,7 +2489,7 @@ private function createFirstClassCallable( foreach ($variants as $variant) { $returnType = $variant->getReturnType(); - if ($variant instanceof ParametersAcceptorWithPhpDocs) { + if ($variant instanceof ExtendedParametersAcceptor) { $returnType = $this->nativeTypesPromoted ? $variant->getNativeReturnType() : $returnType; } @@ -2510,7 +2508,7 @@ private function createFirstClassCallable( $throwPoints = []; $impurePoints = []; - $acceptsNamedArguments = true; + $acceptsNamedArguments = TrinaryLogic::createYes(); if ($variant instanceof CallableParametersAcceptor) { $throwPoints = $variant->getThrowPoints(); $impurePoints = $variant->getImpurePoints(); @@ -2549,13 +2547,14 @@ private function createFirstClassCallable( $variant->isVariadic(), $variant->getTemplateTypeMap(), $variant->getResolvedTemplateTypeMap(), - $variant instanceof ParametersAcceptorWithPhpDocs ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $variant instanceof ExtendedParametersAcceptor ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), $templateTags, $throwPoints, $impurePoints, [], [], $acceptsNamedArguments, + $variant->isDeprecated(), ); } @@ -2576,10 +2575,6 @@ public function getKeepVoidType(Expr $node): Type return $this->getType($clonedNode); } - /** - * @api - * @deprecated Use getNativeType() - */ public function doNotTreatPhpDocTypesAsCertain(): Scope { return $this->promoteNativeTypes(); @@ -2632,8 +2627,7 @@ public function hasPropertyNativeType($propertyFetch): bool return !$propertyReflection->getNativeType() instanceof MixedType; } - /** @api */ - protected function getTypeFromArrayDimFetch( + private function getTypeFromArrayDimFetch( Expr\ArrayDimFetch $arrayDimFetch, Type $offsetType, Type $offsetAccessibleType, @@ -2770,15 +2764,6 @@ public function getTypeFromValue($value): Type return ConstantTypeHelper::getTypeFromValue($value); } - /** - * @api - * @deprecated use hasExpressionType instead - */ - public function isSpecified(Expr $node): bool - { - return !$node instanceof Variable && $this->hasExpressionType($node)->yes(); - } - /** @api */ public function hasExpressionType(Expr $node): TrinaryLogic { @@ -3078,7 +3063,6 @@ public function enterFunction( ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, - bool $isFinal, ?bool $isPure = null, bool $acceptsNamedArguments = true, ?Assertions $asserts = null, @@ -3102,7 +3086,6 @@ public function enterFunction( $deprecatedDescription, $isDeprecated, $isInternal, - $isFinal, $isPure, $acceptsNamedArguments, $asserts ?? Assertions::createEmpty(), @@ -3154,10 +3137,10 @@ private function enterFunctionLike( $paramExprString = '$' . $parameter->getName(); if ($parameter->isVariadic()) { - if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()) { + if (!$this->getPhpVersion()->supportsNamedArguments()->no() && $functionReflection->acceptsNamedArguments()->yes()) { $parameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $parameterType); } else { - $parameterType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $parameterType)); + $parameterType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $parameterType), new AccessoryArrayListType()); } } $parameterNode = new Variable($parameter->getName()); @@ -3169,10 +3152,10 @@ private function enterFunctionLike( $nativeParameterType = $parameter->getNativeType(); if ($parameter->isVariadic()) { - if ($this->phpVersion->supportsNamedArguments() && $functionReflection->acceptsNamedArguments()) { + if (!$this->getPhpVersion()->supportsNamedArguments()->no() && $functionReflection->acceptsNamedArguments()->yes()) { $nativeParameterType = new ArrayType(new UnionType([new IntegerType(), new StringType()]), $nativeParameterType); } else { - $nativeParameterType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $nativeParameterType)); + $nativeParameterType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $nativeParameterType), new AccessoryArrayListType()); } } $nativeExpressionTypes[$paramExprString] = ExpressionTypeHolder::createYes($parameterNode, $nativeParameterType); @@ -3358,7 +3341,7 @@ public function isInClosureBind(): bool */ public function enterAnonymousFunction( Expr\Closure $closure, - ?array $callableParameters = null, + ?array $callableParameters, ): self { $anonymousFunctionReflection = $this->getType($closure); @@ -3393,7 +3376,7 @@ public function enterAnonymousFunction( */ private function enterAnonymousFunctionWithoutReflection( Expr\Closure $closure, - ?array $callableParameters = null, + ?array $callableParameters, ): self { $expressionTypes = []; @@ -3459,9 +3442,6 @@ private function enterAnonymousFunctionWithoutReflection( continue; } foreach ($variables as $variable) { - if (!$variable instanceof Variable) { - continue 2; - } if (!is_string($variable->name)) { continue 2; } @@ -3538,7 +3518,7 @@ private function invalidateStaticExpressions(array $expressionTypes): array * @api * @param ParameterReflection[]|null $callableParameters */ - public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $callableParameters = null): self + public function enterArrowFunction(Expr\ArrowFunction $arrowFunction, ?array $callableParameters): self { $anonymousFunctionReflection = $this->getType($arrowFunction); if (!$anonymousFunctionReflection instanceof ClosureType) { @@ -3599,7 +3579,7 @@ private function enterArrowFunctionWithoutReflection(Expr\ArrowFunction $arrowFu if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { throw new ShouldNotHappenException(); } - $arrowFunctionScope = $arrowFunctionScope->assignVariable($parameter->var->name, $parameterType, $parameterType); + $arrowFunctionScope = $arrowFunctionScope->assignVariable($parameter->var->name, $parameterType, $parameterType, TrinaryLogic::createYes()); } if ($arrowFunction->static) { @@ -3647,7 +3627,7 @@ public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type ); } if ($isVariadic) { - if ($this->phpVersion->supportsNamedArguments()) { + if (!$this->getPhpVersion()->supportsNamedArguments()->no()) { return new ArrayType(new UnionType([new IntegerType(), new StringType()]), $this->getFunctionType( $type, false, @@ -3655,11 +3635,11 @@ public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type )); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $this->getFunctionType( + return TypeCombinator::intersect(new ArrayType(new IntegerType(), $this->getFunctionType( $type, false, false, - ))); + )), new AccessoryArrayListType()); } if ($type instanceof Name) { @@ -3718,6 +3698,7 @@ public function enterForeach(self $originalScope, Expr $iteratee, string $valueN $valueName, $originalScope->getIterableValueType($iterateeType), $originalScope->getIterableValueType($nativeIterateeType), + TrinaryLogic::createYes(), ); if ($keyName !== null) { $scope = $scope->enterForeachKey($originalScope, $iteratee, $keyName); @@ -3734,6 +3715,7 @@ public function enterForeachKey(self $originalScope, Expr $iteratee, string $key $keyName, $originalScope->getIterableKeyType($iterateeType), $originalScope->getIterableKeyType($nativeIterateeType), + TrinaryLogic::createYes(), ); if ($iterateeType->isArray()->yes()) { @@ -3747,17 +3729,6 @@ public function enterForeachKey(self $originalScope, Expr $iteratee, string $key return $scope; } - /** - * @deprecated Use enterCatchType - * @param Node\Name[] $classes - */ - public function enterCatch(array $classes, ?string $variableName): self - { - $type = TypeCombinator::union(...array_map(static fn (Node\Name $class): ObjectType => new ObjectType((string) $class), $classes)); - - return $this->enterCatchType($type, $variableName); - } - public function enterCatchType(Type $catchType, ?string $variableName): self { if ($variableName === null) { @@ -3768,6 +3739,7 @@ public function enterCatchType(Type $catchType, ?string $variableName): self $variableName, TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)), TypeCombinator::intersect($catchType, new ObjectType(Throwable::class)), + TrinaryLogic::createYes(), ); } @@ -3842,7 +3814,7 @@ public function isInExpressionAssign(Expr $expr): bool public function setAllowedUndefinedExpression(Expr $expr): self { - if ($this->phpVersion->deprecatesDynamicProperties() && $expr instanceof Expr\StaticPropertyFetch) { + if ($expr instanceof Expr\StaticPropertyFetch) { return $this; } @@ -3913,18 +3885,16 @@ public function isUndefinedExpressionAllowed(Expr $expr): bool return array_key_exists($exprString, $this->currentlyAllowedUndefinedExpressions); } - public function assignVariable(string $variableName, Type $type, Type $nativeType, ?TrinaryLogic $certainty = null): self + public function assignVariable(string $variableName, Type $type, Type $nativeType, TrinaryLogic $certainty): self { $node = new Variable($variableName); $scope = $this->assignExpression($node, $type, $nativeType); - if ($certainty !== null) { - if ($certainty->no()) { - throw new ShouldNotHappenException(); - } elseif (!$certainty->yes()) { - $exprString = '$' . $variableName; - $scope->expressionTypes[$exprString] = new ExpressionTypeHolder($node, $type, $certainty); - $scope->nativeExpressionTypes[$exprString] = new ExpressionTypeHolder($node, $nativeType, $certainty); - } + if ($certainty->no()) { + throw new ShouldNotHappenException(); + } elseif (!$certainty->yes()) { + $exprString = '$' . $variableName; + $scope->expressionTypes[$exprString] = new ExpressionTypeHolder($node, $type, $certainty); + $scope->nativeExpressionTypes[$exprString] = new ExpressionTypeHolder($node, $nativeType, $certainty); } $parameterOriginalValueExprString = $this->getNodeKey(new ParameterVariableOriginalValueExpr($variableName)); @@ -3972,7 +3942,7 @@ public function unsetExpression(Expr $expr): self return $scope->invalidateExpression($expr); } - public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, ?TrinaryLogic $certainty = null): self + public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, TrinaryLogic $certainty): self { if ($expr instanceof ConstFetch) { $loweredConstName = strtolower($expr->name->toString()); @@ -4020,9 +3990,7 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, } } - if ($certainty === null) { - $certainty = TrinaryLogic::createYes(); - } elseif ($certainty->no()) { + if ($certainty->no()) { throw new ShouldNotHappenException(); } @@ -4058,11 +4026,8 @@ public function specifyExpressionType(Expr $expr, Type $type, Type $nativeType, return $scope; } - public function assignExpression(Expr $expr, Type $type, ?Type $nativeType = null): self + public function assignExpression(Expr $expr, Type $type, Type $nativeType): self { - if ($nativeType === null) { - $nativeType = new MixedType(); - } $scope = $this; if ($expr instanceof PropertyFetch) { $scope = $this->invalidateExpression($expr) @@ -4073,7 +4038,7 @@ public function assignExpression(Expr $expr, Type $type, ?Type $nativeType = nul $scope = $this->invalidateExpression($expr); } - return $scope->specifyExpressionType($expr, $type, $nativeType); + return $scope->specifyExpressionType($expr, $type, $nativeType, TrinaryLogic::createYes()); } public function assignInitializedProperty(Type $fetchedOnType, string $propertyName): self @@ -4277,13 +4242,14 @@ public function addTypeToExpression(Expr $expr, Type $type): self if ($originalExprType->equals($nativeType)) { $newType = TypeCombinator::intersect($type, $originalExprType); - return $this->specifyExpressionType($expr, $newType, $newType); + return $this->specifyExpressionType($expr, $newType, $newType, TrinaryLogic::createYes()); } return $this->specifyExpressionType( $expr, TypeCombinator::intersect($type, $originalExprType), TypeCombinator::intersect($type, $nativeType), + TrinaryLogic::createYes(), ); } @@ -4300,6 +4266,7 @@ public function removeTypeFromExpression(Expr $expr, Type $typeToRemove): self $expr, TypeCombinator::remove($exprType, $typeToRemove), TypeCombinator::remove($this->getNativeType($expr), $typeToRemove), + TrinaryLogic::createYes(), ); } @@ -4789,7 +4756,7 @@ private function processFinallyScopeVariableTypeHolders( } /** - * @param Expr\ClosureUse[] $byRefUses + * @param Node\ClosureUse[] $byRefUses */ public function processClosureScope( self $closureScope, @@ -5066,7 +5033,7 @@ private static function generalizeType(Type $a, Type $b, int $depth): Type $resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); } if ($constantArraysA->isList()->yes() && $constantArraysB->isList()->yes()) { - $resultType = AccessoryArrayListType::intersectWith($resultType); + $resultType = TypeCombinator::intersect($resultType, new AccessoryArrayListType()); } $resultTypes[] = $resultType; } @@ -5109,7 +5076,7 @@ private static function generalizeType(Type $a, Type $b, int $depth): Type $resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); } if ($generalArraysA->isList()->yes() && $generalArraysB->isList()->yes()) { - $resultType = AccessoryArrayListType::intersectWith($resultType); + $resultType = TypeCombinator::intersect($resultType, new AccessoryArrayListType()); } if ($generalArraysA->isOversizedArray()->yes() && $generalArraysB->isOversizedArray()->yes()) { $resultType = TypeCombinator::intersect($resultType, new OversizedArrayType()); @@ -5265,11 +5232,11 @@ private static function generalizeType(Type $a, Type $b, int $depth): Type private static function getArrayDepth(Type $type): int { $depth = 0; - $arrays = TypeUtils::getAnyArrays($type); + $arrays = TypeUtils::toBenevolentUnion($type)->getArrays(); while (count($arrays) > 0) { $temp = $type->getIterableValueType(); $type = $temp; - $arrays = TypeUtils::getAnyArrays($type); + $arrays = TypeUtils::toBenevolentUnion($type)->getArrays(); $depth++; } @@ -5347,7 +5314,7 @@ public function canCallMethod(MethodReflection $methodReflection): bool } /** @api */ - public function canAccessConstant(ConstantReflection $constantReflection): bool + public function canAccessConstant(ClassConstantReflection $constantReflection): bool { return $this->canAccessClassMember($constantReflection); } @@ -5539,54 +5506,22 @@ private function exactInstantiation(New_ $node, string $className): ?Type $constructorMethod->getNamedArgumentsVariants(), ); - if ($this->explicitMixedInUnknownGenericNew) { - $resolvedTemplateTypeMap = $parametersAcceptor->getResolvedTemplateTypeMap(); - return TypeTraverser::map(new GenericObjectType( - $resolvedClassName, - $classReflection->typeMapToList($classReflection->getTemplateTypeMap()), - ), static function (Type $type, callable $traverse) use ($resolvedTemplateTypeMap): Type { - if ($type instanceof TemplateType && !$type->isArgument()) { - $newType = $resolvedTemplateTypeMap->getType($type->getName()); - if ($newType === null || $newType instanceof ErrorType) { - return $type->getBound(); - } - - return TemplateTypeHelper::generalizeInferredTemplateType($type, $newType); + $resolvedTemplateTypeMap = $parametersAcceptor->getResolvedTemplateTypeMap(); + return TypeTraverser::map(new GenericObjectType( + $resolvedClassName, + $classReflection->typeMapToList($classReflection->getTemplateTypeMap()), + ), static function (Type $type, callable $traverse) use ($resolvedTemplateTypeMap): Type { + if ($type instanceof TemplateType && !$type->isArgument()) { + $newType = $resolvedTemplateTypeMap->getType($type->getName()); + if ($newType === null || $newType instanceof ErrorType) { + return $type->getDefault() ?? $type->getBound(); } - return $traverse($type); - }); - } - - $resolvedPhpDoc = $classReflection->getResolvedPhpDoc(); - if ($resolvedPhpDoc === null) { - return $objectType; - } - - $list = []; - $typeMap = $parametersAcceptor->getResolvedTemplateTypeMap(); - foreach ($resolvedPhpDoc->getTemplateTags() as $tag) { - $templateType = $typeMap->getType($tag->getName()); - if ($templateType !== null) { - $list[] = $templateType; - continue; - } - $default = $tag->getDefault(); - if ($default !== null) { - $list[] = $default; - continue; + return TemplateTypeHelper::generalizeInferredTemplateType($type, $newType); } - $bound = $tag->getBound(); - if ($bound instanceof MixedType && $bound->isExplicitMixed()) { - $bound = new MixedType(false); - } - $list[] = $bound; - } - return new GenericObjectType( - $resolvedClassName, - $list, - ); + return $traverse($type); + }); } private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): ?Type @@ -5613,7 +5548,6 @@ public function getMethodReflection(Type $typeWithMethod, string $methodName): ? return $type->getMethod($methodName, $this); } - /** @api */ public function getNakedMethod(Type $typeWithMethod, string $methodName): ?ExtendedMethodReflection { $type = $this->filterTypeWithMethod($typeWithMethod, $methodName); @@ -5722,7 +5656,7 @@ private function propertyFetchType(Type $fetchedOnType, string $propertyName, Ex return $propertyReflection->getReadableType(); } - public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ConstantReflection + public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ClassConstantReflection { if ($typeWithConstant instanceof UnionType) { $typeWithConstant = $typeWithConstant->filterTypes(static fn (Type $innerType) => $innerType->hasConstant($constantName)->yes()); @@ -5750,6 +5684,25 @@ private function getConstantTypes(): array return $constantTypes; } + private function getGlobalConstantType(Name $name): ?Type + { + $fetches = []; + if (!$name->isFullyQualified() && $this->getNamespace() !== null) { + $fetches[] = new ConstFetch(new FullyQualified([$this->getNamespace(), $name->toString()])); + } + + $fetches[] = new ConstFetch(new FullyQualified($name->toString())); + $fetches[] = new ConstFetch($name); + + foreach ($fetches as $constFetch) { + if ($this->hasExpressionType($constFetch)->yes()) { + return $this->getType($constFetch); + } + } + + return null; + } + /** * @return array */ @@ -5790,4 +5743,17 @@ public function getIterableValueType(Type $iteratee): Type return $iteratee->getIterableValueType(); } + public function getPhpVersion(): PhpVersions + { + $constType = $this->getGlobalConstantType(new Name('PHP_VERSION_ID')); + if ($constType !== null) { + return new PhpVersions($constType); + } + + if (is_array($this->configPhpVersion)) { + return new PhpVersions(IntegerRangeType::fromInterval($this->configPhpVersion['min'], $this->configPhpVersion['max'])); + } + return new PhpVersions(new ConstantIntegerType($this->phpVersion->getVersionId())); + } + } diff --git a/src/Analyser/NameScope.php b/src/Analyser/NameScope.php index fbc602329e..1426b804a1 100644 --- a/src/Analyser/NameScope.php +++ b/src/Analyser/NameScope.php @@ -18,9 +18,8 @@ /** * @api - * @final */ -class NameScope +final class NameScope { private TemplateTypeMap $templateTypeMap; @@ -223,21 +222,4 @@ public function hasTypeAlias(string $alias): bool return array_key_exists($alias, $this->typeAliasesMap); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self( - $properties['namespace'], - $properties['uses'], - $properties['className'], - $properties['functionName'], - $properties['templateTypeMap'], - $properties['typeAliasesMap'], - $properties['bypassTypeAliases'], - $properties['constUses'], - ); - } - } diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 5f518077a2..a70c0ca5ec 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_; @@ -132,16 +131,16 @@ use PHPStan\Reflection\Callables\SimpleThrowPoint; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\Native\NativeMethodReflection; use PHPStan\Reflection\Native\NativeParameterReflection; use PHPStan\Reflection\ParameterReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ParametersAcceptorSelector; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection; use PHPStan\Reflection\Php\PhpMethodFromParserNodeReflection; use PHPStan\Reflection\Php\PhpMethodReflection; @@ -172,6 +171,7 @@ use PHPStan\Type\NullType; use PHPStan\Type\ObjectType; use PHPStan\Type\ObjectWithoutClassType; +use PHPStan\Type\ParserNodeTypeToPHPStanType; use PHPStan\Type\ResourceType; use PHPStan\Type\StaticType; use PHPStan\Type\StaticTypeFactory; @@ -255,15 +255,12 @@ public function __construct( private readonly ScopeFactory $scopeFactory, private readonly bool $polluteScopeWithLoopInitialAssignments, private readonly bool $polluteScopeWithAlwaysIterableForeach, + private readonly bool $polluteScopeWithBlock, private readonly array $earlyTerminatingMethodCalls, private readonly array $earlyTerminatingFunctionCalls, private readonly array $universalObjectCratesClasses, private readonly bool $implicitThrows, private readonly bool $treatPhpDocTypesAsCertain, - private readonly bool $detectDeadTypeInMultiCatch, - private readonly bool $paramOutType, - private readonly bool $preciseMissingReturn, - private readonly bool $explicitThrow, ) { $earlyTerminatingMethodNames = []; @@ -330,12 +327,9 @@ public function processStmtNodes( array $stmts, MutatingScope $scope, callable $nodeCallback, - ?StatementContext $context = null, + StatementContext $context, ): StatementResult { - if ($context === null) { - $context = StatementContext::createTopLevel(); - } $exitPoints = []; $throwPoints = []; $impurePoints = []; @@ -365,7 +359,7 @@ public function processStmtNodes( $parentNode = $parentNode; $endStatements = $statementResult->getEndStatements(); - if ($this->preciseMissingReturn && count($endStatements) > 0) { + if (count($endStatements) > 0) { foreach ($endStatements as $endStatement) { $endStatementResult = $endStatement->getResult(); $nodeCallback(new ExecutionEndNode( @@ -446,7 +440,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_ ) { @@ -475,7 +468,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); } @@ -494,7 +490,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; @@ -519,7 +515,7 @@ private function processStmtNode( $throwPoints = []; $impurePoints = []; $this->processAttributeGroups($stmt, $stmt->attrGroups, $scope, $nodeCallback); - [$templateTypeMap, $phpDocParameterTypes, $phpDocImmediatelyInvokedCallableParameters, $phpDocClosureThisTypeParameters, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $acceptsNamedArguments, , $phpDocComment, $asserts,, $phpDocParameterOutTypes] = $this->getPhpDocs($scope, $stmt); + [$templateTypeMap, $phpDocParameterTypes, $phpDocImmediatelyInvokedCallableParameters, $phpDocClosureThisTypeParameters, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, , $isPure, $acceptsNamedArguments, , $phpDocComment, $asserts,, $phpDocParameterOutTypes] = $this->getPhpDocs($scope, $stmt); foreach ($stmt->params as $param) { $this->processParamNode($stmt, $param, $scope, $nodeCallback); @@ -538,7 +534,6 @@ private function processStmtNode( $deprecatedDescription, $isDeprecated, $isInternal, - $isFinal, $isPure, $acceptsNamedArguments, $asserts, @@ -655,7 +650,7 @@ private function processStmtNode( $nodeCallback(new ClassPropertyNode( $param->var->name, $param->flags, - $param->type, + $param->type !== null ? ParserNodeTypeToPHPStanType::resolve($param->type, $scope->getClassReflection()) : null, null, $phpDoc, $phpDocParameterTypes[$param->var->name] ?? null, @@ -791,6 +786,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; @@ -902,17 +900,19 @@ private function processStmtNode( } elseif (isset($varTags[$propertyName])) { $phpDocType = $varTags[$propertyName]->getType(); } + $propStmt = clone $stmt; + $propStmt->setAttributes($prop->getAttributes()); $nodeCallback( new ClassPropertyNode( $propertyName, $stmt->flags, - $stmt->type, + $stmt->type !== null ? ParserNodeTypeToPHPStanType::resolve($stmt->type, $scope->getClassReflection()) : null, $prop->default, $docComment, $phpDocType, false, false, - $prop, + $propStmt, $isReadOnly, $scope->isInTrait(), $scope->getClassReflection()->isReadOnly(), @@ -926,14 +926,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(); @@ -1522,7 +1514,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) { @@ -1576,8 +1568,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; @@ -1588,10 +1579,7 @@ private function processStmtNode( } // implicit only - if ( - count($matchingThrowPoints) === 0 - || ($this->explicitThrow && $onlyExplicitIsThrow) - ) { + if (count($matchingThrowPoints) === 0 || $onlyExplicitIsThrow) { foreach ($throwPoints as $throwPointIndex => $throwPoint) { if ($throwPoint->isExplicit()) { continue; @@ -1622,19 +1610,14 @@ private function processStmtNode( } // emit error - if ($this->detectDeadTypeInMultiCatch) { - foreach ($matchingCatchTypes as $catchTypeIndex => $matched) { - if ($matched) { - continue; - } - $nodeCallback(new CatchWithUnthrownExceptionNode($catchNode, $catchTypes[$catchTypeIndex], $originalCatchTypes[$catchTypeIndex]), $scope); + foreach ($matchingCatchTypes as $catchTypeIndex => $matched) { + if ($matched) { + continue; } + $nodeCallback(new CatchWithUnthrownExceptionNode($catchNode, $catchTypes[$catchTypeIndex], $originalCatchTypes[$catchTypeIndex]), $scope); } if (count($matchingThrowPoints) === 0) { - if (!$this->detectDeadTypeInMultiCatch) { - $nodeCallback(new CatchWithUnthrownExceptionNode($catchNode, $catchType, $originalCatchType), $scope); - } continue; } @@ -1684,7 +1667,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) { @@ -1712,7 +1695,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(); @@ -1829,7 +1812,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { continue; } - $scope = $scope->assignVariable($var->name, new MixedType(), new MixedType()); + $scope = $scope->assignVariable($var->name, new MixedType(), new MixedType(), TrinaryLogic::createYes()); $vars[] = $var->name; } $scope = $this->processVarAnnotation($scope, $vars, $stmt); @@ -1862,7 +1845,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void { $impurePoints = array_merge($impurePoints, $varResult->getImpurePoints()); $scope = $scope->exitExpressionAssign($var->var); - $scope = $scope->assignVariable($var->var->name, new MixedType(), new MixedType()); + $scope = $scope->assignVariable($var->var->name, new MixedType(), new MixedType(), TrinaryLogic::createYes()); $vars[] = $var->var->name; } @@ -1878,9 +1861,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)); @@ -1918,6 +1898,21 @@ 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) { + $result = $this->processStmtNodes($stmt, $stmt->stmts, $scope, $nodeCallback, $context); + if ($this->polluteScopeWithBlock) { + return $result; + } + + return new StatementResult( + $scope->mergeWith($result->getScope()), + $result->hasYield(), + $result->isAlwaysTerminating(), + $result->getExitPoints(), + $result->getThrowPoints(), + $result->getImpurePoints(), + $result->getEndStatements(), + ); } elseif ($stmt instanceof Node\Stmt\Nop) { $hasYield = false; $throwPoints = $overridingThrowPoints ?? []; @@ -2053,7 +2048,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; @@ -2099,6 +2094,7 @@ private function ensureShallowNonNullability(MutatingScope $scope, Scope $origin $exprToSpecify, $exprTypeWithoutNull, TypeCombinator::removeNull($nativeType), + TrinaryLogic::createYes(), ); return new EnsuredNonNullabilityResult( @@ -2465,7 +2461,7 @@ static function (): void { $functionReflection !== null && in_array($functionReflection->getName(), ['fopen', 'file_get_contents'], true) ) { - $scope = $scope->assignVariable('http_response_header', AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())), new ArrayType(new IntegerType(), new StringType())); + $scope = $scope->assignVariable('http_response_header', TypeCombinator::intersect(new ArrayType(new IntegerType(), new StringType()), new AccessoryArrayListType()), new ArrayType(new IntegerType(), new StringType()), TrinaryLogic::createYes()); } if ( @@ -2672,7 +2668,7 @@ static function (): void { TemplateTypeHelper::resolveTemplateTypes( $selfOutType, $parametersAcceptor->getResolvedTemplateTypeMap(), - $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $parametersAcceptor instanceof ExtendedParametersAcceptor ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createCovariant(), ), $scope->getNativeType($expr->var), @@ -2958,11 +2954,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()); @@ -2993,9 +2992,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()); @@ -3658,7 +3654,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'), @@ -3863,7 +3859,7 @@ static function (?Type $offsetType, Type $valueType, bool $optional) use (&$arra ? TypeCombinator::intersect($array, new NonEmptyArrayType()) : $array; $constantArray = $isList - ? AccessoryArrayListType::intersectWith($constantArray) + ? TypeCombinator::intersect($constantArray, new AccessoryArrayListType()) : $constantArray; } @@ -3902,11 +3898,11 @@ private function getArraySortPreserveListFunctionType(Type $type): Type return $traverse($type); } - if (!$type instanceof ArrayType) { + if (!$type instanceof ArrayType && !$type instanceof ConstantArrayType) { return $type; } - $newArrayType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $type->getIterableValueType())); + $newArrayType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $type->getIterableValueType()), new AccessoryArrayListType()); if ($isIterableAtLeastOnce->yes()) { $newArrayType = TypeCombinator::intersect($newArrayType, new NonEmptyArrayType()); } @@ -4141,7 +4137,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) { @@ -4237,7 +4233,7 @@ private function processClosureNode( $variableNativeType = TypeCombinator::union($scope->getVariableType($inAssignRightSideVariableName), $inAssignRightSideNativeType); } } - $scope = $scope->assignVariable($inAssignRightSideVariableName, $variableType, $variableNativeType); + $scope = $scope->assignVariable($inAssignRightSideVariableName, $variableType, $variableNativeType, TrinaryLogic::createYes()); } } $this->processExprNode($stmt, $use->var, $useScope, $nodeCallback, $context); @@ -4593,7 +4589,7 @@ private function processArgs( $assignByReference = $parameters[$i]->passedByReference()->createsNewVariable(); $parameterType = $parameters[$i]->getType(); - if ($parameters[$i] instanceof ParameterReflectionWithPhpDocs) { + if ($parameters[$i] instanceof ExtendedParameterReflection) { $parameterNativeType = $parameters[$i]->getNativeType(); } $parameter = $parameters[$i]; @@ -4602,7 +4598,7 @@ private function processArgs( $assignByReference = $lastParameter->passedByReference()->createsNewVariable(); $parameterType = $lastParameter->getType(); - if ($lastParameter instanceof ParameterReflectionWithPhpDocs) { + if ($lastParameter instanceof ExtendedParameterReflection) { $parameterNativeType = $lastParameter->getNativeType(); } $parameter = $lastParameter; @@ -4639,7 +4635,7 @@ private function processArgs( $scopeToPass = $closureBindScope; } - if ($parameter instanceof ParameterReflectionWithPhpDocs) { + if ($parameter instanceof ExtendedParameterReflection) { $parameterCallImmediately = $parameter->isImmediatelyInvokedCallable(); if ($parameterCallImmediately->maybe()) { $callCallbackImmediately = $calleeReflection instanceof FunctionReflection; @@ -4653,12 +4649,12 @@ private function processArgs( $restoreThisScope = null; if ( $closureBindScope === null - && $parameter instanceof ParameterReflectionWithPhpDocs + && $parameter instanceof ExtendedParameterReflection && $parameter->getClosureThisType() !== null && !$arg->value->static ) { $restoreThisScope = $scopeToPass; - $scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType()); + $scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType(), TrinaryLogic::createYes()); } if ($parameter !== null) { @@ -4706,11 +4702,11 @@ private function processArgs( } elseif ($arg->value instanceof Expr\ArrowFunction) { if ( $closureBindScope === null - && $parameter instanceof ParameterReflectionWithPhpDocs + && $parameter instanceof ExtendedParameterReflection && $parameter->getClosureThisType() !== null && !$arg->value->static ) { - $scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType()); + $scopeToPass = $scopeToPass->assignVariable('this', $parameter->getClosureThisType(), new ObjectWithoutClassType(), TrinaryLogic::createYes()); } if ($parameter !== null) { @@ -4782,18 +4778,16 @@ private function processArgs( if ($currentParameter !== null) { $assignByReference = $currentParameter->passedByReference()->createsNewVariable(); if ($assignByReference) { - if ($currentParameter instanceof ParameterReflectionWithPhpDocs && $currentParameter->getOutType() !== null) { + if ($currentParameter instanceof ExtendedParameterReflection && $currentParameter->getOutType() !== null) { $byRefType = $currentParameter->getOutType(); } elseif ( $calleeReflection instanceof MethodReflection && !$calleeReflection->getDeclaringClass()->isBuiltin() - && $this->paramOutType ) { $byRefType = $currentParameter->getType(); } elseif ( $calleeReflection instanceof FunctionReflection && !$calleeReflection->isBuiltin() - && $this->paramOutType ) { $byRefType = $currentParameter->getType(); } @@ -5016,7 +5010,7 @@ private function processAssignVar( $conditionalExpressions = $this->processSureNotTypesForConditionalExpressionsAfterAssign($scope, $var->name, $conditionalExpressions, $falseySpecifiedTypes, $falseyType); $nodeCallback(new VariableAssignNode($var, $assignedExpr, $isAssignOp), $result->getScope()); - $scope = $scope->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr)); + $scope = $scope->assignVariable($var->name, $type, $scope->getNativeType($assignedExpr), TrinaryLogic::createYes()); foreach ($conditionalExpressions as $exprString => $holders) { $scope = $scope->addConditionalExpressions($exprString, $holders); } @@ -5145,7 +5139,7 @@ private function processAssignVar( if ($varType->isArray()->yes() || !(new ObjectType(ArrayAccess::class))->isSuperTypeOf($varType)->yes()) { if ($var instanceof Variable && is_string($var->name)) { $nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope); - $scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite); + $scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite, TrinaryLogic::createYes()); } else { if ($var instanceof PropertyFetch || $var instanceof StaticPropertyFetch) { $nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope); @@ -5291,7 +5285,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()); @@ -5322,7 +5316,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; } @@ -5397,7 +5391,7 @@ static function (): void { if ($var instanceof Variable && is_string($var->name)) { $nodeCallback(new VariableAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope); - $scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite); + $scope = $scope->assignVariable($var->name, $valueToWrite, $nativeValueToWrite, TrinaryLogic::createYes()); } else { if ($var instanceof PropertyFetch || $var instanceof StaticPropertyFetch) { $nodeCallback(new PropertyAssignNode($var, $assignedPropertyExpr, $isAssignOp), $scope); @@ -5646,13 +5640,13 @@ private function processVarAnnotation(MutatingScope $scope, array $variableNames $variableType = $varTags[$variableName]->getType(); $changed = true; - $scope = $scope->assignVariable($variableName, $variableType, new MixedType()); + $scope = $scope->assignVariable($variableName, $variableType, new MixedType(), TrinaryLogic::createYes()); } if (count($variableNames) === 1 && count($varTags) === 1 && isset($varTags[0])) { $variableType = $varTags[0]->getType(); $changed = true; - $scope = $scope->assignVariable($variableNames[0], $variableType, new MixedType()); + $scope = $scope->assignVariable($variableNames[0], $variableType, new MixedType(), TrinaryLogic::createYes()); } return $scope; @@ -5838,7 +5832,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)) { @@ -5927,9 +5921,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()) { diff --git a/src/Analyser/OutOfClassScope.php b/src/Analyser/OutOfClassScope.php index 42a85108c9..925e35a50e 100644 --- a/src/Analyser/OutOfClassScope.php +++ b/src/Analyser/OutOfClassScope.php @@ -2,9 +2,9 @@ namespace PHPStan\Analyser; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\PropertyReflection; @@ -36,7 +36,7 @@ public function canCallMethod(MethodReflection $methodReflection): bool return $methodReflection->isPublic(); } - public function canAccessConstant(ConstantReflection $constantReflection): bool + public function canAccessConstant(ClassConstantReflection $constantReflection): bool { return $constantReflection->isPublic(); } diff --git a/src/Analyser/RuleErrorTransformer.php b/src/Analyser/RuleErrorTransformer.php index 0cb9f9ef98..b45ce15acd 100644 --- a/src/Analyser/RuleErrorTransformer.php +++ b/src/Analyser/RuleErrorTransformer.php @@ -10,7 +10,6 @@ use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; -use function is_string; final class RuleErrorTransformer { @@ -19,7 +18,7 @@ final class RuleErrorTransformer * @param class-string $nodeType */ public function transform( - string|RuleError $ruleError, + RuleError $ruleError, Scope $scope, string $nodeType, int $nodeLine, @@ -39,43 +38,40 @@ public function transform( $traitFilePath = $traitReflection->getFileName(); } } - if (is_string($ruleError)) { - $message = $ruleError; - } else { - $message = $ruleError->getMessage(); - if ( - $ruleError instanceof LineRuleError - && $ruleError->getLine() !== -1 - ) { - $line = $ruleError->getLine(); - } - if ( - $ruleError instanceof FileRuleError - && $ruleError->getFile() !== '' - ) { - $fileName = $ruleError->getFileDescription(); - $filePath = $ruleError->getFile(); - $traitFilePath = null; - } - if ($ruleError instanceof TipRuleError) { - $tip = $ruleError->getTip(); - } + if ( + $ruleError instanceof LineRuleError + && $ruleError->getLine() !== -1 + ) { + $line = $ruleError->getLine(); + } + if ( + $ruleError instanceof FileRuleError + && $ruleError->getFile() !== '' + ) { + $fileName = $ruleError->getFileDescription(); + $filePath = $ruleError->getFile(); + $traitFilePath = null; + } - if ($ruleError instanceof IdentifierRuleError) { - $identifier = $ruleError->getIdentifier(); - } + if ($ruleError instanceof TipRuleError) { + $tip = $ruleError->getTip(); + } - if ($ruleError instanceof MetadataRuleError) { - $metadata = $ruleError->getMetadata(); - } + if ($ruleError instanceof IdentifierRuleError) { + $identifier = $ruleError->getIdentifier(); + } - if ($ruleError instanceof NonIgnorableRuleError) { - $canBeIgnored = false; - } + if ($ruleError instanceof MetadataRuleError) { + $metadata = $ruleError->getMetadata(); } + + if ($ruleError instanceof NonIgnorableRuleError) { + $canBeIgnored = false; + } + return new Error( - $message, + $ruleError->getMessage(), $fileName, $line, $canBeIgnored, diff --git a/src/Analyser/Scope.php b/src/Analyser/Scope.php index b1fe0cff97..bf89cbdf48 100644 --- a/src/Analyser/Scope.php +++ b/src/Analyser/Scope.php @@ -6,9 +6,10 @@ use PhpParser\Node\Expr; use PhpParser\Node\Name; use PhpParser\Node\Param; +use PHPStan\Php\PhpVersions; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\FunctionReflection; @@ -78,7 +79,7 @@ public function getPropertyReflection(Type $typeWithProperty, string $propertyNa public function getMethodReflection(Type $typeWithMethod, string $methodName): ?ExtendedMethodReflection; - public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ConstantReflection; + public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ClassConstantReflection; public function getIterableKeyType(Type $iteratee): Type; @@ -96,11 +97,6 @@ public function getNativeType(Expr $expr): Type; public function getKeepVoidType(Expr $node): Type; - /** - * @deprecated Use getNativeType() - */ - public function doNotTreatPhpDocTypesAsCertain(): self; - public function resolveName(Name $name): string; public function resolveTypeByName(Name $name): TypeWithClassName; @@ -110,9 +106,6 @@ public function resolveTypeByName(Name $name): TypeWithClassName; */ public function getTypeFromValue($value): Type; - /** @deprecated use hasExpressionType instead */ - public function isSpecified(Expr $node): bool; - public function hasExpressionType(Expr $node): TrinaryLogic; public function isInClassExists(string $className): bool; @@ -144,4 +137,6 @@ public function filterByFalseyValue(Expr $expr): self; public function isInFirstLevelStatement(): bool; + public function getPhpVersion(): PhpVersions; + } diff --git a/src/Analyser/ScopeFactory.php b/src/Analyser/ScopeFactory.php index ae35c9d74c..ade6e1d894 100644 --- a/src/Analyser/ScopeFactory.php +++ b/src/Analyser/ScopeFactory.php @@ -4,9 +4,8 @@ /** * @api - * @final */ -class ScopeFactory +final class ScopeFactory { public function __construct(private InternalScopeFactory $internalScopeFactory) diff --git a/src/Analyser/SpecifiedTypes.php b/src/Analyser/SpecifiedTypes.php index ca290a17c4..fd9ddda81d 100644 --- a/src/Analyser/SpecifiedTypes.php +++ b/src/Analyser/SpecifiedTypes.php @@ -9,22 +9,78 @@ final class SpecifiedTypes { + private bool $overwrite = false; + + /** @var array */ + private array $newConditionalExpressionHolders = []; + + private ?Expr $rootExpr = null; + /** * @api * @param array $sureTypes * @param array $sureNotTypes - * @param array $newConditionalExpressionHolders */ public function __construct( private array $sureTypes = [], private array $sureNotTypes = [], - private bool $overwrite = false, - private array $newConditionalExpressionHolders = [], - private ?Expr $rootExpr = null, ) { } + /** + * Normally, $sureTypes in truthy context are used to intersect with the pre-existing type. + * And $sureNotTypes are used to remove type from the pre-existing type. + * + * Example: By default, non-empty-string intersected with '' (ConstantStringType) will lead to NeverType. + * Because it's not possible to narrow non-empty-string to an empty string. + * + * In rare cases, a type-specifying extension might want to overwrite the pre-existing types + * without taking the pre-existing types into consideration. + * + * In that case it should also call setAlwaysOverwriteTypes() on + * the returned object. + * + * ! Only do this if you're certain. Otherwise, this is a source of common bugs. ! + * + * @api + */ + public function setAlwaysOverwriteTypes(): self + { + $self = new self($this->sureTypes, $this->sureNotTypes); + $self->overwrite = true; + $self->newConditionalExpressionHolders = $this->newConditionalExpressionHolders; + $self->rootExpr = $this->rootExpr; + + return $self; + } + + /** + * @api + */ + public function setRootExpr(?Expr $rootExpr): self + { + $self = new self($this->sureTypes, $this->sureNotTypes); + $self->overwrite = $this->overwrite; + $self->newConditionalExpressionHolders = $this->newConditionalExpressionHolders; + $self->rootExpr = $rootExpr; + + return $self; + } + + /** + * @param array $newConditionalExpressionHolders + */ + public function setNewConditionalExpressionHolders(array $newConditionalExpressionHolders): self + { + $self = new self($this->sureTypes, $this->sureNotTypes); + $self->overwrite = $this->overwrite; + $self->newConditionalExpressionHolders = $newConditionalExpressionHolders; + $self->rootExpr = $this->rootExpr; + + return $self; + } + /** * @api * @return array @@ -90,7 +146,12 @@ public function intersectWith(SpecifiedTypes $other): self ]; } - return new self($sureTypeUnion, $sureNotTypeUnion, $this->overwrite && $other->overwrite, [], $rootExpr); + $result = new self($sureTypeUnion, $sureNotTypeUnion); + if ($this->overwrite && $other->overwrite) { + $result = $result->setAlwaysOverwriteTypes(); + } + + return $result->setRootExpr($rootExpr); } /** @api */ @@ -122,7 +183,12 @@ public function unionWith(SpecifiedTypes $other): self ]; } - return new self($sureTypeUnion, $sureNotTypeUnion, $this->overwrite || $other->overwrite, [], $rootExpr); + $result = new self($sureTypeUnion, $sureNotTypeUnion); + if ($this->overwrite || $other->overwrite) { + $result = $result->setAlwaysOverwriteTypes(); + } + + return $result->setRootExpr($rootExpr); } public function normalize(Scope $scope): self @@ -138,7 +204,12 @@ public function normalize(Scope $scope): self $sureTypes[$exprString][1] = TypeCombinator::remove($sureTypes[$exprString][1], $sureNotType); } - return new self($sureTypes, [], $this->overwrite, $this->newConditionalExpressionHolders, $this->rootExpr); + $result = new self($sureTypes, []); + if ($this->overwrite) { + $result = $result->setAlwaysOverwriteTypes(); + } + + return $result->setRootExpr($this->rootExpr); } private function mergeRootExpr(?Expr $rootExprA, ?Expr $rootExprB): ?Expr diff --git a/src/Analyser/StatementContext.php b/src/Analyser/StatementContext.php index e9308cfb77..5fd5381601 100644 --- a/src/Analyser/StatementContext.php +++ b/src/Analyser/StatementContext.php @@ -2,6 +2,14 @@ namespace PHPStan\Analyser; +/** + * Object of this class is one of the parameters of `NodeScopeResolver::processStmtNodes()`. + * + * It determines whether loops will be analysed once or multiple times + * until the types "stabilize". + * + * When in doubt, use `StatementContext::createTopLevel()`. + */ final class StatementContext { @@ -11,11 +19,17 @@ private function __construct( { } + /** + * @api + */ public static function createTopLevel(): self { return new self(true); } + /** + * @api + */ public static function createDeep(): self { return new self(false); diff --git a/src/Analyser/StatementExitPoint.php b/src/Analyser/StatementExitPoint.php index 14c8d24824..5c4916373e 100644 --- a/src/Analyser/StatementExitPoint.php +++ b/src/Analyser/StatementExitPoint.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class StatementExitPoint +final class StatementExitPoint { public function __construct(private Stmt $statement, private MutatingScope $scope) diff --git a/src/Analyser/StatementResult.php b/src/Analyser/StatementResult.php index bb9ae78f2e..dad528dc18 100644 --- a/src/Analyser/StatementResult.php +++ b/src/Analyser/StatementResult.php @@ -2,14 +2,13 @@ namespace PHPStan\Analyser; -use PhpParser\Node\Scalar\LNumber; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Stmt; /** * @api - * @final */ -class StatementResult +final class StatementResult { /** @@ -58,7 +57,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); } @@ -82,7 +81,7 @@ public function getExitPoints(): array /** * @param class-string|class-string $stmtClass - * @return StatementExitPoint[] + * @return list */ public function getExitPointsByType(string $stmtClass): array { @@ -99,7 +98,7 @@ public function getExitPointsByType(string $stmtClass): array continue; } - if (!$value instanceof LNumber) { + if (!$value instanceof Int_) { $exitPoints[] = $exitPoint; continue; } @@ -116,7 +115,7 @@ public function getExitPointsByType(string $stmtClass): array } /** - * @return StatementExitPoint[] + * @return list */ public function getExitPointsForOuterLoop(): array { @@ -130,7 +129,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 +139,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/Analyser/ThrowPoint.php b/src/Analyser/ThrowPoint.php index 1de4b937f9..873c11e425 100644 --- a/src/Analyser/ThrowPoint.php +++ b/src/Analyser/ThrowPoint.php @@ -10,9 +10,8 @@ /** * @api - * @final */ -class ThrowPoint +final class ThrowPoint { /** diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php index 088236bac5..17032ec814 100644 --- a/src/Analyser/TypeSpecifier.php +++ b/src/Analyser/TypeSpecifier.php @@ -22,10 +22,11 @@ use PHPStan\Node\Expr\AlwaysRememberedExpr; use PHPStan\Node\IssetExpr; use PHPStan\Node\Printer\ExprPrinter; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\Assertions; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ParametersAcceptorSelector; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\ResolvedFunctionVariant; use PHPStan\Rules\Arrays\AllowedArrayKeysTypes; @@ -102,6 +103,7 @@ final class TypeSpecifier public function __construct( private ExprPrinter $exprPrinter, private ReflectionProvider $reflectionProvider, + private PhpVersion $phpVersion, private array $functionTypeSpecifyingExtensions, private array $methodTypeSpecifyingExtensions, private array $staticMethodTypeSpecifyingExtensions, @@ -122,13 +124,10 @@ public function specifyTypesInCondition( Scope $scope, Expr $expr, TypeSpecifierContext $context, - ?Expr $rootExpr = null, ): SpecifiedTypes { - $rootExpr ??= $expr; - if ($expr instanceof Expr\CallLike && $expr->isFirstClassCallable()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } if ($expr instanceof Instanceof_) { @@ -152,7 +151,7 @@ public function specifyTypesInCondition( } else { $type = new ObjectType($className); } - return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); + return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr); } $classType = $scope->getType($expr->class); @@ -178,64 +177,58 @@ public function specifyTypesInCondition( $type, new ObjectWithoutClassType(), ); - return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); + return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr); } elseif ($context->false()) { $exprType = $scope->getType($expr->expr); if (!$type->isSuperTypeOf($exprType)->yes()) { - return $this->create($exprNode, $type, $context, false, $scope, $rootExpr); + return $this->create($exprNode, $type, $context, $scope)->setRootExpr($expr); } } } if ($context->true()) { - return $this->create($exprNode, new ObjectWithoutClassType(), $context, false, $scope, $rootExpr); + return $this->create($exprNode, new ObjectWithoutClassType(), $context, $scope)->setRootExpr($exprNode); } } elseif ($expr instanceof Node\Expr\BinaryOp\Identical) { - return $this->resolveIdentical($expr, $scope, $context, $rootExpr); + return $this->resolveIdentical($expr, $scope, $context); } elseif ($expr instanceof Node\Expr\BinaryOp\NotIdentical) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Identical($expr->left, $expr->right)), $context, - $rootExpr, - ); + )->setRootExpr($expr); } elseif ($expr instanceof Expr\Cast\Bool_) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BinaryOp\Equal($expr->expr, new ConstFetch(new Name\FullyQualified('true'))), $context, - $rootExpr, - ); + )->setRootExpr($expr); } elseif ($expr instanceof Expr\Cast\String_) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BinaryOp\NotEqual($expr->expr, new Node\Scalar\String_('')), $context, - $rootExpr, - ); + )->setRootExpr($expr); } elseif ($expr instanceof Expr\Cast\Int_) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BinaryOp\NotEqual($expr->expr, new Node\Scalar\LNumber(0)), $context, - $rootExpr, - ); + )->setRootExpr($expr); } elseif ($expr instanceof Expr\Cast\Double) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BinaryOp\NotEqual($expr->expr, new Node\Scalar\DNumber(0.0)), $context, - $rootExpr, - ); + )->setRootExpr($expr); } elseif ($expr instanceof Node\Expr\BinaryOp\Equal) { - return $this->resolveEqual($expr, $scope, $context, $rootExpr); + return $this->resolveEqual($expr, $scope, $context); } elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) { return $this->specifyTypesInCondition( $scope, new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Equal($expr->left, $expr->right)), $context, - $rootExpr, - ); + )->setRootExpr($expr); } elseif ($expr instanceof Node\Expr\BinaryOp\Smaller || $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual) { @@ -258,14 +251,13 @@ public function specifyTypesInCondition( $scope, new Node\Expr\BooleanNot($inverseOperator), $context, - $rootExpr, - ); + )->setRootExpr($expr); } $orEqual = $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual; $offset = $orEqual ? 0 : 1; $leftType = $scope->getType($expr->left); - $result = new SpecifiedTypes([], [], false, [], $rootExpr); + $result = (new SpecifiedTypes([], []))->setRootExpr($expr); if ( !$context->null() @@ -289,7 +281,7 @@ public function specifyTypesInCondition( $sizeType = $leftType; } - $narrowed = $this->narrowUnionByArraySize($expr->right, $argType, $sizeType, $context, $scope, $rootExpr); + $narrowed = $this->narrowUnionByArraySize($expr->right, $argType, $sizeType, $context, $scope, $expr); if ($narrowed !== null) { return $narrowed; } @@ -320,18 +312,18 @@ public function specifyTypesInCondition( if (count($countables) > 0) { $countableType = TypeCombinator::union(...$countables); - return $this->create($expr->right->getArgs()[0]->value, $countableType, $context, false, $scope, $rootExpr); + return $this->create($expr->right->getArgs()[0]->value, $countableType, $context, $scope)->setRootExpr($expr); } } if ($argType->isArray()->yes()) { $newType = new NonEmptyArrayType(); if ($context->true() && $argType->isList()->yes()) { - $newType = AccessoryArrayListType::intersectWith($newType); + $newType = TypeCombinator::intersect($newType, new AccessoryArrayListType()); } $result = $result->unionWith( - $this->create($expr->right->getArgs()[0]->value, $newType, $context, false, $scope, $rootExpr), + $this->create($expr->right->getArgs()[0]->value, $newType, $context, $scope)->setRootExpr($expr), ); } } @@ -349,8 +341,7 @@ public function specifyTypesInCondition( $scope, new Expr\BinaryOp\NotIdentical($expr->right, new ConstFetch(new Name('false'))), $context, - $rootExpr, - ); + )->setRootExpr($expr); } if ( @@ -373,7 +364,7 @@ public function specifyTypesInCondition( $accessory = new AccessoryNonFalsyStringType(); } - $result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, $accessory, $context, false, $scope, $rootExpr)); + $result = $result->unionWith($this->create($expr->right->getArgs()[0]->value, $accessory, $context, $scope)->setRootExpr($expr)); } } } @@ -381,21 +372,21 @@ public function specifyTypesInCondition( if ($leftType instanceof ConstantIntegerType) { if ($expr->right instanceof Expr\PostInc) { $result = $result->unionWith($this->createRangeTypes( - $rootExpr, + $expr, $expr->right->var, IntegerRangeType::fromInterval($leftType->getValue(), null, $offset + 1), $context, )); } elseif ($expr->right instanceof Expr\PostDec) { $result = $result->unionWith($this->createRangeTypes( - $rootExpr, + $expr, $expr->right->var, IntegerRangeType::fromInterval($leftType->getValue(), null, $offset - 1), $context, )); } elseif ($expr->right instanceof Expr\PreInc || $expr->right instanceof Expr\PreDec) { $result = $result->unionWith($this->createRangeTypes( - $rootExpr, + $expr, $expr->right->var, IntegerRangeType::fromInterval($leftType->getValue(), null, $offset), $context, @@ -407,21 +398,21 @@ public function specifyTypesInCondition( if ($rightType instanceof ConstantIntegerType) { if ($expr->left instanceof Expr\PostInc) { $result = $result->unionWith($this->createRangeTypes( - $rootExpr, + $expr, $expr->left->var, IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset + 1), $context, )); } elseif ($expr->left instanceof Expr\PostDec) { $result = $result->unionWith($this->createRangeTypes( - $rootExpr, + $expr, $expr->left->var, IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset - 1), $context, )); } elseif ($expr->left instanceof Expr\PreInc || $expr->left instanceof Expr\PreDec) { $result = $result->unionWith($this->createRangeTypes( - $rootExpr, + $expr, $expr->left->var, IntegerRangeType::fromInterval(null, $rightType->getValue(), -$offset), $context, @@ -434,24 +425,20 @@ public function specifyTypesInCondition( $result = $result->unionWith( $this->create( $expr->left, - $orEqual ? $rightType->getSmallerOrEqualType() : $rightType->getSmallerType(), + $orEqual ? $rightType->getSmallerOrEqualType($this->phpVersion) : $rightType->getSmallerType($this->phpVersion), TypeSpecifierContext::createTruthy(), - false, $scope, - $rootExpr, - ), + )->setRootExpr($expr), ); } if (!$expr->right instanceof Node\Scalar) { $result = $result->unionWith( $this->create( $expr->right, - $orEqual ? $leftType->getGreaterOrEqualType() : $leftType->getGreaterType(), + $orEqual ? $leftType->getGreaterOrEqualType($this->phpVersion) : $leftType->getGreaterType($this->phpVersion), TypeSpecifierContext::createTruthy(), - false, $scope, - $rootExpr, - ), + )->setRootExpr($expr), ); } } elseif ($context->false()) { @@ -459,24 +446,20 @@ public function specifyTypesInCondition( $result = $result->unionWith( $this->create( $expr->left, - $orEqual ? $rightType->getGreaterType() : $rightType->getGreaterOrEqualType(), + $orEqual ? $rightType->getGreaterType($this->phpVersion) : $rightType->getGreaterOrEqualType($this->phpVersion), TypeSpecifierContext::createTruthy(), - false, $scope, - $rootExpr, - ), + )->setRootExpr($expr), ); } if (!$expr->right instanceof Node\Scalar) { $result = $result->unionWith( $this->create( $expr->right, - $orEqual ? $leftType->getSmallerType() : $leftType->getSmallerOrEqualType(), + $orEqual ? $leftType->getSmallerType($this->phpVersion) : $leftType->getSmallerOrEqualType($this->phpVersion), TypeSpecifierContext::createTruthy(), - false, $scope, - $rootExpr, - ), + )->setRootExpr($expr), ); } } @@ -484,10 +467,10 @@ public function specifyTypesInCondition( return $result; } elseif ($expr instanceof Node\Expr\BinaryOp\Greater) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Smaller($expr->right, $expr->left), $context, $rootExpr); + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Smaller($expr->right, $expr->left), $context)->setRootExpr($expr); } elseif ($expr instanceof Node\Expr\BinaryOp\GreaterOrEqual) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left), $context, $rootExpr); + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left), $context)->setRootExpr($expr); } elseif ($expr instanceof FuncCall && $expr->name instanceof Name) { if ($this->reflectionProvider->hasFunction($expr->name, $scope)) { @@ -518,7 +501,7 @@ public function specifyTypesInCondition( $asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( $type, $parametersAcceptor->getResolvedTemplateTypeMap(), - $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $parametersAcceptor instanceof ExtendedParametersAcceptor ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant(), )); $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); @@ -528,7 +511,7 @@ public function specifyTypesInCondition( } } - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + return $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope); } elseif ($expr instanceof MethodCall && $expr->name instanceof Node\Identifier) { $methodCalledOnType = $scope->getType($expr->var); $methodReflection = $scope->getMethodReflection($methodCalledOnType, $expr->name->name); @@ -566,7 +549,7 @@ public function specifyTypesInCondition( $asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( $type, $parametersAcceptor->getResolvedTemplateTypeMap(), - $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $parametersAcceptor instanceof ExtendedParametersAcceptor ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant(), )); $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); @@ -576,7 +559,7 @@ public function specifyTypesInCondition( } } - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + return $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope); } elseif ($expr instanceof StaticCall && $expr->name instanceof Node\Identifier) { if ($expr->class instanceof Name) { $calleeType = $scope->resolveTypeByName($expr->class); @@ -619,7 +602,7 @@ public function specifyTypesInCondition( $asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( $type, $parametersAcceptor->getResolvedTemplateTypeMap(), - $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $parametersAcceptor instanceof ExtendedParametersAcceptor ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant(), )); $specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope); @@ -629,28 +612,25 @@ public function specifyTypesInCondition( } } - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + return $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope); } elseif ($expr instanceof BooleanAnd || $expr instanceof LogicalAnd) { if (!$scope instanceof MutatingScope) { throw new ShouldNotHappenException(); } - $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context, $rootExpr); + $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context)->setRootExpr($expr); $rightScope = $scope->filterByTruthyValue($expr->left); - $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context, $rootExpr); + $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context)->setRootExpr($expr); $types = $context->true() ? $leftTypes->unionWith($rightTypes) : $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($rightScope)); if ($context->false()) { - return new SpecifiedTypes( + return (new SpecifiedTypes( $types->getSureTypes(), $types->getSureNotTypes(), - false, - array_merge( - $this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), - $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), - $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), - $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes), - ), - $rootExpr, - ); + ))->setNewConditionalExpressionHolders(array_merge( + $this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), + $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes), + ))->setRootExpr($expr); } return $types; @@ -658,37 +638,34 @@ public function specifyTypesInCondition( if (!$scope instanceof MutatingScope) { throw new ShouldNotHappenException(); } - $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context, $rootExpr); + $leftTypes = $this->specifyTypesInCondition($scope, $expr->left, $context)->setRootExpr($expr); $rightScope = $scope->filterByFalseyValue($expr->left); - $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context, $rootExpr); + $rightTypes = $this->specifyTypesInCondition($rightScope, $expr->right, $context)->setRootExpr($expr); $types = $context->true() ? $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($rightScope)) : $leftTypes->unionWith($rightTypes); if ($context->true()) { - return new SpecifiedTypes( + return (new SpecifiedTypes( $types->getSureTypes(), $types->getSureNotTypes(), - false, - array_merge( - $this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), - $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), - $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), - $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes), - ), - $rootExpr, - ); + ))->setNewConditionalExpressionHolders(array_merge( + $this->processBooleanNotSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanNotSureConditionalTypes($scope, $rightTypes, $leftTypes), + $this->processBooleanSureConditionalTypes($scope, $leftTypes, $rightTypes), + $this->processBooleanSureConditionalTypes($scope, $rightTypes, $leftTypes), + ))->setRootExpr($expr); } return $types; } elseif ($expr instanceof Node\Expr\BooleanNot && !$context->null()) { - return $this->specifyTypesInCondition($scope, $expr->expr, $context->negate(), $rootExpr); + return $this->specifyTypesInCondition($scope, $expr->expr, $context->negate())->setRootExpr($expr); } elseif ($expr instanceof Node\Expr\Assign) { if (!$scope instanceof MutatingScope) { throw new ShouldNotHappenException(); } if ($context->null()) { - return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->expr, $context, $rootExpr); + return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->expr, $context)->setRootExpr($expr); } - return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->var, $context, $rootExpr); + return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->var, $context)->setRootExpr($expr); } elseif ( $expr instanceof Expr\Isset_ && count($expr->vars) > 0 @@ -716,7 +693,7 @@ public function specifyTypesInCondition( throw new ShouldNotHappenException(); } - return $this->specifyTypesInCondition($scope, $andChain, $context, $rootExpr); + return $this->specifyTypesInCondition($scope, $andChain, $context)->setRootExpr($expr); } $issetExpr = $expr->vars[0]; @@ -738,10 +715,8 @@ public function specifyTypesInCondition( $issetExpr, new NullType(), $context->negate(), - false, $scope, - $rootExpr, - ); + )->setRootExpr($expr); if ($issetExpr instanceof Expr\Variable && is_string($issetExpr->name)) { if ($isset === true) { @@ -754,10 +729,8 @@ public function specifyTypesInCondition( new IssetExpr($issetExpr), new NullType(), $context, - false, $scope, - $rootExpr, - )); + ))->setRootExpr($expr); } if ($isNullable) { @@ -766,10 +739,8 @@ public function specifyTypesInCondition( new IssetExpr($issetExpr), new NullType(), $context->negate(), - false, $scope, - $rootExpr, - )); + ))->setRootExpr($expr); } // variable cannot exist in !isset() @@ -777,10 +748,8 @@ public function specifyTypesInCondition( new IssetExpr($issetExpr), new NullType(), $context, - false, $scope, - $rootExpr, - ); + )->setRootExpr($expr); } if ($isNullable && $isset === true) { @@ -814,7 +783,7 @@ public function specifyTypesInCondition( if ($var instanceof Expr\Variable && is_string($var->name)) { if ($scope->hasVariableType($var->name)->no()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } } @@ -831,10 +800,8 @@ public function specifyTypesInCondition( $var->var, new HasOffsetType($dimType), $context, - false, $scope, - $rootExpr, - ), + )->setRootExpr($expr), ); } else { $varType = $scope->getType($var->var); @@ -845,10 +812,8 @@ public function specifyTypesInCondition( $var->dim, $narrowedKey, $context, - false, $scope, - $rootExpr, - ), + )->setRootExpr($expr), ); } } @@ -862,7 +827,7 @@ public function specifyTypesInCondition( $this->create($var->var, new IntersectionType([ new ObjectWithoutClassType(), new HasPropertyType($var->name->toString()), - ]), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr), + ]), TypeSpecifierContext::createTruthy(), $scope)->setRootExpr($expr), ); } elseif ( $var instanceof StaticPropertyFetch @@ -873,12 +838,12 @@ public function specifyTypesInCondition( $this->create($var->class, new IntersectionType([ new ObjectWithoutClassType(), new HasPropertyType($var->name->toString()), - ]), TypeSpecifierContext::createTruthy(), false, $scope, $rootExpr), + ]), TypeSpecifierContext::createTruthy(), $scope)->setRootExpr($expr), ); } $types = $types->unionWith( - $this->create($var, new NullType(), TypeSpecifierContext::createFalse(), false, $scope, $rootExpr), + $this->create($var, new NullType(), TypeSpecifierContext::createFalse(), $scope)->setRootExpr($expr), ); } @@ -902,10 +867,8 @@ public function specifyTypesInCondition( $expr->left, new NullType(), $context->negate(), - false, $scope, - $rootExpr, - ); + )->setRootExpr($expr); } if ((new ConstantBooleanType(false))->isSuperTypeOf($scope->getType($expr->right)->toBoolean())->yes()) { @@ -913,10 +876,8 @@ public function specifyTypesInCondition( $expr->left, new NullType(), TypeSpecifierContext::createFalse(), - false, $scope, - $rootExpr, - ); + )->setRootExpr($expr); } } elseif ( @@ -934,9 +895,9 @@ public function specifyTypesInCondition( return $this->specifyTypesInCondition($scope, new BooleanOr( new Expr\BooleanNot(new Expr\Isset_([$expr->expr])), new Expr\BooleanNot($expr->expr), - ), $context, $rootExpr); + ), $context)->setRootExpr($expr); } elseif ($expr instanceof Expr\ErrorSuppress) { - return $this->specifyTypesInCondition($scope, $expr->expr, $context, $rootExpr); + return $this->specifyTypesInCondition($scope, $expr->expr, $context)->setRootExpr($expr); } elseif ( $expr instanceof Expr\Ternary && !$context->null() @@ -947,7 +908,7 @@ public function specifyTypesInCondition( $conditionExpr = new BooleanAnd($conditionExpr, $expr->if); } - return $this->specifyTypesInCondition($scope, $conditionExpr, $context, $rootExpr); + return $this->specifyTypesInCondition($scope, $conditionExpr, $context)->setRootExpr($expr); } elseif ($expr instanceof Expr\NullsafePropertyFetch && !$context->null()) { $types = $this->specifyTypesInCondition( @@ -957,10 +918,9 @@ public function specifyTypesInCondition( new PropertyFetch($expr->var, $expr->name), ), $context, - $rootExpr, - ); + )->setRootExpr($expr); - $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope); return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope)); } elseif ($expr instanceof Expr\NullsafeMethodCall && !$context->null()) { $types = $this->specifyTypesInCondition( @@ -970,10 +930,9 @@ public function specifyTypesInCondition( new MethodCall($expr->var, $expr->name, $expr->args), ), $context, - $rootExpr, - ); + )->setRootExpr($expr); - $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + $nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope); return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope)); } elseif ( $expr instanceof Expr\New_ @@ -992,7 +951,7 @@ public function specifyTypesInCondition( $asserts = $asserts->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes( $type, $parametersAcceptor->getResolvedTemplateTypeMap(), - $parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $parametersAcceptor instanceof ExtendedParametersAcceptor ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), TemplateTypeVariance::createInvariant(), )); @@ -1004,10 +963,10 @@ public function specifyTypesInCondition( } } } elseif (!$context->null()) { - return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope); + return $this->handleDefaultTruthyOrFalseyContext($context, $expr, $scope); } - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } private function narrowUnionByArraySize(FuncCall $countFuncCall, UnionType $argType, ?Type $sizeType, TypeSpecifierContext $context, Scope $scope, ?Expr $rootExpr): ?SpecifiedTypes @@ -1020,7 +979,7 @@ private function narrowUnionByArraySize(FuncCall $countFuncCall, UnionType $argT $isNormalCount = TrinaryLogic::createYes(); } else { $mode = $scope->getType($countFuncCall->getArgs()[1]->value); - $isNormalCount = (new ConstantIntegerType(COUNT_NORMAL))->isSuperTypeOf($mode)->or($argType->getIterableValueType()->isArray()->negate()); + $isNormalCount = (new ConstantIntegerType(COUNT_NORMAL))->isSuperTypeOf($mode)->result->or($argType->getIterableValueType()->isArray()->negate()); } if ( @@ -1050,7 +1009,7 @@ private function narrowUnionByArraySize(FuncCall $countFuncCall, UnionType $argT $result[] = $innerType; } - return $this->create($countFuncCall->getArgs()[0]->value, TypeCombinator::union(...$result), $context, false, $scope, $rootExpr); + return $this->create($countFuncCall->getArgs()[0]->value, TypeCombinator::union(...$result), $context, $scope)->setRootExpr($rootExpr); } return null; @@ -1064,7 +1023,7 @@ private function turnListIntoConstantArray(FuncCall $countFuncCall, Type $type, $isNormalCount = TrinaryLogic::createYes(); } else { $mode = $scope->getType($countFuncCall->getArgs()[1]->value); - $isNormalCount = (new ConstantIntegerType(COUNT_NORMAL))->isSuperTypeOf($mode)->or($argType->getIterableValueType()->isArray()->negate()); + $isNormalCount = (new ConstantIntegerType(COUNT_NORMAL))->isSuperTypeOf($mode)->result->or($argType->getIterableValueType()->isArray()->negate()); } if ( @@ -1126,11 +1085,11 @@ private function specifyTypesForConstantBinaryExpression( Type $constantType, TypeSpecifierContext $context, Scope $scope, - ?Expr $rootExpr, + Expr $rootExpr, ): ?SpecifiedTypes { if (!$context->null() && $constantType->isFalse()->yes()) { - $types = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + $types = $this->create($exprNode, $constantType, $context, $scope)->setRootExpr($rootExpr); if ($exprNode instanceof Expr\NullsafeMethodCall || $exprNode instanceof Expr\NullsafePropertyFetch) { return $types; } @@ -1139,12 +1098,11 @@ private function specifyTypesForConstantBinaryExpression( $scope, $exprNode, $context->true() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createFalse()->negate(), - $rootExpr, - )); + )->setRootExpr($rootExpr)); } if (!$context->null() && $constantType->isTrue()->yes()) { - $types = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); + $types = $this->create($exprNode, $constantType, $context, $scope)->setRootExpr($rootExpr); if ($exprNode instanceof Expr\NullsafeMethodCall || $exprNode instanceof Expr\NullsafePropertyFetch) { return $types; } @@ -1153,8 +1111,7 @@ private function specifyTypesForConstantBinaryExpression( $scope, $exprNode, $context->true() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createTrue()->negate(), - $rootExpr, - )); + )->setRootExpr($rootExpr)); } return null; @@ -1165,7 +1122,7 @@ private function specifyTypesForConstantStringBinaryExpression( Type $constantType, TypeSpecifierContext $context, Scope $scope, - ?Expr $rootExpr, + Expr $rootExpr, ): ?SpecifiedTypes { $scalarValues = $constantType->getConstantScalarValues(); @@ -1207,8 +1164,8 @@ private function specifyTypesForConstantStringBinaryExpression( } if ($type !== null) { - $callType = $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr); - $argType = $this->create($exprNode->getArgs()[0]->value, $type, $context, false, $scope, $rootExpr); + $callType = $this->create($exprNode, $constantType, $context, $scope)->setRootExpr($rootExpr); + $argType = $this->create($exprNode->getArgs()[0]->value, $type, $context, $scope)->setRootExpr($rootExpr); return $callType->unionWith($argType); } } @@ -1229,9 +1186,8 @@ private function specifyTypesForConstantStringBinaryExpression( $exprNode->getArgs()[0]->value, $classStringType, $context, - false, $scope, - ); + )->setRootExpr($rootExpr); } if ($argType->isObject()->yes()) { @@ -1239,37 +1195,35 @@ private function specifyTypesForConstantStringBinaryExpression( $exprNode->getArgs()[0]->value, $objectType, $context, - false, $scope, - ); + )->setRootExpr($rootExpr); } return $this->create( $exprNode->getArgs()[0]->value, TypeCombinator::union($objectType, $classStringType), $context, - false, $scope, - ); + )->setRootExpr($rootExpr); } return null; } - private function handleDefaultTruthyOrFalseyContext(TypeSpecifierContext $context, ?Expr $rootExpr, Expr $expr, Scope $scope): SpecifiedTypes + private function handleDefaultTruthyOrFalseyContext(TypeSpecifierContext $context, Expr $expr, Scope $scope): SpecifiedTypes { if ($context->null()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } if (!$context->truthy()) { $type = StaticTypeFactory::truthy(); - return $this->create($expr, $type, TypeSpecifierContext::createFalse(), false, $scope, $rootExpr); + return $this->create($expr, $type, TypeSpecifierContext::createFalse(), $scope)->setRootExpr($expr); } elseif (!$context->falsey()) { $type = StaticTypeFactory::falsey(); - return $this->create($expr, $type, TypeSpecifierContext::createFalse(), false, $scope, $rootExpr); + return $this->create($expr, $type, TypeSpecifierContext::createFalse(), $scope)->setRootExpr($expr); } - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } private function specifyTypesFromConditionalReturnType( @@ -1354,7 +1308,6 @@ public function getConditionalSpecifiedTypes( $argsMap[$parameterName], $targetType, $context, - false, $scope, ); @@ -1450,10 +1403,8 @@ static function (Type $type, callable $traverse) use ($templateTypeMap, &$contai $assertExpr, $assertedType, $assert->isNegated() ? TypeSpecifierContext::createFalse() : TypeSpecifierContext::createTrue(), - false, $scope, - $containsUnresolvedTemplate || $assert->isEquality() ? $call : null, - ); + )->setRootExpr($containsUnresolvedTemplate || $assert->isEquality() ? $call : null); $types = $types !== null ? $types->unionWith($newTypes) : $newTypes; if (!$context->null() || !$assertedType instanceof ConstantBooleanType) { @@ -1650,13 +1601,11 @@ public function create( Expr $expr, Type $type, TypeSpecifierContext $context, - bool $overwrite = false, - ?Scope $scope = null, - ?Expr $rootExpr = null, + Scope $scope, ): SpecifiedTypes { if ($expr instanceof Instanceof_ || $expr instanceof Expr\List_) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } $specifiedExprs = []; @@ -1682,7 +1631,7 @@ public function create( $types = null; foreach ($specifiedExprs as $specifiedExpr) { - $newTypes = $this->createForExpr($specifiedExpr, $type, $context, $overwrite, $scope, $rootExpr); + $newTypes = $this->createForExpr($specifiedExpr, $type, $context, $scope); if ($types === null) { $types = $newTypes; @@ -1698,17 +1647,13 @@ private function createForExpr( Expr $expr, Type $type, TypeSpecifierContext $context, - bool $overwrite = false, - ?Scope $scope = null, - ?Expr $rootExpr = null, + Scope $scope, ): SpecifiedTypes { - if ($scope !== null) { - if ($context->true()) { - $containsNull = !$type->isNull()->no() && !$scope->getType($expr)->isNull()->no(); - } elseif ($context->false()) { - $containsNull = !TypeCombinator::containsNull($type) && !$scope->getType($expr)->isNull()->no(); - } + if ($context->true()) { + $containsNull = !$type->isNull()->no() && !$scope->getType($expr)->isNull()->no(); + } elseif ($context->false()) { + $containsNull = !TypeCombinator::containsNull($type) && !$scope->getType($expr)->isNull()->no(); } $originalExpr = $expr; @@ -1717,8 +1662,7 @@ private function createForExpr( } if ( - $scope !== null - && !$context->null() + !$context->null() && $expr instanceof Expr\BinaryOp\Coalesce ) { $rightIsSuperType = $type->isSuperTypeOf($scope->getType($expr->right)); @@ -1734,24 +1678,23 @@ private function createForExpr( $has = $this->reflectionProvider->hasFunction($expr->name, $scope); if (!$has) { // backwards compatibility with previous behaviour - return new SpecifiedTypes([], [], false, [], $rootExpr); + return new SpecifiedTypes([], []); } $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); $hasSideEffects = $functionReflection->hasSideEffects(); if ($hasSideEffects->yes()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return new SpecifiedTypes([], []); } if (!$this->rememberPossiblyImpureFunctionValues && !$hasSideEffects->no()) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return new SpecifiedTypes([], []); } } if ( $expr instanceof MethodCall && $expr->name instanceof Node\Identifier - && $scope !== null ) { $methodName = $expr->name->toString(); $calledOnType = $scope->getType($expr->var); @@ -1762,17 +1705,16 @@ private function createForExpr( || (!$this->rememberPossiblyImpureFunctionValues && !$methodReflection->hasSideEffects()->no()) ) { if (isset($containsNull) && !$containsNull) { - return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type); + return $this->createNullsafeTypes($originalExpr, $scope, $context, $type); } - return new SpecifiedTypes([], [], false, [], $rootExpr); + return new SpecifiedTypes([], []); } } if ( $expr instanceof StaticCall && $expr->name instanceof Node\Identifier - && $scope !== null ) { $methodName = $expr->name->toString(); if ($expr->class instanceof Name) { @@ -1788,10 +1730,10 @@ private function createForExpr( || (!$this->rememberPossiblyImpureFunctionValues && !$methodReflection->hasSideEffects()->no()) ) { if (isset($containsNull) && !$containsNull) { - return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type); + return $this->createNullsafeTypes($originalExpr, $scope, $context, $type); } - return new SpecifiedTypes([], [], false, [], $rootExpr); + return new SpecifiedTypes([], []); } } @@ -1811,61 +1753,61 @@ private function createForExpr( } } - $types = new SpecifiedTypes($sureTypes, $sureNotTypes, $overwrite, [], $rootExpr); - if ($scope !== null && isset($containsNull) && !$containsNull) { - return $this->createNullsafeTypes($rootExpr, $originalExpr, $scope, $context, $overwrite, $type)->unionWith($types); + $types = new SpecifiedTypes($sureTypes, $sureNotTypes); + if (isset($containsNull) && !$containsNull) { + return $this->createNullsafeTypes($originalExpr, $scope, $context, $type)->unionWith($types); } return $types; } - private function createNullsafeTypes(?Expr $rootExpr, Expr $expr, Scope $scope, TypeSpecifierContext $context, bool $overwrite, ?Type $type): SpecifiedTypes + private function createNullsafeTypes(Expr $expr, Scope $scope, TypeSpecifierContext $context, ?Type $type): SpecifiedTypes { if ($expr instanceof Expr\NullsafePropertyFetch) { if ($type !== null) { - $propertyFetchTypes = $this->create(new PropertyFetch($expr->var, $expr->name), $type, $context, false, $scope, $rootExpr); + $propertyFetchTypes = $this->create(new PropertyFetch($expr->var, $expr->name), $type, $context, $scope); } else { - $propertyFetchTypes = $this->create(new PropertyFetch($expr->var, $expr->name), new NullType(), TypeSpecifierContext::createFalse(), false, $scope, $rootExpr); + $propertyFetchTypes = $this->create(new PropertyFetch($expr->var, $expr->name), new NullType(), TypeSpecifierContext::createFalse(), $scope); } return $propertyFetchTypes->unionWith( - $this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr), + $this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $scope), ); } if ($expr instanceof Expr\NullsafeMethodCall) { if ($type !== null) { - $methodCallTypes = $this->create(new MethodCall($expr->var, $expr->name, $expr->args), $type, $context, $overwrite, $scope, $rootExpr); + $methodCallTypes = $this->create(new MethodCall($expr->var, $expr->name, $expr->args), $type, $context, $scope); } else { - $methodCallTypes = $this->create(new MethodCall($expr->var, $expr->name, $expr->args), new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr); + $methodCallTypes = $this->create(new MethodCall($expr->var, $expr->name, $expr->args), new NullType(), TypeSpecifierContext::createFalse(), $scope); } return $methodCallTypes->unionWith( - $this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $overwrite, $scope, $rootExpr), + $this->create($expr->var, new NullType(), TypeSpecifierContext::createFalse(), $scope), ); } if ($expr instanceof Expr\PropertyFetch) { - return $this->createNullsafeTypes($rootExpr, $expr->var, $scope, $context, $overwrite, null); + return $this->createNullsafeTypes($expr->var, $scope, $context, null); } if ($expr instanceof Expr\MethodCall) { - return $this->createNullsafeTypes($rootExpr, $expr->var, $scope, $context, $overwrite, null); + return $this->createNullsafeTypes($expr->var, $scope, $context, null); } if ($expr instanceof Expr\ArrayDimFetch) { - return $this->createNullsafeTypes($rootExpr, $expr->var, $scope, $context, $overwrite, null); + return $this->createNullsafeTypes($expr->var, $scope, $context, null); } if ($expr instanceof Expr\StaticPropertyFetch && $expr->class instanceof Expr) { - return $this->createNullsafeTypes($rootExpr, $expr->class, $scope, $context, $overwrite, null); + return $this->createNullsafeTypes($expr->class, $scope, $context, null); } if ($expr instanceof Expr\StaticCall && $expr->class instanceof Expr) { - return $this->createNullsafeTypes($rootExpr, $expr->class, $scope, $context, $overwrite, null); + return $this->createNullsafeTypes($expr->class, $scope, $context, null); } - return new SpecifiedTypes([], [], $overwrite, [], $rootExpr); + return new SpecifiedTypes([], []); } private function createRangeTypes(?Expr $rootExpr, Expr $expr, Type $type, TypeSpecifierContext $context): SpecifiedTypes @@ -1882,7 +1824,7 @@ private function createRangeTypes(?Expr $rootExpr, Expr $expr, Type $type, TypeS } } - return new SpecifiedTypes([], $sureNotTypes, false, [], $rootExpr); + return (new SpecifiedTypes([], $sureNotTypes))->setRootExpr($rootExpr); } /** @@ -1944,7 +1886,7 @@ private function getTypeSpecifyingExtensionsForType(array $extensions, string $c return array_merge(...$extensionsForClass); } - public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecifierContext $context, ?Expr $rootExpr): SpecifiedTypes + public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { $expressions = $this->findTypeExpressionsFromBinaryOperation($scope, $expr); if ($expressions !== null) { @@ -1961,7 +1903,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif new ConstantStringType(''), new ConstantArrayType([], []), ]; - return $this->create($exprNode, new UnionType($trueTypes), $context, false, $scope, $rootExpr); + return $this->create($exprNode, new UnionType($trueTypes), $context, $scope)->setRootExpr($expr); } if (!$context->null() && $constantType->getValue() === false) { @@ -1969,8 +1911,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif $scope, $exprNode, $context->true() ? TypeSpecifierContext::createFalsey() : TypeSpecifierContext::createFalsey()->negate(), - $rootExpr, - ); + )->setRootExpr($expr); } if (!$context->null() && $constantType->getValue() === true) { @@ -1978,8 +1919,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif $scope, $exprNode, $context->true() ? TypeSpecifierContext::createTruthy() : TypeSpecifierContext::createTruthy()->negate(), - $rootExpr, - ); + )->setRootExpr($expr); } if (!$context->null() && $constantType->getValue() === 0 && !$otherType->isInteger()->yes() && !$otherType->isBoolean()->yes()) { @@ -2003,7 +1943,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif new ConstantStringType('0'), ]; } - return $this->create($exprNode, new UnionType($trueTypes), $context, false, $scope, $rootExpr); + return $this->create($exprNode, new UnionType($trueTypes), $context, $scope)->setRootExpr($expr); } if (!$context->null() && $constantType->getValue() === '') { @@ -2025,7 +1965,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif new ConstantStringType(''), ]; } - return $this->create($exprNode, new UnionType($trueTypes), $context, false, $scope, $rootExpr); + return $this->create($exprNode, new UnionType($trueTypes), $context, $scope)->setRootExpr($expr); } if ( @@ -2035,7 +1975,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif && isset($exprNode->getArgs()[0]) && $constantType->isString()->yes() ) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr); + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context)->setRootExpr($expr); } if ( @@ -2045,7 +1985,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif && $exprNode->name->toLowerString() === 'preg_match' && (new ConstantIntegerType(1))->isSuperTypeOf($constantType)->yes() ) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr); + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context)->setRootExpr($expr); } } @@ -2061,8 +2001,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif $expr->right, ), $context, - $rootExpr, - ); + )->setRootExpr($expr); } $rightBooleanType = $rightType->toBoolean(); @@ -2074,8 +2013,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif new ConstFetch(new Name($rightBooleanType->getValue() ? 'true' : 'false')), ), $context, - $rootExpr, - ); + )->setRootExpr($expr); } if ( @@ -2083,7 +2021,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif && $rightType->isArray()->yes() && $leftType->isConstantArray()->yes() && $leftType->isIterableAtLeastOnce()->no() ) { - return $this->create($expr->right, new NonEmptyArrayType(), $context->negate(), false, $scope, $rootExpr); + return $this->create($expr->right, new NonEmptyArrayType(), $context->negate(), $scope)->setRootExpr($expr); } if ( @@ -2091,7 +2029,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif && $leftType->isArray()->yes() && $rightType->isConstantArray()->yes() && $rightType->isIterableAtLeastOnce()->no() ) { - return $this->create($expr->left, new NonEmptyArrayType(), $context->negate(), false, $scope, $rootExpr); + return $this->create($expr->left, new NonEmptyArrayType(), $context->negate(), $scope)->setRootExpr($expr); } if ( @@ -2100,26 +2038,26 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif || ($leftType->isFloat()->yes() && $rightType->isFloat()->yes()) || ($leftType->isEnum()->yes() && $rightType->isEnum()->yes()) ) { - return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context, $rootExpr); + return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Identical($expr->left, $expr->right), $context)->setRootExpr($expr); } $leftExprString = $this->exprPrinter->printExpr($expr->left); $rightExprString = $this->exprPrinter->printExpr($expr->right); if ($leftExprString === $rightExprString) { if (!$expr->left instanceof Expr\Variable || !$expr->right instanceof Expr\Variable) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } } - $leftTypes = $this->create($expr->left, $leftType, $context, false, $scope, $rootExpr); - $rightTypes = $this->create($expr->right, $rightType, $context, false, $scope, $rootExpr); + $leftTypes = $this->create($expr->left, $leftType, $context, $scope)->setRootExpr($expr); + $rightTypes = $this->create($expr->right, $rightType, $context, $scope)->setRootExpr($expr); return $context->true() ? $leftTypes->unionWith($rightTypes) : $leftTypes->normalize($scope)->intersectWith($rightTypes->normalize($scope)); } - public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, TypeSpecifierContext $context, ?Expr $rootExpr): SpecifiedTypes + public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes { // Normalize to: fn() === expr $leftExpr = $expr->left; @@ -2149,13 +2087,13 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty && $rightType->isInteger()->yes() ) { if (IntegerRangeType::fromInterval(null, -1)->isSuperTypeOf($rightType)->yes()) { - return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, false, $scope, $rootExpr); + return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, $scope)->setRootExpr($expr); } $argType = $scope->getType($unwrappedLeftExpr->getArgs()[0]->value); $isZero = (new ConstantIntegerType(0))->isSuperTypeOf($rightType); if ($isZero->yes()) { - $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr); + $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr); if ($context->truthy() && !$argType->isArray()->yes()) { $newArgType = new UnionType([ @@ -2167,12 +2105,12 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty } return $funcTypes->unionWith( - $this->create($unwrappedLeftExpr->getArgs()[0]->value, $newArgType, $context, false, $scope, $rootExpr), + $this->create($unwrappedLeftExpr->getArgs()[0]->value, $newArgType, $context, $scope)->setRootExpr($expr), ); } if ($argType instanceof UnionType) { - $narrowed = $this->narrowUnionByArraySize($unwrappedLeftExpr, $argType, $rightType, $context, $scope, $rootExpr); + $narrowed = $this->narrowUnionByArraySize($unwrappedLeftExpr, $argType, $rightType, $context, $scope, $expr); if ($narrowed !== null) { return $narrowed; } @@ -2184,18 +2122,18 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $argType->isConstantArray()->yes() && $rightType->isSuperTypeOf($argType->getArraySize())->no() ) { - return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, false, $scope, $rootExpr); + return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, $scope)->setRootExpr($expr); } - $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr); + $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr); $constArray = $this->turnListIntoConstantArray($unwrappedLeftExpr, $argType, $rightType, $scope); if ($constArray !== null) { return $funcTypes->unionWith( - $this->create($unwrappedLeftExpr->getArgs()[0]->value, $constArray, $context, false, $scope, $rootExpr), + $this->create($unwrappedLeftExpr->getArgs()[0]->value, $constArray, $context, $scope)->setRootExpr($expr), ); } elseif (IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($rightType)->yes()) { return $funcTypes->unionWith( - $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NonEmptyArrayType(), $context, false, $scope, $rootExpr), + $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NonEmptyArrayType(), $context, $scope)->setRootExpr($expr), ); } @@ -2214,27 +2152,27 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty && $rightType->isInteger()->yes() ) { if (IntegerRangeType::fromInterval(null, -1)->isSuperTypeOf($rightType)->yes()) { - return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, false, $scope, $rootExpr); + return $this->create($unwrappedLeftExpr->getArgs()[0]->value, new NeverType(), $context, $scope)->setRootExpr($expr); } $isZero = (new ConstantIntegerType(0))->isSuperTypeOf($rightType); if ($isZero->yes()) { - $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr); + $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr); return $funcTypes->unionWith( - $this->create($unwrappedLeftExpr->getArgs()[0]->value, new ConstantStringType(''), $context, false, $scope, $rootExpr), + $this->create($unwrappedLeftExpr->getArgs()[0]->value, new ConstantStringType(''), $context, $scope)->setRootExpr($expr), ); } if ($context->truthy() && IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($rightType)->yes()) { $argType = $scope->getType($unwrappedLeftExpr->getArgs()[0]->value); if ($argType->isString()->yes()) { - $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr); + $funcTypes = $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr); $accessory = new AccessoryNonEmptyStringType(); if (IntegerRangeType::fromInterval(2, null)->isSuperTypeOf($rightType)->yes()) { $accessory = new AccessoryNonFalsyStringType(); } - $valueTypes = $this->create($unwrappedLeftExpr->getArgs()[0]->value, $accessory, $context, false, $scope, $rootExpr); + $valueTypes = $this->create($unwrappedLeftExpr->getArgs()[0]->value, $accessory, $context, $scope)->setRootExpr($expr); return $funcTypes->unionWith($valueTypes); } @@ -2253,8 +2191,7 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $scope, $leftExpr, $context, - $rootExpr, - ); + )->setRootExpr($expr); } // get_class($a) === 'Foo' @@ -2270,10 +2207,8 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $unwrappedLeftExpr->getArgs()[0]->value, $rightType->getClassStringObjectType(), $context, - false, $scope, - $rootExpr, - )->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); + )->unionWith($this->create($leftExpr, $rightType, $context, $scope))->setRootExpr($expr); } } @@ -2298,25 +2233,23 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $unwrappedLeftExpr->getArgs()[0]->value, TypeCombinator::intersect($argType, new AccessoryNonFalsyStringType()), $context, - false, $scope, - ); + )->setRootExpr($expr); } return $this->create( $unwrappedLeftExpr->getArgs()[0]->value, TypeCombinator::intersect($argType, new AccessoryNonEmptyStringType()), $context, - false, $scope, - ); + )->setRootExpr($expr); } } if ($rightType->isString()->yes()) { $types = null; foreach ($rightType->getConstantStrings() as $constantString) { - $specifiedType = $this->specifyTypesForConstantStringBinaryExpression($unwrappedLeftExpr, $constantString, $context, $scope, $rootExpr); + $specifiedType = $this->specifyTypesForConstantStringBinaryExpression($unwrappedLeftExpr, $constantString, $context, $scope, $expr); if ($specifiedType === null) { continue; @@ -2331,7 +2264,7 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty if ($types !== null) { if ($leftExpr !== $unwrappedLeftExpr) { - $types = $types->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); + $types = $types->unionWith($this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr)); } return $types; } @@ -2347,11 +2280,11 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $unwrappedExprNode = $exprNode->getExpr(); } - $specifiedType = $this->specifyTypesForConstantBinaryExpression($unwrappedExprNode, $constantType, $context, $scope, $rootExpr); + $specifiedType = $this->specifyTypesForConstantBinaryExpression($unwrappedExprNode, $constantType, $context, $scope, $expr); if ($specifiedType !== null) { if ($exprNode !== $unwrappedExprNode) { $specifiedType = $specifiedType->unionWith( - $this->create($exprNode, $constantType, $context, false, $scope, $rootExpr), + $this->create($exprNode, $constantType, $context, $scope)->setRootExpr($expr), ); } return $specifiedType; @@ -2376,8 +2309,7 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty new Name($rightType->getValue()), ), $context, - $rootExpr, - )->unionWith($this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr)); + )->unionWith($this->create($leftExpr, $rightType, $context, $scope))->setRootExpr($expr); } $leftType = $scope->getType($leftExpr); @@ -2400,8 +2332,7 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty new Name($leftType->getValue()), ), $context, - $rootExpr, - )->unionWith($this->create($rightExpr, $leftType, $context, false, $scope, $rootExpr)); + )->unionWith($this->create($rightExpr, $leftType, $context, $scope)->setRootExpr($expr)); } if ($context->false()) { @@ -2409,16 +2340,16 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty if ($identicalType instanceof ConstantBooleanType) { $never = new NeverType(); $contextForTypes = $identicalType->getValue() ? $context->negate() : $context; - $leftTypes = $this->create($leftExpr, $never, $contextForTypes, false, $scope, $rootExpr); - $rightTypes = $this->create($rightExpr, $never, $contextForTypes, false, $scope, $rootExpr); + $leftTypes = $this->create($leftExpr, $never, $contextForTypes, $scope)->setRootExpr($expr); + $rightTypes = $this->create($rightExpr, $never, $contextForTypes, $scope)->setRootExpr($expr); if ($leftExpr instanceof AlwaysRememberedExpr) { $leftTypes = $leftTypes->unionWith( - $this->create($unwrappedLeftExpr, $never, $contextForTypes, false, $scope, $rootExpr), + $this->create($unwrappedLeftExpr, $never, $contextForTypes, $scope)->setRootExpr($expr), ); } if ($rightExpr instanceof AlwaysRememberedExpr) { $rightTypes = $rightTypes->unionWith( - $this->create($unwrappedRightExpr, $never, $contextForTypes, false, $scope, $rootExpr), + $this->create($unwrappedRightExpr, $never, $contextForTypes, $scope)->setRootExpr($expr), ); } return $leftTypes->unionWith($rightTypes); @@ -2438,19 +2369,15 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $rightExpr, $leftType, $context, - false, $scope, - $rootExpr, - ); + )->setRootExpr($expr); if ($rightExpr instanceof AlwaysRememberedExpr) { $types = $types->unionWith($this->create( $unwrappedRightExpr, $leftType, $context, - false, $scope, - $rootExpr, - )); + ))->setRootExpr($expr); } } if ( @@ -2466,19 +2393,15 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $leftExpr, $rightType, $context, - false, $scope, - $rootExpr, - ); + )->setRootExpr($expr); if ($leftExpr instanceof AlwaysRememberedExpr) { $leftTypes = $leftTypes->unionWith($this->create( $unwrappedLeftExpr, $rightType, $context, - false, $scope, - $rootExpr, - )); + ))->setRootExpr($expr); } if ($types !== null) { $types = $types->unionWith($leftTypes); @@ -2495,30 +2418,30 @@ public function resolveIdentical(Expr\BinaryOp\Identical $expr, Scope $scope, Ty $rightExprString = $this->exprPrinter->printExpr($unwrappedRightExpr); if ($leftExprString === $rightExprString) { if (!$unwrappedLeftExpr instanceof Expr\Variable || !$unwrappedRightExpr instanceof Expr\Variable) { - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } } if ($context->true()) { - $leftTypes = $this->create($leftExpr, $rightType, $context, false, $scope, $rootExpr); - $rightTypes = $this->create($rightExpr, $leftType, $context, false, $scope, $rootExpr); + $leftTypes = $this->create($leftExpr, $rightType, $context, $scope)->setRootExpr($expr); + $rightTypes = $this->create($rightExpr, $leftType, $context, $scope)->setRootExpr($expr); if ($leftExpr instanceof AlwaysRememberedExpr) { $leftTypes = $leftTypes->unionWith( - $this->create($unwrappedLeftExpr, $rightType, $context, false, $scope, $rootExpr), + $this->create($unwrappedLeftExpr, $rightType, $context, $scope)->setRootExpr($expr), ); } if ($rightExpr instanceof AlwaysRememberedExpr) { $rightTypes = $rightTypes->unionWith( - $this->create($unwrappedRightExpr, $leftType, $context, false, $scope, $rootExpr), + $this->create($unwrappedRightExpr, $leftType, $context, $scope)->setRootExpr($expr), ); } return $leftTypes->unionWith($rightTypes); } elseif ($context->false()) { - return $this->create($leftExpr, $leftType, $context, false, $scope, $rootExpr)->normalize($scope) - ->intersectWith($this->create($rightExpr, $rightType, $context, false, $scope, $rootExpr)->normalize($scope)); + return $this->create($leftExpr, $leftType, $context, $scope)->setRootExpr($expr)->normalize($scope) + ->intersectWith($this->create($rightExpr, $rightType, $context, $scope)->setRootExpr($expr)->normalize($scope)); } - return new SpecifiedTypes([], [], false, [], $rootExpr); + return (new SpecifiedTypes([], []))->setRootExpr($expr); } } diff --git a/src/Analyser/TypeSpecifierContext.php b/src/Analyser/TypeSpecifierContext.php index 3cd0ead0f9..fe09aa861c 100644 --- a/src/Analyser/TypeSpecifierContext.php +++ b/src/Analyser/TypeSpecifierContext.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class TypeSpecifierContext +final class TypeSpecifierContext { public const CONTEXT_TRUE = 0b0001; diff --git a/src/Analyser/TypeSpecifierFactory.php b/src/Analyser/TypeSpecifierFactory.php index 60219c3b6d..83315b6e0c 100644 --- a/src/Analyser/TypeSpecifierFactory.php +++ b/src/Analyser/TypeSpecifierFactory.php @@ -5,6 +5,7 @@ use PHPStan\Broker\BrokerFactory; use PHPStan\DependencyInjection\Container; use PHPStan\Node\Printer\ExprPrinter; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ReflectionProvider; use function array_merge; @@ -24,6 +25,7 @@ public function create(): TypeSpecifier $typeSpecifier = new TypeSpecifier( $this->container->getByType(ExprPrinter::class), $this->container->getByType(ReflectionProvider::class), + $this->container->getByType(PhpVersion::class), $this->container->getServicesByTag(self::FUNCTION_TYPE_SPECIFYING_EXTENSION_TAG), $this->container->getServicesByTag(self::METHOD_TYPE_SPECIFYING_EXTENSION_TAG), $this->container->getServicesByTag(self::STATIC_METHOD_TYPE_SPECIFYING_EXTENSION_TAG), diff --git a/src/Broker/Broker.php b/src/Broker/Broker.php deleted file mode 100644 index 8db42d1f45..0000000000 --- a/src/Broker/Broker.php +++ /dev/null @@ -1,147 +0,0 @@ -reflectionProvider->hasClass($className); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function getClass(string $className): ClassReflection - { - return $this->reflectionProvider->getClass($className); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function getClassName(string $className): string - { - return $this->reflectionProvider->getClassName($className); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function supportsAnonymousClasses(): bool - { - return $this->reflectionProvider->supportsAnonymousClasses(); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope): ClassReflection - { - return $this->reflectionProvider->getAnonymousClassReflection($classNode, $scope); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function hasFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool - { - return $this->reflectionProvider->hasFunction($nameNode, $namespaceAnswerer); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function getFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): FunctionReflection - { - return $this->reflectionProvider->getFunction($nameNode, $namespaceAnswerer); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function resolveFunctionName(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ?string - { - return $this->reflectionProvider->resolveFunctionName($nameNode, $namespaceAnswerer); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function hasConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool - { - return $this->reflectionProvider->hasConstant($nameNode, $namespaceAnswerer); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): GlobalConstantReflection - { - return $this->reflectionProvider->getConstant($nameNode, $namespaceAnswerer); - } - - /** - * @deprecated Use PHPStan\Reflection\ReflectionProvider instead - */ - public function resolveConstantName(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ?string - { - return $this->reflectionProvider->resolveConstantName($nameNode, $namespaceAnswerer); - } - - /** - * @deprecated Inject %universalObjectCratesClasses% parameter instead. - * - * @return string[] - */ - public function getUniversalObjectCratesClasses(): array - { - return $this->universalObjectCratesClasses; - } - -} diff --git a/src/Broker/BrokerFactory.php b/src/Broker/BrokerFactory.php index 177b6b5843..bbd8d97a3d 100644 --- a/src/Broker/BrokerFactory.php +++ b/src/Broker/BrokerFactory.php @@ -2,9 +2,6 @@ namespace PHPStan\Broker; -use PHPStan\DependencyInjection\Container; -use PHPStan\Reflection\ReflectionProvider; - final class BrokerFactory { @@ -17,16 +14,4 @@ final class BrokerFactory public const OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG = 'phpstan.broker.operatorTypeSpecifyingExtension'; public const EXPRESSION_TYPE_RESOLVER_EXTENSION_TAG = 'phpstan.broker.expressionTypeResolverExtension'; - public function __construct(private Container $container) - { - } - - public function create(): Broker - { - return new Broker( - $this->container->getByType(ReflectionProvider::class), - $this->container->getParameter('universalObjectCratesClasses'), - ); - } - } diff --git a/src/Cache/FileCacheStorage.php b/src/Cache/FileCacheStorage.php index 5ba76a768a..1b66f26e2a 100644 --- a/src/Cache/FileCacheStorage.php +++ b/src/Cache/FileCacheStorage.php @@ -4,16 +4,31 @@ use InvalidArgumentException; use Nette\Utils\Random; +use PHPStan\File\CouldNotReadFileException; +use PHPStan\File\CouldNotWriteFileException; +use PHPStan\File\FileReader; use PHPStan\File\FileWriter; use PHPStan\Internal\DirectoryCreator; use PHPStan\Internal\DirectoryCreatorException; use PHPStan\ShouldNotHappenException; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use function array_keys; +use function closedir; +use function dirname; use function error_get_last; +use function is_dir; use function is_file; +use function opendir; +use function readdir; use function rename; +use function rmdir; use function sha1; use function sprintf; +use function str_starts_with; +use function strlen; use function substr; +use function uksort; use function unlink; use function var_export; use const DIRECTORY_SEPARATOR; @@ -21,6 +36,8 @@ final class FileCacheStorage implements CacheStorage { + private const CACHED_CLEARED_VERSION = 'v2-new'; + public function __construct(private string $directory) { } @@ -100,4 +117,90 @@ private function getFilePaths(string $key): array ]; } + public function clearUnusedFiles(): void + { + if (!is_dir($this->directory)) { + return; + } + + $cachedClearedFile = $this->directory . '/cache-cleared'; + if (is_file($cachedClearedFile)) { + try { + $cachedClearedContents = FileReader::read($cachedClearedFile); + if ($cachedClearedContents === self::CACHED_CLEARED_VERSION) { + return; + } + } catch (CouldNotReadFileException) { + return; + } + } + + $iterator = new RecursiveDirectoryIterator($this->directory); + $iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS); + $files = new RecursiveIteratorIterator($iterator); + $beginFunction = sprintf( + "getPathname(); + $contents = FileReader::read($path); + if ( + !str_starts_with($contents, $beginFunction) + && !str_starts_with($contents, $beginMethod) + && str_starts_with($contents, $beginNew) + ) { + continue; + } + + $emptyDirectoriesToCheck[dirname($path)] = true; + $emptyDirectoriesToCheck[dirname($path, 2)] = true; + + @unlink($path); + } catch (CouldNotReadFileException) { + continue; + } + } + + uksort($emptyDirectoriesToCheck, static fn ($a, $b) => strlen($b) - strlen($a)); + + foreach (array_keys($emptyDirectoriesToCheck) as $directory) { + if (!$this->isDirectoryEmpty($directory)) { + continue; + } + + @rmdir($directory); + } + + try { + FileWriter::write($cachedClearedFile, self::CACHED_CLEARED_VERSION); + } catch (CouldNotWriteFileException) { + // pass + } + } + + private function isDirectoryEmpty(string $directory): bool + { + $handle = opendir($directory); + if ($handle === false) { + return false; + } + while (($entry = readdir($handle)) !== false) { + if ($entry !== '.' && $entry !== '..') { + closedir($handle); + return false; + } + } + + closedir($handle); + return true; + } + } diff --git a/src/Collectors/CollectedData.php b/src/Collectors/CollectedData.php index e6817382b6..1ae0078880 100644 --- a/src/Collectors/CollectedData.php +++ b/src/Collectors/CollectedData.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class CollectedData implements JsonSerializable +final class CollectedData implements JsonSerializable { /** diff --git a/src/Command/AnalyseCommand.php b/src/Command/AnalyseCommand.php index a112f22235..a81115e108 100644 --- a/src/Command/AnalyseCommand.php +++ b/src/Command/AnalyseCommand.php @@ -171,6 +171,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $level, $allowXdebug, $debugEnabled, + true, ); } catch (InceptionNotSuccessfulException $e) { return 1; @@ -182,15 +183,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $errorOutput = $inceptionResult->getErrorOutput(); - $obsoleteDockerImage = $_SERVER['PHPSTAN_OBSOLETE_DOCKER_IMAGE'] ?? 'false'; - if ($obsoleteDockerImage === 'true') { - $errorOutput->writeLineFormatted('⚠️ You\'re using an obsolete PHPStan Docker image. ⚠️️'); - $errorOutput->writeLineFormatted(' You can obtain the current one from ghcr.io/phpstan/phpstan.'); - $errorOutput->writeLineFormatted(' Read more about it here:'); - $errorOutput->writeLineFormatted(' https://phpstan.org/user-guide/docker'); - $errorOutput->writeLineFormatted(''); - } - $errorFormat = $input->getOption('error-format'); if (!is_string($errorFormat) && $errorFormat !== null) { @@ -243,17 +235,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (count($files) === 0) { - $bleedingEdge = (bool) $container->getParameter('featureToggles')['zeroFiles']; - $this->runDiagnoseExtensions($container, $inceptionResult->getErrorOutput()); - if (!$bleedingEdge) { - $inceptionResult->getErrorOutput()->getStyle()->note('No files found to analyse.'); - $inceptionResult->getErrorOutput()->getStyle()->warning('This will cause a non-zero exit code in PHPStan 2.0.'); - - return $inceptionResult->handleReturn(0, null, $this->analysisStartTime); - } - $inceptionResult->getErrorOutput()->getStyle()->error('No files found to analyse.'); return $inceptionResult->handleReturn(1, null, $this->analysisStartTime); @@ -511,12 +494,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $errorOutput->writeLineFormatted(''); - $bleedingEdge = (bool) $container->getParameter('featureToggles')['projectServicesNotInAnalysedPaths']; - if ($bleedingEdge) { - return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes(), $this->analysisStartTime); - } - - $errorOutput->getStyle()->warning('This will cause a non-zero exit code in PHPStan 2.0.'); + return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes(), $this->analysisStartTime); } } diff --git a/src/Command/AnalysisResult.php b/src/Command/AnalysisResult.php index 6ddf536bc1..1697b5f38a 100644 --- a/src/Command/AnalysisResult.php +++ b/src/Command/AnalysisResult.php @@ -5,15 +5,13 @@ use PHPStan\Analyser\Error; use PHPStan\Analyser\InternalError; use PHPStan\Collectors\CollectedData; -use function array_map; use function count; use function usort; /** * @api - * @final */ -class AnalysisResult +final class AnalysisResult { /** @var list sorted by their file name, line number and message */ @@ -83,15 +81,6 @@ public function getNotFileSpecificErrors(): array return $this->notFileSpecificErrors; } - /** - * @deprecated Use getInternalErrorObjects - * @return list - */ - public function getInternalErrors(): array - { - return array_map(static fn (InternalError $internalError) => $internalError->getMessage(), $this->internalErrors); - } - /** * @return list */ diff --git a/src/Command/ClearResultCacheCommand.php b/src/Command/ClearResultCacheCommand.php index 89e3c45ee7..ac41019e2b 100644 --- a/src/Command/ClearResultCacheCommand.php +++ b/src/Command/ClearResultCacheCommand.php @@ -81,6 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int '0', $allowXdebug, $debugEnabled, + true, ); } catch (InceptionNotSuccessfulException) { return 1; diff --git a/src/Command/CommandHelper.php b/src/Command/CommandHelper.php index b0219c9fac..499ebb48e8 100644 --- a/src/Command/CommandHelper.php +++ b/src/Command/CommandHelper.php @@ -12,7 +12,7 @@ use Nette\Schema\ValidationException; use Nette\Utils\AssertionException; use Nette\Utils\Strings; -use PHPStan\Analyser\MutatingScope; +use PHPStan\Cache\FileCacheStorage; use PHPStan\Command\Symfony\SymfonyOutput; use PHPStan\Command\Symfony\SymfonyStyle; use PHPStan\DependencyInjection\Container; @@ -89,8 +89,8 @@ public static function begin( ?string $generateBaselineFile, ?string $level, bool $allowXdebug, - bool $debugEnabled = false, - bool $cleanupContainerCache = true, + bool $debugEnabled, + bool $cleanupContainerCache, ): InceptionResult { $stdOutput = new SymfonyOutput($output, new SymfonyStyle(new ErrorsConsoleStyle($input, $output))); @@ -212,7 +212,10 @@ public static function begin( $paths = array_map(static fn (string $path): string => $currentWorkingDirectoryFileHelper->normalizePath($currentWorkingDirectoryFileHelper->absolutizePath($path)), $paths); $analysedPathsFromConfig = []; - $containerFactory = new ContainerFactory($currentWorkingDirectory, true); + $containerFactory = new ContainerFactory($currentWorkingDirectory); + if ($cleanupContainerCache) { + $containerFactory->setJournalContainer(); + } $projectConfig = null; if ($projectConfigFile !== null) { if (!is_file($projectConfigFile)) { @@ -434,7 +437,10 @@ public static function begin( } if ($cleanupContainerCache) { - $containerFactory->clearOldContainers($tmpDir); + $cacheStorage = $container->getService('cacheStorage'); + if ($cacheStorage instanceof FileCacheStorage) { + $cacheStorage->clearUnusedFiles(); + } } /** @var bool|null $customRulesetUsed */ @@ -524,74 +530,6 @@ public static function begin( throw new InceptionNotSuccessfulException(); } - $excludesAnalyse = $container->getParameter('excludes_analyse'); - $excludePaths = $container->getParameter('excludePaths'); - if (count($excludesAnalyse) > 0 && $excludePaths !== null) { - $errorOutput->writeLineFormatted(sprintf('Configuration parameters excludes_analyse and excludePaths cannot be used at the same time.')); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted(sprintf('Parameter excludes_analyse has been deprecated so use excludePaths only from now on.')); - $errorOutput->writeLineFormatted(''); - - throw new InceptionNotSuccessfulException(); - } elseif (count($excludesAnalyse) > 0) { - $errorOutput->writeLineFormatted('⚠️ You\'re using a deprecated config option excludes_analyse. ⚠️️'); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted(sprintf('Parameter excludes_analyse has been deprecated so use excludePaths only from now on.')); - } - - if ($container->hasParameter('scopeClass') && $container->getParameter('scopeClass') !== MutatingScope::class) { - $errorOutput->writeLineFormatted('⚠️ You\'re using a deprecated config option scopeClass. ⚠️️'); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted(sprintf('Please implement PHPStan\Type\ExpressionTypeResolverExtension interface instead and register it as a service.')); - } - - if ($projectConfig !== null) { - $parameters = $projectConfig['parameters'] ?? []; - /** @var bool $checkMissingIterableValueType */ - $checkMissingIterableValueType = $parameters['checkMissingIterableValueType'] ?? true; - if (!$checkMissingIterableValueType) { - $errorOutput->writeLineFormatted('⚠️ You\'re using a deprecated config option checkMissingIterableValueType ⚠️️'); - $errorOutput->writeLineFormatted(''); - - $featureToggles = $container->getParameter('featureToggles'); - if (!((bool) $featureToggles['bleedingEdge'])) { - $errorOutput->writeLineFormatted('It\'s strongly recommended to remove it from your configuration file'); - $errorOutput->writeLineFormatted('and add the missing array typehints.'); - $errorOutput->writeLineFormatted(''); - } - - $errorOutput->writeLineFormatted('If you want to continue ignoring missing typehints from arrays,'); - $errorOutput->writeLineFormatted('add missingType.iterableValue error identifier to your ignoreErrors:'); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted('parameters:'); - $errorOutput->writeLineFormatted("\tignoreErrors:"); - $errorOutput->writeLineFormatted("\t\t-"); - $errorOutput->writeLineFormatted("\t\t\tidentifier: missingType.iterableValue"); - $errorOutput->writeLineFormatted(''); - } - - /** @var bool $checkGenericClassInNonGenericObjectType */ - $checkGenericClassInNonGenericObjectType = $parameters['checkGenericClassInNonGenericObjectType'] ?? true; - if (!$checkGenericClassInNonGenericObjectType) { - $errorOutput->writeLineFormatted('⚠️ You\'re using a deprecated config option checkGenericClassInNonGenericObjectType ⚠️️'); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted('It\'s strongly recommended to remove it from your configuration file'); - $errorOutput->writeLineFormatted('and add the missing generic typehints.'); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted('If you want to continue ignoring missing typehints from generics,'); - $errorOutput->writeLineFormatted('add missingType.generics error identifier to your ignoreErrors:'); - $errorOutput->writeLineFormatted(''); - $errorOutput->writeLineFormatted('parameters:'); - $errorOutput->writeLineFormatted("\tignoreErrors:"); - $errorOutput->writeLineFormatted("\t\t-"); - $errorOutput->writeLineFormatted("\t\t\tidentifier: missingType.generics"); - $errorOutput->writeLineFormatted(''); - } - } - - $tempResultCachePath = $container->getParameter('tempResultCachePath'); - $createDir($tempResultCachePath); - /** @var FileFinder $fileFinder */ $fileFinder = $container->getService('fileFinderAnalyse'); @@ -609,7 +547,7 @@ public static function begin( $pathRoutingParser->setAnalysedFiles($files); - $stubFilesExcluder = new FileExcluder($currentWorkingDirectoryFileHelper, $stubFilesProvider->getProjectStubFiles(), true); + $stubFilesExcluder = new FileExcluder($currentWorkingDirectoryFileHelper, $stubFilesProvider->getProjectStubFiles()); $files = array_values(array_filter($files, static fn (string $file) => !$stubFilesExcluder->isExcludedFromAnalysing($file))); diff --git a/src/Command/DiagnoseCommand.php b/src/Command/DiagnoseCommand.php index 2f8a5a47b0..5a9f17e0ab 100644 --- a/src/Command/DiagnoseCommand.php +++ b/src/Command/DiagnoseCommand.php @@ -79,6 +79,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int null, $level, false, + false, + false, ); } catch (InceptionNotSuccessfulException) { return 1; diff --git a/src/Command/DumpParametersCommand.php b/src/Command/DumpParametersCommand.php index b3085db0c6..ccb8188933 100644 --- a/src/Command/DumpParametersCommand.php +++ b/src/Command/DumpParametersCommand.php @@ -81,6 +81,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int null, $level, false, + false, + false, ); } catch (InceptionNotSuccessfulException) { return 1; diff --git a/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php b/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php index b6dd1e2c2f..ac02e1f9e1 100644 --- a/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php +++ b/src/Command/ErrorFormatter/BaselineNeonErrorFormatter.php @@ -9,6 +9,7 @@ use PHPStan\Command\Output; use PHPStan\File\RelativePathHelper; use PHPStan\ShouldNotHappenException; +use function count; use function ksort; use function preg_quote; use function substr; @@ -37,29 +38,57 @@ public function formatErrors( if (!$fileSpecificError->canBeIgnored()) { continue; } - $fileErrors[$this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError->getMessage(); + $fileErrors[$this->relativePathHelper->getRelativePath($fileSpecificError->getFilePath())][] = $fileSpecificError; } ksort($fileErrors, SORT_STRING); $errorsToOutput = []; - foreach ($fileErrors as $file => $errorMessages) { - $fileErrorsCounts = []; - foreach ($errorMessages as $errorMessage) { - if (!isset($fileErrorsCounts[$errorMessage])) { - $fileErrorsCounts[$errorMessage] = 1; + foreach ($fileErrors as $file => $errors) { + $fileErrorsByMessage = []; + foreach ($errors as $error) { + $errorMessage = $error->getMessage(); + $identifier = $error->getIdentifier(); + if (!isset($fileErrorsByMessage[$errorMessage])) { + $fileErrorsByMessage[$errorMessage] = [ + 1, + $identifier !== null ? [$identifier => 1] : [], + ]; continue; } - $fileErrorsCounts[$errorMessage]++; + $fileErrorsByMessage[$errorMessage][0]++; + + if ($identifier === null) { + continue; + } + + if (!isset($fileErrorsByMessage[$errorMessage][1][$identifier])) { + $fileErrorsByMessage[$errorMessage][1][$identifier] = 1; + continue; + } + + $fileErrorsByMessage[$errorMessage][1][$identifier]++; } - ksort($fileErrorsCounts, SORT_STRING); - - foreach ($fileErrorsCounts as $message => $count) { - $errorsToOutput[] = [ - 'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'), - 'count' => $count, - 'path' => Helpers::escape($file), - ]; + ksort($fileErrorsByMessage, SORT_STRING); + + foreach ($fileErrorsByMessage as $message => [$totalCount, $identifiers]) { + ksort($identifiers, SORT_STRING); + if (count($identifiers) > 0) { + foreach ($identifiers as $identifier => $identifierCount) { + $errorsToOutput[] = [ + 'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'), + 'identifier' => $identifier, + 'count' => $identifierCount, + 'path' => Helpers::escape($file), + ]; + } + } else { + $errorsToOutput[] = [ + 'message' => Helpers::escape('#^' . preg_quote($message, '#') . '$#'), + 'count' => $totalCount, + 'path' => Helpers::escape($file), + ]; + } } } diff --git a/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php b/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php index 8107aba19b..65cafffb9f 100644 --- a/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php +++ b/src/Command/ErrorFormatter/BaselinePhpErrorFormatter.php @@ -6,12 +6,9 @@ use PHPStan\Command\AnalysisResult; use PHPStan\Command\Output; use PHPStan\File\RelativePathHelper; -use function array_keys; use function count; -use function implode; use function ksort; use function preg_quote; -use function sort; use function sprintf; use function var_export; use const SORT_STRING; @@ -54,42 +51,50 @@ public function formatErrors( $fileErrorsByMessage = []; foreach ($errors as $error) { $errorMessage = $error->getMessage(); + $identifier = $error->getIdentifier(); if (!isset($fileErrorsByMessage[$errorMessage])) { $fileErrorsByMessage[$errorMessage] = [ 1, - $error->getIdentifier() !== null ? [$error->getIdentifier() => true] : [], + $identifier !== null ? [$identifier => 1] : [], ]; continue; } $fileErrorsByMessage[$errorMessage][0]++; - if ($error->getIdentifier() === null) { + if ($identifier === null) { continue; } - $fileErrorsByMessage[$errorMessage][1][$error->getIdentifier()] = true; + + if (!isset($fileErrorsByMessage[$errorMessage][1][$identifier])) { + $fileErrorsByMessage[$errorMessage][1][$identifier] = 1; + continue; + } + + $fileErrorsByMessage[$errorMessage][1][$identifier]++; } ksort($fileErrorsByMessage, SORT_STRING); - foreach ($fileErrorsByMessage as $message => [$count, $identifiersInKeys]) { - $identifiers = array_keys($identifiersInKeys); - sort($identifiers); - $identifiersComment = ''; + foreach ($fileErrorsByMessage as $message => [$totalCount, $identifiers]) { + ksort($identifiers, SORT_STRING); if (count($identifiers) > 0) { - if (count($identifiers) === 1) { - $identifiersComment = "\n\t// identifier: " . $identifiers[0]; - } else { - $identifiersComment = "\n\t// identifiers: " . implode(', ', $identifiers); + foreach ($identifiers as $identifier => $identifierCount) { + $php .= sprintf( + "\$ignoreErrors[] = [\n\t'message' => %s,\n\t'identifier' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n", + var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true), + var_export(Helpers::escape($identifier), true), + var_export($identifierCount, true), + var_export(Helpers::escape($file), true), + ); } + } else { + $php .= sprintf( + "\$ignoreErrors[] = [\n\t'message' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n", + var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true), + var_export($totalCount, true), + var_export(Helpers::escape($file), true), + ); } - - $php .= sprintf( - "\$ignoreErrors[] = [%s\n\t'message' => %s,\n\t'count' => %d,\n\t'path' => __DIR__ . %s,\n];\n", - $identifiersComment, - var_export(Helpers::escape('#^' . preg_quote($message, '#') . '$#'), true), - var_export($count, true), - var_export(Helpers::escape($file), true), - ); } } diff --git a/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php b/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php index a6c66bbafb..38d0a67439 100644 --- a/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php +++ b/src/Command/ErrorFormatter/CiDetectedErrorFormatter.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class CiDetectedErrorFormatter implements ErrorFormatter +final class CiDetectedErrorFormatter implements ErrorFormatter { public function __construct( diff --git a/src/Command/ErrorFormatter/TableErrorFormatter.php b/src/Command/ErrorFormatter/TableErrorFormatter.php index fb3d949c4e..7da56bdff1 100644 --- a/src/Command/ErrorFormatter/TableErrorFormatter.php +++ b/src/Command/ErrorFormatter/TableErrorFormatter.php @@ -9,12 +9,10 @@ use PHPStan\File\RelativePathHelper; use PHPStan\File\SimpleRelativePathHelper; use Symfony\Component\Console\Formatter\OutputFormatter; -use function array_key_exists; use function array_map; use function count; use function explode; use function getenv; -use function in_array; use function is_string; use function ltrim; use function sprintf; @@ -69,36 +67,12 @@ public function formatErrors( /** @var array $fileErrors */ $fileErrors = []; - $outputIdentifiers = $output->isVerbose(); - $outputIdentifiersInFile = []; foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { if (!isset($fileErrors[$fileSpecificError->getFile()])) { $fileErrors[$fileSpecificError->getFile()] = []; } $fileErrors[$fileSpecificError->getFile()][] = $fileSpecificError; - if ($outputIdentifiers) { - continue; - } - - $filePath = $fileSpecificError->getTraitFilePath() ?? $fileSpecificError->getFilePath(); - if (array_key_exists($filePath, $outputIdentifiersInFile)) { - continue; - } - - if ($fileSpecificError->getIdentifier() === null) { - continue; - } - - if (!in_array($fileSpecificError->getIdentifier(), [ - 'ignore.unmatchedIdentifier', - 'ignore.parseError', - 'ignore.unmatched', - ], true)) { - continue; - } - - $outputIdentifiersInFile[$filePath] = true; } foreach ($fileErrors as $file => $errors) { @@ -106,7 +80,7 @@ public function formatErrors( foreach ($errors as $error) { $message = $error->getMessage(); $filePath = $error->getTraitFilePath() ?? $error->getFilePath(); - if (($outputIdentifiers || array_key_exists($filePath, $outputIdentifiersInFile)) && $error->getIdentifier() !== null && $error->canBeIgnored()) { + if ($error->getIdentifier() !== null && $error->canBeIgnored()) { $message .= "\n"; $message .= '🪪 ' . $error->getIdentifier(); } diff --git a/src/Command/FixerApplication.php b/src/Command/FixerApplication.php index 40668741d9..1a9e64d7fe 100644 --- a/src/Command/FixerApplication.php +++ b/src/Command/FixerApplication.php @@ -303,7 +303,7 @@ private function downloadPhar( ): void { $currentVersion = null; - $branch = '1.1.x'; + $branch = '2.0.x'; if (is_file($pharPath) && is_file($infoPath)) { /** @var array{version: string, date: string, branch?: string} $currentInfo */ $currentInfo = Json::decode(FileReader::read($infoPath), Json::FORCE_ARRAY); diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php index 231db1ba7d..d8d87fd352 100644 --- a/src/Dependency/DependencyResolver.php +++ b/src/Dependency/DependencyResolver.php @@ -16,13 +16,12 @@ use PHPStan\Node\InClassMethodNode; use PHPStan\Node\InFunctionNode; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ClosureType; use PHPStan\Type\FileTypeMapper; -use PHPStan\Type\ParserNodeTypeToPHPStanType; use PHPStan\Type\Type; use function array_merge; use function count; @@ -85,9 +84,8 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies } } } elseif ($node instanceof ClassPropertyNode) { - $nativeTypeNode = $node->getNativeType(); - if ($nativeTypeNode !== null) { - $nativeType = ParserNodeTypeToPHPStanType::resolve($nativeTypeNode, $node->getClassReflection()); + $nativeType = $node->getNativeType(); + if ($nativeType !== null) { foreach ($nativeType->getReferencedClasses() as $referencedClass) { $this->addClassToDependencies($referencedClass, $dependenciesReflections); } @@ -171,7 +169,7 @@ public function resolveDependencies(Node $node, Scope $scope): NodeDependencies } foreach ($variant->getParameters() as $parameter) { - if (!$parameter instanceof ParameterReflectionWithPhpDocs) { + if (!$parameter instanceof ExtendedParameterReflection) { continue; } if ($parameter->getOutType() !== null) { @@ -476,12 +474,8 @@ 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(); + return $itemType->isClassString()->yes(); } /** @@ -630,7 +624,7 @@ private function getFunctionReflection(Node\Name $nameNode, ?Scope $scope): Func * @param array $dependenciesReflections */ private function extractFromParametersAcceptor( - ParametersAcceptorWithPhpDocs $parametersAcceptor, + ExtendedParametersAcceptor $parametersAcceptor, array &$dependenciesReflections, ): void { diff --git a/src/Dependency/ExportedNode/ExportedAttributeNode.php b/src/Dependency/ExportedNode/ExportedAttributeNode.php index 5612e74ea1..f7d00465ad 100644 --- a/src/Dependency/ExportedNode/ExportedAttributeNode.php +++ b/src/Dependency/ExportedNode/ExportedAttributeNode.php @@ -45,9 +45,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -72,9 +71,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedClassConstantNode.php b/src/Dependency/ExportedNode/ExportedClassConstantNode.php index 8827656c48..2aec4d44fa 100644 --- a/src/Dependency/ExportedNode/ExportedClassConstantNode.php +++ b/src/Dependency/ExportedNode/ExportedClassConstantNode.php @@ -45,9 +45,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -58,9 +57,8 @@ public static function __set_state(array $properties): ExportedNode /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedClassConstantsNode.php b/src/Dependency/ExportedNode/ExportedClassConstantsNode.php index 23ebd61ae0..e555874fc7 100644 --- a/src/Dependency/ExportedNode/ExportedClassConstantsNode.php +++ b/src/Dependency/ExportedNode/ExportedClassConstantsNode.php @@ -54,9 +54,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['constants'], @@ -69,9 +68,8 @@ public static function __set_state(array $properties): ExportedNode /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( array_map(static function (array $constantData): ExportedClassConstantNode { diff --git a/src/Dependency/ExportedNode/ExportedClassNode.php b/src/Dependency/ExportedNode/ExportedClassNode.php index b420a0a9ad..cb57bddb4c 100644 --- a/src/Dependency/ExportedNode/ExportedClassNode.php +++ b/src/Dependency/ExportedNode/ExportedClassNode.php @@ -96,9 +96,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -139,9 +138,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedEnumCaseNode.php b/src/Dependency/ExportedNode/ExportedEnumCaseNode.php index 19f8f6a22b..65b3273315 100644 --- a/src/Dependency/ExportedNode/ExportedEnumCaseNode.php +++ b/src/Dependency/ExportedNode/ExportedEnumCaseNode.php @@ -37,9 +37,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -50,9 +49,8 @@ public static function __set_state(array $properties): ExportedNode /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedEnumNode.php b/src/Dependency/ExportedNode/ExportedEnumNode.php index ea5ce3970b..b703518ab9 100644 --- a/src/Dependency/ExportedNode/ExportedEnumNode.php +++ b/src/Dependency/ExportedNode/ExportedEnumNode.php @@ -76,9 +76,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -111,9 +110,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedFunctionNode.php b/src/Dependency/ExportedNode/ExportedFunctionNode.php index c7e98d3643..d0ebd50613 100644 --- a/src/Dependency/ExportedNode/ExportedFunctionNode.php +++ b/src/Dependency/ExportedNode/ExportedFunctionNode.php @@ -74,9 +74,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -109,9 +108,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedInterfaceNode.php b/src/Dependency/ExportedNode/ExportedInterfaceNode.php index ef72841c5e..0e6d6632db 100644 --- a/src/Dependency/ExportedNode/ExportedInterfaceNode.php +++ b/src/Dependency/ExportedNode/ExportedInterfaceNode.php @@ -56,9 +56,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -87,9 +86,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedMethodNode.php b/src/Dependency/ExportedNode/ExportedMethodNode.php index 817482ef93..af2b4255ce 100644 --- a/src/Dependency/ExportedNode/ExportedMethodNode.php +++ b/src/Dependency/ExportedNode/ExportedMethodNode.php @@ -83,9 +83,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -128,9 +127,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedParameterNode.php b/src/Dependency/ExportedNode/ExportedParameterNode.php index c4a7769e28..9f4cf02d61 100644 --- a/src/Dependency/ExportedNode/ExportedParameterNode.php +++ b/src/Dependency/ExportedNode/ExportedParameterNode.php @@ -51,9 +51,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['name'], @@ -86,9 +85,8 @@ public function jsonSerialize() /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['name'], diff --git a/src/Dependency/ExportedNode/ExportedPhpDocNode.php b/src/Dependency/ExportedNode/ExportedPhpDocNode.php index a39cb4ef8a..9288a58107 100644 --- a/src/Dependency/ExportedNode/ExportedPhpDocNode.php +++ b/src/Dependency/ExportedNode/ExportedPhpDocNode.php @@ -48,18 +48,16 @@ public function jsonSerialize() /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self($properties['phpDocString'], $properties['namespace'], $properties['uses'], $properties['constUses'] ?? []); } /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self($data['phpDocString'], $data['namespace'], $data['uses'], $data['constUses'] ?? []); } diff --git a/src/Dependency/ExportedNode/ExportedPropertiesNode.php b/src/Dependency/ExportedNode/ExportedPropertiesNode.php index de0b4d2b49..af58d51738 100644 --- a/src/Dependency/ExportedNode/ExportedPropertiesNode.php +++ b/src/Dependency/ExportedNode/ExportedPropertiesNode.php @@ -76,9 +76,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['names'], @@ -94,9 +93,8 @@ public static function __set_state(array $properties): ExportedNode /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['names'], diff --git a/src/Dependency/ExportedNode/ExportedTraitNode.php b/src/Dependency/ExportedNode/ExportedTraitNode.php index f0f47ae021..8f6808f2b3 100644 --- a/src/Dependency/ExportedNode/ExportedTraitNode.php +++ b/src/Dependency/ExportedNode/ExportedTraitNode.php @@ -21,18 +21,16 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self($properties['traitName']); } /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self($data['traitName']); } diff --git a/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php b/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php index 38e9227624..85c515fac4 100644 --- a/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php +++ b/src/Dependency/ExportedNode/ExportedTraitUseAdaptation.php @@ -59,9 +59,8 @@ public function equals(ExportedNode $node): bool /** * @param mixed[] $properties - * @return self */ - public static function __set_state(array $properties): ExportedNode + public static function __set_state(array $properties): self { return new self( $properties['traitName'], @@ -74,9 +73,8 @@ public static function __set_state(array $properties): ExportedNode /** * @param mixed[] $data - * @return self */ - public static function decode(array $data): ExportedNode + public static function decode(array $data): self { return new self( $data['traitName'], diff --git a/src/Dependency/ExportedNodeResolver.php b/src/Dependency/ExportedNodeResolver.php index 8e6eb17f61..441c785c99 100644 --- a/src/Dependency/ExportedNodeResolver.php +++ b/src/Dependency/ExportedNodeResolver.php @@ -294,7 +294,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/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/DependencyInjection/Configurator.php b/src/DependencyInjection/Configurator.php index 31886c52bf..9536925b9d 100644 --- a/src/DependencyInjection/Configurator.php +++ b/src/DependencyInjection/Configurator.php @@ -2,15 +2,31 @@ namespace PHPStan\DependencyInjection; +use DirectoryIterator; use Nette\DI\Config\Loader; use Nette\DI\Container as OriginalNetteContainer; use Nette\DI\ContainerLoader; use PHPStan\File\CouldNotReadFileException; +use PHPStan\File\CouldNotWriteFileException; +use PHPStan\File\FileReader; +use PHPStan\File\FileWriter; use function array_keys; +use function count; use function error_reporting; +use function explode; +use function implode; +use function in_array; +use function is_dir; +use function is_file; use function restore_error_handler; use function set_error_handler; use function sha1_file; +use function sprintf; +use function str_ends_with; +use function substr; +use function time; +use function trim; +use function unlink; use const E_USER_DEPRECATED; use const PHP_RELEASE_VERSION; use const PHP_VERSION_ID; @@ -21,7 +37,7 @@ final class Configurator extends \Nette\Bootstrap\Configurator /** @var string[] */ private array $allConfigFiles = []; - public function __construct(private LoaderFactory $loaderFactory) + public function __construct(private LoaderFactory $loaderFactory, private bool $journalContainer) { parent::__construct(); } @@ -59,10 +75,106 @@ public function loadContainer(): string $this->staticParameters['debugMode'], ); - return $loader->load( + $className = $loader->load( [$this, 'generateContainer'], [$this->staticParameters, array_keys($this->dynamicParameters), $this->configs, PHP_VERSION_ID - PHP_RELEASE_VERSION, NeonAdapter::CACHE_KEY, $this->getAllConfigFilesHashes()], ); + + if ($this->journalContainer) { + $this->journal($className); + } + + return $className; + } + + private function journal(string $currentContainerClassName): void + { + $directory = $this->getContainerCacheDirectory(); + if (!is_dir($directory)) { + return; + } + + $journalFile = $directory . '/container.journal'; + if (!is_file($journalFile)) { + try { + FileWriter::write($journalFile, sprintf("%s:%d\n", $currentContainerClassName, time())); + } catch (CouldNotWriteFileException) { + // pass + } + + return; + } + + try { + $journalContents = FileReader::read($journalFile); + } catch (CouldNotReadFileException) { + return; + } + + $journalLines = explode("\n", trim($journalContents)); + $linesToWrite = []; + $usedInTheLastWeek = []; + $now = time(); + $currentAlreadyInTheJournal = false; + foreach ($journalLines as $journalLine) { + if ($journalLine === '') { + continue; + } + $journalLineParts = explode(':', $journalLine); + if (count($journalLineParts) !== 2) { + return; + } + $className = $journalLineParts[0]; + $containerLastUsedTime = (int) $journalLineParts[1]; + + $week = 3600 * 24 * 7; + + if ($containerLastUsedTime + $week < $now) { + continue; + } + + $usedInTheLastWeek[] = $className; + + if ($currentContainerClassName !== $className) { + $linesToWrite[] = sprintf('%s:%d', $className, $containerLastUsedTime); + continue; + } + + $linesToWrite[] = sprintf('%s:%d', $currentContainerClassName, $now); + $currentAlreadyInTheJournal = true; + } + + if (!$currentAlreadyInTheJournal) { + $linesToWrite[] = sprintf('%s:%d', $currentContainerClassName, $now); + $usedInTheLastWeek[] = $currentContainerClassName; + } + + try { + FileWriter::write($journalFile, implode("\n", $linesToWrite) . "\n"); + } catch (CouldNotWriteFileException) { + return; + } + + foreach (new DirectoryIterator($directory) as $fileInfo) { + if ($fileInfo->isDot()) { + continue; + } + $fileName = $fileInfo->getFilename(); + if ($fileName === 'container.journal') { + continue; + } + if (!str_ends_with($fileName, '.php')) { + continue; + } + $fileClassName = substr($fileName, 0, -4); + if (in_array($fileClassName, $usedInTheLastWeek, true)) { + continue; + } + $basePathname = $fileInfo->getPathname(); + @unlink($basePathname); + @unlink($basePathname . '.lock'); + @unlink($basePathname . '.meta'); + } } public function createContainer(bool $initialize = true): OriginalNetteContainer diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index 5c8dad2f23..75c79d6678 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -22,7 +22,6 @@ use PHPStan\BetterReflection\Reflector\Reflector; use PHPStan\BetterReflection\SourceLocator\SourceStubber\PhpStormStubsSourceStubber; use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator; -use PHPStan\Broker\Broker; use PHPStan\Command\CommandHelper; use PHPStan\File\FileHelper; use PHPStan\Node\Printer\Printer; @@ -31,11 +30,9 @@ use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\ReflectionProviderStaticAccessor; use PHPStan\ShouldNotHappenException; -use PHPStan\Type\Accessory\AccessoryArrayListType; -use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\ObjectType; -use Symfony\Component\Finder\Finder; use function array_diff_key; +use function array_key_exists; use function array_map; use function array_merge; use function array_unique; @@ -45,21 +42,17 @@ use function getenv; use function ini_get; use function is_array; -use function is_dir; use function is_file; use function is_readable; use function spl_object_id; use function sprintf; use function str_ends_with; use function substr; -use function time; -use function unlink; /** * @api - * @final */ -class ContainerFactory +final class ContainerFactory { private FileHelper $fileHelper; @@ -70,8 +63,10 @@ class ContainerFactory private static ?int $lastInitializedContainerId = null; + private bool $journalContainer = false; + /** @api */ - public function __construct(private string $currentWorkingDirectory, private bool $checkDuplicateFiles = false) + public function __construct(private string $currentWorkingDirectory) { $this->fileHelper = new FileHelper($currentWorkingDirectory); @@ -87,6 +82,11 @@ public function __construct(private string $currentWorkingDirectory, private boo $this->configDirectory = $originalRootDir . '/conf'; } + public function setJournalContainer(): void + { + $this->journalContainer = true; + } + /** * @param string[] $additionalConfigFiles * @param string[] $analysedPaths @@ -118,7 +118,7 @@ public function create( $this->rootDirectory, $this->currentWorkingDirectory, $generateBaselineFile, - )); + ), $this->journalContainer); $configurator->defaultExtensions = [ 'php' => PhpExtension::class, 'extensions' => ExtensionsExtension::class, @@ -184,52 +184,12 @@ public static function postInitializeContainer(Container $container): void $container->getByType(Printer::class), ); - $broker = $container->getByType(Broker::class); - Broker::registerInstance($broker); ReflectionProviderStaticAccessor::registerInstance($container->getByType(ReflectionProvider::class)); PhpVersionStaticAccessor::registerInstance($container->getByType(PhpVersion::class)); ObjectType::resetCaches(); $container->getService('typeSpecifier'); BleedingEdgeToggle::setBleedingEdge($container->getParameter('featureToggles')['bleedingEdge']); - AccessoryArrayListType::setListTypeEnabled($container->getParameter('featureToggles')['listType']); - TemplateTypeVariance::setInvarianceCompositionEnabled($container->getParameter('featureToggles')['invarianceComposition']); - } - - public function clearOldContainers(string $tempDirectory): void - { - $configurator = new Configurator(new LoaderFactory( - $this->fileHelper, - $this->rootDirectory, - $this->currentWorkingDirectory, - null, - )); - $configurator->setDebugMode(true); - $configurator->setTempDirectory($tempDirectory); - - $containerDirectory = $configurator->getContainerCacheDirectory(); - if (!is_dir($containerDirectory)) { - return; - } - - $finder = new Finder(); - $finder->name('Container_*')->in($containerDirectory); - $twoDaysAgo = time() - 24 * 60 * 60 * 2; - - foreach ($finder as $containerFile) { - $path = $containerFile->getRealPath(); - if ($path === false) { - continue; - } - if ($containerFile->getATime() > $twoDaysAgo) { - continue; - } - if ($containerFile->getCTime() > $twoDaysAgo) { - continue; - } - - @unlink($path); - } } public function getCurrentWorkingDirectory(): string @@ -277,10 +237,6 @@ private function detectDuplicateIncludedFiles( return [$normalized, $configArray]; } - if (!$this->checkDuplicateFiles) { - return [$normalized, $configArray]; - } - $duplicateFiles = array_unique(array_diff_key($normalized, $deduplicated)); throw new DuplicateIncludedFilesException($duplicateFiles); @@ -355,6 +311,18 @@ private function validateParameters(array $parameters, array $parametersSchema): $context->path = ['parameters']; }; $processor->process($schema, $parameters); + + if ( + !array_key_exists('phpVersion', $parameters) + || !is_array($parameters['phpVersion'])) { + return; + } + + $phpVersion = $parameters['phpVersion']; + + if ($phpVersion['max'] < $phpVersion['min']) { + throw new InvalidPhpVersionException('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.'); + } } /** diff --git a/src/DependencyInjection/DerivativeContainerFactory.php b/src/DependencyInjection/DerivativeContainerFactory.php index a32bc2eb6a..218eb4e252 100644 --- a/src/DependencyInjection/DerivativeContainerFactory.php +++ b/src/DependencyInjection/DerivativeContainerFactory.php @@ -35,6 +35,7 @@ public function create(array $additionalConfigFiles): Container $containerFactory = new ContainerFactory( $this->currentWorkingDirectory, ); + $containerFactory->setJournalContainer(); return $containerFactory->create( $this->tempDirectory, diff --git a/src/DependencyInjection/InvalidPhpVersionException.php b/src/DependencyInjection/InvalidPhpVersionException.php new file mode 100644 index 0000000000..f9b41690a3 --- /dev/null +++ b/src/DependencyInjection/InvalidPhpVersionException.php @@ -0,0 +1,10 @@ +container->getByType(MixinPropertiesClassReflectionExtension::class); $this->registry = new ClassReflectionExtensionRegistry( - $this->container->getByType(Broker::class), array_merge([$phpClassReflectionExtension], $this->container->getServicesByTag(BrokerFactory::PROPERTIES_CLASS_REFLECTION_EXTENSION_TAG), [$annotationsPropertiesClassReflectionExtension, $mixinPropertiesClassReflectionExtension]), array_merge([$phpClassReflectionExtension], $this->container->getServicesByTag(BrokerFactory::METHODS_CLASS_REFLECTION_EXTENSION_TAG), [$annotationsMethodsClassReflectionExtension, $mixinMethodsClassReflectionExtension]), $this->container->getServicesByTag(BrokerFactory::ALLOWED_SUB_TYPES_CLASS_REFLECTION_EXTENSION_TAG), diff --git a/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php b/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php index 9a15af910f..3dea120177 100644 --- a/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php +++ b/src/DependencyInjection/Type/LazyDynamicReturnTypeExtensionRegistryProvider.php @@ -2,7 +2,6 @@ namespace PHPStan\DependencyInjection\Type; -use PHPStan\Broker\Broker; use PHPStan\Broker\BrokerFactory; use PHPStan\DependencyInjection\Container; use PHPStan\Reflection\ReflectionProvider; @@ -21,7 +20,6 @@ public function getRegistry(): DynamicReturnTypeExtensionRegistry { if ($this->registry === null) { $this->registry = new DynamicReturnTypeExtensionRegistry( - $this->container->getByType(Broker::class), $this->container->getByType(ReflectionProvider::class), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_METHOD_RETURN_TYPE_EXTENSION_TAG), $this->container->getServicesByTag(BrokerFactory::DYNAMIC_STATIC_METHOD_RETURN_TYPE_EXTENSION_TAG), diff --git a/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php b/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php index 5f1a719b48..2be97ee777 100644 --- a/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php +++ b/src/DependencyInjection/Type/LazyOperatorTypeSpecifyingExtensionRegistryProvider.php @@ -2,7 +2,6 @@ namespace PHPStan\DependencyInjection\Type; -use PHPStan\Broker\Broker; use PHPStan\Broker\BrokerFactory; use PHPStan\DependencyInjection\Container; use PHPStan\Type\OperatorTypeSpecifyingExtensionRegistry; @@ -20,7 +19,6 @@ public function getRegistry(): OperatorTypeSpecifyingExtensionRegistry { if ($this->registry === null) { $this->registry = new OperatorTypeSpecifyingExtensionRegistry( - $this->container->getByType(Broker::class), $this->container->getServicesByTag(BrokerFactory::OPERATOR_TYPE_SPECIFYING_EXTENSION_TAG), ); } diff --git a/src/DependencyInjection/ValidateExcludePathsExtension.php b/src/DependencyInjection/ValidateExcludePathsExtension.php index b322c4b18c..6d099d1c10 100644 --- a/src/DependencyInjection/ValidateExcludePathsExtension.php +++ b/src/DependencyInjection/ValidateExcludePathsExtension.php @@ -28,8 +28,7 @@ public function loadConfiguration(): void } $errors = []; - $noImplicitWildcard = $builder->parameters['featureToggles']['noImplicitWildcard']; - if ($builder->parameters['__validate'] && $noImplicitWildcard) { + if ($builder->parameters['__validate']) { $paths = []; if (array_key_exists('analyse', $excludePaths)) { $paths = $excludePaths['analyse']; diff --git a/src/DependencyInjection/ValidateIgnoredErrorsExtension.php b/src/DependencyInjection/ValidateIgnoredErrorsExtension.php index 71a1e04c07..4560fde44c 100644 --- a/src/DependencyInjection/ValidateIgnoredErrorsExtension.php +++ b/src/DependencyInjection/ValidateIgnoredErrorsExtension.php @@ -12,6 +12,7 @@ use PHPStan\Command\IgnoredRegexValidator; use PHPStan\DependencyInjection\Type\OperatorTypeSpecifyingExtensionRegistryProvider; use PHPStan\File\FileExcluder; +use PHPStan\Php\ComposerPhpVersionFactory; use PHPStan\Php\PhpVersion; use PHPStan\PhpDoc\DirectTypeNodeResolverExtensionRegistryProvider; use PHPStan\PhpDoc\TypeNodeResolver; @@ -20,6 +21,7 @@ use PHPStan\PhpDocParser\Lexer\Lexer; use PHPStan\PhpDocParser\Parser\ConstExprParser; use PHPStan\PhpDocParser\Parser\TypeParser; +use PHPStan\PhpDocParser\ParserConfig; use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\Reflection\PhpVersionStaticAccessor; use PHPStan\Reflection\ReflectionProvider\DirectReflectionProviderProvider; @@ -58,20 +60,21 @@ public function loadConfiguration(): void return; } - $noImplicitWildcard = $builder->parameters['featureToggles']['noImplicitWildcard']; - /** @throws void */ $parser = Llk::load(new Read(__DIR__ . '/../../resources/RegexGrammar.pp')); $reflectionProvider = new DummyReflectionProvider(); $reflectionProviderProvider = new DirectReflectionProviderProvider($reflectionProvider); ReflectionProviderStaticAccessor::registerInstance($reflectionProvider); PhpVersionStaticAccessor::registerInstance(new PhpVersion(PHP_VERSION_ID)); - $constantResolver = new ConstantResolver($reflectionProviderProvider, []); + $composerPhpVersionFactory = new ComposerPhpVersionFactory([]); + $constantResolver = new ConstantResolver($reflectionProviderProvider, [], null, $composerPhpVersionFactory); + + $phpDocParserConfig = new ParserConfig([]); $ignoredRegexValidator = new IgnoredRegexValidator( $parser, new TypeStringResolver( - new Lexer(), - new TypeParser(new ConstExprParser($builder->parameters['featureToggles']['unescapeStrings'])), + new Lexer($phpDocParserConfig), + new TypeParser($phpDocParserConfig, new ConstExprParser($phpDocParserConfig)), new TypeNodeResolver( new DirectTypeNodeResolverExtensionRegistryProvider( new class implements TypeNodeResolverExtensionRegistry { @@ -102,10 +105,10 @@ public function resolveTypeAlias(string $aliasName, NameScope $nameScope): ?Type public function getRegistry(): OperatorTypeSpecifyingExtensionRegistry { - return new OperatorTypeSpecifyingExtensionRegistry(null, []); + return new OperatorTypeSpecifyingExtensionRegistry([]); } - }, new OversizedArrayBuilder()), + }, new OversizedArrayBuilder(), true), ), ), ); @@ -138,7 +141,7 @@ public function getRegistry(): OperatorTypeSpecifyingExtensionRegistry $reportUnmatched = (bool) $builder->parameters['reportUnmatchedIgnoredErrors']; - if ($noImplicitWildcard && $reportUnmatched) { + if ($reportUnmatched) { foreach ($ignoreErrors as $ignoreError) { if (!is_array($ignoreError)) { continue; diff --git a/src/Diagnose/PHPStanDiagnoseExtension.php b/src/Diagnose/PHPStanDiagnoseExtension.php index 7c3057190c..35cb6a862e 100644 --- a/src/Diagnose/PHPStanDiagnoseExtension.php +++ b/src/Diagnose/PHPStanDiagnoseExtension.php @@ -7,6 +7,7 @@ use PHPStan\ExtensionInstaller\GeneratedConfig; use PHPStan\File\FileHelper; use PHPStan\Internal\ComposerHelper; +use PHPStan\Php\ComposerPhpVersionFactory; use PHPStan\Php\PhpVersion; use ReflectionClass; use function array_key_exists; @@ -17,6 +18,7 @@ use function explode; use function implode; use function in_array; +use function is_array; use function is_file; use function is_readable; use function sprintf; @@ -29,14 +31,17 @@ final class PHPStanDiagnoseExtension implements DiagnoseExtension { /** + * @param int|array{min: int, max: int}|null $configPhpVersion * @param string[] $composerAutoloaderProjectPaths * @param string [] $allConfigFiles */ public function __construct( private PhpVersion $phpVersion, + private int|array|null $configPhpVersion, private FileHelper $fileHelper, private array $composerAutoloaderProjectPaths, private array $allConfigFiles, + private ComposerPhpVersionFactory $composerPhpVersionFactory, ) { } @@ -48,11 +53,45 @@ public function print(Output $output): void 'PHP runtime version: %s', $phpRuntimeVersion->getVersionString(), )); - $output->writeLineFormatted(sprintf( - 'PHP version for analysis: %s (from %s)', - $this->phpVersion->getVersionString(), - $this->phpVersion->getSourceLabel(), - )); + + if ( + $this->phpVersion->getSource() === PhpVersion::SOURCE_CONFIG + && is_array($this->configPhpVersion) + ) { + $minVersion = new PhpVersion($this->configPhpVersion['min']); + $maxVersion = new PhpVersion($this->configPhpVersion['max']); + + $output->writeLineFormatted(sprintf( + 'PHP version for analysis: %s-%s (from %s)', + $minVersion->getVersionString(), + $maxVersion->getVersionString(), + $this->phpVersion->getSourceLabel(), + )); + + } else { + $minComposerPhpVersion = $this->composerPhpVersionFactory->getMinVersion(); + $maxComposerPhpVersion = $this->composerPhpVersionFactory->getMaxVersion(); + if ($minComposerPhpVersion !== null && $maxComposerPhpVersion !== null) { + if ($minComposerPhpVersion->getVersionId() !== $maxComposerPhpVersion->getVersionId()) { + $output->writeLineFormatted(sprintf( + 'PHP composer.json required version: %s-%s', + $minComposerPhpVersion->getVersionString(), + $maxComposerPhpVersion->getVersionString(), + )); + } else { + $output->writeLineFormatted(sprintf( + 'PHP composer.json required version: %s', + $minComposerPhpVersion->getVersionString(), + )); + } + } + + $output->writeLineFormatted(sprintf( + 'PHP version for analysis: %s (from %s)', + $this->phpVersion->getVersionString(), + $this->phpVersion->getSourceLabel(), + )); + } $output->writeLineFormatted(''); $output->writeLineFormatted(sprintf( diff --git a/src/File/FileExcluder.php b/src/File/FileExcluder.php index 7e6fefdaca..ba314cbb67 100644 --- a/src/File/FileExcluder.php +++ b/src/File/FileExcluder.php @@ -50,9 +50,8 @@ final class FileExcluder * @param string[] $analyseExcludes */ public function __construct( - FileHelper $fileHelper, + private FileHelper $fileHelper, array $analyseExcludes, - private bool $noImplicitWildcard, ) { foreach ($analyseExcludes as $exclude) { @@ -68,18 +67,14 @@ public function __construct( if (self::isFnmatchPattern($normalized)) { $this->fnmatchAnalyseExcludes[] = $normalized; } else { - if ($this->noImplicitWildcard) { - if (is_file($normalized)) { - $this->literalAnalyseFilesExcludes[] = $normalized; - } elseif (is_dir($normalized)) { - if (!$trailingDirSeparator) { - $normalized .= DIRECTORY_SEPARATOR; - } - - $this->literalAnalyseDirectoryExcludes[] = $normalized; + if (is_file($normalized)) { + $this->literalAnalyseFilesExcludes[] = $normalized; + } elseif (is_dir($normalized)) { + if (!$trailingDirSeparator) { + $normalized .= DIRECTORY_SEPARATOR; } - } else { - $this->literalAnalyseExcludes[] = $fileHelper->absolutizePath($normalized); + + $this->literalAnalyseDirectoryExcludes[] = $normalized; } } } @@ -94,21 +89,21 @@ public function __construct( public function isExcludedFromAnalysing(string $file): bool { + $file = $this->fileHelper->normalizePath($file); + foreach ($this->literalAnalyseExcludes as $exclude) { if (str_starts_with($file, $exclude)) { return true; } } - if ($this->noImplicitWildcard) { - foreach ($this->literalAnalyseDirectoryExcludes as $exclude) { - if (str_starts_with($file, $exclude)) { - return true; - } + foreach ($this->literalAnalyseDirectoryExcludes as $exclude) { + if (str_starts_with($file, $exclude)) { + return true; } - foreach ($this->literalAnalyseFilesExcludes as $exclude) { - if ($file === $exclude) { - return true; - } + } + foreach ($this->literalAnalyseFilesExcludes as $exclude) { + if ($file === $exclude) { + return true; } } foreach ($this->fnmatchAnalyseExcludes as $exclude) { diff --git a/src/File/FileExcluderFactory.php b/src/File/FileExcluderFactory.php index c15b426f6e..0bdae44c20 100644 --- a/src/File/FileExcluderFactory.php +++ b/src/File/FileExcluderFactory.php @@ -11,23 +11,17 @@ final class FileExcluderFactory { /** - * @param string[] $obsoleteExcludesAnalyse - * @param array{analyse?: array, analyseAndScan?: array}|null $excludePaths + * @param array{analyse?: array, analyseAndScan?: array} $excludePaths */ public function __construct( private FileExcluderRawFactory $fileExcluderRawFactory, - private array $obsoleteExcludesAnalyse, - private ?array $excludePaths, + private array $excludePaths, ) { } public function createAnalyseFileExcluder(): FileExcluder { - if ($this->excludePaths === null) { - return $this->fileExcluderRawFactory->create($this->obsoleteExcludesAnalyse); - } - $paths = []; if (array_key_exists('analyse', $this->excludePaths)) { $paths = $this->excludePaths['analyse']; @@ -41,10 +35,6 @@ public function createAnalyseFileExcluder(): FileExcluder public function createScanFileExcluder(): FileExcluder { - if ($this->excludePaths === null) { - return $this->fileExcluderRawFactory->create($this->obsoleteExcludesAnalyse); - } - $paths = []; if (array_key_exists('analyseAndScan', $this->excludePaths)) { $paths = $this->excludePaths['analyseAndScan']; diff --git a/src/Node/BooleanAndNode.php b/src/Node/BooleanAndNode.php index 6d508713e7..361177c705 100644 --- a/src/Node/BooleanAndNode.php +++ b/src/Node/BooleanAndNode.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class BooleanAndNode extends Expr implements VirtualNode +final class BooleanAndNode extends Expr implements VirtualNode { public function __construct(private BooleanAnd|LogicalAnd $originalNode, private Scope $rightScope) diff --git a/src/Node/BooleanOrNode.php b/src/Node/BooleanOrNode.php index ca327164ee..c2ca5d14be 100644 --- a/src/Node/BooleanOrNode.php +++ b/src/Node/BooleanOrNode.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class BooleanOrNode extends Expr implements VirtualNode +final class BooleanOrNode extends Expr implements VirtualNode { public function __construct(private BooleanOr|LogicalOr $originalNode, private Scope $rightScope) diff --git a/src/Node/BreaklessWhileLoopNode.php b/src/Node/BreaklessWhileLoopNode.php index 3d3ff248a2..f7df71bf19 100644 --- a/src/Node/BreaklessWhileLoopNode.php +++ b/src/Node/BreaklessWhileLoopNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class BreaklessWhileLoopNode extends NodeAbstract implements VirtualNode +final class BreaklessWhileLoopNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/CatchWithUnthrownExceptionNode.php b/src/Node/CatchWithUnthrownExceptionNode.php index d1872895dd..9f06bf2009 100644 --- a/src/Node/CatchWithUnthrownExceptionNode.php +++ b/src/Node/CatchWithUnthrownExceptionNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class CatchWithUnthrownExceptionNode extends NodeAbstract implements VirtualNode +final class CatchWithUnthrownExceptionNode extends NodeAbstract implements VirtualNode { public function __construct(private Catch_ $originalNode, private Type $caughtType, private Type $originalCaughtType) diff --git a/src/Node/ClassConstantsNode.php b/src/Node/ClassConstantsNode.php index 0b12946d8c..4da543a2d7 100644 --- a/src/Node/ClassConstantsNode.php +++ b/src/Node/ClassConstantsNode.php @@ -10,9 +10,8 @@ /** * @api - * @final */ -class ClassConstantsNode extends NodeAbstract implements VirtualNode +final class ClassConstantsNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/ClassMethod.php b/src/Node/ClassMethod.php index e3f2cef221..2aec877cf5 100644 --- a/src/Node/ClassMethod.php +++ b/src/Node/ClassMethod.php @@ -2,33 +2,22 @@ namespace PHPStan\Node; -use PhpParser\Node\Stmt\ClassMethod as PhpParserClassMethod; - /** * @api - * @final */ -class ClassMethod extends PhpParserClassMethod +final class ClassMethod { public function __construct( - \PhpParser\Node\Stmt\ClassMethod $node, + private \PhpParser\Node\Stmt\ClassMethod $node, private bool $isDeclaredInTrait, ) { - parent::__construct($node->name, [ - 'flags' => $node->flags, - 'byRef' => $node->byRef, - 'params' => $node->params, - 'returnType' => $node->returnType, - 'stmts' => $node->stmts, - 'attrGroups' => $node->attrGroups, - ], $node->attributes); } - public function getNode(): PhpParserClassMethod + public function getNode(): \PhpParser\Node\Stmt\ClassMethod { - return $this; + return $this->node; } public function isDeclaredInTrait(): bool diff --git a/src/Node/ClassMethodsNode.php b/src/Node/ClassMethodsNode.php index 3a8a2df77d..4c46fd9253 100644 --- a/src/Node/ClassMethodsNode.php +++ b/src/Node/ClassMethodsNode.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class ClassMethodsNode extends NodeAbstract implements VirtualNode +final class ClassMethodsNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/ClassPropertiesNode.php b/src/Node/ClassPropertiesNode.php index 7afc4bc874..c22ec65c29 100644 --- a/src/Node/ClassPropertiesNode.php +++ b/src/Node/ClassPropertiesNode.php @@ -18,7 +18,6 @@ use PHPStan\Node\Property\PropertyWrite; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\MethodReflection; -use PHPStan\Rules\Properties\ReadWritePropertiesExtension; use PHPStan\Rules\Properties\ReadWritePropertiesExtensionProvider; use PHPStan\TrinaryLogic; use PHPStan\Type\NeverType; @@ -31,9 +30,8 @@ /** * @api - * @final */ -class ClassPropertiesNode extends NodeAbstract implements VirtualNode +final class ClassPropertiesNode extends NodeAbstract implements VirtualNode { /** @@ -98,13 +96,11 @@ public function getClassReflection(): ClassReflection /** * @param string[] $constructors - * @param ReadWritePropertiesExtension[]|null $extensions * @return array{array, array, array} */ public function getUninitializedProperties( Scope $scope, array $constructors, - ?array $extensions = null, ): array { if (!$this->getClass() instanceof Class_) { @@ -116,9 +112,7 @@ public function getUninitializedProperties( $originalProperties = []; $initialInitializedProperties = []; $initializedProperties = []; - if ($extensions === null) { - $extensions = $this->readWritePropertiesExtensionProvider->getExtensions(); - } + $extensions = $this->readWritePropertiesExtensionProvider->getExtensions(); $initializedViaExtension = []; foreach ($this->getProperties() as $property) { if ($property->isStatic()) { @@ -271,9 +265,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..c8602aef79 100644 --- a/src/Node/ClassPropertyNode.php +++ b/src/Node/ClassPropertyNode.php @@ -2,32 +2,29 @@ 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; /** * @api - * @final */ -class ClassPropertyNode extends NodeAbstract implements VirtualNode +final class ClassPropertyNode extends NodeAbstract implements VirtualNode { public function __construct( private string $name, private int $flags, - private Identifier|Name|Node\ComplexType|null $type, + private ?Type $type, private ?Expr $default, private ?string $phpDoc, private ?Type $phpDocType, private bool $isPromoted, private bool $isPromotedFromTrait, - Node $originalNode, + private Node\Stmt\Property|Node\Param $originalNode, private bool $isReadonlyByPhpDoc, private bool $isDeclaredInTrait, private bool $isReadonlyClass, @@ -75,28 +72,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 @@ -114,12 +111,22 @@ public function isAllowedPrivateMutation(): bool return $this->isAllowedPrivateMutation; } + public function isAbstract(): bool + { + return (bool) ($this->flags & Modifiers::ABSTRACT); + } + + public function getNativeType(): ?Type + { + return $this->type; + } + /** - * @return Identifier|Name|Node\ComplexType|null + * @return Node\Identifier|Node\Name|Node\ComplexType|null */ - public function getNativeType() + public function getNativeTypeNode() { - return $this->type; + return $this->originalNode->type; } public function getClassReflection(): ClassReflection @@ -140,4 +147,17 @@ public function getSubNodeNames(): array return []; } + public function hasHooks(): bool + { + return $this->getHooks() !== []; + } + + /** + * @return Node\PropertyHook[] + */ + public function getHooks(): array + { + return $this->originalNode->hooks; + } + } 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/ClosureReturnStatementsNode.php b/src/Node/ClosureReturnStatementsNode.php index 7231c02e5f..920b61750b 100644 --- a/src/Node/ClosureReturnStatementsNode.php +++ b/src/Node/ClosureReturnStatementsNode.php @@ -13,9 +13,8 @@ /** * @api - * @final */ -class ClosureReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode +final class ClosureReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode { private Node\Expr\Closure $closureExpr; diff --git a/src/Node/CollectedDataNode.php b/src/Node/CollectedDataNode.php index 7588947625..8c0f52dc3b 100644 --- a/src/Node/CollectedDataNode.php +++ b/src/Node/CollectedDataNode.php @@ -10,9 +10,8 @@ /** * @api - * @final */ -class CollectedDataNode extends NodeAbstract implements VirtualNode +final class CollectedDataNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/Constant/ClassConstantFetch.php b/src/Node/Constant/ClassConstantFetch.php index 8f23935dd1..bda533900b 100644 --- a/src/Node/Constant/ClassConstantFetch.php +++ b/src/Node/Constant/ClassConstantFetch.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class ClassConstantFetch +final class ClassConstantFetch { public function __construct(private ClassConstFetch $node, private Scope $scope) diff --git a/src/Node/ExecutionEndNode.php b/src/Node/ExecutionEndNode.php index e9cf081b13..5e0ddf13da 100644 --- a/src/Node/ExecutionEndNode.php +++ b/src/Node/ExecutionEndNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class ExecutionEndNode extends NodeAbstract implements VirtualNode +final class ExecutionEndNode extends NodeAbstract implements VirtualNode { public function __construct( diff --git a/src/Node/FileNode.php b/src/Node/FileNode.php index 355a4b9559..286168fb6a 100644 --- a/src/Node/FileNode.php +++ b/src/Node/FileNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class FileNode extends NodeAbstract implements VirtualNode +final class FileNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/FinallyExitPointsNode.php b/src/Node/FinallyExitPointsNode.php index 32c2adb50c..fed8d4888d 100644 --- a/src/Node/FinallyExitPointsNode.php +++ b/src/Node/FinallyExitPointsNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class FinallyExitPointsNode extends NodeAbstract implements VirtualNode +final class FinallyExitPointsNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/FunctionCallableNode.php b/src/Node/FunctionCallableNode.php index 00e9e24fba..9cd2cfc8c8 100644 --- a/src/Node/FunctionCallableNode.php +++ b/src/Node/FunctionCallableNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class FunctionCallableNode extends Expr implements VirtualNode +final class FunctionCallableNode extends Expr implements VirtualNode { public function __construct(private Name|Expr $name, private Expr\FuncCall $originalNode) diff --git a/src/Node/FunctionReturnStatementsNode.php b/src/Node/FunctionReturnStatementsNode.php index 4ab53d25c3..14582f309b 100644 --- a/src/Node/FunctionReturnStatementsNode.php +++ b/src/Node/FunctionReturnStatementsNode.php @@ -14,9 +14,8 @@ /** * @api - * @final */ -class FunctionReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode +final class FunctionReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode { /** diff --git a/src/Node/InArrowFunctionNode.php b/src/Node/InArrowFunctionNode.php index fb60b2b404..20acb7c36f 100644 --- a/src/Node/InArrowFunctionNode.php +++ b/src/Node/InArrowFunctionNode.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class InArrowFunctionNode extends NodeAbstract implements VirtualNode +final class InArrowFunctionNode extends NodeAbstract implements VirtualNode { private Node\Expr\ArrowFunction $originalNode; diff --git a/src/Node/InClassMethodNode.php b/src/Node/InClassMethodNode.php index f74db8e890..52b50c17fd 100644 --- a/src/Node/InClassMethodNode.php +++ b/src/Node/InClassMethodNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class InClassMethodNode extends Node\Stmt implements VirtualNode +final class InClassMethodNode extends Node\Stmt implements VirtualNode { public function __construct( diff --git a/src/Node/InClassNode.php b/src/Node/InClassNode.php index 1be1b7fab2..84a4ecab83 100644 --- a/src/Node/InClassNode.php +++ b/src/Node/InClassNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class InClassNode extends Node\Stmt implements VirtualNode +final class InClassNode extends Node\Stmt implements VirtualNode { public function __construct(private ClassLike $originalNode, private ClassReflection $classReflection) diff --git a/src/Node/InClosureNode.php b/src/Node/InClosureNode.php index 21def5dbef..3e95aea867 100644 --- a/src/Node/InClosureNode.php +++ b/src/Node/InClosureNode.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class InClosureNode extends NodeAbstract implements VirtualNode +final class InClosureNode extends NodeAbstract implements VirtualNode { private Node\Expr\Closure $originalNode; diff --git a/src/Node/InFunctionNode.php b/src/Node/InFunctionNode.php index 550c00e41b..ce90bb7f38 100644 --- a/src/Node/InFunctionNode.php +++ b/src/Node/InFunctionNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class InFunctionNode extends Node\Stmt implements VirtualNode +final class InFunctionNode extends Node\Stmt implements VirtualNode { public function __construct( diff --git a/src/Node/InTraitNode.php b/src/Node/InTraitNode.php index 2a3a810fb5..b7834e713f 100644 --- a/src/Node/InTraitNode.php +++ b/src/Node/InTraitNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class InTraitNode extends Node\Stmt implements VirtualNode +final class InTraitNode extends Node\Stmt implements VirtualNode { public function __construct(private Node\Stmt\Trait_ $originalNode, private ClassReflection $traitReflection, private ClassReflection $implementingClassReflection) diff --git a/src/Node/InstantiationCallableNode.php b/src/Node/InstantiationCallableNode.php index 289fb6fe5f..98d838b1be 100644 --- a/src/Node/InstantiationCallableNode.php +++ b/src/Node/InstantiationCallableNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class InstantiationCallableNode extends Expr implements VirtualNode +final class InstantiationCallableNode extends Expr implements VirtualNode { public function __construct(private Name|Expr $class, private Expr\New_ $originalNode) diff --git a/src/Node/InvalidateExprNode.php b/src/Node/InvalidateExprNode.php index a59799f0aa..5fb5ba27de 100644 --- a/src/Node/InvalidateExprNode.php +++ b/src/Node/InvalidateExprNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class InvalidateExprNode extends NodeAbstract implements VirtualNode +final class InvalidateExprNode extends NodeAbstract implements VirtualNode { public function __construct(private Expr $expr) diff --git a/src/Node/LiteralArrayItem.php b/src/Node/LiteralArrayItem.php index ea9be27be6..4d9699121b 100644 --- a/src/Node/LiteralArrayItem.php +++ b/src/Node/LiteralArrayItem.php @@ -2,14 +2,13 @@ namespace PHPStan\Node; -use PhpParser\Node\Expr\ArrayItem; +use PhpParser\Node\ArrayItem; use PHPStan\Analyser\Scope; /** * @api - * @final */ -class LiteralArrayItem +final class LiteralArrayItem { public function __construct(private Scope $scope, private ?ArrayItem $arrayItem) diff --git a/src/Node/LiteralArrayNode.php b/src/Node/LiteralArrayNode.php index e0bd824fad..9c8a693ff6 100644 --- a/src/Node/LiteralArrayNode.php +++ b/src/Node/LiteralArrayNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class LiteralArrayNode extends NodeAbstract implements VirtualNode +final class LiteralArrayNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/MatchExpressionArm.php b/src/Node/MatchExpressionArm.php index 427ed83cae..bad6265698 100644 --- a/src/Node/MatchExpressionArm.php +++ b/src/Node/MatchExpressionArm.php @@ -4,9 +4,8 @@ /** * @api - * @final */ -class MatchExpressionArm +final class MatchExpressionArm { /** diff --git a/src/Node/MatchExpressionArmBody.php b/src/Node/MatchExpressionArmBody.php index 628f0f777c..dbb6f3f917 100644 --- a/src/Node/MatchExpressionArmBody.php +++ b/src/Node/MatchExpressionArmBody.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class MatchExpressionArmBody +final class MatchExpressionArmBody { public function __construct(private Scope $scope, private Expr $body) diff --git a/src/Node/MatchExpressionArmCondition.php b/src/Node/MatchExpressionArmCondition.php index 4b3bc54720..95a291cce3 100644 --- a/src/Node/MatchExpressionArmCondition.php +++ b/src/Node/MatchExpressionArmCondition.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class MatchExpressionArmCondition +final class MatchExpressionArmCondition { public function __construct(private Expr $condition, private Scope $scope, private int $line) diff --git a/src/Node/MatchExpressionNode.php b/src/Node/MatchExpressionNode.php index 0dd31d9b2b..fb7f360642 100644 --- a/src/Node/MatchExpressionNode.php +++ b/src/Node/MatchExpressionNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class MatchExpressionNode extends NodeAbstract implements VirtualNode +final class MatchExpressionNode extends NodeAbstract implements VirtualNode { /** diff --git a/src/Node/Method/MethodCall.php b/src/Node/Method/MethodCall.php index c88997a3f9..d3726915a9 100644 --- a/src/Node/Method/MethodCall.php +++ b/src/Node/Method/MethodCall.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class MethodCall +final class MethodCall { public function __construct( diff --git a/src/Node/MethodCallableNode.php b/src/Node/MethodCallableNode.php index 7e7f1240dd..b1e52bf1e6 100644 --- a/src/Node/MethodCallableNode.php +++ b/src/Node/MethodCallableNode.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class MethodCallableNode extends Expr implements VirtualNode +final class MethodCallableNode extends Expr implements VirtualNode { public function __construct( diff --git a/src/Node/MethodReturnStatementsNode.php b/src/Node/MethodReturnStatementsNode.php index 96218713d3..2444df30b5 100644 --- a/src/Node/MethodReturnStatementsNode.php +++ b/src/Node/MethodReturnStatementsNode.php @@ -15,9 +15,8 @@ /** * @api - * @final */ -class MethodReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode +final class MethodReturnStatementsNode extends NodeAbstract implements ReturnStatementsNode { private ClassMethod $classMethod; diff --git a/src/Node/Printer/ExprPrinter.php b/src/Node/Printer/ExprPrinter.php index 6df730ddfc..32505ef568 100644 --- a/src/Node/Printer/ExprPrinter.php +++ b/src/Node/Printer/ExprPrinter.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ExprPrinter +final class ExprPrinter { public function __construct(private Printer $printer) diff --git a/src/Node/Printer/Printer.php b/src/Node/Printer/Printer.php index 78455184f0..6d9dab1062 100644 --- a/src/Node/Printer/Printer.php +++ b/src/Node/Printer/Printer.php @@ -19,14 +19,12 @@ use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @api + */ final class Printer extends Standard { - public function __construct() - { - parent::__construct(['shortArraySyntax' => true]); - } - protected function pPHPStan_Node_TypeExpr(TypeExpr $expr): string // phpcs:ignore { return sprintf('__phpstanType(%s)', $expr->getExprType()->describe(VerbosityLevel::precise())); diff --git a/src/Node/Property/PropertyRead.php b/src/Node/Property/PropertyRead.php index 1c24537453..86c220b77f 100644 --- a/src/Node/Property/PropertyRead.php +++ b/src/Node/Property/PropertyRead.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class PropertyRead +final class PropertyRead { public function __construct( diff --git a/src/Node/Property/PropertyWrite.php b/src/Node/Property/PropertyWrite.php index fec7a1c4f0..df39b83d0b 100644 --- a/src/Node/Property/PropertyWrite.php +++ b/src/Node/Property/PropertyWrite.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class PropertyWrite +final class PropertyWrite { public function __construct(private PropertyFetch|StaticPropertyFetch $fetch, private Scope $scope, private bool $promotedPropertyWrite) diff --git a/src/Node/ReturnStatement.php b/src/Node/ReturnStatement.php index 7a5da6f203..153faf1534 100644 --- a/src/Node/ReturnStatement.php +++ b/src/Node/ReturnStatement.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class ReturnStatement +final class ReturnStatement { private Node\Stmt\Return_ $returnNode; diff --git a/src/Node/StaticMethodCallableNode.php b/src/Node/StaticMethodCallableNode.php index 19e823234b..407a5cfa4c 100644 --- a/src/Node/StaticMethodCallableNode.php +++ b/src/Node/StaticMethodCallableNode.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class StaticMethodCallableNode extends Expr implements VirtualNode +final class StaticMethodCallableNode extends Expr implements VirtualNode { public function __construct( diff --git a/src/Node/UnreachableStatementNode.php b/src/Node/UnreachableStatementNode.php index 7c3cfb163c..e0c8cb0af9 100644 --- a/src/Node/UnreachableStatementNode.php +++ b/src/Node/UnreachableStatementNode.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class UnreachableStatementNode extends Stmt implements VirtualNode +final class UnreachableStatementNode extends Stmt implements VirtualNode { public function __construct(private Stmt $originalStatement) diff --git a/src/Parser/FunctionCallStatementFinder.php b/src/Parser/FunctionCallStatementFinder.php deleted file mode 100644 index 9a4c1dd6bb..0000000000 --- a/src/Parser/FunctionCallStatementFinder.php +++ /dev/null @@ -1,47 +0,0 @@ -findFunctionCallInStatements($functionNames, $statement); - if ($result !== null) { - return $result; - } - } - - if (!($statement instanceof Node)) { - continue; - } - - if ($statement instanceof FuncCall && $statement->name instanceof Name) { - if (in_array((string) $statement->name, $functionNames, true)) { - return $statement; - } - } - - $result = $this->findFunctionCallInStatements($functionNames, $statement); - if ($result !== null) { - return $result; - } - } - - return null; - } - -} diff --git a/src/Parser/LastConditionVisitor.php b/src/Parser/LastConditionVisitor.php index ce21f571fd..d20a8f4b90 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; @@ -64,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/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..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 @@ -31,4 +32,9 @@ public function parse(string $code, ?ErrorHandler $errorHandler = null): array } } + public function getTokens(): array + { + throw new ShouldNotHappenException('PhpParserDecorator::getTokens() should not be called'); + } + } diff --git a/src/Parser/PhpParserFactory.php b/src/Parser/PhpParserFactory.php new file mode 100644 index 0000000000..3a1f2cb4ea --- /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); + } + +} 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/Parser/RichParser.php b/src/Parser/RichParser.php index fb481b9923..a50ec45dbe 100644 --- a/src/Parser/RichParser.php +++ b/src/Parser/RichParser.php @@ -3,10 +3,10 @@ namespace PHPStan\Parser; use PhpParser\ErrorHandler\Collecting; -use PhpParser\Lexer; 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 +17,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; @@ -42,11 +41,9 @@ final class RichParser implements Parser public function __construct( private \PhpParser\Parser $parser, - private Lexer $lexer, private NameResolver $nameResolver, private Container $container, private IgnoreLexer $ignoreLexer, - private bool $enableIgnoreErrorsWithinPhpDocs = false, ) { } @@ -72,8 +69,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); } @@ -114,7 +110,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 @@ -124,12 +120,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) { @@ -160,12 +152,12 @@ 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'); - if ($this->enableIgnoreErrorsWithinPhpDocs && $type === T_DOC_COMMENT) { - $lines += $this->getLinesToIgnoreForTokenByIgnoreComment($text, $line, '@phpstan-ignore-line'); + if ($type === T_DOC_COMMENT) { + $lines += $this->getLinesToIgnoreForTokenByIgnoreComment($text, $line, '@phpstan-ignore-line', false); if ($isNextLine) { $pattern = sprintf('~%s~si', implode('|', [self::PHPDOC_TAG_REGEX, self::PHPDOC_DOCTRINE_TAG_REGEX])); $r = preg_match_all($pattern, $text, $pregMatches, PREG_OFFSET_CAPTURE); @@ -195,7 +187,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; @@ -209,20 +201,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) { @@ -255,7 +247,7 @@ private function getLinesToIgnoreForTokenByIgnoreComment( string $tokenText, int $tokenLine, string $ignoreComment, - bool $ignoreNextLine = false, + bool $ignoreNextLine, ): array { $lines = []; diff --git a/src/Parser/SimpleParser.php b/src/Parser/SimpleParser.php index 713c1502ef..8fbd112742 100644 --- a/src/Parser/SimpleParser.php +++ b/src/Parser/SimpleParser.php @@ -15,6 +15,8 @@ final class SimpleParser implements Parser public function __construct( private \PhpParser\Parser $parser, private NameResolver $nameResolver, + private VariadicMethodsVisitor $variadicMethodsVisitor, + private VariadicFunctionsVisitor $variadicFunctionsVisitor, ) { } @@ -48,6 +50,8 @@ public function parseString(string $sourceCode): array $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor($this->nameResolver); + $nodeTraverser->addVisitor($this->variadicMethodsVisitor); + $nodeTraverser->addVisitor($this->variadicFunctionsVisitor); /** @var array */ return $nodeTraverser->traverse($nodes); diff --git a/src/Parser/StandaloneThrowExprVisitor.php b/src/Parser/StandaloneThrowExprVisitor.php new file mode 100644 index 0000000000..386c903281 --- /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/Parser/StubParser.php b/src/Parser/StubParser.php new file mode 100644 index 0000000000..d98a2cc721 --- /dev/null +++ b/src/Parser/StubParser.php @@ -0,0 +1,56 @@ +parseString(FileReader::read($file)); + } catch (ParserErrorsException $e) { + throw new ParserErrorsException($e->getErrors(), $file); + } + } + + /** + * @return Node\Stmt[] + */ + public function parseString(string $sourceCode): array + { + $errorHandler = new Collecting(); + $nodes = $this->parser->parse($sourceCode, $errorHandler); + if ($errorHandler->hasErrors()) { + throw new ParserErrorsException($errorHandler->getErrors(), null); + } + if ($nodes === null) { + throw new ShouldNotHappenException(); + } + + $nodeTraverser = new NodeTraverser(); + $nodeTraverser->addVisitor($this->nameResolver); + + /** @var array */ + return $nodeTraverser->traverse($nodes); + } + +} diff --git a/src/Parser/VariadicFunctionsVisitor.php b/src/Parser/VariadicFunctionsVisitor.php new file mode 100644 index 0000000000..5276d0eb47 --- /dev/null +++ b/src/Parser/VariadicFunctionsVisitor.php @@ -0,0 +1,94 @@ + */ + public static array $cache = []; + + /** @var array */ + private array $variadicFunctions = []; + + public const ATTRIBUTE_NAME = 'variadicFunctions'; + + public function beforeTraverse(array $nodes): ?array + { + $this->topNode = null; + $this->variadicFunctions = []; + $this->inNamespace = null; + $this->inFunction = null; + + return null; + } + + public function enterNode(Node $node): ?Node + { + if ($this->topNode === null) { + $this->topNode = $node; + } + + if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) { + $this->inNamespace = $node->name->toString(); + } + + if ($node instanceof Node\Stmt\Function_) { + $this->inFunction = $this->inNamespace !== null ? $this->inNamespace . '\\' . $node->name->name : $node->name->name; + } + + if ( + $this->inFunction !== null + && $node instanceof Node\Expr\FuncCall + && $node->name instanceof Name + && in_array((string) $node->name, ParametersAcceptor::VARIADIC_FUNCTIONS, true) + && !array_key_exists($this->inFunction, $this->variadicFunctions) + ) { + $this->variadicFunctions[$this->inFunction] = true; + } + + return null; + } + + public function leaveNode(Node $node): ?Node + { + if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) { + $this->inNamespace = null; + } + + if ($node instanceof Node\Stmt\Function_ && $this->inFunction !== null) { + $this->variadicFunctions[$this->inFunction] ??= false; + $this->inFunction = null; + } + + return null; + } + + public function afterTraverse(array $nodes): ?array + { + if ($this->topNode !== null && $this->variadicFunctions !== []) { + foreach ($this->variadicFunctions as $name => $variadic) { + self::$cache[$name] = $variadic; + } + $functions = array_filter($this->variadicFunctions, static fn (bool $variadic) => $variadic); + $this->topNode->setAttribute(self::ATTRIBUTE_NAME, $functions); + } + + return null; + } + +} diff --git a/src/Parser/VariadicMethodsVisitor.php b/src/Parser/VariadicMethodsVisitor.php new file mode 100644 index 0000000000..cc3821d9f2 --- /dev/null +++ b/src/Parser/VariadicMethodsVisitor.php @@ -0,0 +1,135 @@ + */ + private array $classStack = []; + + private ?string $inMethod = null; + + /** @var array> */ + public static array $cache = []; + + /** @var array> */ + private array $variadicMethods = []; + + public function beforeTraverse(array $nodes): ?array + { + $this->topNode = null; + $this->variadicMethods = []; + $this->inNamespace = null; + $this->classStack = []; + $this->inMethod = null; + + return null; + } + + public function enterNode(Node $node): ?Node + { + if ($this->topNode === null) { + $this->topNode = $node; + } + + if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) { + $this->inNamespace = $node->name->toString(); + } + + if ($node instanceof Node\Stmt\ClassLike) { + if (!$node->name instanceof Node\Identifier) { + $className = sprintf('%s:%s:%s', self::ANONYMOUS_CLASS_PREFIX, $node->getStartLine(), $node->getEndLine()); + $this->classStack[] = $className; + } else { + $className = $node->name->name; + $this->classStack[] = $this->inNamespace !== null ? $this->inNamespace . '\\' . $className : $className; + } + } + + if ($node instanceof ClassMethod) { + $this->inMethod = $node->name->name; + } + + if ( + $this->inMethod !== null + && $node instanceof Node\Expr\FuncCall + && $node->name instanceof Name + && in_array((string) $node->name, ParametersAcceptor::VARIADIC_FUNCTIONS, true) + ) { + $lastClass = $this->classStack[count($this->classStack) - 1] ?? null; + if ($lastClass !== null) { + if ( + !array_key_exists($lastClass, $this->variadicMethods) + || !array_key_exists($this->inMethod, $this->variadicMethods[$lastClass]) + ) { + $this->variadicMethods[$lastClass][$this->inMethod] = true; + } + } + + } + + return null; + } + + public function leaveNode(Node $node): ?Node + { + if ($node instanceof ClassMethod) { + $lastClass = $this->classStack[count($this->classStack) - 1] ?? null; + if ($lastClass !== null) { + $this->variadicMethods[$lastClass][$this->inMethod] ??= false; + } + $this->inMethod = null; + } + + if ($node instanceof Node\Stmt\ClassLike) { + array_pop($this->classStack); + } + + if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) { + $this->inNamespace = null; + } + + return null; + } + + public function afterTraverse(array $nodes): ?array + { + if ($this->topNode !== null && $this->variadicMethods !== []) { + $filteredMethods = []; + foreach ($this->variadicMethods as $class => $methods) { + foreach ($methods as $name => $variadic) { + self::$cache[$class][$name] = $variadic; + if (!$variadic) { + continue; + } + + $filteredMethods[$class][$name] = true; + } + } + $this->topNode->setAttribute(self::ATTRIBUTE_NAME, $filteredMethods); + } + + return null; + } + +} diff --git a/src/Php/ComposerPhpVersionFactory.php b/src/Php/ComposerPhpVersionFactory.php new file mode 100644 index 0000000000..88b81022ee --- /dev/null +++ b/src/Php/ComposerPhpVersionFactory.php @@ -0,0 +1,121 @@ +initialized = true; + + // don't limit minVersion... PHPStan can analyze even PHP5 + $this->maxVersion = new PhpVersion(PhpVersionFactory::MAX_PHP_VERSION); + + // fallback to composer.json based php-version constraint + $composerPhpVersion = $this->getComposerRequireVersion(); + if ($composerPhpVersion === null) { + return; + } + + $parser = new VersionParser(); + $constraint = $parser->parseConstraints($composerPhpVersion); + + if (!$constraint->getLowerBound()->isZero()) { + $minVersion = $this->buildVersion($constraint->getLowerBound()->getVersion(), false); + + if ($minVersion !== null) { + $this->minVersion = new PhpVersion($minVersion->getVersionId()); + } + } + if ($constraint->getUpperBound()->isPositiveInfinity()) { + return; + } + + $this->maxVersion = $this->buildVersion($constraint->getUpperBound()->getVersion(), true); + } + + public function getMinVersion(): ?PhpVersion + { + if ($this->initialized === false) { + $this->initializeVersions(); + } + + return $this->minVersion; + } + + public function getMaxVersion(): ?PhpVersion + { + if ($this->initialized === false) { + $this->initializeVersions(); + } + + return $this->maxVersion; + } + + private function getComposerRequireVersion(): ?string + { + $composerPhpVersion = null; + + if (count($this->composerAutoloaderProjectPaths) > 0) { + $composer = ComposerHelper::getComposerConfig(end($this->composerAutoloaderProjectPaths)); + if ($composer !== null) { + $requiredVersion = $composer['require']['php'] ?? null; + + if (is_string($requiredVersion)) { + $composerPhpVersion = $requiredVersion; + } + } + } + + return $composerPhpVersion; + } + + private function buildVersion(string $version, bool $isMaxVersion): ?PhpVersion + { + $matches = Strings::match($version, '#^(\d+)\.(\d+)(?:\.(\d+))?#'); + if ($matches === null) { + return null; + } + + $major = $matches[1]; + $minor = $matches[2]; + $patch = $matches[3] ?? 0; + $versionId = (int) sprintf('%d%02d%02d', $major, $minor, $patch); + + if ($isMaxVersion && $version === '6.0.0.0-dev') { + $versionId = min($versionId, PhpVersionFactory::MAX_PHP5_VERSION); + } elseif ($isMaxVersion && $version === '8.0.0.0-dev') { + $versionId = min($versionId, PhpVersionFactory::MAX_PHP7_VERSION); + } else { + $versionId = min($versionId, PhpVersionFactory::MAX_PHP_VERSION); + } + + return new PhpVersion($versionId); + } + +} diff --git a/src/Php/PhpVersion.php b/src/Php/PhpVersion.php index b275c464eb..e636945cc2 100644 --- a/src/Php/PhpVersion.php +++ b/src/Php/PhpVersion.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class PhpVersion +final class PhpVersion { public const SOURCE_RUNTIME = 1; @@ -23,6 +22,14 @@ public function __construct(private int $versionId, private int $source = self:: { } + /** + * @return self::SOURCE_* + */ + public function getSource(): int + { + return $this->source; + } + public function getSourceLabel(): string { switch ($this->source) { @@ -42,11 +49,26 @@ public function getVersionId(): int return $this->versionId; } + public function getMajorVersionId(): int + { + return (int) floor($this->versionId / 10000); + } + + public function getMinorVersionId(): int + { + return (int) floor(($this->versionId % 10000) / 100); + } + + public function getPatchVersionId(): int + { + return (int) floor($this->versionId % 100); + } + public function getVersionString(): string { - $first = (int) floor($this->versionId / 10000); - $second = (int) floor(($this->versionId % 10000) / 100); - $third = (int) floor($this->versionId % 100); + $first = $this->getMajorVersionId(); + $second = $this->getMinorVersionId(); + $third = $this->getPatchVersionId(); return $first . '.' . $second . ($third !== 0 ? '.' . $third : ''); } @@ -325,6 +347,11 @@ public function supportsPregCaptureOnlyNamedGroups(): bool return $this->versionId >= 80200; } + public function supportsPropertyHooks(): bool + { + return $this->versionId >= 80400; + } + public function hasDateTimeExceptions(): bool { return $this->versionId >= 80300; diff --git a/src/Php/PhpVersionFactory.php b/src/Php/PhpVersionFactory.php index d926420e77..bd1bfcabf5 100644 --- a/src/Php/PhpVersionFactory.php +++ b/src/Php/PhpVersionFactory.php @@ -10,6 +10,11 @@ final class PhpVersionFactory { + public const MIN_PHP_VERSION = 70100; + public const MAX_PHP_VERSION = 80499; + public const MAX_PHP5_VERSION = 50699; + public const MAX_PHP7_VERSION = 70499; + public function __construct( private ?int $versionId, private ?string $composerPhpVersion, @@ -25,8 +30,8 @@ public function create(): PhpVersion } elseif ($this->composerPhpVersion !== null) { $parts = explode('.', $this->composerPhpVersion); $tmp = (int) $parts[0] * 10000 + (int) ($parts[1] ?? 0) * 100 + (int) ($parts[2] ?? 0); - $tmp = max($tmp, 70100); - $versionId = min($tmp, 80499); + $tmp = max($tmp, self::MIN_PHP_VERSION); + $versionId = min($tmp, self::MAX_PHP_VERSION); $source = PhpVersion::SOURCE_COMPOSER_PLATFORM_PHP; } else { $versionId = PHP_VERSION_ID; diff --git a/src/Php/PhpVersionFactoryFactory.php b/src/Php/PhpVersionFactoryFactory.php index c578ef06fc..0190ca0e82 100644 --- a/src/Php/PhpVersionFactoryFactory.php +++ b/src/Php/PhpVersionFactoryFactory.php @@ -8,17 +8,20 @@ use PHPStan\File\FileReader; use function count; use function end; +use function is_array; use function is_file; +use function is_int; use function is_string; final class PhpVersionFactoryFactory { /** + * @param int|array{min: int, max: int}|null $phpVersion * @param string[] $composerAutoloaderProjectPaths */ public function __construct( - private ?int $versionId, + private int|array|null $phpVersion, private array $composerAutoloaderProjectPaths, ) { @@ -43,7 +46,17 @@ public function create(): PhpVersionFactory } } - return new PhpVersionFactory($this->versionId, $composerPhpVersion); + $versionId = null; + + if (is_int($this->phpVersion)) { + $versionId = $this->phpVersion; + } + + if (is_array($this->phpVersion)) { + $versionId = $this->phpVersion['min']; + } + + return new PhpVersionFactory($versionId, $composerPhpVersion); } } diff --git a/src/Php/PhpVersions.php b/src/Php/PhpVersions.php new file mode 100644 index 0000000000..229dccb72d --- /dev/null +++ b/src/Php/PhpVersions.php @@ -0,0 +1,41 @@ +phpVersions; + } + + public function supportsNoncapturingCatches(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function producesWarningForFinalPrivateMethods(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result; + } + + public function supportsNamedArguments(): TrinaryLogic + { + return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result; + } + +} diff --git a/src/PhpDoc/ConstExprParserFactory.php b/src/PhpDoc/ConstExprParserFactory.php deleted file mode 100644 index 4af1282a78..0000000000 --- a/src/PhpDoc/ConstExprParserFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -unescapeStrings, $this->unescapeStrings); - } - -} diff --git a/src/PhpDoc/CountableStubFilesExtension.php b/src/PhpDoc/CountableStubFilesExtension.php deleted file mode 100644 index 3fc3a15666..0000000000 --- a/src/PhpDoc/CountableStubFilesExtension.php +++ /dev/null @@ -1,21 +0,0 @@ -bleedingEdge) { - return [__DIR__ . '/../../stubs/bleedingEdge/Countable.stub']; - } - - return [__DIR__ . '/../../stubs/Countable.stub']; - } - -} diff --git a/src/PhpDoc/PhpDocBlock.php b/src/PhpDoc/PhpDocBlock.php index fd75fa5306..c64a74cea2 100644 --- a/src/PhpDoc/PhpDocBlock.php +++ b/src/PhpDoc/PhpDocBlock.php @@ -3,8 +3,8 @@ namespace PHPStan\PhpDoc; use PHPStan\PhpDoc\Tag\AssertTagParameter; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Reflection\Php\PhpPropertyReflection; @@ -334,7 +334,7 @@ private static function resolvePhpDocBlockFromClass( ): ?self { if ($classReflection->$hasMethodName($name)) { - /** @var PropertyReflection|MethodReflection|ConstantReflection $parentReflection */ + /** @var PropertyReflection|MethodReflection|ClassConstantReflection $parentReflection */ $parentReflection = $classReflection->$getMethodName($name); if ($parentReflection->isPrivate()) { return null; diff --git a/src/PhpDoc/PhpDocNodeResolver.php b/src/PhpDoc/PhpDocNodeResolver.php index 02fed04bcc..1c31ee55d0 100644 --- a/src/PhpDoc/PhpDocNodeResolver.php +++ b/src/PhpDoc/PhpDocNodeResolver.php @@ -112,7 +112,6 @@ public function resolvePropertyTags(PhpDocNode $phpDocNode, NameScope $nameScope $resolved[$propertyName] = new PropertyTag( $propertyType, $propertyType, - $propertyType, ); } } @@ -128,7 +127,6 @@ public function resolvePropertyTags(PhpDocNode $phpDocNode, NameScope $nameScope } $resolved[$propertyName] = new PropertyTag( - $propertyType, $propertyType, $writableType, ); @@ -146,7 +144,6 @@ public function resolvePropertyTags(PhpDocNode $phpDocNode, NameScope $nameScope } $resolved[$propertyName] = new PropertyTag( - $readableType ?? $propertyType, $readableType, $propertyType, ); @@ -593,19 +590,19 @@ private function resolveAssertTagsFor(PhpDocNode $phpDocNode, NameScope $nameSco foreach ($phpDocNode->getAssertTagValues($tagName) as $assertTagValue) { $type = $this->typeNodeResolver->resolve($assertTagValue->type, $nameScope); $parameter = new AssertTagParameter($assertTagValue->parameter, null, null); - $resolved[] = new AssertTag($if, $type, $parameter, $assertTagValue->isNegated, $assertTagValue->isEquality ?? false, true); + $resolved[] = new AssertTag($if, $type, $parameter, $assertTagValue->isNegated, $assertTagValue->isEquality, true); } foreach ($phpDocNode->getAssertPropertyTagValues($tagName) as $assertTagValue) { $type = $this->typeNodeResolver->resolve($assertTagValue->type, $nameScope); $parameter = new AssertTagParameter($assertTagValue->parameter, $assertTagValue->property, null); - $resolved[] = new AssertTag($if, $type, $parameter, $assertTagValue->isNegated, $assertTagValue->isEquality ?? false, true); + $resolved[] = new AssertTag($if, $type, $parameter, $assertTagValue->isNegated, $assertTagValue->isEquality, true); } foreach ($phpDocNode->getAssertMethodTagValues($tagName) as $assertTagValue) { $type = $this->typeNodeResolver->resolve($assertTagValue->type, $nameScope); $parameter = new AssertTagParameter($assertTagValue->parameter, null, $assertTagValue->method); - $resolved[] = new AssertTag($if, $type, $parameter, $assertTagValue->isNegated, $assertTagValue->isEquality ?? false, true); + $resolved[] = new AssertTag($if, $type, $parameter, $assertTagValue->isNegated, $assertTagValue->isEquality, true); } return $resolved; diff --git a/src/PhpDoc/ResolvedPhpDocBlock.php b/src/PhpDoc/ResolvedPhpDocBlock.php index ed45d60e48..6cd991341b 100644 --- a/src/PhpDoc/ResolvedPhpDocBlock.php +++ b/src/PhpDoc/ResolvedPhpDocBlock.php @@ -42,9 +42,8 @@ /** * @api - * @final */ -class ResolvedPhpDocBlock +final class ResolvedPhpDocBlock { public const EMPTY_DOC_STRING = '/** */'; diff --git a/src/PhpDoc/StubValidator.php b/src/PhpDoc/StubValidator.php index ee4fcaa2a2..39ebcf09b3 100644 --- a/src/PhpDoc/StubValidator.php +++ b/src/PhpDoc/StubValidator.php @@ -6,7 +6,6 @@ use PHPStan\Analyser\FileAnalyser; use PHPStan\Analyser\InternalError; use PHPStan\Analyser\NodeScopeResolver; -use PHPStan\Broker\Broker; use PHPStan\Collectors\Registry as CollectorRegistry; use PHPStan\DependencyInjection\Container; use PHPStan\DependencyInjection\DerivativeContainerFactory; @@ -48,6 +47,8 @@ use PHPStan\Rules\Generics\ClassAncestorsRule; use PHPStan\Rules\Generics\ClassTemplateTypeRule; use PHPStan\Rules\Generics\CrossCheckInterfacesHelper; +use PHPStan\Rules\Generics\EnumAncestorsRule; +use PHPStan\Rules\Generics\EnumTemplateTypeRule; use PHPStan\Rules\Generics\FunctionSignatureVarianceRule; use PHPStan\Rules\Generics\FunctionTemplateTypeRule; use PHPStan\Rules\Generics\GenericAncestorsCheck; @@ -59,8 +60,10 @@ use PHPStan\Rules\Generics\MethodTagTemplateTypeRule; use PHPStan\Rules\Generics\MethodTagTemplateTypeTraitRule; use PHPStan\Rules\Generics\MethodTemplateTypeRule; +use PHPStan\Rules\Generics\PropertyVarianceRule; use PHPStan\Rules\Generics\TemplateTypeCheck; use PHPStan\Rules\Generics\TraitTemplateTypeRule; +use PHPStan\Rules\Generics\UsedTraitsRule; use PHPStan\Rules\Generics\VarianceCheck; use PHPStan\Rules\Methods\ExistingClassesInTypehintsRule; use PHPStan\Rules\Methods\MethodParameterComparisonHelper; @@ -70,6 +73,10 @@ use PHPStan\Rules\Methods\MissingMethodSelfOutTypeRule; use PHPStan\Rules\Methods\OverridingMethodRule; use PHPStan\Rules\MissingTypehintCheck; +use PHPStan\Rules\PhpDoc\AssertRuleHelper; +use PHPStan\Rules\PhpDoc\ConditionalReturnTypeRuleHelper; +use PHPStan\Rules\PhpDoc\FunctionAssertRule; +use PHPStan\Rules\PhpDoc\FunctionConditionalReturnTypeRule; use PHPStan\Rules\PhpDoc\GenericCallableRuleHelper; use PHPStan\Rules\PhpDoc\IncompatibleClassConstantPhpDocTypeRule; use PHPStan\Rules\PhpDoc\IncompatibleParamImmediatelyInvokedCallableRule; @@ -79,6 +86,8 @@ use PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule; use PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule; use PHPStan\Rules\PhpDoc\InvalidThrowsPhpDocValueRule; +use PHPStan\Rules\PhpDoc\MethodAssertRule; +use PHPStan\Rules\PhpDoc\MethodConditionalReturnTypeRule; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; use PHPStan\Rules\Properties\ExistingClassesInPropertiesRule; use PHPStan\Rules\Properties\MissingPropertyTypehintRule; @@ -95,7 +104,6 @@ final class StubValidator public function __construct( private DerivativeContainerFactory $derivativeContainerFactory, - private bool $duplicateStubs, ) { } @@ -110,7 +118,6 @@ public function validate(array $stubFiles, bool $debug): array return []; } - $originalBroker = Broker::getInstance(); $originalReflectionProvider = ReflectionProviderStaticAccessor::getInstance(); $originalPhpVersion = PhpVersionStaticAccessor::getInstance(); $container = $this->derivativeContainerFactory->create([ @@ -159,7 +166,6 @@ static function (): void { } } - Broker::registerInstance($originalBroker); ReflectionProviderStaticAccessor::registerInstance($originalReflectionProvider); PhpVersionStaticAccessor::registerInstance($originalPhpVersion); ObjectType::resetCaches(); @@ -186,6 +192,12 @@ private function getRuleRegistry(Container $container): RuleRegistry $genericCallableRuleHelper = $container->getByType(GenericCallableRuleHelper::class); $methodTagTemplateTypeCheck = $container->getByType(MethodTagTemplateTypeCheck::class); $mixinCheck = $container->getByType(MixinCheck::class); + $methodTagCheck = new MethodTagCheck($reflectionProvider, $classNameCheck, $genericObjectTypeCheck, $missingTypehintCheck, $unresolvableTypeHelper, true, true); + $propertyTagCheck = new PropertyTagCheck($reflectionProvider, $classNameCheck, $genericObjectTypeCheck, $missingTypehintCheck, $unresolvableTypeHelper, true, true); + $reflector = $container->getService('stubReflector'); + $relativePathHelper = $container->getService('simpleRelativePathHelper'); + $assertRuleHelper = $container->getByType(AssertRuleHelper::class); + $conditionalReturnTypeRuleHelper = $container->getByType(ConditionalReturnTypeRuleHelper::class); $rules = [ // level 0 @@ -196,10 +208,11 @@ private function getRuleRegistry(Container $container): RuleRegistry new ExistingClassesInTypehintsRule($functionDefinitionCheck), new \PHPStan\Rules\Functions\ExistingClassesInTypehintsRule($functionDefinitionCheck), new ExistingClassesInPropertiesRule($reflectionProvider, $classNameCheck, $unresolvableTypeHelper, $phpVersion, true, false), - new OverridingMethodRule($phpVersion, new MethodSignatureRule($phpClassReflectionExtension, true, true, $container->getParameter('featureToggles')['abstractTraitMethod']), true, new MethodParameterComparisonHelper($phpVersion, $container->getParameter('featureToggles')['genericPrototypeMessage']), $phpClassReflectionExtension, $container->getParameter('featureToggles')['genericPrototypeMessage'], $container->getParameter('featureToggles')['finalByPhpDoc'], $container->getParameter('checkMissingOverrideMethodAttribute')), + new OverridingMethodRule($phpVersion, new MethodSignatureRule($phpClassReflectionExtension, true, true), true, new MethodParameterComparisonHelper($phpVersion), $phpClassReflectionExtension, $container->getParameter('checkMissingOverrideMethodAttribute')), new DuplicateDeclarationRule(), new LocalTypeAliasesRule($localTypeAliasesCheck), new LocalTypeTraitAliasesRule($localTypeAliasesCheck, $reflectionProvider), + new LocalTypeTraitUseAliasesRule($localTypeAliasesCheck), // level 2 new ClassAncestorsRule($genericAncestorsCheck, $crossCheckInterfacesHelper), @@ -217,55 +230,46 @@ 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), + new MixinTraitRule($mixinCheck, $reflectionProvider), + new MixinRule($mixinCheck), + new MixinTraitUseRule($mixinCheck), + new MethodTagRule($methodTagCheck), + new MethodTagTraitRule($methodTagCheck, $reflectionProvider), + new MethodTagTraitUseRule($methodTagCheck), + new MethodTagTemplateTypeTraitRule($methodTagTemplateTypeCheck, $reflectionProvider), + new PropertyTagRule($propertyTagCheck), + new PropertyTagTraitRule($propertyTagCheck, $reflectionProvider), + new PropertyTagTraitUseRule($propertyTagCheck), + new EnumAncestorsRule($genericAncestorsCheck, $crossCheckInterfacesHelper), + new EnumTemplateTypeRule(), + new PropertyVarianceRule($varianceCheck), + new UsedTraitsRule($fileTypeMapper, $genericAncestorsCheck), + new FunctionAssertRule($assertRuleHelper), + new MethodAssertRule($assertRuleHelper), + new FunctionConditionalReturnTypeRule($conditionalReturnTypeRuleHelper), + new MethodConditionalReturnTypeRule($conditionalReturnTypeRuleHelper), // level 6 - new MissingFunctionParameterTypehintRule($missingTypehintCheck, $container->getParameter('featureToggles')['paramOutType']), + new MissingFunctionParameterTypehintRule($missingTypehintCheck), new MissingFunctionReturnTypehintRule($missingTypehintCheck), - new MissingMethodParameterTypehintRule($missingTypehintCheck, $container->getParameter('featureToggles')['paramOutType']), + new MissingMethodParameterTypehintRule($missingTypehintCheck), new MissingMethodReturnTypehintRule($missingTypehintCheck), new MissingPropertyTypehintRule($missingTypehintCheck), - ]; - - if ($this->duplicateStubs) { - $reflector = $container->getService('stubReflector'); - $relativePathHelper = $container->getService('simpleRelativePathHelper'); - $rules[] = new DuplicateClassDeclarationRule($reflector, $relativePathHelper); - $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); + new MissingMethodSelfOutTypeRule($missingTypehintCheck), - $methodTagCheck = new MethodTagCheck($reflectionProvider, $classNameCheck, $genericObjectTypeCheck, $missingTypehintCheck, $unresolvableTypeHelper, true, true); - $rules[] = new MethodTagRule($methodTagCheck); - $rules[] = new MethodTagTraitRule($methodTagCheck, $reflectionProvider); - $rules[] = new MethodTagTraitUseRule($methodTagCheck); - - $propertyTagCheck = new PropertyTagCheck($reflectionProvider, $classNameCheck, $genericObjectTypeCheck, $missingTypehintCheck, $unresolvableTypeHelper, true, true); - $rules[] = new PropertyTagRule($propertyTagCheck); - $rules[] = new PropertyTagTraitRule($propertyTagCheck, $reflectionProvider); - $rules[] = new PropertyTagTraitUseRule($propertyTagCheck); - $rules[] = new MixinRule($mixinCheck); - $rules[] = new MixinTraitRule($mixinCheck, $reflectionProvider); - $rules[] = new MixinTraitUseRule($mixinCheck); - $rules[] = new LocalTypeTraitUseAliasesRule($localTypeAliasesCheck); - $rules[] = new MethodTagTemplateTypeTraitRule($methodTagTemplateTypeCheck, $reflectionProvider); - } + // duplicate stubs + new DuplicateClassDeclarationRule($reflector, $relativePathHelper), + new DuplicateFunctionDeclarationRule($reflector, $relativePathHelper), + ]; return new DirectRuleRegistry($rules); } diff --git a/src/PhpDoc/Tag/DeprecatedTag.php b/src/PhpDoc/Tag/DeprecatedTag.php index e7bf3c553f..9bc036e1d8 100644 --- a/src/PhpDoc/Tag/DeprecatedTag.php +++ b/src/PhpDoc/Tag/DeprecatedTag.php @@ -4,9 +4,8 @@ /** * @api - * @final */ -class DeprecatedTag +final class DeprecatedTag { public function __construct(private ?string $message) diff --git a/src/PhpDoc/Tag/ExtendsTag.php b/src/PhpDoc/Tag/ExtendsTag.php index e8a48922b4..72cb97f7cf 100644 --- a/src/PhpDoc/Tag/ExtendsTag.php +++ b/src/PhpDoc/Tag/ExtendsTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ExtendsTag +final class ExtendsTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/ImplementsTag.php b/src/PhpDoc/Tag/ImplementsTag.php index bc82888d3f..556959b68d 100644 --- a/src/PhpDoc/Tag/ImplementsTag.php +++ b/src/PhpDoc/Tag/ImplementsTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ImplementsTag +final class ImplementsTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/MethodTag.php b/src/PhpDoc/Tag/MethodTag.php index 793fd3d6d2..43bda4cf97 100644 --- a/src/PhpDoc/Tag/MethodTag.php +++ b/src/PhpDoc/Tag/MethodTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class MethodTag +final class MethodTag { /** @@ -19,7 +18,7 @@ public function __construct( private Type $returnType, private bool $isStatic, private array $parameters, - private array $templateTags = [], + private array $templateTags, ) { } diff --git a/src/PhpDoc/Tag/MethodTagParameter.php b/src/PhpDoc/Tag/MethodTagParameter.php index 21f4377ce6..3e4c817bf8 100644 --- a/src/PhpDoc/Tag/MethodTagParameter.php +++ b/src/PhpDoc/Tag/MethodTagParameter.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class MethodTagParameter +final class MethodTagParameter { public function __construct( diff --git a/src/PhpDoc/Tag/MixinTag.php b/src/PhpDoc/Tag/MixinTag.php index 5df36d74bd..c115c2cacb 100644 --- a/src/PhpDoc/Tag/MixinTag.php +++ b/src/PhpDoc/Tag/MixinTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class MixinTag +final class MixinTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/ParamClosureThisTag.php b/src/PhpDoc/Tag/ParamClosureThisTag.php index ae601dabc2..92a91a4da8 100644 --- a/src/PhpDoc/Tag/ParamClosureThisTag.php +++ b/src/PhpDoc/Tag/ParamClosureThisTag.php @@ -6,7 +6,6 @@ /** * @api - * @final */ final class ParamClosureThisTag implements TypedTag { @@ -22,10 +21,7 @@ public function getType(): Type return $this->type; } - /** - * @return self - */ - public function withType(Type $type): TypedTag + public function withType(Type $type): self { return new self($type); } diff --git a/src/PhpDoc/Tag/ParamOutTag.php b/src/PhpDoc/Tag/ParamOutTag.php index 8bc982f292..f720897deb 100644 --- a/src/PhpDoc/Tag/ParamOutTag.php +++ b/src/PhpDoc/Tag/ParamOutTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ParamOutTag implements TypedTag +final class ParamOutTag implements TypedTag { public function __construct(private Type $type) @@ -20,10 +19,7 @@ public function getType(): Type return $this->type; } - /** - * @return self - */ - public function withType(Type $type): TypedTag + public function withType(Type $type): self { return new self($type); } diff --git a/src/PhpDoc/Tag/ParamTag.php b/src/PhpDoc/Tag/ParamTag.php index f21038c4e1..498dd64ce7 100644 --- a/src/PhpDoc/Tag/ParamTag.php +++ b/src/PhpDoc/Tag/ParamTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ParamTag implements TypedTag +final class ParamTag implements TypedTag { public function __construct( @@ -28,10 +27,7 @@ public function isVariadic(): bool return $this->isVariadic; } - /** - * @return self - */ - public function withType(Type $type): TypedTag + public function withType(Type $type): self { return new self($type, $this->isVariadic); } diff --git a/src/PhpDoc/Tag/PropertyTag.php b/src/PhpDoc/Tag/PropertyTag.php index a46bb9cdbf..16090c44b0 100644 --- a/src/PhpDoc/Tag/PropertyTag.php +++ b/src/PhpDoc/Tag/PropertyTag.php @@ -6,27 +6,17 @@ /** * @api - * @final */ -class PropertyTag +final class PropertyTag { public function __construct( - private Type $type, private ?Type $readableType, private ?Type $writableType, ) { } - /** - * @deprecated Use getReadableType() / getWritableType() - */ - public function getType(): Type - { - return $this->type; - } - public function getReadableType(): ?Type { return $this->readableType; diff --git a/src/PhpDoc/Tag/RequireExtendsTag.php b/src/PhpDoc/Tag/RequireExtendsTag.php index 60861f7615..97bf685468 100644 --- a/src/PhpDoc/Tag/RequireExtendsTag.php +++ b/src/PhpDoc/Tag/RequireExtendsTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class RequireExtendsTag +final class RequireExtendsTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/RequireImplementsTag.php b/src/PhpDoc/Tag/RequireImplementsTag.php index 12702bce71..aafd560260 100644 --- a/src/PhpDoc/Tag/RequireImplementsTag.php +++ b/src/PhpDoc/Tag/RequireImplementsTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class RequireImplementsTag +final class RequireImplementsTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/ReturnTag.php b/src/PhpDoc/Tag/ReturnTag.php index ef5b130293..b501dd67e1 100644 --- a/src/PhpDoc/Tag/ReturnTag.php +++ b/src/PhpDoc/Tag/ReturnTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ReturnTag implements TypedTag +final class ReturnTag implements TypedTag { public function __construct(private Type $type, private bool $isExplicit) @@ -25,10 +24,7 @@ public function isExplicit(): bool return $this->isExplicit; } - /** - * @return self - */ - public function withType(Type $type): TypedTag + public function withType(Type $type): self { return new self($type, $this->isExplicit); } diff --git a/src/PhpDoc/Tag/SelfOutTypeTag.php b/src/PhpDoc/Tag/SelfOutTypeTag.php index 1e1dacc2fa..10bb054179 100644 --- a/src/PhpDoc/Tag/SelfOutTypeTag.php +++ b/src/PhpDoc/Tag/SelfOutTypeTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class SelfOutTypeTag implements TypedTag +final class SelfOutTypeTag implements TypedTag { public function __construct(private Type $type) @@ -20,10 +19,7 @@ public function getType(): Type return $this->type; } - /** - * @return self - */ - public function withType(Type $type): TypedTag + public function withType(Type $type): self { return new self($type); } diff --git a/src/PhpDoc/Tag/TemplateTag.php b/src/PhpDoc/Tag/TemplateTag.php index 4ae755597f..bafa555833 100644 --- a/src/PhpDoc/Tag/TemplateTag.php +++ b/src/PhpDoc/Tag/TemplateTag.php @@ -7,9 +7,8 @@ /** * @api - * @final */ -class TemplateTag +final class TemplateTag { /** diff --git a/src/PhpDoc/Tag/ThrowsTag.php b/src/PhpDoc/Tag/ThrowsTag.php index 220eefae95..1c1e30b897 100644 --- a/src/PhpDoc/Tag/ThrowsTag.php +++ b/src/PhpDoc/Tag/ThrowsTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class ThrowsTag +final class ThrowsTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/TypeAliasTag.php b/src/PhpDoc/Tag/TypeAliasTag.php index 5a360b8613..d5cd10e5d6 100644 --- a/src/PhpDoc/Tag/TypeAliasTag.php +++ b/src/PhpDoc/Tag/TypeAliasTag.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class TypeAliasTag +final class TypeAliasTag { public function __construct( diff --git a/src/PhpDoc/Tag/UsesTag.php b/src/PhpDoc/Tag/UsesTag.php index 63ec60d0b4..1679997ed3 100644 --- a/src/PhpDoc/Tag/UsesTag.php +++ b/src/PhpDoc/Tag/UsesTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class UsesTag +final class UsesTag { public function __construct(private Type $type) diff --git a/src/PhpDoc/Tag/VarTag.php b/src/PhpDoc/Tag/VarTag.php index 0d93daeac8..85c26f1b6c 100644 --- a/src/PhpDoc/Tag/VarTag.php +++ b/src/PhpDoc/Tag/VarTag.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class VarTag implements TypedTag +final class VarTag implements TypedTag { public function __construct(private Type $type) @@ -20,10 +19,7 @@ public function getType(): Type return $this->type; } - /** - * @return self - */ - public function withType(Type $type): TypedTag + public function withType(Type $type): self { return new self($type); } diff --git a/src/PhpDoc/TypeNodeResolver.php b/src/PhpDoc/TypeNodeResolver.php index 744265adf6..715311c8b5 100644 --- a/src/PhpDoc/TypeNodeResolver.php +++ b/src/PhpDoc/TypeNodeResolver.php @@ -60,6 +60,7 @@ use PHPStan\Type\ClosureType; use PHPStan\Type\ConditionalType; use PHPStan\Type\ConditionalTypeForParameter; +use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantArrayTypeBuilder; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantFloatType; @@ -430,15 +431,11 @@ private function resolveIdentifierTypeNode(IdentifierTypeNode $typeNode, NameSco return new NonAcceptingNeverType(); case 'list': - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType())); + return TypeCombinator::intersect(new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), new AccessoryArrayListType()); case 'non-empty-list': - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( - new ArrayType(new IntegerType(), new MixedType()), - new NonEmptyArrayType(), - )); - case '__always-list': return TypeCombinator::intersect( - new ArrayType(new IntegerType(), new MixedType()), + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), + new NonEmptyArrayType(), new AccessoryArrayListType(), ); @@ -583,10 +580,12 @@ private function resolveUnionTypeNode(UnionTypeNode $typeNode, NameScope $nameSc continue; } - if ($type instanceof ObjectType) { + if ($type instanceof ObjectType && !$type instanceof GenericObjectType) { $type = new IntersectionType([$type, new IterableType(new MixedType(), $arrayTypeType)]); } elseif ($type instanceof ArrayType) { $type = new ArrayType(new MixedType(), $arrayTypeType); + } elseif ($type instanceof ConstantArrayType) { + $type = new ArrayType(new MixedType(), $arrayTypeType); } elseif ($type instanceof IterableType) { $type = new IterableType(new MixedType(), $arrayTypeType); } else { @@ -678,7 +677,7 @@ static function (string $variance): TemplateTypeVariance { return $arrayType; } elseif (in_array($mainTypeName, ['list', 'non-empty-list'], true)) { if (count($genericTypes) === 1) { // list - $listType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $genericTypes[0])); + $listType = TypeCombinator::intersect(new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), $genericTypes[0]), new AccessoryArrayListType()); if ($mainTypeName === 'non-empty-list') { return TypeCombinator::intersect($listType, new NonEmptyArrayType()); } @@ -924,7 +923,7 @@ private function resolveCallableTypeNode(CallableTypeNode $typeNode, NameScope $ { $templateTags = []; - if (count($typeNode->templateTypes ?? []) > 0) { + if (count($typeNode->templateTypes) > 0) { foreach ($typeNode->templateTypes as $templateType) { $templateTags[$templateType->name] = new TemplateTag( $templateType->name, @@ -952,7 +951,7 @@ private function resolveCallableTypeNode(CallableTypeNode $typeNode, NameScope $ $mainType = $this->resolve($typeNode->identifier, $nameScope); $isVariadic = false; - $parameters = array_map( + $parameters = array_values(array_map( function (CallableTypeParameterNode $parameterNode) use ($nameScope, &$isVariadic): NativeParameterReflection { $isVariadic = $isVariadic || $parameterNode->isVariadic; $parameterName = $parameterNode->parameterName; @@ -970,7 +969,7 @@ function (CallableTypeParameterNode $parameterNode) use ($nameScope, &$isVariadi ); }, $typeNode->parameters, - ); + )); $returnType = $this->resolve($typeNode->returnType, $nameScope); @@ -1031,7 +1030,7 @@ private function resolveArrayShapeNode(ArrayShapeNode $typeNode, NameScope $name ArrayShapeNode::KIND_LIST, ArrayShapeNode::KIND_NON_EMPTY_LIST, ], true)) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); + $arrayType = TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } if (in_array($typeNode->kind, [ @@ -1231,7 +1230,7 @@ private function expandIntMaskToType(Type $type): ?Type /** * @api * @param TypeNode[] $typeNodes - * @return Type[] + * @return list */ public function resolveMultiple(array $typeNodes, NameScope $nameScope): array { diff --git a/src/Reflection/Annotations/AnnotationMethodReflection.php b/src/Reflection/Annotations/AnnotationMethodReflection.php index b4065332ce..865abdbe04 100644 --- a/src/Reflection/Annotations/AnnotationMethodReflection.php +++ b/src/Reflection/Annotations/AnnotationMethodReflection.php @@ -5,9 +5,9 @@ use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\MixedType; @@ -17,11 +17,11 @@ final class AnnotationMethodReflection implements ExtendedMethodReflection { - /** @var FunctionVariantWithPhpDocs[]|null */ + /** @var list|null */ private ?array $variants = null; /** - * @param AnnotationsMethodParameterReflection[] $parameters + * @param list $parameters */ public function __construct( private string $name, @@ -70,7 +70,7 @@ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( $this->templateTypeMap, null, $this->parameters, @@ -84,7 +84,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -147,9 +147,9 @@ public function getAsserts(): Assertions return Assertions::createEmpty(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->declaringClass->acceptsNamedArguments(); + return TrinaryLogic::createFromBoolean($this->declaringClass->acceptsNamedArguments()); } public function getSelfOutType(): ?Type diff --git a/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php b/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php index cb86e0fec4..51bddcaabe 100644 --- a/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php +++ b/src/Reflection/Annotations/AnnotationsMethodParameterReflection.php @@ -2,13 +2,13 @@ namespace PHPStan\Reflection\Annotations; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\PassedByReference; use PHPStan\TrinaryLogic; use PHPStan\Type\MixedType; use PHPStan\Type\Type; -final class AnnotationsMethodParameterReflection implements ParameterReflectionWithPhpDocs +final class AnnotationsMethodParameterReflection implements ExtendedParameterReflection { public function __construct(private string $name, private Type $type, private PassedByReference $passedByReference, private bool $isOptional, private bool $isVariadic, private ?Type $defaultValue) diff --git a/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php b/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php index c234e8e2d1..9ad470b0ee 100644 --- a/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php +++ b/src/Reflection/Annotations/AnnotationsMethodsClassReflectionExtension.php @@ -5,7 +5,6 @@ use PHPStan\PhpDoc\Tag\TemplateTag; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodsClassReflectionExtension; use PHPStan\Type\Generic\TemplateTypeFactory; use PHPStan\Type\Generic\TemplateTypeHelper; @@ -35,10 +34,7 @@ public function hasMethod(ClassReflection $classReflection, string $methodName): return isset($this->methods[$classReflection->getCacheKey()][$methodName]); } - /** - * @return ExtendedMethodReflection - */ - public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection + public function getMethod(ClassReflection $classReflection, string $methodName): ExtendedMethodReflection { return $this->methods[$classReflection->getCacheKey()][$methodName]; } diff --git a/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php b/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php index d6d69179d5..5d25367e70 100644 --- a/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php +++ b/src/Reflection/Annotations/AnnotationsPropertiesClassReflectionExtension.php @@ -5,7 +5,6 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\PropertiesClassReflectionExtension; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Type\Generic\TemplateTypeHelper; use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\NeverType; @@ -29,10 +28,7 @@ public function hasProperty(ClassReflection $classReflection, string $propertyNa return isset($this->properties[$classReflection->getCacheKey()][$propertyName]); } - /** - * @return ExtendedPropertyReflection - */ - public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection + public function getProperty(ClassReflection $classReflection, string $propertyName): ExtendedPropertyReflection { return $this->properties[$classReflection->getCacheKey()][$propertyName]; } diff --git a/src/Reflection/Assertions.php b/src/Reflection/Assertions.php index 988652d0d4..a1f7ebfa6d 100644 --- a/src/Reflection/Assertions.php +++ b/src/Reflection/Assertions.php @@ -12,9 +12,8 @@ /** * @api - * @final */ -class Assertions +final class Assertions { private static ?self $empty = null; diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php index 6ae28ec9c6..72f918f62b 100644 --- a/src/Reflection/BetterReflection/BetterReflectionProvider.php +++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php @@ -34,9 +34,9 @@ use PHPStan\Reflection\ClassNameHelper; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\Constant\RuntimeConstantReflection; +use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\FunctionReflection; use PHPStan\Reflection\FunctionReflectionFactory; -use PHPStan\Reflection\GlobalConstantReflection; use PHPStan\Reflection\InitializerExprContext; use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\Reflection\NamespaceAnswerer; @@ -51,6 +51,7 @@ use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Type; use function array_key_exists; +use function array_key_first; use function array_map; use function base64_decode; use function in_array; @@ -70,11 +71,11 @@ final class BetterReflectionProvider implements ReflectionProvider /** @var ClassReflection[] */ private static array $anonymousClasses = []; - /** @var array */ + /** @var array */ private array $cachedConstants = []; /** - * @param string[] $universalObjectCratesClasses + * @param list $universalObjectCratesClasses */ public function __construct( private ReflectionProvider\ReflectionProviderProvider $reflectionProviderProvider, @@ -178,11 +179,6 @@ public function getClassName(string $className): string return $reflectionClass->getName(); } - public function supportsAnonymousClasses(): bool - { - return true; - } - public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope): ClassReflection { if (isset($classNode->namespacedName)) { @@ -204,6 +200,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]; @@ -216,12 +213,23 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $ null, ); + $displayParentName = $reflectionClass->getParentClassName(); + if ($displayParentName === null) { + // https://3v4l.org/6FBuP + $classInterfaceNames = $reflectionClass->getInterfaceNames(); + if ($classInterfaceNames !== []) { + $displayParentName = $classInterfaceNames[array_key_first($classInterfaceNames)]; + } else { + $displayParentName = 'class'; + } + } + /** @var int|null $classLineIndex */ $classLineIndex = $classNode->getAttribute(AnonymousClassVisitor::ATTRIBUTE_LINE_INDEX); if ($classLineIndex === null) { - $displayName = sprintf('class@anonymous/%s:%s', $filename, $classNode->getStartLine()); + $displayName = sprintf('%s@anonymous/%s:%s', $displayParentName, $filename, $classNode->getStartLine()); } else { - $displayName = sprintf('class@anonymous/%s:%s:%d', $filename, $classNode->getStartLine(), $classLineIndex); + $displayName = sprintf('%s@anonymous/%s:%s:%d', $displayParentName, $filename, $classNode->getStartLine(), $classLineIndex); } self::$anonymousClasses[$className] = new ClassReflection( @@ -249,6 +257,11 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $ return self::$anonymousClasses[$className]; } + public function getUniversalObjectCratesClasses(): array + { + return $this->universalObjectCratesClasses; + } + public function hasFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool { return $this->resolveFunctionName($nameNode, $namespaceAnswerer) !== null; @@ -291,7 +304,6 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $deprecatedTag = null; $isDeprecated = false; $isInternal = false; - $isFinal = false; $isPure = null; $asserts = Assertions::createEmpty(); $acceptsNamedArguments = true; @@ -314,7 +326,6 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $deprecatedTag = $resolvedPhpDoc->getDeprecatedTag(); $isDeprecated = $resolvedPhpDoc->isDeprecated(); $isInternal = $resolvedPhpDoc->isInternal(); - $isFinal = $resolvedPhpDoc->isFinal(); $isPure = $resolvedPhpDoc->isPure(); $asserts = Assertions::createFromResolvedPhpDocBlock($resolvedPhpDoc); if ($resolvedPhpDoc->hasPhpDocString()) { @@ -335,7 +346,6 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection $deprecatedTag !== null ? $deprecatedTag->getMessage() : null, $isDeprecated, $isInternal, - $isFinal, $reflectionFunction->getFileName() !== false ? $reflectionFunction->getFileName() : null, $isPure, $asserts, @@ -376,7 +386,7 @@ public function hasConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn return $this->resolveConstantName($nameNode, $namespaceAnswerer) !== null; } - public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): GlobalConstantReflection + public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ConstantReflection { $constantName = $this->resolveConstantName($nameNode, $namespaceAnswerer); if ($constantName === 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/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php deleted file mode 100644 index cc939049bc..0000000000 --- a/src/Reflection/BetterReflection/SourceLocator/NewOptimizedDirectorySourceLocator.php +++ /dev/null @@ -1,217 +0,0 @@ - $classToFile - * @param array> $functionToFiles - * @param array $constantToFile - */ - public function __construct( - private FileNodesFetcher $fileNodesFetcher, - private array $classToFile, - private array $functionToFiles, - private array $constantToFile, - ) - { - } - - public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection - { - if ($identifier->isClass()) { - $className = strtolower($identifier->getName()); - $file = $this->findFileByClass($className); - if ($file === null) { - return null; - } - - $fetchedClassNodes = $this->fileNodesFetcher->fetchNodes($file)->getClassNodes(); - - if (!array_key_exists($className, $fetchedClassNodes)) { - return null; - } - - /** @var FetchedNode $fetchedClassNode */ - $fetchedClassNode = current($fetchedClassNodes[$className]); - - return $this->nodeToReflection($reflector, $fetchedClassNode); - } - - if ($identifier->isFunction()) { - $functionName = strtolower($identifier->getName()); - $files = $this->findFilesByFunction($functionName); - - $fetchedFunctionNode = null; - foreach ($files as $file) { - $fetchedFunctionNodes = $this->fileNodesFetcher->fetchNodes($file)->getFunctionNodes(); - - if (!array_key_exists($functionName, $fetchedFunctionNodes)) { - continue; - } - - /** @var FetchedNode $fetchedFunctionNode */ - $fetchedFunctionNode = current($fetchedFunctionNodes[$functionName]); - } - - if ($fetchedFunctionNode === null) { - return null; - } - - return $this->nodeToReflection($reflector, $fetchedFunctionNode); - } - - if ($identifier->isConstant()) { - $constantName = ConstantNameHelper::normalize($identifier->getName()); - $file = $this->findFileByConstant($constantName); - - if ($file === null) { - return null; - } - - $fetchedConstantNodes = $this->fileNodesFetcher->fetchNodes($file)->getConstantNodes(); - - if (!array_key_exists($constantName, $fetchedConstantNodes)) { - return null; - } - - /** @var FetchedNode $fetchedConstantNode */ - $fetchedConstantNode = current($fetchedConstantNodes[$constantName]); - - return $this->nodeToReflection( - $reflector, - $fetchedConstantNode, - $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $constantName), - ); - } - - return null; - } - - /** - * @param FetchedNode|FetchedNode|FetchedNode $fetchedNode - */ - private function nodeToReflection(Reflector $reflector, FetchedNode $fetchedNode, ?int $positionInNode = null): Reflection - { - $nodeToReflection = new NodeToReflection(); - return $nodeToReflection->__invoke( - $reflector, - $fetchedNode->getNode(), - $fetchedNode->getLocatedSource(), - $fetchedNode->getNamespace(), - $positionInNode, - ); - } - - private function findFileByClass(string $className): ?string - { - if (!array_key_exists($className, $this->classToFile)) { - return null; - } - - return $this->classToFile[$className]; - } - - private function findFileByConstant(string $constantName): ?string - { - if (!array_key_exists($constantName, $this->constantToFile)) { - return null; - } - - return $this->constantToFile[$constantName]; - } - - /** - * @return string[] - */ - private function findFilesByFunction(string $functionName): array - { - if (!array_key_exists($functionName, $this->functionToFiles)) { - return []; - } - - return $this->functionToFiles[$functionName]; - } - - /** - * @return list - */ - public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array - { - $reflections = []; - if ($identifierType->isClass()) { - foreach ($this->classToFile as $file) { - $fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file); - foreach ($fetchedNodesResult->getClassNodes() as $identifierName => $fetchedClassNodes) { - foreach ($fetchedClassNodes as $fetchedClassNode) { - $reflections[$identifierName] = $this->nodeToReflection($reflector, $fetchedClassNode); - } - } - } - } elseif ($identifierType->isFunction()) { - foreach ($this->functionToFiles as $files) { - foreach ($files as $file) { - $fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file); - foreach ($fetchedNodesResult->getFunctionNodes() as $identifierName => $fetchedFunctionNodes) { - foreach ($fetchedFunctionNodes as $fetchedFunctionNode) { - $reflections[$identifierName] = $this->nodeToReflection($reflector, $fetchedFunctionNode); - continue 2; - } - } - } - } - } elseif ($identifierType->isConstant()) { - foreach ($this->constantToFile as $file) { - $fetchedNodesResult = $this->fileNodesFetcher->fetchNodes($file); - foreach ($fetchedNodesResult->getConstantNodes() as $identifierName => $fetchedConstantNodes) { - foreach ($fetchedConstantNodes as $fetchedConstantNode) { - $reflections[$identifierName] = $this->nodeToReflection( - $reflector, - $fetchedConstantNode, - $this->findConstantPositionInConstNode($fetchedConstantNode->getNode(), $identifierName), - ); - } - } - } - } - - return array_values($reflections); - } - - private function findConstantPositionInConstNode(Node\Stmt\Const_|Node\Expr\FuncCall $constantNode, string $constantName): ?int - { - if ($constantNode instanceof Node\Expr\FuncCall) { - return null; - } - - /** @var int $position */ - foreach ($constantNode->consts as $position => $const) { - if ($const->namespacedName === null) { - throw new ShouldNotHappenException(); - } - - if (ConstantNameHelper::normalize($const->namespacedName->toString()) === $constantName) { - return $position; - } - } - - throw new ShouldNotHappenException(); - } - -} diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php index 32fabbc757..b56a981bab 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocator.php @@ -9,52 +9,28 @@ use PHPStan\BetterReflection\Reflector\Reflector; use PHPStan\BetterReflection\SourceLocator\Ast\Strategy\NodeToReflection; use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator; -use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ConstantNameHelper; use PHPStan\ShouldNotHappenException; use function array_key_exists; use function array_values; -use function count; use function current; -use function in_array; -use function ltrim; -use function php_strip_whitespace; -use function preg_match_all; -use function preg_replace; -use function sprintf; use function strtolower; -/** - * @deprecated Use NewOptimizedDirectorySourceLocator - */ final class OptimizedDirectorySourceLocator implements SourceLocator { - private PhpFileCleaner $cleaner; - - private string $extraTypes; - - /** @var array|null */ - private ?array $classToFile = null; - - /** @var array|null */ - private ?array $constantToFile = null; - - /** @var array>|null */ - private ?array $functionToFiles = null; - /** - * @param string[] $files + * @param array $classToFile + * @param array> $functionToFiles + * @param array $constantToFile */ public function __construct( private FileNodesFetcher $fileNodesFetcher, - private PhpVersion $phpVersion, - private array $files, + private array $classToFile, + private array $functionToFiles, + private array $constantToFile, ) { - $this->extraTypes = $this->phpVersion->supportsEnums() ? '|enum' : ''; - - $this->cleaner = new PhpFileCleaner(); } public function locateIdentifier(Reflector $reflector, Identifier $identifier): ?Reflection @@ -145,13 +121,6 @@ private function nodeToReflection(Reflector $reflector, FetchedNode $fetchedNode private function findFileByClass(string $className): ?string { - if ($this->classToFile === null) { - $this->init(); - if ($this->classToFile === null) { - throw new ShouldNotHappenException(); - } - } - if (!array_key_exists($className, $this->classToFile)) { return null; } @@ -161,13 +130,6 @@ private function findFileByClass(string $className): ?string private function findFileByConstant(string $constantName): ?string { - if ($this->constantToFile === null) { - $this->init(); - if ($this->constantToFile === null) { - throw new ShouldNotHappenException(); - } - } - if (!array_key_exists($constantName, $this->constantToFile)) { return null; } @@ -180,13 +142,6 @@ private function findFileByConstant(string $constantName): ?string */ private function findFilesByFunction(string $functionName): array { - if ($this->functionToFiles === null) { - $this->init(); - if ($this->functionToFiles === null) { - throw new ShouldNotHappenException(); - } - } - if (!array_key_exists($functionName, $this->functionToFiles)) { return []; } @@ -194,118 +149,11 @@ private function findFilesByFunction(string $functionName): array return $this->functionToFiles[$functionName]; } - private function init(): void - { - $classToFile = []; - $constantToFile = []; - $functionToFiles = []; - foreach ($this->files as $file) { - $symbols = $this->findSymbols($file); - foreach ($symbols['classes'] as $classInFile) { - $classToFile[$classInFile] = $file; - } - foreach ($symbols['constants'] as $constantInFile) { - $constantToFile[$constantInFile] = $file; - } - foreach ($symbols['functions'] as $functionInFile) { - if (!array_key_exists($functionInFile, $functionToFiles)) { - $functionToFiles[$functionInFile] = []; - } - $functionToFiles[$functionInFile][] = $file; - } - } - - $this->classToFile = $classToFile; - $this->functionToFiles = $functionToFiles; - $this->constantToFile = $constantToFile; - } - - /** - * Inspired by Composer\Autoload\ClassMapGenerator::findClasses() - * @link https://github.com/composer/composer/blob/45d3e133a4691eccb12e9cd6f9dfd76eddc1906d/src/Composer/Autoload/ClassMapGenerator.php#L216 - * - * @return array{classes: string[], functions: string[], constants: string[]} - */ - private function findSymbols(string $file): array - { - $contents = @php_strip_whitespace($file); - if ($contents === '') { - return ['classes' => [], 'functions' => [], 'constants' => []]; - } - - $matchResults = (bool) preg_match_all(sprintf('{\b(?:(?:class|interface|trait|const|function%s)\s)|(?:define\s*\()}i', $this->extraTypes), $contents, $matches); - if (!$matchResults) { - return ['classes' => [], 'functions' => [], 'constants' => []]; - } - - $contents = $this->cleaner->clean($contents, count($matches[0])); - - preg_match_all(sprintf('{ - (?: - \b(?])(?: - (?: (?Pclass|interface|trait%s) \s++ (?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\-]*+) ) - | (?: (?Pfunction) \s++ (?:&\s*)? (?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\-]*+) \s*+ [&\(] ) - | (?: (?Pconst) \s++ (?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\-]*+) \s*+ [^;] ) - | (?: (?:\\\)? (?Pdefine) \s*+ \( \s*+ [\'"] (?P[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:[\\\\]{1,2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+) ) - | (?: (?Pnamespace) (?P\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;] ) - ) - ) - }ix', $this->extraTypes), $contents, $matches); - - $classes = []; - $functions = []; - $constants = []; - $namespace = ''; - - for ($i = 0, $len = count($matches['type']); $i < $len; $i++) { - if (isset($matches['ns'][$i]) && $matches['ns'][$i] !== '') { - $namespace = preg_replace('~\s+~', '', strtolower($matches['nsname'][$i])) . '\\'; - continue; - } - - if ($matches['function'][$i] !== '') { - $functions[] = strtolower(ltrim($namespace . $matches['fname'][$i], '\\')); - continue; - } - - if ($matches['constant'][$i] !== '') { - $constants[] = ConstantNameHelper::normalize(ltrim($namespace . $matches['cname'][$i], '\\')); - } - - if ($matches['define'][$i] !== '') { - $constants[] = ConstantNameHelper::normalize($matches['dname'][$i]); - continue; - } - - $name = $matches['name'][$i]; - - // skip anon classes extending/implementing - if (in_array($name, ['extends', 'implements'], true)) { - continue; - } - - $classes[] = strtolower(ltrim($namespace . $name, '\\')); - } - - return [ - 'classes' => $classes, - 'functions' => $functions, - 'constants' => $constants, - ]; - } - /** * @return list */ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array { - if ($this->classToFile === null || $this->functionToFiles === null || $this->constantToFile === null) { - $this->init(); - if ($this->classToFile === null || $this->functionToFiles === null || $this->constantToFile === null) { - throw new ShouldNotHappenException(); - } - } - $reflections = []; if ($identifierType->isClass()) { foreach ($this->classToFile as $file) { diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php index 864f1fff21..620284912f 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorFactory.php @@ -35,7 +35,7 @@ public function __construct( $this->cleaner = new PhpFileCleaner(); } - public function createByDirectory(string $directory): NewOptimizedDirectorySourceLocator + public function createByDirectory(string $directory): OptimizedDirectorySourceLocator { $files = $this->fileFinder->findFiles([$directory])->getFiles(); $fileHashes = []; @@ -79,7 +79,7 @@ public function createByDirectory(string $directory): NewOptimizedDirectorySourc [$classToFile, $functionToFiles, $constantToFile] = $this->changeStructure($cached); - return new NewOptimizedDirectorySourceLocator( + return new OptimizedDirectorySourceLocator( $this->fileNodesFetcher, $classToFile, $functionToFiles, @@ -90,7 +90,7 @@ public function createByDirectory(string $directory): NewOptimizedDirectorySourc /** * @param string[] $files */ - public function createByFiles(array $files): NewOptimizedDirectorySourceLocator + public function createByFiles(array $files): OptimizedDirectorySourceLocator { $symbols = []; foreach ($files as $file) { @@ -100,7 +100,7 @@ public function createByFiles(array $files): NewOptimizedDirectorySourceLocator [$classToFile, $functionToFiles, $constantToFile] = $this->changeStructure($symbols); - return new NewOptimizedDirectorySourceLocator( + return new OptimizedDirectorySourceLocator( $this->fileNodesFetcher, $classToFile, $functionToFiles, diff --git a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php index 25f5bd3e84..f71d4dcf8a 100644 --- a/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php +++ b/src/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorRepository.php @@ -7,14 +7,14 @@ final class OptimizedDirectorySourceLocatorRepository { - /** @var array */ + /** @var array */ private array $locators = []; public function __construct(private OptimizedDirectorySourceLocatorFactory $factory) { } - public function getOrCreate(string $directory): NewOptimizedDirectorySourceLocator + public function getOrCreate(string $directory): OptimizedDirectorySourceLocator { if (array_key_exists($directory, $this->locators)) { return $this->locators[$directory]; diff --git a/src/Reflection/BetterReflection/Type/AdapterReflectionEnumCaseDynamicReturnTypeExtension.php b/src/Reflection/BetterReflection/Type/AdapterReflectionEnumCaseDynamicReturnTypeExtension.php new file mode 100644 index 0000000000..4e1cfbcea6 --- /dev/null +++ b/src/Reflection/BetterReflection/Type/AdapterReflectionEnumCaseDynamicReturnTypeExtension.php @@ -0,0 +1,65 @@ +class; + } + + public function isMethodSupported(MethodReflection $methodReflection): bool + { + return in_array($methodReflection->getName(), [ + 'getDocComment', + 'getType', + ], true); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type + { + if ($this->phpVersion->getVersionId() >= 80000) { + return null; + } + + if ($methodReflection->getName() === 'getDocComment') { + return new UnionType([ + new StringType(), + new ConstantBooleanType(false), + ]); + } + + if ($methodReflection->getName() === 'getType') { + return new UnionType([ + new ObjectType(ReflectionType::class), + new NullType(), + ]); + } + + return null; + } + +} diff --git a/src/Reflection/BetterReflection/Type/AdapterReflectionEnumDynamicReturnTypeExtension.php b/src/Reflection/BetterReflection/Type/AdapterReflectionEnumDynamicReturnTypeExtension.php new file mode 100644 index 0000000000..dfa3218442 --- /dev/null +++ b/src/Reflection/BetterReflection/Type/AdapterReflectionEnumDynamicReturnTypeExtension.php @@ -0,0 +1,102 @@ +getName(), [ + 'getFileName', + 'getStartLine', + 'getEndLine', + 'getDocComment', + 'getReflectionConstant', + 'getParentClass', + 'getExtensionName', + 'getBackingType', + ], true); + } + + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type + { + if ($this->phpVersion->getVersionId() >= 80000) { + return null; + } + + if (in_array($methodReflection->getName(), ['getFileName', 'getExtensionName'], true)) { + return new UnionType([ + new IntersectionType([ + new StringType(), + new AccessoryNonEmptyStringType(), + ]), + new ConstantBooleanType(false), + ]); + } + + if ($methodReflection->getName() === 'getDocComment') { + return new UnionType([ + new StringType(), + new ConstantBooleanType(false), + ]); + } + + if (in_array($methodReflection->getName(), ['getStartLine', 'getEndLine'], true)) { + return new IntegerType(); + } + + if ($methodReflection->getName() === 'getReflectionConstant') { + return new UnionType([ + new ObjectType(ReflectionClassConstant::class), + new ConstantBooleanType(false), + ]); + } + + if ($methodReflection->getName() === 'getParentClass') { + return new UnionType([ + new ObjectType(ReflectionClass::class), + new ConstantBooleanType(false), + ]); + } + + if ($methodReflection->getName() === 'getBackingType') { + return new UnionType([ + new ObjectType(ReflectionNamedType::class), + new NullType(), + ]); + } + + return null; + } + +} diff --git a/src/Reflection/BrokerAwareExtension.php b/src/Reflection/BrokerAwareExtension.php deleted file mode 100644 index 9ca104d127..0000000000 --- a/src/Reflection/BrokerAwareExtension.php +++ /dev/null @@ -1,16 +0,0 @@ - new self($function, $variant), $variants); + return array_map(static fn (ExtendedParametersAcceptor $variant) => new self($function, $variant), $variants); } public function getTemplateTypeMap(): TemplateTypeMap @@ -52,7 +52,7 @@ public function getResolvedTemplateTypeMap(): TemplateTypeMap } /** - * @return array + * @return list */ public function getParameters(): array { @@ -135,6 +135,11 @@ public function isPure(): TrinaryLogic return $certainCount > 0 ? TrinaryLogic::createNo() : TrinaryLogic::createMaybe(); } + public function isDeprecated(): TrinaryLogic + { + return $this->function->isDeprecated(); + } + public function getImpurePoints(): array { if ($this->impurePoints !== null) { @@ -163,7 +168,7 @@ public function getUsedVariables(): array return []; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->function->acceptsNamedArguments(); } diff --git a/src/Reflection/ClassConstantReflection.php b/src/Reflection/ClassConstantReflection.php index 00874b9081..cafc201341 100644 --- a/src/Reflection/ClassConstantReflection.php +++ b/src/Reflection/ClassConstantReflection.php @@ -3,158 +3,22 @@ namespace PHPStan\Reflection; use PhpParser\Node\Expr; -use PHPStan\BetterReflection\NodeCompiler\Exception\UnableToCompileNode; -use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClassConstant; -use PHPStan\TrinaryLogic; use PHPStan\Type\Type; -use PHPStan\Type\TypehintHelper; -use const NAN; -/** - * @api - * @final - */ -class ClassConstantReflection implements ConstantReflection +/** @api */ +interface ClassConstantReflection extends ClassMemberReflection, ConstantReflection { - private ?Type $valueType = null; + public function getValueExpr(): Expr; - public function __construct( - private InitializerExprTypeResolver $initializerExprTypeResolver, - private ClassReflection $declaringClass, - private ReflectionClassConstant $reflection, - private ?Type $nativeType, - private ?Type $phpDocType, - private ?string $deprecatedDescription, - private bool $isDeprecated, - private bool $isInternal, - private bool $isFinal, - ) - { - } + public function isFinal(): bool; - public function getName(): string - { - return $this->reflection->getName(); - } + public function hasPhpDocType(): bool; - public function getFileName(): ?string - { - return $this->declaringClass->getFileName(); - } + public function getPhpDocType(): ?Type; - /** - * @deprecated Use getValueExpr() - * @return mixed - */ - public function getValue() - { - try { - return $this->reflection->getValue(); - } catch (UnableToCompileNode) { - return NAN; - } - } + public function hasNativeType(): bool; - public function getValueExpr(): Expr - { - return $this->reflection->getValueExpression(); - } - - public function hasPhpDocType(): bool - { - return $this->phpDocType !== null; - } - - public function getPhpDocType(): ?Type - { - return $this->phpDocType; - } - - public function hasNativeType(): bool - { - return $this->nativeType !== null; - } - - public function getNativeType(): ?Type - { - return $this->nativeType; - } - - public function getValueType(): Type - { - if ($this->valueType === null) { - if ($this->phpDocType !== null) { - if ($this->nativeType !== null) { - return $this->valueType = TypehintHelper::decideType( - $this->nativeType, - $this->phpDocType, - ); - } - - return $this->phpDocType; - } elseif ($this->nativeType !== null) { - return $this->nativeType; - } - - $this->valueType = $this->initializerExprTypeResolver->getType($this->getValueExpr(), InitializerExprContext::fromClassReflection($this->declaringClass)); - } - - return $this->valueType; - } - - public function getDeclaringClass(): ClassReflection - { - return $this->declaringClass; - } - - public function isStatic(): bool - { - return true; - } - - public function isPrivate(): bool - { - return $this->reflection->isPrivate(); - } - - public function isPublic(): bool - { - return $this->reflection->isPublic(); - } - - public function isFinal(): bool - { - return $this->isFinal || $this->reflection->isFinal(); - } - - public function isDeprecated(): TrinaryLogic - { - return TrinaryLogic::createFromBoolean($this->isDeprecated); - } - - public function getDeprecatedDescription(): ?string - { - if ($this->isDeprecated) { - return $this->deprecatedDescription; - } - - return null; - } - - public function isInternal(): TrinaryLogic - { - return TrinaryLogic::createFromBoolean($this->isInternal); - } - - public function getDocComment(): ?string - { - $docComment = $this->reflection->getDocComment(); - if ($docComment === false) { - return null; - } - - return $docComment; - } + public function getNativeType(): ?Type; } diff --git a/src/Reflection/ClassMemberAccessAnswerer.php b/src/Reflection/ClassMemberAccessAnswerer.php index ed1803e786..e1c62c60ca 100644 --- a/src/Reflection/ClassMemberAccessAnswerer.php +++ b/src/Reflection/ClassMemberAccessAnswerer.php @@ -17,6 +17,6 @@ public function canAccessProperty(PropertyReflection $propertyReflection): bool; public function canCallMethod(MethodReflection $methodReflection): bool; - public function canAccessConstant(ConstantReflection $constantReflection): bool; + public function canAccessConstant(ClassConstantReflection $constantReflection): bool; } diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index 02705f32cd..54555706ee 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -71,9 +71,8 @@ /** * @api - * @final */ -class ClassReflection +final class ClassReflection { /** @var ExtendedMethodReflection[] */ @@ -82,7 +81,7 @@ class ClassReflection /** @var ExtendedPropertyReflection[] */ private array $properties = []; - /** @var ClassConstantReflection[] */ + /** @var RealClassClassConstantReflection[] */ private array $constants = []; /** @var EnumCaseReflection[]|null */ @@ -131,7 +130,7 @@ class ClassReflection private false|ResolvedPhpDocBlock $traitContextResolvedPhpDocBlock = false; - /** @var ClassReflection[]|null */ + /** @var array|null */ private ?array $cachedInterfaces = null; private ClassReflection|false|null $cachedParentClass = false; @@ -199,14 +198,6 @@ public function getFileName(): ?string return $this->filename = $fileName; } - /** - * @deprecated Use getFileName() - */ - public function getFileNameWithPhpDocs(): ?string - { - return $this->getFileName(); - } - public function getParentClass(): ?ClassReflection { if (!is_bool($this->cachedParentClass)) { @@ -369,7 +360,7 @@ public function getClassHierarchyDistances(): array } /** - * @return ReflectionClass[] + * @return list */ private function collectTraits(ReflectionClass|ReflectionEnum $class): array { @@ -410,7 +401,6 @@ public function allowsDynamicProperties(): bool if (UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( $this->reflectionProvider, - $this->universalObjectCratesClasses, $this, )) { return true; @@ -855,7 +845,7 @@ public function implementsInterface(string $className): bool } /** - * @return ClassReflection[] + * @return list */ public function getParents(): array { @@ -870,7 +860,7 @@ public function getParents(): array } /** - * @return ClassReflection[] + * @return array */ public function getInterfaces(): array { @@ -904,7 +894,7 @@ public function getInterfaces(): array } /** - * @return ClassReflection[] + * @return array */ private function collectInterfaces(ClassReflection $interface): array { @@ -920,7 +910,7 @@ private function collectInterfaces(ClassReflection $interface): array } /** - * @return ClassReflection[] + * @return array */ public function getImmediateInterfaces(): array { @@ -1093,7 +1083,7 @@ public function getConstant(string $name): ClassConstantReflection $nativeType = $this->signatureMapProvider->getClassConstantMetadata($declaringClass->getName(), $name)['nativeType']; } - $this->constants[$name] = new ClassConstantReflection( + $this->constants[$name] = new RealClassClassConstantReflection( $this->initializerExprTypeResolver, $declaringClass, $reflectionConstant, @@ -1114,7 +1104,7 @@ public function hasTraitUse(string $traitName): bool } /** - * @return string[] + * @return list */ private function getTraitNames(): array { @@ -1471,7 +1461,7 @@ public function varianceMapFromList(array $variances): TemplateTypeVarianceMap return new TemplateTypeVarianceMap($map); } - /** @return array */ + /** @return list */ public function typeMapToList(TemplateTypeMap $typeMap): array { $resolvedPhpDoc = $this->getResolvedPhpDoc(); @@ -1487,7 +1477,7 @@ public function typeMapToList(TemplateTypeMap $typeMap): array return $list; } - /** @return array */ + /** @return list */ public function varianceMapToList(TemplateTypeVarianceMap $varianceMap): array { $resolvedPhpDoc = $this->getResolvedPhpDoc(); @@ -1787,7 +1777,7 @@ public function getMethodTags(): array } /** - * @return array + * @return list */ public function getResolvedMixinTypes(): array { diff --git a/src/Reflection/ClassReflectionExtensionRegistry.php b/src/Reflection/ClassReflectionExtensionRegistry.php index 2dd864952a..1705f47461 100644 --- a/src/Reflection/ClassReflectionExtensionRegistry.php +++ b/src/Reflection/ClassReflectionExtensionRegistry.php @@ -2,10 +2,8 @@ namespace PHPStan\Reflection; -use PHPStan\Broker\Broker; use PHPStan\Reflection\RequireExtension\RequireExtendsMethodsClassReflectionExtension; use PHPStan\Reflection\RequireExtension\RequireExtendsPropertiesClassReflectionExtension; -use function array_merge; final class ClassReflectionExtensionRegistry { @@ -16,7 +14,6 @@ final class ClassReflectionExtensionRegistry * @param AllowedSubTypesClassReflectionExtension[] $allowedSubTypesClassReflectionExtensions */ public function __construct( - Broker $broker, private array $propertiesClassReflectionExtensions, private array $methodsClassReflectionExtensions, private array $allowedSubTypesClassReflectionExtensions, @@ -24,13 +21,6 @@ public function __construct( private RequireExtendsMethodsClassReflectionExtension $requireExtendsMethodsClassReflectionExtension, ) { - foreach (array_merge($propertiesClassReflectionExtensions, $methodsClassReflectionExtensions, $allowedSubTypesClassReflectionExtensions) as $extension) { - if (!($extension instanceof BrokerAwareExtension)) { - continue; - } - - $extension->setBroker($broker); - } } /** diff --git a/src/Reflection/Constant/RuntimeConstantReflection.php b/src/Reflection/Constant/RuntimeConstantReflection.php index 9940b28505..4b31de502d 100644 --- a/src/Reflection/Constant/RuntimeConstantReflection.php +++ b/src/Reflection/Constant/RuntimeConstantReflection.php @@ -2,11 +2,11 @@ namespace PHPStan\Reflection\Constant; -use PHPStan\Reflection\GlobalConstantReflection; +use PHPStan\Reflection\ConstantReflection; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; -final class RuntimeConstantReflection implements GlobalConstantReflection +final class RuntimeConstantReflection implements ConstantReflection { public function __construct( diff --git a/src/Reflection/ConstantReflection.php b/src/Reflection/ConstantReflection.php index 5e3d2548c1..ebae755849 100644 --- a/src/Reflection/ConstantReflection.php +++ b/src/Reflection/ConstantReflection.php @@ -2,18 +2,23 @@ namespace PHPStan\Reflection; -use PhpParser\Node\Expr; +use PHPStan\TrinaryLogic; +use PHPStan\Type\Type; /** @api */ -interface ConstantReflection extends ClassMemberReflection, GlobalConstantReflection +interface ConstantReflection { - /** - * @deprecated Use getValueExpr() - * @return mixed - */ - public function getValue(); + public function getName(): string; - public function getValueExpr(): Expr; + public function getValueType(): Type; + + public function isDeprecated(): TrinaryLogic; + + public function getDeprecatedDescription(): ?string; + + public function isInternal(): TrinaryLogic; + + public function getFileName(): ?string; } diff --git a/src/Reflection/Dummy/ChangedTypeMethodReflection.php b/src/Reflection/Dummy/ChangedTypeMethodReflection.php index b81e30e846..3b3279596a 100644 --- a/src/Reflection/Dummy/ChangedTypeMethodReflection.php +++ b/src/Reflection/Dummy/ChangedTypeMethodReflection.php @@ -6,7 +6,7 @@ use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; @@ -17,8 +17,8 @@ final class ChangedTypeMethodReflection implements ExtendedMethodReflection { /** - * @param ParametersAcceptorWithPhpDocs[] $variants - * @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants + * @param list $variants + * @param list|null $namedArgumentsVariants */ public function __construct(private ClassReflection $declaringClass, private ExtendedMethodReflection $reflection, private array $variants, private ?array $namedArgumentsVariants) { @@ -64,7 +64,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { $variants = $this->getVariants(); if (count($variants) !== 1) { @@ -119,7 +119,7 @@ public function getAsserts(): Assertions return $this->reflection->getAsserts(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->reflection->acceptsNamedArguments(); } diff --git a/src/Reflection/Dummy/DummyConstantReflection.php b/src/Reflection/Dummy/DummyClassConstantReflection.php similarity index 76% rename from src/Reflection/Dummy/DummyConstantReflection.php rename to src/Reflection/Dummy/DummyClassConstantReflection.php index 330c77562c..e38a8740dc 100644 --- a/src/Reflection/Dummy/DummyConstantReflection.php +++ b/src/Reflection/Dummy/DummyClassConstantReflection.php @@ -4,15 +4,15 @@ use PhpParser\Node\Expr; use PHPStan\Node\Expr\TypeExpr; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ReflectionProviderStaticAccessor; use PHPStan\TrinaryLogic; use PHPStan\Type\MixedType; use PHPStan\Type\Type; use stdClass; -final class DummyConstantReflection implements ConstantReflection +final class DummyClassConstantReflection implements ClassConstantReflection { public function __construct(private string $name) @@ -26,6 +26,11 @@ public function getDeclaringClass(): ClassReflection return $reflectionProvider->getClass(stdClass::class); } + public function isFinal(): bool + { + return false; + } + public function getFileName(): ?string { return null; @@ -51,16 +56,6 @@ public function getName(): string return $this->name; } - /** - * @deprecated - * @return mixed - */ - public function getValue() - { - // so that Scope::getTypeFromValue() returns mixed - return new stdClass(); - } - public function getValueType(): Type { return new MixedType(); @@ -91,4 +86,24 @@ public function getDocComment(): ?string return null; } + public function hasPhpDocType(): bool + { + return false; + } + + public function getPhpDocType(): ?Type + { + return null; + } + + public function hasNativeType(): bool + { + return false; + } + + public function getNativeType(): ?Type + { + return null; + } + } diff --git a/src/Reflection/Dummy/DummyConstructorReflection.php b/src/Reflection/Dummy/DummyConstructorReflection.php index ca67c3c2e2..e3dff92c38 100644 --- a/src/Reflection/Dummy/DummyConstructorReflection.php +++ b/src/Reflection/Dummy/DummyConstructorReflection.php @@ -5,9 +5,9 @@ use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\MixedType; @@ -54,7 +54,7 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { return [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( TemplateTypeMap::createEmpty(), null, [], @@ -67,7 +67,7 @@ public function getVariants(): array ]; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -117,9 +117,9 @@ public function getAsserts(): Assertions return Assertions::createEmpty(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->declaringClass->acceptsNamedArguments(); + return TrinaryLogic::createFromBoolean($this->declaringClass->acceptsNamedArguments()); } public function getSelfOutType(): ?Type diff --git a/src/Reflection/Dummy/DummyMethodReflection.php b/src/Reflection/Dummy/DummyMethodReflection.php index ba4faeded3..c02b5ea370 100644 --- a/src/Reflection/Dummy/DummyMethodReflection.php +++ b/src/Reflection/Dummy/DummyMethodReflection.php @@ -6,7 +6,7 @@ use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\ReflectionProviderStaticAccessor; use PHPStan\Reflection\TrivialParametersAcceptor; use PHPStan\TrinaryLogic; @@ -59,7 +59,7 @@ public function getVariants(): array ]; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -114,9 +114,9 @@ public function getAsserts(): Assertions return Assertions::createEmpty(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return true; + return TrinaryLogic::createYes(); } public function getSelfOutType(): ?Type diff --git a/src/Reflection/EnumCaseReflection.php b/src/Reflection/EnumCaseReflection.php index 234ccbf95b..2ce5cc63cf 100644 --- a/src/Reflection/EnumCaseReflection.php +++ b/src/Reflection/EnumCaseReflection.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class EnumCaseReflection +final class EnumCaseReflection { public function __construct(private ClassReflection $declaringEnum, private string $name, private ?Type $backingValueType) diff --git a/src/Reflection/CallableFunctionVariantWithPhpDocs.php b/src/Reflection/ExtendedCallableFunctionVariant.php similarity index 81% rename from src/Reflection/CallableFunctionVariantWithPhpDocs.php rename to src/Reflection/ExtendedCallableFunctionVariant.php index 9e6644c0f1..8239ec81b9 100644 --- a/src/Reflection/CallableFunctionVariantWithPhpDocs.php +++ b/src/Reflection/ExtendedCallableFunctionVariant.php @@ -11,11 +11,11 @@ use PHPStan\Type\Generic\TemplateTypeVarianceMap; use PHPStan\Type\Type; -final class CallableFunctionVariantWithPhpDocs extends FunctionVariantWithPhpDocs implements CallableParametersAcceptor +final class ExtendedCallableFunctionVariant extends ExtendedFunctionVariant implements CallableParametersAcceptor { /** - * @param array $parameters + * @param list $parameters * @param SimpleThrowPoint[] $throwPoints * @param SimpleImpurePoint[] $impurePoints * @param InvalidateExprNode[] $invalidateExpressions @@ -32,10 +32,11 @@ public function __construct( ?TemplateTypeVarianceMap $callSiteVarianceMap, private array $throwPoints, private TrinaryLogic $isPure, + private TrinaryLogic $isDeprecated, private array $impurePoints, private array $invalidateExpressions, private array $usedVariables, - private bool $acceptsNamedArguments, + private TrinaryLogic $acceptsNamedArguments, ) { parent::__construct( @@ -60,6 +61,11 @@ public function isPure(): TrinaryLogic return $this->isPure; } + public function isDeprecated(): TrinaryLogic + { + return $this->isDeprecated; + } + public function getImpurePoints(): array { return $this->impurePoints; @@ -75,7 +81,7 @@ public function getUsedVariables(): array return $this->usedVariables; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->acceptsNamedArguments; } diff --git a/src/Reflection/FunctionVariantWithPhpDocs.php b/src/Reflection/ExtendedFunctionVariant.php similarity index 77% rename from src/Reflection/FunctionVariantWithPhpDocs.php rename to src/Reflection/ExtendedFunctionVariant.php index 0b047b08b5..e45f402bb0 100644 --- a/src/Reflection/FunctionVariantWithPhpDocs.php +++ b/src/Reflection/ExtendedFunctionVariant.php @@ -9,12 +9,12 @@ /** * @api */ -class FunctionVariantWithPhpDocs extends FunctionVariant implements ParametersAcceptorWithPhpDocs +class ExtendedFunctionVariant extends FunctionVariant implements ExtendedParametersAcceptor { /** + * @param list $parameters * @api - * @param array $parameters */ public function __construct( TemplateTypeMap $templateTypeMap, @@ -38,11 +38,11 @@ public function __construct( } /** - * @return array + * @return list */ public function getParameters(): array { - /** @var array $parameters */ + /** @var list $parameters */ $parameters = parent::getParameters(); return $parameters; diff --git a/src/Reflection/ExtendedMethodReflection.php b/src/Reflection/ExtendedMethodReflection.php index 7cb583f1dc..b49a71bb1a 100644 --- a/src/Reflection/ExtendedMethodReflection.php +++ b/src/Reflection/ExtendedMethodReflection.php @@ -23,21 +23,21 @@ interface ExtendedMethodReflection extends MethodReflection { /** - * @return ParametersAcceptorWithPhpDocs[] + * @return list */ public function getVariants(): array; /** * @internal */ - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs; + public function getOnlyVariant(): ExtendedParametersAcceptor; /** - * @return ParametersAcceptorWithPhpDocs[]|null + * @return list|null */ public function getNamedArgumentsVariants(): ?array; - public function acceptsNamedArguments(): bool; + public function acceptsNamedArguments(): TrinaryLogic; public function getAsserts(): Assertions; diff --git a/src/Reflection/ParameterReflectionWithPhpDocs.php b/src/Reflection/ExtendedParameterReflection.php similarity index 84% rename from src/Reflection/ParameterReflectionWithPhpDocs.php rename to src/Reflection/ExtendedParameterReflection.php index 943338a493..db8df05ab8 100644 --- a/src/Reflection/ParameterReflectionWithPhpDocs.php +++ b/src/Reflection/ExtendedParameterReflection.php @@ -6,7 +6,7 @@ use PHPStan\Type\Type; /** @api */ -interface ParameterReflectionWithPhpDocs extends ParameterReflection +interface ExtendedParameterReflection extends ParameterReflection { public function getPhpDocType(): Type; diff --git a/src/Reflection/ParametersAcceptorWithPhpDocs.php b/src/Reflection/ExtendedParametersAcceptor.php similarity index 75% rename from src/Reflection/ParametersAcceptorWithPhpDocs.php rename to src/Reflection/ExtendedParametersAcceptor.php index f8ae03e477..77fb213b49 100644 --- a/src/Reflection/ParametersAcceptorWithPhpDocs.php +++ b/src/Reflection/ExtendedParametersAcceptor.php @@ -6,11 +6,11 @@ use PHPStan\Type\Type; /** @api */ -interface ParametersAcceptorWithPhpDocs extends ParametersAcceptor +interface ExtendedParametersAcceptor extends ParametersAcceptor { /** - * @return array + * @return list */ public function getParameters(): array; diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index e09ceb27ed..33b355b844 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -14,28 +14,26 @@ public function getName(): string; public function getFileName(): ?string; /** - * @return ParametersAcceptorWithPhpDocs[] + * @return list */ public function getVariants(): array; /** * @internal */ - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs; + public function getOnlyVariant(): ExtendedParametersAcceptor; /** - * @return ParametersAcceptorWithPhpDocs[]|null + * @return list|null */ public function getNamedArgumentsVariants(): ?array; - public function acceptsNamedArguments(): bool; + public function acceptsNamedArguments(): TrinaryLogic; public function isDeprecated(): TrinaryLogic; public function getDeprecatedDescription(): ?string; - public function isFinal(): TrinaryLogic; - public function isInternal(): TrinaryLogic; public function getThrowType(): ?Type; diff --git a/src/Reflection/FunctionReflectionFactory.php b/src/Reflection/FunctionReflectionFactory.php index 4333954ff3..405eea46b1 100644 --- a/src/Reflection/FunctionReflectionFactory.php +++ b/src/Reflection/FunctionReflectionFactory.php @@ -25,7 +25,6 @@ public function create( ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, - bool $isFinal, ?string $filename, ?bool $isPure, Assertions $asserts, diff --git a/src/Reflection/FunctionVariant.php b/src/Reflection/FunctionVariant.php index b6023cae16..7c69274ef0 100644 --- a/src/Reflection/FunctionVariant.php +++ b/src/Reflection/FunctionVariant.php @@ -16,7 +16,7 @@ class FunctionVariant implements ParametersAcceptor /** * @api - * @param array $parameters + * @param list $parameters */ public function __construct( private TemplateTypeMap $templateTypeMap, @@ -46,7 +46,7 @@ public function getCallSiteVarianceMap(): TemplateTypeVarianceMap } /** - * @return array + * @return list */ public function getParameters(): array { diff --git a/src/Reflection/GenericParametersAcceptorResolver.php b/src/Reflection/GenericParametersAcceptorResolver.php index 5aa65587de..47b1c75524 100644 --- a/src/Reflection/GenericParametersAcceptorResolver.php +++ b/src/Reflection/GenericParametersAcceptorResolver.php @@ -3,7 +3,7 @@ namespace PHPStan\Reflection; use PHPStan\Reflection\Callables\CallableParametersAcceptor; -use PHPStan\Reflection\Php\DummyParameterWithPhpDocs; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\TrinaryLogic; use PHPStan\Type\ConditionalTypeForParameter; use PHPStan\Type\ErrorType; @@ -25,7 +25,7 @@ final class GenericParametersAcceptorResolver * @api * @param array $argTypes */ - public static function resolve(array $argTypes, ParametersAcceptor $parametersAcceptor): ParametersAcceptorWithPhpDocs + public static function resolve(array $argTypes, ParametersAcceptor $parametersAcceptor): ExtendedParametersAcceptor { $typeMap = TemplateTypeMap::createEmpty(); $passedArgs = []; @@ -87,11 +87,11 @@ public static function resolve(array $argTypes, ParametersAcceptor $parametersAc $originalParametersAcceptor = $parametersAcceptor; - if (!$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs) { - $parametersAcceptor = new FunctionVariantWithPhpDocs( + if (!$parametersAcceptor instanceof ExtendedParametersAcceptor) { + $parametersAcceptor = new ExtendedFunctionVariant( $parametersAcceptor->getTemplateTypeMap(), $parametersAcceptor->getResolvedTemplateTypeMap(), - array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + array_map(static fn (ParameterReflection $parameter): ExtendedParameterReflection => new ExtendedDummyParameter( $parameter->getName(), $parameter->getType(), $parameter->isOptional(), @@ -123,6 +123,7 @@ public static function resolve(array $argTypes, ParametersAcceptor $parametersAc $result, $originalParametersAcceptor->getThrowPoints(), $originalParametersAcceptor->isPure(), + $originalParametersAcceptor->isDeprecated(), $originalParametersAcceptor->getImpurePoints(), $originalParametersAcceptor->getInvalidateExpressions(), $originalParametersAcceptor->getUsedVariables(), diff --git a/src/Reflection/GlobalConstantReflection.php b/src/Reflection/GlobalConstantReflection.php deleted file mode 100644 index 6483e72e86..0000000000 --- a/src/Reflection/GlobalConstantReflection.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ public function getParameters(): array { return []; @@ -65,6 +62,11 @@ public function isPure(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isDeprecated(): TrinaryLogic + { + return $this->methodReflection->isDeprecated(); + } + public function getImpurePoints(): array { return [ @@ -86,7 +88,7 @@ public function getUsedVariables(): array return []; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->methodReflection->acceptsNamedArguments(); } diff --git a/src/Reflection/InitializerExprContext.php b/src/Reflection/InitializerExprContext.php index 4289056bcf..9d7d9aa5bf 100644 --- a/src/Reflection/InitializerExprContext.php +++ b/src/Reflection/InitializerExprContext.php @@ -17,9 +17,8 @@ /** * @api - * @final */ -class InitializerExprContext implements NamespaceAnswerer +final class InitializerExprContext implements NamespaceAnswerer { /** diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index a55fd7831d..fc8ad21c17 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; @@ -105,7 +105,7 @@ public function __construct( private PhpVersion $phpVersion, private OperatorTypeSpecifyingExtensionRegistryProvider $operatorTypeSpecifyingExtensionRegistryProvider, private OversizedArrayBuilder $oversizedArrayBuilder, - private bool $usePathConstantsAsConstantString = false, + private bool $usePathConstantsAsConstantString, ) { } @@ -116,10 +116,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_) { @@ -319,19 +319,19 @@ public function getType(Expr $expr, InitializerExprContext $context): Type } if ($expr instanceof Expr\BinaryOp\Smaller) { - return $this->getType($expr->left, $context)->isSmallerThan($this->getType($expr->right, $context))->toBooleanType(); + return $this->getType($expr->left, $context)->isSmallerThan($this->getType($expr->right, $context), $this->phpVersion)->toBooleanType(); } if ($expr instanceof Expr\BinaryOp\SmallerOrEqual) { - return $this->getType($expr->left, $context)->isSmallerThanOrEqual($this->getType($expr->right, $context))->toBooleanType(); + return $this->getType($expr->left, $context)->isSmallerThanOrEqual($this->getType($expr->right, $context), $this->phpVersion)->toBooleanType(); } if ($expr instanceof Expr\BinaryOp\Greater) { - return $this->getType($expr->right, $context)->isSmallerThan($this->getType($expr->left, $context))->toBooleanType(); + return $this->getType($expr->right, $context)->isSmallerThan($this->getType($expr->left, $context), $this->phpVersion)->toBooleanType(); } if ($expr instanceof Expr\BinaryOp\GreaterOrEqual) { - return $this->getType($expr->right, $context)->isSmallerThanOrEqual($this->getType($expr->left, $context))->toBooleanType(); + return $this->getType($expr->right, $context)->isSmallerThanOrEqual($this->getType($expr->left, $context), $this->phpVersion)->toBooleanType(); } if ($expr instanceof Expr\BinaryOp\LogicalXor) { @@ -536,10 +536,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(); @@ -583,7 +579,7 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type $arrayType = $arrayBuilder->getArray(); if ($isList === true) { - return AccessoryArrayListType::intersectWith($arrayType); + return TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } return $arrayType; @@ -1056,7 +1052,7 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback): $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); } if ($leftType->isList()->yes() && $rightType->isList()->yes()) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); + $arrayType = TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } return $arrayType; @@ -1375,8 +1371,8 @@ public function resolveIdenticalType(Type $leftType, Type $rightType): TypeResul return new TypeResult(new ConstantBooleanType($leftTypeFiniteTypes[0]->equals($rightTypeFiniteType[0])), []); } - $leftIsSuperTypeOfRight = $leftType->isSuperTypeOfWithReason($rightType); - $rightIsSuperTypeOfLeft = $rightType->isSuperTypeOfWithReason($leftType); + $leftIsSuperTypeOfRight = $leftType->isSuperTypeOf($rightType); + $rightIsSuperTypeOfLeft = $rightType->isSuperTypeOf($leftType); if ($leftIsSuperTypeOfRight->no() && $rightIsSuperTypeOfLeft->no()) { return new TypeResult(new ConstantBooleanType(false), array_merge($leftIsSuperTypeOfRight->reasons, $rightIsSuperTypeOfLeft->reasons)); } @@ -1937,7 +1933,7 @@ function (Type $type, callable $traverse): Type { ); } - if ($constantClassType->isClassStringType()->yes()) { + if ($constantClassType->isClassString()->yes()) { if ($constantClassType->isConstantScalarValue()->yes()) { $isObject = false; } @@ -2069,7 +2065,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/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index 8d601e9471..529a5011dd 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -14,7 +14,7 @@ public function getName(): string; public function getPrototype(): ClassMemberReflection; /** - * @return ParametersAcceptor[] + * @return list */ public function getVariants(): array; diff --git a/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php b/src/Reflection/Native/ExtendedNativeParameterReflection.php similarity index 69% rename from src/Reflection/Native/NativeParameterWithPhpDocsReflection.php rename to src/Reflection/Native/ExtendedNativeParameterReflection.php index 3e303b82b9..7e1388bf5a 100644 --- a/src/Reflection/Native/NativeParameterWithPhpDocsReflection.php +++ b/src/Reflection/Native/ExtendedNativeParameterReflection.php @@ -2,12 +2,12 @@ namespace PHPStan\Reflection\Native; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\PassedByReference; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; -final class NativeParameterWithPhpDocsReflection implements ParameterReflectionWithPhpDocs +final class ExtendedNativeParameterReflection implements ExtendedParameterReflection { public function __construct( @@ -81,24 +81,4 @@ public function getClosureThisType(): ?Type return $this->closureThisType; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self( - $properties['name'], - $properties['optional'], - $properties['type'], - $properties['phpDocType'], - $properties['nativeType'], - $properties['passedByReference'], - $properties['variadic'], - $properties['defaultValue'], - $properties['outType'], - $properties['immediatelyInvokedCallable'], - $properties['closureThisType'], - ); - } - } diff --git a/src/Reflection/Native/NativeFunctionReflection.php b/src/Reflection/Native/NativeFunctionReflection.php index c2a61a0131..730f8c61e9 100644 --- a/src/Reflection/Native/NativeFunctionReflection.php +++ b/src/Reflection/Native/NativeFunctionReflection.php @@ -3,8 +3,8 @@ namespace PHPStan\Reflection\Native; use PHPStan\Reflection\Assertions; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; @@ -18,8 +18,8 @@ final class NativeFunctionReflection implements FunctionReflection private TrinaryLogic $returnsByReference; /** - * @param ParametersAcceptorWithPhpDocs[] $variants - * @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants + * @param list $variants + * @param list|null $namedArgumentsVariants */ public function __construct( private string $name, @@ -28,10 +28,10 @@ public function __construct( private ?Type $throwType, private TrinaryLogic $hasSideEffects, private bool $isDeprecated, - ?Assertions $assertions = null, - private ?string $phpDocComment = null, - ?TrinaryLogic $returnsByReference = null, - private bool $acceptsNamedArguments = true, + ?Assertions $assertions, + private ?string $phpDocComment, + ?TrinaryLogic $returnsByReference, + private bool $acceptsNamedArguments, ) { $this->assertions = $assertions ?? Assertions::createEmpty(); @@ -53,7 +53,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { $variants = $this->getVariants(); if (count($variants) !== 1) { @@ -88,11 +88,6 @@ public function isInternal(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isFinal(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - public function hasSideEffects(): TrinaryLogic { if ($this->isVoid()) { @@ -142,9 +137,9 @@ public function returnsByReference(): TrinaryLogic return $this->returnsByReference; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->acceptsNamedArguments; + return TrinaryLogic::createFromBoolean($this->acceptsNamedArguments); } } diff --git a/src/Reflection/Native/NativeMethodReflection.php b/src/Reflection/Native/NativeMethodReflection.php index d588cea558..731d4973fe 100644 --- a/src/Reflection/Native/NativeMethodReflection.php +++ b/src/Reflection/Native/NativeMethodReflection.php @@ -2,13 +2,13 @@ namespace PHPStan\Reflection\Native; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod; use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\MethodPrototypeReflection; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; -use PHPStan\Reflection\Php\BuiltinMethodReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; @@ -22,13 +22,13 @@ final class NativeMethodReflection implements ExtendedMethodReflection { /** - * @param ParametersAcceptorWithPhpDocs[] $variants - * @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants + * @param list $variants + * @param list|null $namedArgumentsVariants */ public function __construct( private ReflectionProvider $reflectionProvider, private ClassReflection $declaringClass, - private BuiltinMethodReflection $reflection, + private ReflectionMethod $reflection, private array $variants, private ?array $namedArgumentsVariants, private TrinaryLogic $hasSideEffects, @@ -81,7 +81,7 @@ public function getPrototype(): ClassMemberReflection $tentativeReturnType = null; if ($prototypeMethod->getTentativeReturnType() !== null) { - $tentativeReturnType = TypehintHelper::decideTypeFromReflection($prototypeMethod->getTentativeReturnType()); + $tentativeReturnType = TypehintHelper::decideTypeFromReflection($prototypeMethod->getTentativeReturnType(), null, $prototypeDeclaringClass); } return new MethodPrototypeReflection( @@ -111,7 +111,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { $variants = $this->getVariants(); if (count($variants) !== 1) { @@ -133,7 +133,7 @@ public function getDeprecatedDescription(): ?string public function isDeprecated(): TrinaryLogic { - return $this->reflection->isDeprecated(); + return TrinaryLogic::createFromBoolean($this->reflection->isDeprecated()); } public function isInternal(): TrinaryLogic @@ -200,9 +200,9 @@ public function getAsserts(): Assertions return $this->assertions; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->declaringClass->acceptsNamedArguments() && $this->acceptsNamedArguments; + return TrinaryLogic::createFromBoolean($this->declaringClass->acceptsNamedArguments() && $this->acceptsNamedArguments); } public function getSelfOutType(): ?Type @@ -212,7 +212,7 @@ public function getSelfOutType(): ?Type public function returnsByReference(): TrinaryLogic { - return $this->reflection->returnsByReference(); + return TrinaryLogic::createFromBoolean($this->reflection->returnsReference()); } } diff --git a/src/Reflection/Native/NativeParameterReflection.php b/src/Reflection/Native/NativeParameterReflection.php index bdfce9f04c..e812086830 100644 --- a/src/Reflection/Native/NativeParameterReflection.php +++ b/src/Reflection/Native/NativeParameterReflection.php @@ -63,19 +63,4 @@ public function union(self $other): self ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self( - $properties['name'], - $properties['optional'], - $properties['type'], - $properties['passedByReference'], - $properties['variadic'], - $properties['defaultValue'], - ); - } - } diff --git a/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php b/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php index 683a341f2e..fc9b44f79a 100644 --- a/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php +++ b/src/Reflection/PHPStan/NativeReflectionEnumReturnDynamicReturnTypeExtension.php @@ -14,6 +14,9 @@ final class NativeReflectionEnumReturnDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension { + /** + * @param class-string $className + */ public function __construct(private PhpVersion $phpVersion, private string $className, private string $methodName) { } diff --git a/src/Reflection/ParametersAcceptor.php b/src/Reflection/ParametersAcceptor.php index f4c2d4f1c0..b5fa5f1a2d 100644 --- a/src/Reflection/ParametersAcceptor.php +++ b/src/Reflection/ParametersAcceptor.php @@ -20,7 +20,7 @@ public function getTemplateTypeMap(): TemplateTypeMap; public function getResolvedTemplateTypeMap(): TemplateTypeMap; /** - * @return array + * @return list */ public function getParameters(): array; diff --git a/src/Reflection/ParametersAcceptorSelector.php b/src/Reflection/ParametersAcceptorSelector.php index 07a7c28080..d51c00f86c 100644 --- a/src/Reflection/ParametersAcceptorSelector.php +++ b/src/Reflection/ParametersAcceptorSelector.php @@ -18,7 +18,7 @@ use PHPStan\Reflection\Callables\CallableParametersAcceptor; use PHPStan\Reflection\Native\NativeParameterReflection; use PHPStan\Reflection\Php\DummyParameter; -use PHPStan\Reflection\Php\DummyParameterWithPhpDocs; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; @@ -45,6 +45,7 @@ use function array_map; use function array_merge; use function array_slice; +use function array_values; use function constant; use function count; use function defined; @@ -56,35 +57,10 @@ /** * @api - * @final */ -class ParametersAcceptorSelector +final class ParametersAcceptorSelector { - /** - * @deprecated See https://github.com/phpstan/phpstan-src/blob/2.0.x/UPGRADING.md#removed-deprecated-parametersacceptorselectorselectsingle - * - * @template T of ParametersAcceptor - * @param T[] $parametersAcceptors - * @return T - */ - public static function selectSingle( - array $parametersAcceptors, - ): ParametersAcceptor - { - $count = count($parametersAcceptors); - if ($count === 0) { - throw new ShouldNotHappenException( - 'getVariants() must return at least one variant.', - ); - } - if ($count !== 1) { - throw new ShouldNotHappenException('Multiple variants - use selectFromArgs() instead.'); - } - - return $parametersAcceptors[0]; - } - /** * @param Node\Arg[] $args * @param ParametersAcceptor[] $parametersAcceptors @@ -142,7 +118,7 @@ public static function selectFromArgs( $parameters, $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -169,10 +145,10 @@ public static function selectFromArgs( new FunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - $parameters, + array_values($parameters), $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -219,10 +195,10 @@ public static function selectFromArgs( new FunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - $parameters, + array_values($parameters), $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -250,10 +226,10 @@ public static function selectFromArgs( new FunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - $parameters, + array_values($parameters), $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -281,10 +257,10 @@ public static function selectFromArgs( new FunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - $parameters, + array_values($parameters), $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -326,7 +302,7 @@ public static function selectFromArgs( $parameters, $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -366,10 +342,10 @@ public static function selectFromArgs( new FunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - $parameters, + array_values($parameters), $acceptor->isVariadic(), $acceptor->getReturnType(), - $acceptor instanceof ParametersAcceptorWithPhpDocs ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $acceptor instanceof ExtendedParametersAcceptor ? $acceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), ), ]; } @@ -446,7 +422,7 @@ private static function hasAcceptorTemplateOrLateResolvableType(ParametersAccept foreach ($acceptor->getParameters() as $parameter) { if ( - $parameter instanceof ParameterReflectionWithPhpDocs + $parameter instanceof ExtendedParameterReflection && $parameter->getOutType() !== null && self::hasTemplateOrLateResolvableType($parameter->getOutType()) ) { @@ -454,7 +430,7 @@ private static function hasAcceptorTemplateOrLateResolvableType(ParametersAccept } if ( - $parameter instanceof ParameterReflectionWithPhpDocs + $parameter instanceof ExtendedParameterReflection && $parameter->getClosureThisType() !== null && self::hasTemplateOrLateResolvableType($parameter->getClosureThisType()) ) { @@ -566,7 +542,7 @@ public static function selectFromTypes( if ($parameter->getType() instanceof MixedType) { $isSuperType = $isSuperType->and(TrinaryLogic::createMaybe()); } else { - $isSuperType = $isSuperType->and($parameter->getType()->isSuperTypeOf($type)); + $isSuperType = $isSuperType->and($parameter->getType()->isSuperTypeOf($type)->result); } } @@ -598,7 +574,7 @@ public static function selectFromTypes( /** * @param ParametersAcceptor[] $acceptors */ - public static function combineAcceptors(array $acceptors): ParametersAcceptorWithPhpDocs + public static function combineAcceptors(array $acceptors): ExtendedParametersAcceptor { if (count($acceptors) === 0) { throw new ShouldNotHappenException( @@ -635,15 +611,16 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $callableOccurred = false; $throwPoints = []; $isPure = TrinaryLogic::createNo(); + $isDeprecated = TrinaryLogic::createNo(); $impurePoints = []; $invalidateExpressions = []; $usedVariables = []; - $acceptsNamedArguments = false; + $acceptsNamedArguments = TrinaryLogic::createNo(); foreach ($acceptors as $acceptor) { $returnTypes[] = $acceptor->getReturnType(); - if ($acceptor instanceof ParametersAcceptorWithPhpDocs) { + if ($acceptor instanceof ExtendedParametersAcceptor) { $phpDocReturnTypes[] = $acceptor->getPhpDocReturnType(); $nativeReturnTypes[] = $acceptor->getNativeReturnType(); } @@ -651,27 +628,28 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $callableOccurred = true; $throwPoints = array_merge($throwPoints, $acceptor->getThrowPoints()); $isPure = $isPure->or($acceptor->isPure()); + $isDeprecated = $isDeprecated->or($acceptor->isDeprecated()); $impurePoints = array_merge($impurePoints, $acceptor->getImpurePoints()); $invalidateExpressions = array_merge($invalidateExpressions, $acceptor->getInvalidateExpressions()); $usedVariables = array_merge($usedVariables, $acceptor->getUsedVariables()); - $acceptsNamedArguments = $acceptsNamedArguments || $acceptor->acceptsNamedArguments(); + $acceptsNamedArguments = $acceptsNamedArguments->or($acceptor->acceptsNamedArguments()); } $isVariadic = $isVariadic || $acceptor->isVariadic(); foreach ($acceptor->getParameters() as $i => $parameter) { if (!isset($parameters[$i])) { - $parameters[$i] = new DummyParameterWithPhpDocs( + $parameters[$i] = new ExtendedDummyParameter( $parameter->getName(), $parameter->getType(), $i + 1 > $minimumNumberOfParameters, $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue(), - $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getNativeType() : new MixedType(), - $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getPhpDocType() : new MixedType(), - $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getOutType() : null, - $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->isImmediatelyInvokedCallable() : TrinaryLogic::createMaybe(), - $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getClosureThisType() : null, + $parameter instanceof ExtendedParameterReflection ? $parameter->getNativeType() : new MixedType(), + $parameter instanceof ExtendedParameterReflection ? $parameter->getPhpDocType() : new MixedType(), + $parameter instanceof ExtendedParameterReflection ? $parameter->getOutType() : null, + $parameter instanceof ExtendedParameterReflection ? $parameter->isImmediatelyInvokedCallable() : TrinaryLogic::createMaybe(), + $parameter instanceof ExtendedParameterReflection ? $parameter->getClosureThisType() : null, ); continue; } @@ -691,7 +669,7 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $outType = $parameters[$i]->getOutType(); $immediatelyInvokedCallable = $parameters[$i]->isImmediatelyInvokedCallable(); $closureThisType = $parameters[$i]->getClosureThisType(); - if ($parameter instanceof ParameterReflectionWithPhpDocs) { + if ($parameter instanceof ExtendedParameterReflection) { $nativeType = TypeCombinator::union($nativeType, $parameter->getNativeType()); $phpDocType = TypeCombinator::union($phpDocType, $parameter->getPhpDocType()); @@ -716,7 +694,7 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $closureThisType = null; } - $parameters[$i] = new DummyParameterWithPhpDocs( + $parameters[$i] = new ExtendedDummyParameter( $parameters[$i]->getName() !== $parameter->getName() ? sprintf('%s|%s', $parameters[$i]->getName(), $parameter->getName()) : $parameter->getName(), $type, $i + 1 > $minimumNumberOfParameters, @@ -742,10 +720,10 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit $nativeReturnType = $nativeReturnTypes === [] ? null : TypeCombinator::union(...$nativeReturnTypes); if ($callableOccurred) { - return new CallableFunctionVariantWithPhpDocs( + return new ExtendedCallableFunctionVariant( TemplateTypeMap::createEmpty(), null, - $parameters, + array_values($parameters), $isVariadic, $returnType, $phpDocReturnType ?? $returnType, @@ -753,6 +731,7 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit null, $throwPoints, $isPure, + $isDeprecated, $impurePoints, $invalidateExpressions, $usedVariables, @@ -760,10 +739,10 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit ); } - return new FunctionVariantWithPhpDocs( + return new ExtendedFunctionVariant( TemplateTypeMap::createEmpty(), null, - $parameters, + array_values($parameters), $isVariadic, $returnType, $phpDocReturnType ?? $returnType, @@ -771,17 +750,17 @@ public static function combineAcceptors(array $acceptors): ParametersAcceptorWit ); } - private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAcceptorWithPhpDocs + private static function wrapAcceptor(ParametersAcceptor $acceptor): ExtendedParametersAcceptor { - if ($acceptor instanceof ParametersAcceptorWithPhpDocs) { + if ($acceptor instanceof ExtendedParametersAcceptor) { return $acceptor; } if ($acceptor instanceof CallableParametersAcceptor) { - return new CallableFunctionVariantWithPhpDocs( + return new ExtendedCallableFunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => self::wrapParameter($parameter), $acceptor->getParameters()), + array_map(static fn (ParameterReflection $parameter): ExtendedParameterReflection => self::wrapParameter($parameter), $acceptor->getParameters()), $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor->getReturnType(), @@ -789,6 +768,7 @@ private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAc TemplateTypeVarianceMap::createEmpty(), $acceptor->getThrowPoints(), $acceptor->isPure(), + $acceptor->isDeprecated(), $acceptor->getImpurePoints(), $acceptor->getInvalidateExpressions(), $acceptor->getUsedVariables(), @@ -796,10 +776,10 @@ private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAc ); } - return new FunctionVariantWithPhpDocs( + return new ExtendedFunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), - array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => self::wrapParameter($parameter), $acceptor->getParameters()), + array_map(static fn (ParameterReflection $parameter): ExtendedParameterReflection => self::wrapParameter($parameter), $acceptor->getParameters()), $acceptor->isVariadic(), $acceptor->getReturnType(), $acceptor->getReturnType(), @@ -808,9 +788,9 @@ private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAc ); } - private static function wrapParameter(ParameterReflection $parameter): ParameterReflectionWithPhpDocs + private static function wrapParameter(ParameterReflection $parameter): ExtendedParameterReflection { - return $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs( + return $parameter instanceof ExtendedParameterReflection ? $parameter : new ExtendedDummyParameter( $parameter->getName(), $parameter->getType(), $parameter->isOptional(), @@ -942,49 +922,90 @@ private static function getCurlOptValueType(int $curlOpt): ?Type } } + $nullableStringConstants = [ + 'CURLOPT_CUSTOMREQUEST', + 'CURLOPT_DNS_INTERFACE', + 'CURLOPT_DNS_LOCAL_IP4', + 'CURLOPT_DNS_LOCAL_IP6', + 'CURLOPT_DOH_URL', + 'CURLOPT_FTP_ACCOUNT', + 'CURLOPT_FTPPORT', + 'CURLOPT_HSTS', + 'CURLOPT_KRBLEVEL', + 'CURLOPT_RANGE', + 'CURLOPT_RTSP_SESSION_ID', + 'CURLOPT_UNIX_SOCKET_PATH', + 'CURLOPT_XOAUTH2_BEARER', + ]; + foreach ($nullableStringConstants as $constName) { + if (defined($constName) && constant($constName) === $curlOpt) { + return new UnionType([ + new NullType(), + TypeCombinator::intersect( + new StringType(), + new AccessoryNonEmptyStringType(), + ), + ]); + } + } + $nonEmptyStringConstants = [ 'CURLOPT_ABSTRACT_UNIX_SOCKET', + 'CURLOPT_ALTSVC', + 'CURLOPT_AWS_SIGV4', 'CURLOPT_CAINFO', 'CURLOPT_CAPATH', 'CURLOPT_COOKIE', 'CURLOPT_COOKIEJAR', 'CURLOPT_COOKIELIST', - 'CURLOPT_CUSTOMREQUEST', 'CURLOPT_DEFAULT_PROTOCOL', - 'CURLOPT_DNS_INTERFACE', - 'CURLOPT_DNS_LOCAL_IP4', - 'CURLOPT_DNS_LOCAL_IP6', + 'CURLOPT_DNS_SERVERS', 'CURLOPT_EGDSOCKET', - 'CURLOPT_FTPPORT', + 'CURLOPT_FTP_ALTERNATIVE_TO_USER', 'CURLOPT_INTERFACE', 'CURLOPT_KEYPASSWD', 'CURLOPT_KRB4LEVEL', 'CURLOPT_LOGIN_OPTIONS', + 'CURLOPT_MAIL_AUTH', + 'CURLOPT_MAIL_FROM', + 'CURLOPT_NOPROXY', + 'CURLOPT_PASSWORD', 'CURLOPT_PINNEDPUBLICKEY', - 'CURLOPT_PROXY_SERVICE_NAME', + 'CURLOPT_PROTOCOLS_STR', 'CURLOPT_PROXY_CAINFO', 'CURLOPT_PROXY_CAPATH', 'CURLOPT_PROXY_CRLFILE', + 'CURLOPT_PROXY_ISSUERCERT', 'CURLOPT_PROXY_KEYPASSWD', 'CURLOPT_PROXY_PINNEDPUBLICKEY', + 'CURLOPT_PROXY_SERVICE_NAME', + 'CURLOPT_PROXY_SSL_CIPHER_LIST', 'CURLOPT_PROXY_SSLCERT', 'CURLOPT_PROXY_SSLCERTTYPE', - 'CURLOPT_PROXY_SSL_CIPHER_LIST', - 'CURLOPT_PROXY_TLS13_CIPHERS', 'CURLOPT_PROXY_SSLKEY', 'CURLOPT_PROXY_SSLKEYTYPE', + 'CURLOPT_PROXY_TLS13_CIPHERS', 'CURLOPT_PROXY_TLSAUTH_PASSWORD', 'CURLOPT_PROXY_TLSAUTH_TYPE', 'CURLOPT_PROXY_TLSAUTH_USERNAME', + 'CURLOPT_PROXYPASSWORD', + 'CURLOPT_PROXYUSERNAME', 'CURLOPT_PROXYUSERPWD', 'CURLOPT_RANDOM_FILE', - 'CURLOPT_RANGE', + 'CURLOPT_REDIR_PROTOCOLS_STR', 'CURLOPT_REFERER', + 'CURLOPT_REQUEST_TARGET', + 'CURLOPT_RTSP_STREAM_URI', + 'CURLOPT_RTSP_TRANSPORT', + 'CURLOPT_SASL_AUTHZID', 'CURLOPT_SERVICE_NAME', + 'CURLOPT_SOCKS5_GSSAPI_SERVICE', 'CURLOPT_SSH_HOST_PUBLIC_KEY_MD5', - 'CURLOPT_SSH_PUBLIC_KEYFILE', + 'CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256', 'CURLOPT_SSH_PRIVATE_KEYFILE', + 'CURLOPT_SSH_PUBLIC_KEYFILE', 'CURLOPT_SSL_CIPHER_LIST', + 'CURLOPT_SSL_EC_CURVES', 'CURLOPT_SSLCERT', 'CURLOPT_SSLCERTPASSWD', 'CURLOPT_SSLCERTTYPE', @@ -994,13 +1015,14 @@ private static function getCurlOptValueType(int $curlOpt): ?Type 'CURLOPT_SSLKEYPASSWD', 'CURLOPT_SSLKEYTYPE', 'CURLOPT_TLS13_CIPHERS', - 'CURLOPT_UNIX_SOCKET_PATH', + 'CURLOPT_TLSAUTH_PASSWORD', + 'CURLOPT_TLSAUTH_TYPE', + 'CURLOPT_TLSAUTH_USERNAME', + 'CURLOPT_TRANSFER_ENCODING', 'CURLOPT_URL', 'CURLOPT_USERAGENT', 'CURLOPT_USERNAME', - 'CURLOPT_PASSWORD', 'CURLOPT_USERPWD', - 'CURLOPT_XOAUTH2_BEARER', ]; foreach ($nonEmptyStringConstants as $constName) { if (defined($constName) && constant($constName) === $curlOpt) { @@ -1013,7 +1035,7 @@ private static function getCurlOptValueType(int $curlOpt): ?Type $stringConstants = [ 'CURLOPT_COOKIEFILE', - 'CURLOPT_ENCODING', + 'CURLOPT_ENCODING', // Alias: CURLOPT_ACCEPT_ENCODING 'CURLOPT_PRE_PROXY', 'CURLOPT_PRIVATE', 'CURLOPT_PROXY', diff --git a/src/Reflection/PassedByReference.php b/src/Reflection/PassedByReference.php index 5a6bbd4a04..804d049b43 100644 --- a/src/Reflection/PassedByReference.php +++ b/src/Reflection/PassedByReference.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class PassedByReference +final class PassedByReference { private const NO = 1; @@ -77,12 +76,4 @@ public function combine(self $other): self return $this; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self($properties['value']); - } - } diff --git a/src/Reflection/Php/BuiltinMethodReflection.php b/src/Reflection/Php/BuiltinMethodReflection.php deleted file mode 100644 index d2d55336aa..0000000000 --- a/src/Reflection/Php/BuiltinMethodReflection.php +++ /dev/null @@ -1,60 +0,0 @@ -closureType->getTemplateTypeMap(), $this->closureType->getResolvedTemplateTypeMap(), - array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + array_map(static fn (ParameterReflection $parameter): ExtendedParameterReflection => new ExtendedDummyParameter( $parameter->getName(), $parameter->getType(), $parameter->isOptional(), @@ -106,7 +106,7 @@ public function getVariants(): array ]; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -156,7 +156,7 @@ public function getAsserts(): Assertions return $this->nativeMethodReflection->getAsserts(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->nativeMethodReflection->acceptsNamedArguments(); } diff --git a/src/Reflection/Php/EnumCasesMethodReflection.php b/src/Reflection/Php/EnumCasesMethodReflection.php index ff5fd5f9a5..2758c04c27 100644 --- a/src/Reflection/Php/EnumCasesMethodReflection.php +++ b/src/Reflection/Php/EnumCasesMethodReflection.php @@ -5,9 +5,9 @@ use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; @@ -64,7 +64,7 @@ public function getPrototype(): ClassMemberReflection public function getVariants(): array { return [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( TemplateTypeMap::createEmpty(), TemplateTypeMap::createEmpty(), [], @@ -76,7 +76,7 @@ public function getVariants(): array ]; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -126,9 +126,9 @@ public function getAsserts(): Assertions return Assertions::createEmpty(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->declaringClass->acceptsNamedArguments(); + return TrinaryLogic::createFromBoolean($this->declaringClass->acceptsNamedArguments()); } public function getSelfOutType(): ?Type diff --git a/src/Reflection/Php/ExitFunctionReflection.php b/src/Reflection/Php/ExitFunctionReflection.php index dc8f74ecea..76c8e7cf7a 100644 --- a/src/Reflection/Php/ExitFunctionReflection.php +++ b/src/Reflection/Php/ExitFunctionReflection.php @@ -3,9 +3,9 @@ namespace PHPStan\Reflection\Php; use PHPStan\Reflection\Assertions; +use PHPStan\Reflection\ExtendedFunctionVariant; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\PassedByReference; use PHPStan\TrinaryLogic; use PHPStan\Type\Constant\ConstantIntegerType; @@ -42,11 +42,11 @@ public function getVariants(): array new IntegerType(), ]); return [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( TemplateTypeMap::createEmpty(), TemplateTypeMap::createEmpty(), [ - new DummyParameterWithPhpDocs( + new ExtendedDummyParameter( 'status', $parameterType, true, @@ -69,22 +69,22 @@ public function getVariants(): array ]; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } /** - * @return ParametersAcceptorWithPhpDocs[] + * @return list */ public function getNamedArgumentsVariants(): array { return $this->getVariants(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return true; + return TrinaryLogic::createYes(); } public function isDeprecated(): TrinaryLogic @@ -97,11 +97,6 @@ public function getDeprecatedDescription(): ?string return null; } - public function isFinal(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - public function isInternal(): TrinaryLogic { return TrinaryLogic::createYes(); diff --git a/src/Reflection/Php/DummyParameterWithPhpDocs.php b/src/Reflection/Php/ExtendedDummyParameter.php similarity index 86% rename from src/Reflection/Php/DummyParameterWithPhpDocs.php rename to src/Reflection/Php/ExtendedDummyParameter.php index c7d8cc141c..91238c18b9 100644 --- a/src/Reflection/Php/DummyParameterWithPhpDocs.php +++ b/src/Reflection/Php/ExtendedDummyParameter.php @@ -2,12 +2,12 @@ namespace PHPStan\Reflection\Php; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\PassedByReference; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; -final class DummyParameterWithPhpDocs extends DummyParameter implements ParameterReflectionWithPhpDocs +final class ExtendedDummyParameter extends DummyParameter implements ExtendedParameterReflection { public function __construct( diff --git a/src/Reflection/Php/NativeBuiltinMethodReflection.php b/src/Reflection/Php/NativeBuiltinMethodReflection.php deleted file mode 100644 index ba559afac7..0000000000 --- a/src/Reflection/Php/NativeBuiltinMethodReflection.php +++ /dev/null @@ -1,148 +0,0 @@ -reflection->getName(); - } - - public function getReflection(): ReflectionMethod - { - return $this->reflection; - } - - public function getFileName(): ?string - { - $fileName = $this->reflection->getFileName(); - if ($fileName === false) { - return null; - } - - return $fileName; - } - - public function getDeclaringClass(): ReflectionClass - { - return $this->reflection->getDeclaringClass(); - } - - public function getStartLine(): ?int - { - $line = $this->reflection->getStartLine(); - if ($line === false) { - return null; - } - - return $line; - } - - public function getEndLine(): ?int - { - $line = $this->reflection->getEndLine(); - if ($line === false) { - return null; - } - - return $line; - } - - public function getDocComment(): ?string - { - $docComment = $this->reflection->getDocComment(); - if ($docComment === false) { - return null; - } - - return $docComment; - } - - public function isStatic(): bool - { - return $this->reflection->isStatic(); - } - - public function isPrivate(): bool - { - return $this->reflection->isPrivate(); - } - - public function isPublic(): bool - { - return $this->reflection->isPublic(); - } - - public function isConstructor(): bool - { - return $this->reflection->isConstructor(); - } - - public function getPrototype(): BuiltinMethodReflection - { - return new self($this->reflection->getPrototype()); - } - - public function isDeprecated(): TrinaryLogic - { - return TrinaryLogic::createFromBoolean($this->reflection->isDeprecated()); - } - - public function isFinal(): bool - { - return $this->reflection->isFinal(); - } - - public function isInternal(): bool - { - return $this->reflection->isInternal(); - } - - public function isAbstract(): bool - { - return $this->reflection->isAbstract(); - } - - public function isVariadic(): bool - { - return $this->reflection->isVariadic(); - } - - public function getReturnType(): ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null - { - return $this->reflection->getReturnType(); - } - - public function getTentativeReturnType(): ReflectionIntersectionType|ReflectionNamedType|ReflectionUnionType|null - { - return $this->reflection->getTentativeReturnType(); - } - - /** - * @return ReflectionParameter[] - */ - public function getParameters(): array - { - return $this->reflection->getParameters(); - } - - public function returnsByReference(): TrinaryLogic - { - return TrinaryLogic::createFromBoolean($this->reflection->returnsReference()); - } - -} diff --git a/src/Reflection/Php/PhpClassReflectionExtension.php b/src/Reflection/Php/PhpClassReflectionExtension.php index 9b9a9132e1..c42863737c 100644 --- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -10,6 +10,7 @@ use PHPStan\Analyser\NodeScopeResolver; use PHPStan\Analyser\ScopeContext; use PHPStan\Analyser\ScopeFactory; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionProperty; use PHPStan\Parser\Parser; @@ -20,15 +21,14 @@ use PHPStan\Reflection\Annotations\AnnotationsPropertiesClassReflectionExtension; use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ExtendedPropertyReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodsClassReflectionExtension; +use PHPStan\Reflection\Native\ExtendedNativeParameterReflection; use PHPStan\Reflection\Native\NativeMethodReflection; -use PHPStan\Reflection\Native\NativeParameterWithPhpDocsReflection; use PHPStan\Reflection\PropertiesClassReflectionExtension; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\SignatureMap\FunctionSignature; use PHPStan\Reflection\SignatureMap\ParameterSignature; @@ -153,10 +153,7 @@ public function hasProperty(ClassReflection $classReflection, string $propertyNa return $classReflection->getNativeReflection()->hasProperty($propertyName); } - /** - * @return ExtendedPropertyReflection - */ - public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection + public function getProperty(ClassReflection $classReflection, string $propertyName): ExtendedPropertyReflection { if (!isset($this->propertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName])) { $this->propertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName] = $this->createProperty($classReflection, $propertyName, true); @@ -375,16 +372,13 @@ public function hasMethod(ClassReflection $classReflection, string $methodName): return $classReflection->getNativeReflection()->hasMethod($methodName); } - /** - * @return ExtendedMethodReflection - */ - public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection + public function getMethod(ClassReflection $classReflection, string $methodName): ExtendedMethodReflection { if (isset($this->methodsIncludingAnnotations[$classReflection->getCacheKey()][$methodName])) { return $this->methodsIncludingAnnotations[$classReflection->getCacheKey()][$methodName]; } - $nativeMethodReflection = new NativeBuiltinMethodReflection($classReflection->getNativeReflection()->getMethod($methodName)); + $nativeMethodReflection = $classReflection->getNativeReflection()->getMethod($methodName); if (!isset($this->methodsIncludingAnnotations[$classReflection->getCacheKey()][$nativeMethodReflection->getName()])) { $method = $this->createMethod($classReflection, $nativeMethodReflection, true); $this->methodsIncludingAnnotations[$classReflection->getCacheKey()][$nativeMethodReflection->getName()] = $method; @@ -411,8 +405,7 @@ public function getNativeMethod(ClassReflection $classReflection, string $method throw new ShouldNotHappenException(); } - $reflectionMethod = $classReflection->getNativeReflection()->getMethod($methodName); - $nativeMethodReflection = new NativeBuiltinMethodReflection($reflectionMethod); + $nativeMethodReflection = $classReflection->getNativeReflection()->getMethod($methodName); if (!isset($this->nativeMethods[$classReflection->getCacheKey()][$nativeMethodReflection->getName()])) { $method = $this->createMethod($classReflection, $nativeMethodReflection, false); @@ -424,7 +417,7 @@ public function getNativeMethod(ClassReflection $classReflection, string $method private function createMethod( ClassReflection $classReflection, - BuiltinMethodReflection $methodReflection, + ReflectionMethod $methodReflection, bool $includingAnnotations, ): ExtendedMethodReflection { @@ -642,27 +635,25 @@ private function createMethod( ); } - public function createUserlandMethodReflection(ClassReflection $fileDeclaringClass, ClassReflection $actualDeclaringClass, BuiltinMethodReflection $methodReflection, ?string $declaringTraitName): PhpMethodReflection + public function createUserlandMethodReflection(ClassReflection $fileDeclaringClass, ClassReflection $actualDeclaringClass, ReflectionMethod $methodReflection, ?string $declaringTraitName): PhpMethodReflection { $resolvedPhpDoc = null; $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors($fileDeclaringClass, $fileDeclaringClass, $methodReflection->getName(), array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $methodReflection->getParameters())); $phpDocBlockClassReflection = $fileDeclaringClass; - if ($methodReflection->getReflection() !== null) { - $methodDeclaringClass = $methodReflection->getReflection()->getBetterReflection()->getDeclaringClass(); - - if ($stubPhpDocPair === null && $methodDeclaringClass->isTrait()) { - if (! $methodReflection->getDeclaringClass()->isTrait() || $methodDeclaringClass->getName() !== $methodReflection->getDeclaringClass()->getName()) { - $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors( - $this->reflectionProviderProvider->getReflectionProvider()->getClass($methodDeclaringClass->getName()), - $this->reflectionProviderProvider->getReflectionProvider()->getClass($methodReflection->getDeclaringClass()->getName()), - $methodReflection->getName(), - array_map( - static fn (ReflectionParameter $parameter): string => $parameter->getName(), - $methodReflection->getParameters(), - ), - ); - } + $methodDeclaringClass = $methodReflection->getBetterReflection()->getDeclaringClass(); + + if ($stubPhpDocPair === null && $methodDeclaringClass->isTrait()) { + if (! $methodReflection->getDeclaringClass()->isTrait() || $methodDeclaringClass->getName() !== $methodReflection->getDeclaringClass()->getName()) { + $stubPhpDocPair = $this->findMethodPhpDocIncludingAncestors( + $this->reflectionProviderProvider->getReflectionProvider()->getClass($methodDeclaringClass->getName()), + $this->reflectionProviderProvider->getReflectionProvider()->getClass($methodReflection->getDeclaringClass()->getName()), + $methodReflection->getName(), + array_map( + static fn (ReflectionParameter $parameter): string => $parameter->getName(), + $methodReflection->getParameters(), + ), + ); } } @@ -671,7 +662,7 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla } if ($resolvedPhpDoc === null) { - $docComment = $methodReflection->getDocComment(); + $docComment = $methodReflection->getDocComment() !== false ? $methodReflection->getDocComment() : null; $positionalParameterNames = array_map(static fn (ReflectionParameter $parameter): string => $parameter->getName(), $methodReflection->getParameters()); $resolvedPhpDoc = $this->phpDocInheritanceResolver->resolvePhpDocForMethod( @@ -694,10 +685,7 @@ public function createUserlandMethodReflection(ClassReflection $fileDeclaringCla } $phpDocParameterTypes = []; - if ( - $methodReflection instanceof NativeBuiltinMethodReflection - && $methodReflection->isConstructor() - ) { + if ($methodReflection->isConstructor()) { foreach ($methodReflection->getParameters() as $parameter) { if (!$parameter->isPromoted()) { continue; @@ -834,7 +822,7 @@ private function createNativeMethodVariant( array $stubClosureThisParameters, array $closureThisParameters, bool $usePhpDocParameterNames, - ): FunctionVariantWithPhpDocs + ): ExtendedFunctionVariant { $parameters = []; foreach ($methodSignature->getParameters() as $parameterSignature) { @@ -872,7 +860,7 @@ private function createNativeMethodVariant( $closureThisType = $closureThisParameters[$phpDocParameterName]; } - $parameters[] = new NativeParameterWithPhpDocsReflection( + $parameters[] = new ExtendedNativeParameterReflection( $usePhpDocParameterNames ? $phpDocParameterName : $parameterSignature->getName(), @@ -896,7 +884,7 @@ private function createNativeMethodVariant( $returnType = TypehintHelper::decideType($methodSignature->getReturnType(), $phpDocReturnType); } - return new FunctionVariantWithPhpDocs( + return new ExtendedFunctionVariant( TemplateTypeMap::createEmpty(), null, $parameters, @@ -922,14 +910,10 @@ private function findPropertyTrait(ReflectionProperty $propertyReflection): ?str } private function findMethodTrait( - BuiltinMethodReflection $methodReflection, + ReflectionMethod $methodReflection, ): ?string { - if ($methodReflection->getReflection() === null) { - return null; - } - - $declaringClass = $methodReflection->getReflection()->getBetterReflection()->getDeclaringClass(); + $declaringClass = $methodReflection->getBetterReflection()->getDeclaringClass(); if ($declaringClass->isTrait()) { if ($methodReflection->getDeclaringClass()->isTrait() && $declaringClass->getName() === $methodReflection->getDeclaringClass()->getName()) { return null; diff --git a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php index 96ba2f6be1..1d157476df 100644 --- a/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpFunctionFromParserNodeReflection.php @@ -8,10 +8,10 @@ use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; use PHPStan\Reflection\Assertions; +use PHPStan\Reflection\ExtendedFunctionVariant; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\PassedByReference; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; @@ -27,13 +27,13 @@ /** * @api */ -class PhpFunctionFromParserNodeReflection implements FunctionReflection, ParametersAcceptorWithPhpDocs +class PhpFunctionFromParserNodeReflection implements FunctionReflection, ExtendedParametersAcceptor { /** @var Function_|ClassMethod */ private Node\FunctionLike $functionLike; - /** @var FunctionVariantWithPhpDocs[]|null */ + /** @var list|null */ private ?array $variants = null; /** @@ -58,7 +58,6 @@ public function __construct( private ?string $deprecatedDescription, private bool $isDeprecated, private bool $isInternal, - private bool $isFinal, protected ?bool $isPure, private bool $acceptsNamedArguments, private Assertions $assertions, @@ -94,14 +93,11 @@ public function getName(): string return (string) $this->functionLike->namespacedName; } - /** - * @return ParametersAcceptorWithPhpDocs[] - */ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( $this->getTemplateTypeMap(), $this->getResolvedTemplateTypeMap(), $this->getParameters(), @@ -116,7 +112,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this; } @@ -137,7 +133,7 @@ public function getResolvedTemplateTypeMap(): TemplateTypeMap } /** - * @return array + * @return list */ public function getParameters(): array { @@ -235,24 +231,6 @@ public function isInternal(): TrinaryLogic return TrinaryLogic::createFromBoolean($this->isInternal); } - public function isFinal(): TrinaryLogic - { - $finalMethod = false; - if ($this->functionLike instanceof ClassMethod) { - $finalMethod = $this->functionLike->isFinal(); - } - return TrinaryLogic::createFromBoolean($finalMethod || $this->isFinal); - } - - public function isFinalByKeyword(): TrinaryLogic - { - $finalMethod = false; - if ($this->functionLike instanceof ClassMethod) { - $finalMethod = $this->functionLike->isFinal(); - } - return TrinaryLogic::createFromBoolean($finalMethod); - } - public function getThrowType(): ?Type { return $this->throwType; @@ -280,9 +258,9 @@ public function isGenerator(): bool return $this->nodeIsOrContainsYield($this->functionLike); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->acceptsNamedArguments; + return TrinaryLogic::createFromBoolean($this->acceptsNamedArguments); } private function nodeIsOrContainsYield(Node $node): bool diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php index 1f3ffee131..e8fbc2e824 100644 --- a/src/Reflection/Php/PhpFunctionReflection.php +++ b/src/Reflection/Php/PhpFunctionReflection.php @@ -2,20 +2,16 @@ namespace PHPStan\Reflection\Php; -use PhpParser\Node; -use PhpParser\Node\Stmt\Function_; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; -use PHPStan\Cache\Cache; -use PHPStan\Parser\FunctionCallStatementFinder; use PHPStan\Parser\Parser; +use PHPStan\Parser\VariadicFunctionsVisitor; use PHPStan\Reflection\Assertions; +use PHPStan\Reflection\ExtendedFunctionVariant; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; use PHPStan\Reflection\InitializerExprTypeResolver; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptor; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\MixedType; @@ -23,18 +19,18 @@ use PHPStan\Type\TypehintHelper; use function array_key_exists; use function array_map; -use function filemtime; +use function count; use function is_array; use function is_file; -use function sprintf; -use function time; final class PhpFunctionReflection implements FunctionReflection { - /** @var FunctionVariantWithPhpDocs[]|null */ + /** @var list|null */ private ?array $variants = null; + private ?bool $containsVariadicCalls = null; + /** * @param array $phpDocParameterTypes * @param array $phpDocParameterOutTypes @@ -45,8 +41,6 @@ public function __construct( private InitializerExprTypeResolver $initializerExprTypeResolver, private ReflectionFunction $reflection, private Parser $parser, - private FunctionCallStatementFinder $functionCallStatementFinder, - private Cache $cache, private TemplateTypeMap $templateTypeMap, private array $phpDocParameterTypes, private ?Type $phpDocReturnType, @@ -54,7 +48,6 @@ public function __construct( private ?string $deprecatedDescription, private bool $isDeprecated, private bool $isInternal, - private bool $isFinal, private ?string $filename, private ?bool $isPure, private Assertions $asserts, @@ -85,14 +78,11 @@ public function getFileName(): ?string return $this->filename; } - /** - * @return ParametersAcceptorWithPhpDocs[] - */ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( $this->templateTypeMap, null, $this->getParameters(), @@ -107,7 +97,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -118,7 +108,7 @@ public function getNamedArgumentsVariants(): ?array } /** - * @return ParameterReflectionWithPhpDocs[] + * @return list */ private function getParameters(): array { @@ -143,67 +133,33 @@ private function getParameters(): array private function isVariadic(): bool { $isNativelyVariadic = $this->reflection->isVariadic(); - if (!$isNativelyVariadic && $this->reflection - ->getFileName() !== false) { - $fileName = $this->reflection->getFileName(); - if (is_file($fileName)) { - $functionName = $this->reflection->getName(); - $modifiedTime = filemtime($fileName); - if ($modifiedTime === false) { - $modifiedTime = time(); - } - $variableCacheKey = sprintf('%d-v4', $modifiedTime); - $key = sprintf('variadic-function-%s-%s', $functionName, $fileName); - $cachedResult = $this->cache->load($key, $variableCacheKey); - if ($cachedResult === null) { - $nodes = $this->parser->parseFile($fileName); - $result = !$this->containsVariadicFunction($nodes)->no(); - $this->cache->save($key, $variableCacheKey, $result); - return $result; - } + if (!$isNativelyVariadic && $this->reflection->getFileName() !== false && !$this->isBuiltin()) { + $filename = $this->reflection->getFileName(); - return $cachedResult; + if ($this->containsVariadicCalls !== null) { + return $this->containsVariadicCalls; } - } - - return $isNativelyVariadic; - } - - /** - * @param Node[]|scalar[]|Node $node - */ - private function containsVariadicFunction(array|Node $node): TrinaryLogic - { - $result = TrinaryLogic::createMaybe(); - - if ($node instanceof Node) { - if ($node instanceof Function_) { - $functionName = (string) $node->namespacedName; - if ($functionName === $this->reflection->getName()) { - return TrinaryLogic::createFromBoolean($this->isFunctionNodeVariadic($node)); - } + if (array_key_exists($this->reflection->getName(), VariadicFunctionsVisitor::$cache)) { + return $this->containsVariadicCalls = VariadicFunctionsVisitor::$cache[$this->reflection->getName()]; } - foreach ($node->getSubNodeNames() as $subNodeName) { - $innerNode = $node->{$subNodeName}; - if (!$innerNode instanceof Node && !is_array($innerNode)) { - continue; - } + $nodes = $this->parser->parseFile($filename); + if (count($nodes) > 0) { + $variadicFunctions = $nodes[0]->getAttribute(VariadicFunctionsVisitor::ATTRIBUTE_NAME); - $result = $result->and($this->containsVariadicFunction($innerNode)); - } - } elseif (is_array($node)) { - foreach ($node as $subNode) { - if (!$subNode instanceof Node) { - continue; + if ( + is_array($variadicFunctions) + && array_key_exists($this->reflection->getName(), $variadicFunctions) + ) { + return $this->containsVariadicCalls = $variadicFunctions[$this->reflection->getName()]; } - - $result = $result->and($this->containsVariadicFunction($subNode)); } + + return $this->containsVariadicCalls = false; } - return $result; + return $isNativelyVariadic; } private function getReturnType(): Type @@ -249,11 +205,6 @@ public function isInternal(): TrinaryLogic return TrinaryLogic::createFromBoolean($this->isInternal); } - public function isFinal(): TrinaryLogic - { - return TrinaryLogic::createFromBoolean($this->isFinal); - } - public function getThrowType(): ?Type { return $this->phpDocThrowType; @@ -300,24 +251,9 @@ public function returnsByReference(): TrinaryLogic return TrinaryLogic::createFromBoolean($this->reflection->returnsReference()); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->acceptsNamedArguments; - } - - private function isFunctionNodeVariadic(Function_ $node): bool - { - foreach ($node->params as $parameter) { - if ($parameter->variadic) { - return true; - } - } - - if ($this->functionCallStatementFinder->findFunctionCallInStatements(ParametersAcceptor::VARIADIC_FUNCTIONS, $node->getStmts()) !== null) { - return true; - } - - return false; + return TrinaryLogic::createFromBoolean($this->acceptsNamedArguments); } } diff --git a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php index a05f550105..8cd703c8b2 100644 --- a/src/Reflection/Php/PhpMethodFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpMethodFromParserNodeReflection.php @@ -25,9 +25,8 @@ /** * @api - * @final */ -class PhpMethodFromParserNodeReflection extends PhpFunctionFromParserNodeReflection implements ExtendedMethodReflection +final class PhpMethodFromParserNodeReflection extends PhpFunctionFromParserNodeReflection implements ExtendedMethodReflection { /** @@ -39,7 +38,7 @@ class PhpMethodFromParserNodeReflection extends PhpFunctionFromParserNodeReflect */ public function __construct( private ClassReflection $declaringClass, - ClassMethod $classMethod, + private ClassMethod $classMethod, string $fileName, TemplateTypeMap $templateTypeMap, array $realParameterTypes, @@ -51,7 +50,7 @@ public function __construct( ?string $deprecatedDescription, bool $isDeprecated, bool $isInternal, - bool $isFinal, + private bool $isFinal, ?bool $isPure, bool $acceptsNamedArguments, Assertions $assertions, @@ -108,7 +107,6 @@ public function __construct( $deprecatedDescription, $isDeprecated, $isInternal, - $isFinal || $classMethod->isFinal(), $isPure, $acceptsNamedArguments, $assertions, @@ -155,6 +153,16 @@ public function isPublic(): bool return $this->getClassMethod()->isPublic(); } + public function isFinal(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->classMethod->isFinal() || $this->isFinal); + } + + public function isFinalByKeyword(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->classMethod->isFinal()); + } + public function isBuiltin(): bool { return false; diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php index 390ebc886a..d32c16e75e 100644 --- a/src/Reflection/Php/PhpMethodReflection.php +++ b/src/Reflection/Php/PhpMethodReflection.php @@ -2,25 +2,19 @@ namespace PHPStan\Reflection\Php; -use PhpParser\Node; -use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Declare_; -use PhpParser\Node\Stmt\Function_; -use PhpParser\Node\Stmt\Namespace_; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; -use PHPStan\Cache\Cache; -use PHPStan\Parser\FunctionCallStatementFinder; use PHPStan\Parser\Parser; +use PHPStan\Parser\VariadicMethodsVisitor; use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\InitializerExprTypeResolver; use PHPStan\Reflection\MethodPrototypeReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptor; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\ReflectionProvider; use PHPStan\TrinaryLogic; use PHPStan\Type\ArrayType; @@ -35,33 +29,34 @@ use PHPStan\Type\TypehintHelper; use PHPStan\Type\VoidType; use ReflectionException; +use function array_key_exists; use function array_map; +use function count; use function explode; -use function filemtime; use function in_array; -use function is_bool; +use function is_array; use function sprintf; use function strtolower; -use function time; use const PHP_VERSION_ID; /** * @api - * @final */ -class PhpMethodReflection implements ExtendedMethodReflection +final class PhpMethodReflection implements ExtendedMethodReflection { - /** @var PhpParameterReflection[]|null */ + /** @var list|null */ private ?array $parameters = null; private ?Type $returnType = null; private ?Type $nativeReturnType = null; - /** @var FunctionVariantWithPhpDocs[]|null */ + /** @var list|null */ private ?array $variants = null; + private ?bool $containsVariadicCalls = null; + /** * @param Type[] $phpDocParameterTypes * @param Type[] $phpDocParameterOutTypes @@ -72,11 +67,9 @@ public function __construct( private InitializerExprTypeResolver $initializerExprTypeResolver, private ClassReflection $declaringClass, private ?ClassReflection $declaringTrait, - private BuiltinMethodReflection $reflection, + private ReflectionMethod $reflection, private ReflectionProvider $reflectionProvider, private Parser $parser, - private FunctionCallStatementFinder $functionCallStatementFinder, - private Cache $cache, private TemplateTypeMap $templateTypeMap, private array $phpDocParameterTypes, private ?Type $phpDocReturnType, @@ -125,7 +118,7 @@ public function getPrototype(): ClassMemberReflection $tentativeReturnType = null; if ($prototypeMethod->getTentativeReturnType() !== null) { - $tentativeReturnType = TypehintHelper::decideTypeFromReflection($prototypeMethod->getTentativeReturnType()); + $tentativeReturnType = TypehintHelper::decideTypeFromReflection($prototypeMethod->getTentativeReturnType(), null, $prototypeDeclaringClass); } return new MethodPrototypeReflection( @@ -191,13 +184,13 @@ private function getMethodNameWithCorrectCase(string $lowercaseMethodName, strin } /** - * @return ParametersAcceptorWithPhpDocs[] + * @return list */ public function getVariants(): array { if ($this->variants === null) { $this->variants = [ - new FunctionVariantWithPhpDocs( + new ExtendedFunctionVariant( $this->templateTypeMap, null, $this->getParameters(), @@ -212,7 +205,7 @@ public function getVariants(): array return $this->variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -223,7 +216,7 @@ public function getNamedArgumentsVariants(): ?array } /** - * @return ParameterReflectionWithPhpDocs[] + * @return list */ private function getParameters(): array { @@ -232,7 +225,7 @@ private function getParameters(): array $this->initializerExprTypeResolver, $reflection, $this->phpDocParameterTypes[$reflection->getName()] ?? null, - $this->getDeclaringClass()->getName(), + $this->getDeclaringClass(), $this->phpDocParameterOutTypes[$reflection->getName()] ?? null, $this->immediatelyInvokedCallableParameters[$reflection->getName()] ?? TrinaryLogic::createMaybe(), $this->phpDocClosureThisTypeParameters[$reflection->getName()] ?? null, @@ -252,82 +245,40 @@ private function isVariadic(): bool $filename = $this->declaringTrait->getFileName(); } - if (!$isNativelyVariadic && $filename !== null) { - $modifiedTime = @filemtime($filename); - if ($modifiedTime === false) { - $modifiedTime = time(); - } - $key = sprintf('variadic-method-%s-%s-%s', $declaringClass->getName(), $this->reflection->getName(), $filename); - $variableCacheKey = sprintf('%d-v4', $modifiedTime); - $cachedResult = $this->cache->load($key, $variableCacheKey); - if ($cachedResult === null || !is_bool($cachedResult)) { - $nodes = $this->parser->parseFile($filename); - $result = $this->callsFuncGetArgs($declaringClass, $nodes); - $this->cache->save($key, $variableCacheKey, $result); - return $result; + if (!$isNativelyVariadic && $filename !== null && !$this->declaringClass->isBuiltin()) { + if ($this->containsVariadicCalls !== null) { + return $this->containsVariadicCalls; } - return $cachedResult; - } - - return $isNativelyVariadic; - } - - /** - * @param Node[] $nodes - */ - private function callsFuncGetArgs(ClassReflection $declaringClass, array $nodes): bool - { - foreach ($nodes as $node) { - if ( - $node instanceof Node\Stmt\ClassLike - ) { - if (!isset($node->namespacedName)) { - continue; - } - if ($declaringClass->getName() !== (string) $node->namespacedName) { - continue; - } - if ($this->callsFuncGetArgs($declaringClass, $node->stmts)) { - return true; - } - continue; + $className = $declaringClass->getName(); + if ($declaringClass->isAnonymous()) { + $className = sprintf('%s:%s:%s', VariadicMethodsVisitor::ANONYMOUS_CLASS_PREFIX, $declaringClass->getNativeReflection()->getStartLine(), $declaringClass->getNativeReflection()->getEndLine()); } - - if ($node instanceof ClassMethod) { - if ($node->getStmts() === null) { - continue; // interface - } - - $methodName = $node->name->name; - if ($methodName === $this->reflection->getName()) { - return $this->functionCallStatementFinder->findFunctionCallInStatements(ParametersAcceptor::VARIADIC_FUNCTIONS, $node->getStmts()) !== null; + if (array_key_exists($className, VariadicMethodsVisitor::$cache)) { + if (array_key_exists($this->reflection->getName(), VariadicMethodsVisitor::$cache[$className])) { + return $this->containsVariadicCalls = VariadicMethodsVisitor::$cache[$className][$this->reflection->getName()]; } - continue; + return $this->containsVariadicCalls = false; } - if ($node instanceof Function_) { - continue; - } + $nodes = $this->parser->parseFile($filename); + if (count($nodes) > 0) { + $variadicMethods = $nodes[0]->getAttribute(VariadicMethodsVisitor::ATTRIBUTE_NAME); - if ($node instanceof Namespace_) { - if ($this->callsFuncGetArgs($declaringClass, $node->stmts)) { - return true; + if ( + is_array($variadicMethods) + && array_key_exists($className, $variadicMethods) + && array_key_exists($this->reflection->getName(), $variadicMethods[$className]) + ) { + return $this->containsVariadicCalls = $variadicMethods[$className][$this->reflection->getName()]; } - continue; - } - - if (!$node instanceof Declare_ || $node->stmts === null) { - continue; } - if ($this->callsFuncGetArgs($declaringClass, $node->stmts)) { - return true; - } + return $this->containsVariadicCalls = false; } - return false; + return $isNativelyVariadic; } public function isPrivate(): bool @@ -410,7 +361,7 @@ public function isDeprecated(): TrinaryLogic return TrinaryLogic::createYes(); } - return $this->reflection->isDeprecated(); + return TrinaryLogic::createFromBoolean($this->reflection->isDeprecated()); } public function isInternal(): TrinaryLogic @@ -462,9 +413,11 @@ public function getAsserts(): Assertions return $this->asserts; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->declaringClass->acceptsNamedArguments() && $this->acceptsNamedArguments; + return TrinaryLogic::createFromBoolean( + $this->declaringClass->acceptsNamedArguments() && $this->acceptsNamedArguments, + ); } public function getSelfOutType(): ?Type @@ -479,7 +432,7 @@ public function getDocComment(): ?string public function returnsByReference(): TrinaryLogic { - return $this->reflection->returnsByReference(); + return TrinaryLogic::createFromBoolean($this->reflection->returnsReference()); } public function isPure(): TrinaryLogic diff --git a/src/Reflection/Php/PhpMethodReflectionFactory.php b/src/Reflection/Php/PhpMethodReflectionFactory.php index 2aa2aca526..22028286d3 100644 --- a/src/Reflection/Php/PhpMethodReflectionFactory.php +++ b/src/Reflection/Php/PhpMethodReflectionFactory.php @@ -2,6 +2,7 @@ namespace PHPStan\Reflection\Php; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod; use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassReflection; use PHPStan\TrinaryLogic; @@ -20,7 +21,7 @@ interface PhpMethodReflectionFactory public function create( ClassReflection $declaringClass, ?ClassReflection $declaringTrait, - BuiltinMethodReflection $reflection, + ReflectionMethod $reflection, TemplateTypeMap $templateTypeMap, array $phpDocParameterTypes, ?Type $phpDocReturnType, @@ -34,9 +35,9 @@ public function create( ?Type $selfOutType, ?string $phpDocComment, array $phpDocParameterOutTypes, - array $immediatelyInvokedCallableParameters = [], - array $phpDocClosureThisTypeParameters = [], - bool $acceptsNamedArguments = true, + array $immediatelyInvokedCallableParameters, + array $phpDocClosureThisTypeParameters, + bool $acceptsNamedArguments, ): PhpMethodReflection; } diff --git a/src/Reflection/Php/PhpParameterFromParserNodeReflection.php b/src/Reflection/Php/PhpParameterFromParserNodeReflection.php index 61d1852c7d..8ebb272bfd 100644 --- a/src/Reflection/Php/PhpParameterFromParserNodeReflection.php +++ b/src/Reflection/Php/PhpParameterFromParserNodeReflection.php @@ -2,7 +2,7 @@ namespace PHPStan\Reflection\Php; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\PassedByReference; use PHPStan\TrinaryLogic; use PHPStan\Type\MixedType; @@ -10,7 +10,7 @@ use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypehintHelper; -final class PhpParameterFromParserNodeReflection implements ParameterReflectionWithPhpDocs +final class PhpParameterFromParserNodeReflection implements ExtendedParameterReflection { private ?Type $type = null; diff --git a/src/Reflection/Php/PhpParameterReflection.php b/src/Reflection/Php/PhpParameterReflection.php index 26cb1be007..40b28e9ff6 100644 --- a/src/Reflection/Php/PhpParameterReflection.php +++ b/src/Reflection/Php/PhpParameterReflection.php @@ -3,9 +3,10 @@ namespace PHPStan\Reflection\Php; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\InitializerExprContext; use PHPStan\Reflection\InitializerExprTypeResolver; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\PassedByReference; use PHPStan\TrinaryLogic; use PHPStan\Type\MixedType; @@ -13,7 +14,7 @@ use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypehintHelper; -final class PhpParameterReflection implements ParameterReflectionWithPhpDocs +final class PhpParameterReflection implements ExtendedParameterReflection { private ?Type $type = null; @@ -24,7 +25,7 @@ public function __construct( private InitializerExprTypeResolver $initializerExprTypeResolver, private ReflectionParameter $reflection, private ?Type $phpDocType, - private ?string $declaringClassName, + private ?ClassReflection $declaringClass, private ?Type $outType, private TrinaryLogic $immediatelyInvokedCallable, private ?Type $closureThisType, @@ -62,7 +63,7 @@ public function getType(): Type $this->type = TypehintHelper::decideTypeFromReflection( $this->reflection->getType(), $phpDocType, - $this->declaringClassName, + $this->declaringClass, $this->isVariadic(), ); } @@ -97,7 +98,7 @@ public function getNativeType(): Type $this->nativeType = TypehintHelper::decideTypeFromReflection( $this->reflection->getType(), null, - $this->declaringClassName, + $this->declaringClass, $this->isVariadic(), ); } diff --git a/src/Reflection/Php/PhpPropertyReflection.php b/src/Reflection/Php/PhpPropertyReflection.php index b1f2c18656..28e559719a 100644 --- a/src/Reflection/Php/PhpPropertyReflection.php +++ b/src/Reflection/Php/PhpPropertyReflection.php @@ -15,9 +15,8 @@ /** * @api - * @final */ -class PhpPropertyReflection implements ExtendedPropertyReflection +final class PhpPropertyReflection implements ExtendedPropertyReflection { private ?Type $finalNativeType = null; diff --git a/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php b/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php index a39fe6c67b..df06443436 100644 --- a/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php +++ b/src/Reflection/Php/UniversalObjectCratesClassReflectionExtension.php @@ -14,7 +14,7 @@ final class UniversalObjectCratesClassReflectionExtension { /** - * @param string[] $classes + * @param list $classes */ public function __construct( private ReflectionProvider $reflectionProvider, @@ -26,17 +26,29 @@ public function __construct( public function hasProperty(ClassReflection $classReflection, string $propertyName): bool { - return self::isUniversalObjectCrate( + return self::isUniversalObjectCrateImplementation( $this->reflectionProvider, $this->classes, $classReflection, ); } + public static function isUniversalObjectCrate( + ReflectionProvider $reflectionProvider, + ClassReflection $classReflection, + ): bool + { + return self::isUniversalObjectCrateImplementation( + $reflectionProvider, + $reflectionProvider->getUniversalObjectCratesClasses(), + $classReflection, + ); + } + /** - * @param string[] $classes + * @param list $classes */ - public static function isUniversalObjectCrate( + private static function isUniversalObjectCrateImplementation( ReflectionProvider $reflectionProvider, array $classes, ClassReflection $classReflection, diff --git a/src/Reflection/RealClassClassConstantReflection.php b/src/Reflection/RealClassClassConstantReflection.php new file mode 100644 index 0000000000..85d863ba81 --- /dev/null +++ b/src/Reflection/RealClassClassConstantReflection.php @@ -0,0 +1,141 @@ +reflection->getName(); + } + + public function getFileName(): ?string + { + return $this->declaringClass->getFileName(); + } + + public function getValueExpr(): Expr + { + return $this->reflection->getValueExpression(); + } + + public function hasPhpDocType(): bool + { + return $this->phpDocType !== null; + } + + public function getPhpDocType(): ?Type + { + return $this->phpDocType; + } + + public function hasNativeType(): bool + { + return $this->nativeType !== null; + } + + public function getNativeType(): ?Type + { + return $this->nativeType; + } + + public function getValueType(): Type + { + if ($this->valueType === null) { + if ($this->phpDocType !== null) { + if ($this->nativeType !== null) { + return $this->valueType = TypehintHelper::decideType( + $this->nativeType, + $this->phpDocType, + ); + } + + return $this->phpDocType; + } elseif ($this->nativeType !== null) { + return $this->nativeType; + } + + $this->valueType = $this->initializerExprTypeResolver->getType($this->getValueExpr(), InitializerExprContext::fromClassReflection($this->declaringClass)); + } + + return $this->valueType; + } + + public function getDeclaringClass(): ClassReflection + { + return $this->declaringClass; + } + + public function isStatic(): bool + { + return true; + } + + public function isPrivate(): bool + { + return $this->reflection->isPrivate(); + } + + public function isPublic(): bool + { + return $this->reflection->isPublic(); + } + + public function isFinal(): bool + { + return $this->isFinal || $this->reflection->isFinal(); + } + + public function isDeprecated(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->isDeprecated); + } + + public function getDeprecatedDescription(): ?string + { + if ($this->isDeprecated) { + return $this->deprecatedDescription; + } + + return null; + } + + public function isInternal(): TrinaryLogic + { + return TrinaryLogic::createFromBoolean($this->isInternal); + } + + public function getDocComment(): ?string + { + $docComment = $this->reflection->getDocComment(); + if ($docComment === false) { + return null; + } + + return $docComment; + } + +} diff --git a/src/Reflection/ReflectionProvider.php b/src/Reflection/ReflectionProvider.php index e268800f5a..3b7387f85a 100644 --- a/src/Reflection/ReflectionProvider.php +++ b/src/Reflection/ReflectionProvider.php @@ -16,13 +16,14 @@ public function getClass(string $className): ClassReflection; public function getClassName(string $className): string; - public function supportsAnonymousClasses(): bool; - public function getAnonymousClassReflection( Node\Stmt\Class_ $classNode, Scope $scope, ): ClassReflection; + /** @return list */ + public function getUniversalObjectCratesClasses(): array; + public function hasFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool; public function getFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): FunctionReflection; @@ -31,7 +32,7 @@ public function resolveFunctionName(Node\Name $nameNode, ?NamespaceAnswerer $nam public function hasConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool; - public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): GlobalConstantReflection; + public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ConstantReflection; public function resolveConstantName(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ?string; diff --git a/src/Reflection/ReflectionProvider/DummyReflectionProvider.php b/src/Reflection/ReflectionProvider/DummyReflectionProvider.php index 7ee5729483..7d18639f8c 100644 --- a/src/Reflection/ReflectionProvider/DummyReflectionProvider.php +++ b/src/Reflection/ReflectionProvider/DummyReflectionProvider.php @@ -5,8 +5,8 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\GlobalConstantReflection; use PHPStan\Reflection\NamespaceAnswerer; use PHPStan\Reflection\ReflectionProvider; use PHPStan\ShouldNotHappenException; @@ -29,14 +29,14 @@ public function getClassName(string $className): string return $className; } - public function supportsAnonymousClasses(): bool + public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope): ClassReflection { - return false; + throw new ShouldNotHappenException(); } - public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope): ClassReflection + public function getUniversalObjectCratesClasses(): array { - throw new ShouldNotHappenException(); + return []; } public function hasFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool @@ -59,7 +59,7 @@ public function hasConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn return false; } - public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): GlobalConstantReflection + public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ConstantReflection { throw new ShouldNotHappenException(); } diff --git a/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php b/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php index 9d6cacd951..00f4301c7e 100644 --- a/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php +++ b/src/Reflection/ReflectionProvider/MemoizingReflectionProvider.php @@ -5,8 +5,8 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\GlobalConstantReflection; use PHPStan\Reflection\NamespaceAnswerer; use PHPStan\Reflection\ReflectionProvider; use function strtolower; @@ -56,14 +56,14 @@ public function getClassName(string $className): string return $this->classNames[$lowerClassName] = $this->provider->getClassName($className); } - public function supportsAnonymousClasses(): bool + public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope): ClassReflection { - return $this->provider->supportsAnonymousClasses(); + return $this->provider->getAnonymousClassReflection($classNode, $scope); } - public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $scope): ClassReflection + public function getUniversalObjectCratesClasses(): array { - return $this->provider->getAnonymousClassReflection($classNode, $scope); + return $this->provider->getUniversalObjectCratesClasses(); } public function hasFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): bool @@ -86,7 +86,7 @@ public function hasConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn return $this->provider->hasConstant($nameNode, $namespaceAnswerer); } - public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): GlobalConstantReflection + public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ConstantReflection { return $this->provider->getConstant($nameNode, $namespaceAnswerer); } diff --git a/src/Reflection/RequireExtension/RequireExtendsMethodsClassReflectionExtension.php b/src/Reflection/RequireExtension/RequireExtendsMethodsClassReflectionExtension.php index f439f811e9..ee6ada6f6f 100644 --- a/src/Reflection/RequireExtension/RequireExtendsMethodsClassReflectionExtension.php +++ b/src/Reflection/RequireExtension/RequireExtendsMethodsClassReflectionExtension.php @@ -5,7 +5,6 @@ use PHPStan\Analyser\OutOfClassScope; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\MethodsClassReflectionExtension; use PHPStan\ShouldNotHappenException; @@ -17,10 +16,7 @@ public function hasMethod(ClassReflection $classReflection, string $methodName): return $this->findMethod($classReflection, $methodName) !== null; } - /** - * @return ExtendedMethodReflection - */ - public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection + public function getMethod(ClassReflection $classReflection, string $methodName): ExtendedMethodReflection { $method = $this->findMethod($classReflection, $methodName); if ($method === null) { @@ -30,10 +26,7 @@ public function getMethod(ClassReflection $classReflection, string $methodName): return $method; } - /** - * @return ExtendedMethodReflection|null - */ - private function findMethod(ClassReflection $classReflection, string $methodName): ?MethodReflection + private function findMethod(ClassReflection $classReflection, string $methodName): ?ExtendedMethodReflection { if (!$classReflection->isInterface()) { return null; diff --git a/src/Reflection/RequireExtension/RequireExtendsPropertiesClassReflectionExtension.php b/src/Reflection/RequireExtension/RequireExtendsPropertiesClassReflectionExtension.php index 294cc94b62..550a7bee59 100644 --- a/src/Reflection/RequireExtension/RequireExtendsPropertiesClassReflectionExtension.php +++ b/src/Reflection/RequireExtension/RequireExtendsPropertiesClassReflectionExtension.php @@ -6,7 +6,6 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\PropertiesClassReflectionExtension; -use PHPStan\Reflection\PropertyReflection; use PHPStan\ShouldNotHappenException; final class RequireExtendsPropertiesClassReflectionExtension implements PropertiesClassReflectionExtension @@ -17,10 +16,7 @@ public function hasProperty(ClassReflection $classReflection, string $propertyNa return $this->findProperty($classReflection, $propertyName) !== null; } - /** - * @return ExtendedPropertyReflection - */ - public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection + public function getProperty(ClassReflection $classReflection, string $propertyName): ExtendedPropertyReflection { $property = $this->findProperty($classReflection, $propertyName); if ($property === null) { diff --git a/src/Reflection/ResolvedFunctionVariant.php b/src/Reflection/ResolvedFunctionVariant.php index a6139853fb..5b5cb6b4e6 100644 --- a/src/Reflection/ResolvedFunctionVariant.php +++ b/src/Reflection/ResolvedFunctionVariant.php @@ -4,7 +4,7 @@ use PHPStan\Type\Type; -interface ResolvedFunctionVariant extends ParametersAcceptorWithPhpDocs +interface ResolvedFunctionVariant extends ExtendedParametersAcceptor { public function getOriginalParametersAcceptor(): ParametersAcceptor; diff --git a/src/Reflection/ResolvedFunctionVariantWithCallable.php b/src/Reflection/ResolvedFunctionVariantWithCallable.php index ab121486a1..68d9d87414 100644 --- a/src/Reflection/ResolvedFunctionVariantWithCallable.php +++ b/src/Reflection/ResolvedFunctionVariantWithCallable.php @@ -24,10 +24,11 @@ public function __construct( private ResolvedFunctionVariant $parametersAcceptor, private array $throwPoints, private TrinaryLogic $isPure, + private TrinaryLogic $isDeprecated, private array $impurePoints, private array $invalidateExpressions, private array $usedVariables, - private bool $acceptsNamedArguments, + private TrinaryLogic $acceptsNamedArguments, ) { } @@ -97,6 +98,11 @@ public function isPure(): TrinaryLogic return $this->isPure; } + public function isDeprecated(): TrinaryLogic + { + return $this->isDeprecated; + } + public function getImpurePoints(): array { return $this->impurePoints; @@ -112,7 +118,7 @@ public function getUsedVariables(): array return $this->usedVariables; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->acceptsNamedArguments; } diff --git a/src/Reflection/ResolvedFunctionVariantWithOriginal.php b/src/Reflection/ResolvedFunctionVariantWithOriginal.php index c9f0d94ac6..dcf68ca1ef 100644 --- a/src/Reflection/ResolvedFunctionVariantWithOriginal.php +++ b/src/Reflection/ResolvedFunctionVariantWithOriginal.php @@ -2,8 +2,7 @@ namespace PHPStan\Reflection; -use PHPStan\DependencyInjection\BleedingEdgeToggle; -use PHPStan\Reflection\Php\DummyParameterWithPhpDocs; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\Type\ConditionalTypeForParameter; use PHPStan\Type\ErrorType; use PHPStan\Type\Generic\GenericObjectType; @@ -22,7 +21,7 @@ final class ResolvedFunctionVariantWithOriginal implements ResolvedFunctionVariant { - /** @var ParameterReflectionWithPhpDocs[]|null */ + /** @var list|null */ private ?array $parameters = null; private ?Type $returnTypeWithUnresolvableTemplateTypes = null; @@ -37,7 +36,7 @@ final class ResolvedFunctionVariantWithOriginal implements ResolvedFunctionVaria * @param array $passedArgs */ public function __construct( - private ParametersAcceptorWithPhpDocs $parametersAcceptor, + private ExtendedParametersAcceptor $parametersAcceptor, private TemplateTypeMap $resolvedTemplateTypeMap, private TemplateTypeVarianceMap $callSiteVarianceMap, private array $passedArgs, @@ -71,7 +70,7 @@ public function getParameters(): array if ($parameters === null) { $parameters = array_map( - function (ParameterReflectionWithPhpDocs $param): ParameterReflectionWithPhpDocs { + function (ExtendedParameterReflection $param): ExtendedParameterReflection { $paramType = TypeUtils::resolveLateResolvableTypes( TemplateTypeHelper::resolveTemplateTypes( $this->resolveConditionalTypesForParameter($param->getType()), @@ -108,7 +107,7 @@ function (ParameterReflectionWithPhpDocs $param): ParameterReflectionWithPhpDocs ); } - return new DummyParameterWithPhpDocs( + return new ExtendedDummyParameter( $param->getName(), $paramType, $param->isOptional(), @@ -245,7 +244,7 @@ private function resolveResolvableTemplateTypes(Type $type, TemplateTypeVariance }; return TypeTraverser::map($type, function (Type $type, callable $traverse) use ($references, $objectCb): Type { - if (BleedingEdgeToggle::isBleedingEdge() && $type instanceof GenericObjectType) { + if ($type instanceof GenericObjectType) { return TypeTraverser::map($type, $objectCb); } diff --git a/src/Reflection/ResolvedMethodReflection.php b/src/Reflection/ResolvedMethodReflection.php index 477cbdea74..33b70bafe4 100644 --- a/src/Reflection/ResolvedMethodReflection.php +++ b/src/Reflection/ResolvedMethodReflection.php @@ -14,10 +14,10 @@ final class ResolvedMethodReflection implements ExtendedMethodReflection { - /** @var ParametersAcceptorWithPhpDocs[]|null */ + /** @var list|null */ private ?array $variants = null; - /** @var ParametersAcceptorWithPhpDocs[]|null */ + /** @var list|null */ private ?array $namedArgumentVariants = null; private ?Assertions $asserts = null; @@ -52,7 +52,7 @@ public function getVariants(): array return $this->variants = $this->resolveVariants($this->reflection->getVariants()); } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -73,8 +73,8 @@ public function getNamedArgumentsVariants(): ?array } /** - * @param ParametersAcceptorWithPhpDocs[] $variants - * @return ResolvedFunctionVariant[] + * @param ExtendedParametersAcceptor[] $variants + * @return list */ private function resolveVariants(array $variants): array { @@ -175,7 +175,7 @@ public function getAsserts(): Assertions )); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->reflection->acceptsNamedArguments(); } diff --git a/src/Reflection/SignatureMap/FunctionSignature.php b/src/Reflection/SignatureMap/FunctionSignature.php index 07886541f8..f9107d4b23 100644 --- a/src/Reflection/SignatureMap/FunctionSignature.php +++ b/src/Reflection/SignatureMap/FunctionSignature.php @@ -8,7 +8,7 @@ final class FunctionSignature { /** - * @param array $parameters + * @param list $parameters */ public function __construct( private array $parameters, @@ -20,7 +20,7 @@ public function __construct( } /** - * @return array + * @return list */ public function getParameters(): array { diff --git a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php index 32a484c3c9..2a94fc4da5 100644 --- a/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php +++ b/src/Reflection/SignatureMap/NativeFunctionReflectionProvider.php @@ -9,9 +9,9 @@ use PHPStan\PhpDoc\ResolvedPhpDocBlock; use PHPStan\PhpDoc\StubPhpDocProvider; use PHPStan\Reflection\Assertions; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; +use PHPStan\Reflection\ExtendedFunctionVariant; +use PHPStan\Reflection\Native\ExtendedNativeParameterReflection; use PHPStan\Reflection\Native\NativeFunctionReflection; -use PHPStan\Reflection\Native\NativeParameterWithPhpDocsReflection; use PHPStan\TrinaryLogic; use PHPStan\Type\FileTypeMapper; use PHPStan\Type\Generic\TemplateTypeMap; @@ -91,10 +91,10 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef $variantsByType = ['positional' => []]; foreach ($functionSignaturesResult as $signatureType => $functionSignatures) { foreach ($functionSignatures ?? [] as $functionSignature) { - $variantsByType[$signatureType][] = new FunctionVariantWithPhpDocs( + $variantsByType[$signatureType][] = new ExtendedFunctionVariant( TemplateTypeMap::createEmpty(), null, - array_map(static function (ParameterSignature $parameterSignature) use ($phpDoc): NativeParameterWithPhpDocsReflection { + array_map(static function (ParameterSignature $parameterSignature) use ($phpDoc): ExtendedNativeParameterReflection { $type = $parameterSignature->getType(); $phpDocType = null; @@ -112,7 +112,7 @@ public function findFunctionReflection(string $functionName): ?NativeFunctionRef } } - return new NativeParameterWithPhpDocsReflection( + return new ExtendedNativeParameterReflection( $parameterSignature->getName(), $parameterSignature->isOptional(), TypehintHelper::decideType($type, $phpDocType), diff --git a/src/Reflection/SignatureMap/SignatureMapParser.php b/src/Reflection/SignatureMap/SignatureMapParser.php index 0652b11383..e60cede66d 100644 --- a/src/Reflection/SignatureMap/SignatureMapParser.php +++ b/src/Reflection/SignatureMap/SignatureMapParser.php @@ -57,7 +57,7 @@ private function getTypeFromString(string $typeString, ?string $className): Type /** * @param array $parameterMap - * @return array + * @return list */ private function getParameters(array $parameterMap): array { diff --git a/src/Reflection/TrivialParametersAcceptor.php b/src/Reflection/TrivialParametersAcceptor.php index b6e638c979..8c7e3e9a6a 100644 --- a/src/Reflection/TrivialParametersAcceptor.php +++ b/src/Reflection/TrivialParametersAcceptor.php @@ -13,9 +13,8 @@ /** * @api - * @final */ -class TrivialParametersAcceptor implements ParametersAcceptorWithPhpDocs, CallableParametersAcceptor +final class TrivialParametersAcceptor implements ExtendedParametersAcceptor, CallableParametersAcceptor { /** @api */ @@ -73,6 +72,11 @@ public function isPure(): TrinaryLogic return TrinaryLogic::createMaybe(); } + public function isDeprecated(): TrinaryLogic + { + return TrinaryLogic::createNo(); + } + public function getImpurePoints(): array { return [ @@ -94,9 +98,9 @@ public function getUsedVariables(): array return []; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return true; + return TrinaryLogic::createYes(); } } diff --git a/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php b/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php index 5fd19b3105..eaca01ec4c 100644 --- a/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Type/CallbackUnresolvedMethodPrototypeReflection.php @@ -4,11 +4,11 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\Dummy\ChangedTypeMethodReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; -use PHPStan\Reflection\Php\DummyParameterWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\Reflection\ResolvedMethodReflection; use PHPStan\Type\Type; use function array_map; @@ -82,11 +82,11 @@ public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflectio private function transformMethodWithStaticType(ClassReflection $declaringClass, ExtendedMethodReflection $method): ExtendedMethodReflection { - $variantFn = fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs( + $variantFn = fn (ExtendedParametersAcceptor $acceptor): ExtendedParametersAcceptor => new ExtendedFunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), array_map( - fn (ParameterReflectionWithPhpDocs $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + fn (ExtendedParameterReflection $parameter): ExtendedParameterReflection => new ExtendedDummyParameter( $parameter->getName(), $this->transformStaticType($parameter->getType()), $parameter->isOptional(), diff --git a/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php b/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php index 607a08a37f..25f676b5ae 100644 --- a/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php +++ b/src/Reflection/Type/CalledOnTypeUnresolvedMethodPrototypeReflection.php @@ -4,11 +4,11 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\Dummy\ChangedTypeMethodReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; -use PHPStan\Reflection\Php\DummyParameterWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\Reflection\ResolvedMethodReflection; use PHPStan\Type\StaticType; use PHPStan\Type\Type; @@ -77,11 +77,11 @@ public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflectio private function transformMethodWithStaticType(ClassReflection $declaringClass, ExtendedMethodReflection $method): ExtendedMethodReflection { - $variantFn = fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs( + $variantFn = fn (ExtendedParametersAcceptor $acceptor): ExtendedParametersAcceptor => new ExtendedFunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), array_map( - fn (ParameterReflectionWithPhpDocs $parameter): ParameterReflectionWithPhpDocs => new DummyParameterWithPhpDocs( + fn (ExtendedParameterReflection $parameter): ExtendedParameterReflection => new ExtendedDummyParameter( $parameter->getName(), $this->transformStaticType($parameter->getType()), $parameter->isOptional(), diff --git a/src/Reflection/Type/IntersectionTypeMethodReflection.php b/src/Reflection/Type/IntersectionTypeMethodReflection.php index 65c3b8b152..c19986d71c 100644 --- a/src/Reflection/Type/IntersectionTypeMethodReflection.php +++ b/src/Reflection/Type/IntersectionTypeMethodReflection.php @@ -5,11 +5,11 @@ use PHPStan\Reflection\Assertions; use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptor; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; @@ -83,7 +83,7 @@ public function getVariants(): array $phpDocReturnType = TypeCombinator::intersect(...array_map(static fn (MethodReflection $method): Type => TypeCombinator::intersect(...array_map(static fn (ParametersAcceptor $acceptor): Type => $acceptor->getPhpDocReturnType(), $method->getVariants())), $this->methods)); $nativeReturnType = TypeCombinator::intersect(...array_map(static fn (MethodReflection $method): Type => TypeCombinator::intersect(...array_map(static fn (ParametersAcceptor $acceptor): Type => $acceptor->getNativeReturnType(), $method->getVariants())), $this->methods)); - return array_map(static fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs( + return array_map(static fn (ExtendedParametersAcceptor $acceptor): ExtendedParametersAcceptor => new ExtendedFunctionVariant( $acceptor->getTemplateTypeMap(), $acceptor->getResolvedTemplateTypeMap(), $acceptor->getParameters(), @@ -95,7 +95,7 @@ public function getVariants(): array ), $this->methods[0]->getVariants()); } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { $variants = $this->getVariants(); if (count($variants) !== 1) { @@ -198,14 +198,9 @@ public function getAsserts(): Assertions return $assertions; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - $accepts = true; - foreach ($this->methods as $method) { - $accepts = $accepts && $method->acceptsNamedArguments(); - } - - return $accepts; + return TrinaryLogic::lazyMaxMin($this->methods, static fn (MethodReflection $method): TrinaryLogic => $method->acceptsNamedArguments()); } public function getSelfOutType(): ?Type diff --git a/src/Reflection/Type/UnionTypeMethodReflection.php b/src/Reflection/Type/UnionTypeMethodReflection.php index 3808304444..167493c0b8 100644 --- a/src/Reflection/Type/UnionTypeMethodReflection.php +++ b/src/Reflection/Type/UnionTypeMethodReflection.php @@ -6,9 +6,9 @@ use PHPStan\Reflection\ClassMemberReflection; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\MethodReflection; use PHPStan\Reflection\ParametersAcceptorSelector; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; @@ -83,7 +83,7 @@ public function getVariants(): array return [ParametersAcceptorSelector::combineAcceptors($variants)]; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -175,14 +175,9 @@ public function getAsserts(): Assertions return Assertions::createEmpty(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - $accepts = true; - foreach ($this->methods as $method) { - $accepts = $accepts && $method->acceptsNamedArguments(); - } - - return $accepts; + return TrinaryLogic::lazyExtremeIdentity($this->methods, static fn (ExtendedMethodReflection $method): TrinaryLogic => $method->acceptsNamedArguments()); } public function getSelfOutType(): ?Type diff --git a/src/Reflection/WrappedExtendedMethodReflection.php b/src/Reflection/WrappedExtendedMethodReflection.php index 12d263b0e6..c14e51656e 100644 --- a/src/Reflection/WrappedExtendedMethodReflection.php +++ b/src/Reflection/WrappedExtendedMethodReflection.php @@ -2,7 +2,7 @@ namespace PHPStan\Reflection; -use PHPStan\Reflection\Php\DummyParameterWithPhpDocs; +use PHPStan\Reflection\Php\ExtendedDummyParameter; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeVarianceMap; use PHPStan\Type\MixedType; @@ -55,15 +55,15 @@ public function getVariants(): array { $variants = []; foreach ($this->method->getVariants() as $variant) { - if ($variant instanceof ParametersAcceptorWithPhpDocs) { + if ($variant instanceof ExtendedParametersAcceptor) { $variants[] = $variant; continue; } - $variants[] = new FunctionVariantWithPhpDocs( + $variants[] = new ExtendedFunctionVariant( $variant->getTemplateTypeMap(), $variant->getResolvedTemplateTypeMap(), - array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs( + array_map(static fn (ParameterReflection $parameter): ExtendedParameterReflection => $parameter instanceof ExtendedParameterReflection ? $parameter : new ExtendedDummyParameter( $parameter->getName(), $parameter->getType(), $parameter->isOptional(), @@ -87,7 +87,7 @@ public function getVariants(): array return $variants; } - public function getOnlyVariant(): ParametersAcceptorWithPhpDocs + public function getOnlyVariant(): ExtendedParametersAcceptor { return $this->getVariants()[0]; } @@ -142,9 +142,9 @@ public function getAsserts(): Assertions return Assertions::createEmpty(); } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return $this->getDeclaringClass()->acceptsNamedArguments(); + return TrinaryLogic::createFromBoolean($this->getDeclaringClass()->acceptsNamedArguments()); } public function getSelfOutType(): ?Type diff --git a/src/Rules/Api/ApiInstanceofTypeRule.php b/src/Rules/Api/ApiInstanceofTypeRule.php index ccda700696..7369715660 100644 --- a/src/Rules/Api/ApiInstanceofTypeRule.php +++ b/src/Rules/Api/ApiInstanceofTypeRule.php @@ -30,7 +30,6 @@ use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ConstantScalarType; -use PHPStan\Type\ConstantType; use PHPStan\Type\Enum\EnumCaseObjectType; use PHPStan\Type\FloatType; use PHPStan\Type\Generic\GenericClassStringType; @@ -76,7 +75,6 @@ final class ApiInstanceofTypeRule implements Rule GenericClassStringType::class => 'Type::isClassStringType() and Type::getClassStringObjectType()', GenericObjectType::class => null, IntersectionType::class => null, - ConstantType::class => 'Type::isConstantValue() or Type::generalize()', ConstantScalarType::class => 'Type::isConstantScalarValue() or Type::getConstantScalarTypes() or Type::getConstantScalarValues()', ObjectShapeType::class => 'Type::isObject() and Type::hasProperty()', @@ -98,8 +96,6 @@ final class ApiInstanceofTypeRule implements Rule public function __construct( private ReflectionProvider $reflectionProvider, - private bool $enabled, - private bool $deprecationRulesInstalled, ) { } @@ -111,10 +107,6 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { - if (!$this->enabled && !$this->deprecationRulesInstalled) { - return []; - } - if (!$node->class instanceof Node\Name) { return []; } diff --git a/src/Rules/Api/BcUncoveredInterface.php b/src/Rules/Api/BcUncoveredInterface.php index 5b508c2e07..3bf9c0c61d 100644 --- a/src/Rules/Api/BcUncoveredInterface.php +++ b/src/Rules/Api/BcUncoveredInterface.php @@ -4,12 +4,22 @@ use PHPStan\Analyser\Scope; use PHPStan\Command\Output; +use PHPStan\Command\OutputStyle; +use PHPStan\DependencyInjection\Container; +use PHPStan\Node\ReturnStatementsNode; +use PHPStan\Node\VirtualNode; +use PHPStan\PhpDoc\Tag\TypedTag; use PHPStan\Reflection\Callables\CallableParametersAcceptor; +use PHPStan\Reflection\ClassConstantReflection; +use PHPStan\Reflection\ClassMemberAccessAnswerer; +use PHPStan\Reflection\ClassMemberReflection; +use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\NamespaceAnswerer; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\FileRuleError; use PHPStan\Rules\IdentifierRuleError; @@ -18,20 +28,28 @@ use PHPStan\Rules\NonIgnorableRuleError; use PHPStan\Rules\RuleError; use PHPStan\Rules\TipRuleError; +use PHPStan\Type\CompoundType; +use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Type; +use PHPStan\Type\TypeWithClassName; final class BcUncoveredInterface { public const CLASSES = [ Type::class, + CompoundType::class, + TemplateType::class, + TypedTag::class, + TypeWithClassName::class, + VirtualNode::class, ReflectionProvider::class, Scope::class, FunctionReflection::class, ExtendedMethodReflection::class, ExtendedPropertyReflection::class, - ParametersAcceptorWithPhpDocs::class, - ParameterReflectionWithPhpDocs::class, + ExtendedParametersAcceptor::class, + ExtendedParameterReflection::class, CallableParametersAcceptor::class, FileRuleError::class, IdentifierRuleError::class, @@ -41,6 +59,14 @@ final class BcUncoveredInterface RuleError::class, TipRuleError::class, Output::class, + ClassMemberReflection::class, + ConstantReflection::class, + ClassConstantReflection::class, + ClassMemberAccessAnswerer::class, + NamespaceAnswerer::class, + Container::class, + OutputStyle::class, + ReturnStatementsNode::class, ]; } diff --git a/src/Rules/Api/NodeConnectingVisitorAttributesRule.php b/src/Rules/Api/NodeConnectingVisitorAttributesRule.php index a1f27a33e2..7ad74631b9 100644 --- a/src/Rules/Api/NodeConnectingVisitorAttributesRule.php +++ b/src/Rules/Api/NodeConnectingVisitorAttributesRule.php @@ -4,16 +4,12 @@ use PhpParser\Node; use PhpParser\Node\Expr\MethodCall; -use PhpParser\NodeVisitor\NodeConnectingVisitor; use PHPStan\Analyser\Scope; -use PHPStan\DependencyInjection\Container; -use PHPStan\Parser\RichParser; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\ObjectType; use function array_keys; -use function get_class; use function in_array; use function sprintf; use function str_starts_with; @@ -24,10 +20,6 @@ final class NodeConnectingVisitorAttributesRule implements Rule { - public function __construct(private Container $container) - { - } - public function getNodeType(): string { return MethodCall::class; @@ -74,20 +66,6 @@ public function processNode(Node $node, Scope $scope): array return []; } - $isVisitorRegistered = false; - foreach ($this->container->getServicesByTag(RichParser::VISITOR_SERVICE_TAG) as $service) { - if (get_class($service) !== NodeConnectingVisitor::class) { - continue; - } - - $isVisitorRegistered = true; - break; - } - - if ($isVisitorRegistered) { - return []; - } - return [ RuleErrorBuilder::message(sprintf('Node attribute \'%s\' is no longer available.', $argType->getValue())) ->identifier('phpParser.nodeConnectingAttribute') diff --git a/src/Rules/Api/OldPhpParser4ClassRule.php b/src/Rules/Api/OldPhpParser4ClassRule.php new file mode 100644 index 0000000000..8c86e3c713 --- /dev/null +++ b/src/Rules/Api/OldPhpParser4ClassRule.php @@ -0,0 +1,79 @@ + + */ +final class OldPhpParser4ClassRule implements Rule +{ + + private const NAME_MAPPING = [ + // from https://github.com/nikic/PHP-Parser/blob/master/UPGRADE-5.0.md#renamed-nodes + 'PhpParser\Node\Scalar\LNumber' => Node\Scalar\Int_::class, + 'PhpParser\Node\Scalar\DNumber' => Node\Scalar\Float_::class, + 'PhpParser\Node\Scalar\Encapsed' => Node\Scalar\InterpolatedString::class, + 'PhpParser\Node\Scalar\EncapsedStringPart' => Node\InterpolatedStringPart::class, + 'PhpParser\Node\Expr\ArrayItem' => Node\ArrayItem::class, + 'PhpParser\Node\Expr\ClosureUse' => Node\ClosureUse::class, + 'PhpParser\Node\Stmt\DeclareDeclare' => Node\DeclareItem::class, + 'PhpParser\Node\Stmt\PropertyProperty' => Node\PropertyItem::class, + 'PhpParser\Node\Stmt\StaticVar' => Node\StaticVar::class, + 'PhpParser\Node\Stmt\UseUse' => Node\UseItem::class, + ]; + + public function getNodeType(): string + { + return Name::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $nameMapping = array_change_key_case(self::NAME_MAPPING); + $lowerName = $node->toLowerString(); + if (!array_key_exists($lowerName, $nameMapping)) { + return []; + } + + $newName = $nameMapping[$lowerName]; + + if (!$scope->isInClass()) { + return []; + } + + $classReflection = $scope->getClassReflection(); + $hasPhpStanInterface = false; + foreach (array_keys($classReflection->getInterfaces()) as $interfaceName) { + if (!str_starts_with($interfaceName, 'PHPStan\\')) { + continue; + } + + $hasPhpStanInterface = true; + } + + if (!$hasPhpStanInterface) { + return []; + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Class %s not found. It has been renamed to %s in PHP-Parser v5.', + $node->toString(), + $newName, + ))->identifier('phpParser.classRenamed') + ->build(), + ]; + } + +} diff --git a/src/Rules/Arrays/AppendedArrayItemTypeRule.php b/src/Rules/Arrays/AppendedArrayItemTypeRule.php deleted file mode 100644 index dee1dc6c30..0000000000 --- a/src/Rules/Arrays/AppendedArrayItemTypeRule.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -final class AppendedArrayItemTypeRule implements Rule -{ - - public function __construct( - private PropertyReflectionFinder $propertyReflectionFinder, - private RuleLevelHelper $ruleLevelHelper, - ) - { - } - - public function getNodeType(): string - { - return Node\Expr::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if ( - !$node instanceof Assign - && !$node instanceof AssignOp - && !$node instanceof AssignRef - ) { - return []; - } - - if (!($node->var instanceof ArrayDimFetch)) { - return []; - } - - if ( - !$node->var->var instanceof Node\Expr\PropertyFetch - && !$node->var->var instanceof Node\Expr\StaticPropertyFetch - ) { - return []; - } - - $propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($node->var->var, $scope); - if ($propertyReflection === null) { - return []; - } - - $assignedToType = $propertyReflection->getWritableType(); - if (!$assignedToType->isArray()->yes()) { - return []; - } - - if ($node instanceof Assign || $node instanceof AssignRef) { - $assignedValueType = $scope->getType($node->expr); - } else { - $assignedValueType = $scope->getType($node); - } - - $itemType = $assignedToType->getIterableValueType(); - $accepts = $this->ruleLevelHelper->acceptsWithReason($itemType, $assignedValueType, $scope->isDeclareStrictTypes()); - if (!$accepts->result) { - $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($itemType, $assignedValueType); - return [ - RuleErrorBuilder::message(sprintf( - 'Array (%s) does not accept %s.', - $assignedToType->describe($verbosityLevel), - $assignedValueType->describe($verbosityLevel), - )) - ->acceptsReasonsTip($accepts->reasons) - ->identifier('array.valueType') - ->build(), - ]; - } - - return []; - } - -} diff --git a/src/Rules/Arrays/AppendedArrayKeyTypeRule.php b/src/Rules/Arrays/AppendedArrayKeyTypeRule.php deleted file mode 100644 index 3e91fe8dbe..0000000000 --- a/src/Rules/Arrays/AppendedArrayKeyTypeRule.php +++ /dev/null @@ -1,89 +0,0 @@ - - */ -final class AppendedArrayKeyTypeRule implements Rule -{ - - public function __construct( - private PropertyReflectionFinder $propertyReflectionFinder, - private bool $checkUnionTypes, - ) - { - } - - public function getNodeType(): string - { - return Assign::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if (!($node->var instanceof ArrayDimFetch)) { - return []; - } - - if ( - !$node->var->var instanceof Node\Expr\PropertyFetch - && !$node->var->var instanceof Node\Expr\StaticPropertyFetch - ) { - return []; - } - - $propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($node->var->var, $scope); - if ($propertyReflection === null) { - return []; - } - - $arrayType = $propertyReflection->getReadableType(); - if (!$arrayType->isArray()->yes()) { - return []; - } - - if ($node->var->dim !== null) { - $dimensionType = $scope->getType($node->var->dim); - $isValidKey = AllowedArrayKeysTypes::getType()->isSuperTypeOf($dimensionType); - if (!$isValidKey->yes()) { - // already handled by InvalidKeyInArrayDimFetchRule - return []; - } - - $keyType = $dimensionType->toArrayKey(); - if (!$this->checkUnionTypes && $keyType instanceof UnionType) { - return []; - } - } else { - $keyType = new IntegerType(); - } - - if (!$arrayType->getIterableKeyType()->isSuperTypeOf($keyType)->yes()) { - $verbosity = VerbosityLevel::getRecommendedLevelByType($arrayType->getIterableKeyType(), $keyType); - return [ - RuleErrorBuilder::message(sprintf( - 'Array (%s) does not accept key %s.', - $arrayType->describe($verbosity), - $keyType->describe(VerbosityLevel::value()), - ))->identifier('array.keyType')->build(), - ]; - } - - return []; - } - -} diff --git a/src/Rules/Arrays/ArrayDestructuringRule.php b/src/Rules/Arrays/ArrayDestructuringRule.php index ab83f1d019..1d9537d274 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, @@ -86,7 +85,7 @@ private function getErrors(Scope $scope, Expr $var, Expr $expr): array $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); @@ -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 deleted file mode 100644 index 0bfcebf956..0000000000 --- a/src/Rules/Arrays/EmptyArrayItemRule.php +++ /dev/null @@ -1,41 +0,0 @@ - - */ -final class EmptyArrayItemRule implements Rule -{ - - public function getNodeType(): string - { - return LiteralArrayNode::class; - } - - public function processNode(Node $node, Scope $scope): array - { - foreach ($node->getItemNodes() as $itemNode) { - $item = $itemNode->getArrayItem(); - if ($item !== null) { - continue; - } - - return [ - RuleErrorBuilder::message('Literal array contains empty item.') - ->nonIgnorable() - ->identifier('array.emptyItem') - ->build(), - ]; - } - - return []; - } - -} 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/Arrays/NonexistentOffsetInArrayDimFetchCheck.php b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php index 7b329d01a4..5b81f82f1a 100644 --- a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php +++ b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php @@ -14,6 +14,7 @@ use PHPStan\Type\TypeUtils; use PHPStan\Type\UnionType; use PHPStan\Type\VerbosityLevel; +use function count; use function sprintf; final class NonexistentOffsetInArrayDimFetchCheck @@ -22,7 +23,6 @@ final class NonexistentOffsetInArrayDimFetchCheck public function __construct( private RuleLevelHelper $ruleLevelHelper, private bool $reportMaybes, - private bool $bleedingEdge, private bool $reportPossiblyNonexistentGeneralArrayOffset, private bool $reportPossiblyNonexistentConstantArrayOffset, ) @@ -56,7 +56,7 @@ public function check( if ($type->hasOffsetValueType($dimType)->no()) { return [ - RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) + RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(count($dimType->getConstantStrings()) > 0 ? VerbosityLevel::precise() : VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) ->identifier('offsetAccess.notFound') ->build(), ]; @@ -104,15 +104,8 @@ public function check( } if ($report) { - if ($this->bleedingEdge || $this->reportPossiblyNonexistentGeneralArrayOffset || $this->reportPossiblyNonexistentConstantArrayOffset) { - return [ - RuleErrorBuilder::message(sprintf('Offset %s might not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) - ->identifier('offsetAccess.notFound') - ->build(), - ]; - } return [ - RuleErrorBuilder::message(sprintf('Offset %s does not exist on %s.', $dimType->describe(VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) + RuleErrorBuilder::message(sprintf('Offset %s might not exist on %s.', $dimType->describe(count($dimType->getConstantStrings()) > 0 ? VerbosityLevel::precise() : VerbosityLevel::value()), $type->describe(VerbosityLevel::value()))) ->identifier('offsetAccess.notFound') ->build(), ]; diff --git a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php index 3cb1b93328..d3ef021189 100644 --- a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php +++ b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php @@ -12,6 +12,7 @@ use PHPStan\Type\ErrorType; use PHPStan\Type\Type; use PHPStan\Type\VerbosityLevel; +use function count; use function sprintf; /** @@ -74,7 +75,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message(sprintf( 'Cannot access offset %s on %s.', - $dimType->describe(VerbosityLevel::value()), + $dimType->describe(count($dimType->getConstantStrings()) > 0 ? VerbosityLevel::precise() : VerbosityLevel::value()), $isOffsetAccessibleType->describe(VerbosityLevel::value()), ))->identifier('offsetAccess.nonOffsetAccessible')->build(), ]; diff --git a/src/Rules/AttributesCheck.php b/src/Rules/AttributesCheck.php index 6976c7d049..df104b3a20 100644 --- a/src/Rules/AttributesCheck.php +++ b/src/Rules/AttributesCheck.php @@ -136,25 +136,23 @@ public function check( $scope, $attributeConstructor->getDeclaringClass()->isBuiltin(), new New_($attribute->name, $attribute->args, $nodeAttributes), - [ - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, at least %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, at least %d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d-%d required.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d-%d required.', - 'Parameter %s of attribute class ' . $attributeClassName . ' constructor expects %s, %s given.', - '', // constructor does not have a return type - 'Parameter %s of attribute class ' . $attributeClassName . ' constructor is passed by reference, so it expects variables only', - 'Unable to resolve the template type %s in instantiation of attribute class ' . $attributeClassName, - 'Missing parameter $%s in call to ' . $attributeClassName . ' constructor.', - 'Unknown parameter $%s in call to ' . $attributeClassName . ' constructor.', - 'Return type of call to ' . $attributeClassName . ' constructor contains unresolvable type.', - 'Parameter %s of attribute class ' . $attributeClassName . ' constructor contains unresolvable type.', - 'Attribute class ' . $attributeClassName . ' constructor invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'attribute', $attributeConstructor->acceptsNamedArguments(), + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, at least %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, at least %d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameter, %d-%d required.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %d parameters, %d-%d required.', + '%s of attribute class ' . $attributeClassName . ' constructor expects %s, %s given.', + '', // constructor does not have a return type + '%s of attribute class ' . $attributeClassName . ' constructor is passed by reference, so it expects variables only', + 'Unable to resolve the template type %s in instantiation of attribute class ' . $attributeClassName, + 'Missing parameter $%s in call to ' . $attributeClassName . ' constructor.', + 'Unknown parameter $%s in call to ' . $attributeClassName . ' constructor.', + 'Return type of call to ' . $attributeClassName . ' constructor contains unresolvable type.', + '%s of attribute class ' . $attributeClassName . ' constructor contains unresolvable type.', + 'Attribute class ' . $attributeClassName . ' constructor invoked with %s, but it\'s not allowed because of @no-named-arguments.', ); foreach ($parameterErrors as $error) { 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/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/Classes/ClassAttributesRule.php b/src/Rules/Classes/ClassAttributesRule.php index afe9786db0..190be4331b 100644 --- a/src/Rules/Classes/ClassAttributesRule.php +++ b/src/Rules/Classes/ClassAttributesRule.php @@ -8,6 +8,9 @@ use PHPStan\Node\InClassNode; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; +use function count; +use function sprintf; /** * @implements Rule @@ -28,12 +31,39 @@ public function processNode(Node $node, Scope $scope): array { $classLikeNode = $node->getOriginalNode(); - return $this->attributesCheck->check( + $errors = $this->attributesCheck->check( $scope, $classLikeNode->attrGroups, Attribute::TARGET_CLASS, 'class', ); + + $classReflection = $node->getClassReflection(); + if ( + $classReflection->isReadOnly() + || $classReflection->isEnum() + || $classReflection->isInterface() + ) { + $typeName = 'readonly class'; + $identifier = 'class.allowDynamicPropertiesReadonly'; + if ($classReflection->isEnum()) { + $typeName = 'enum'; + $identifier = 'enum.allowDynamicProperties'; + } + if ($classReflection->isInterface()) { + $typeName = 'interface'; + $identifier = 'interface.allowDynamicProperties'; + } + + if (count($classReflection->getNativeReflection()->getAttributes('AllowDynamicProperties')) > 0) { + $errors[] = RuleErrorBuilder::message(sprintf('Attribute class AllowDynamicProperties cannot be used with %s.', $typeName)) + ->identifier($identifier) + ->nonIgnorable() + ->build(); + } + } + + return $errors; } } 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/Classes/ImpossibleInstanceOfRule.php b/src/Rules/Classes/ImpossibleInstanceOfRule.php index b6d9c84ee3..a4b3cfe70c 100644 --- a/src/Rules/Classes/ImpossibleInstanceOfRule.php +++ b/src/Rules/Classes/ImpossibleInstanceOfRule.php @@ -22,7 +22,6 @@ final class ImpossibleInstanceOfRule implements Rule { public function __construct( - private bool $checkAlwaysTrueInstanceof, private bool $treatPhpDocTypesAsCertain, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, @@ -89,28 +88,26 @@ public function processNode(Node $node, Scope $scope): array $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType)), )))->identifier('instanceof.alwaysFalse')->build(), ]; - } elseif ($this->checkAlwaysTrueInstanceof) { - $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); - if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { - return []; - } - - $exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->expr) : $scope->getNativeType($node->expr); - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( - 'Instanceof between %s and %s will always evaluate to true.', - $exprType->describe(VerbosityLevel::typeOnly()), - $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType)), - ))); - if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); - } + } - $errorBuilder->identifier('instanceof.alwaysTrue'); + $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); + if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { + return []; + } - return [$errorBuilder->build()]; + $exprType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->expr) : $scope->getNativeType($node->expr); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Instanceof between %s and %s will always evaluate to true.', + $exprType->describe(VerbosityLevel::typeOnly()), + $classType->describe(VerbosityLevel::getRecommendedLevelByType($classType)), + ))); + if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } - return []; + $errorBuilder->identifier('instanceof.alwaysTrue'); + + return [$errorBuilder->build()]; } } diff --git a/src/Rules/Classes/InstantiationRule.php b/src/Rules/Classes/InstantiationRule.php index 8994a4754b..7dd65488a0 100644 --- a/src/Rules/Classes/InstantiationRule.php +++ b/src/Rules/Classes/InstantiationRule.php @@ -201,25 +201,23 @@ private function checkClassName(string $class, bool $isName, Node $node, Scope $ $scope, $constructorReflection->getDeclaringClass()->isBuiltin(), $node, - [ - 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, %d required.', - 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, %d required.', - 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, at least %d required.', - 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, at least %d required.', - 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, %d-%d required.', - 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, %d-%d required.', - 'Parameter %s of class ' . $classDisplayName . ' constructor expects %s, %s given.', - '', // constructor does not have a return type - 'Parameter %s of class ' . $classDisplayName . ' constructor is passed by reference, so it expects variables only', - 'Unable to resolve the template type %s in instantiation of class ' . $classDisplayName, - 'Missing parameter $%s in call to ' . $classDisplayName . ' constructor.', - 'Unknown parameter $%s in call to ' . $classDisplayName . ' constructor.', - 'Return type of call to ' . $classDisplayName . ' constructor contains unresolvable type.', - 'Parameter %s of class ' . $classDisplayName . ' constructor contains unresolvable type.', - 'Class ' . $classDisplayName . ' constructor invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'new', $constructorReflection->acceptsNamedArguments(), + 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, %d required.', + 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, %d required.', + 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, at least %d required.', + 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, at least %d required.', + 'Class ' . $classDisplayName . ' constructor invoked with %d parameter, %d-%d required.', + 'Class ' . $classDisplayName . ' constructor invoked with %d parameters, %d-%d required.', + '%s of class ' . $classDisplayName . ' constructor expects %s, %s given.', + '', // constructor does not have a return type + ' %s of class ' . $classDisplayName . ' constructor is passed by reference, so it expects variables only', + 'Unable to resolve the template type %s in instantiation of class ' . $classDisplayName, + 'Missing parameter $%s in call to ' . $classDisplayName . ' constructor.', + 'Unknown parameter $%s in call to ' . $classDisplayName . ' constructor.', + 'Return type of call to ' . $classDisplayName . ' constructor contains unresolvable type.', + '%s of class ' . $classDisplayName . ' constructor contains unresolvable type.', + 'Class ' . $classDisplayName . ' constructor invoked with %s, but it\'s not allowed because of @no-named-arguments.', )); } diff --git a/src/Rules/Classes/LocalTypeAliasesCheck.php b/src/Rules/Classes/LocalTypeAliasesCheck.php index e2d463ab9c..28ca78679e 100644 --- a/src/Rules/Classes/LocalTypeAliasesCheck.php +++ b/src/Rules/Classes/LocalTypeAliasesCheck.php @@ -43,7 +43,6 @@ public function __construct( private GenericObjectTypeCheck $genericObjectTypeCheck, private bool $checkMissingTypehints, private bool $checkClassCaseSensitivity, - private bool $absentTypeChecks, ) { } @@ -181,10 +180,6 @@ public function checkInTraitDefinitionContext(ClassReflection $reflection): arra continue; } - if (!$this->absentTypeChecks) { - continue; - } - if (!$this->checkMissingTypehints) { continue; } diff --git a/src/Rules/Classes/MixinCheck.php b/src/Rules/Classes/MixinCheck.php index 3ce9535164..cff3184a6f 100644 --- a/src/Rules/Classes/MixinCheck.php +++ b/src/Rules/Classes/MixinCheck.php @@ -26,7 +26,6 @@ public function __construct( private MissingTypehintCheck $missingTypehintCheck, private UnresolvableTypeHelper $unresolvableTypeHelper, private bool $checkClassCaseSensitivity, - private bool $absentTypeChecks, private bool $checkMissingTypehints, ) { @@ -64,10 +63,6 @@ public function checkInTraitDefinitionContext(ClassReflection $classReflection): continue; } - if (!$this->absentTypeChecks) { - continue; - } - if (!$this->checkMissingTypehints) { continue; } diff --git a/src/Rules/Classes/UnusedConstructorParametersRule.php b/src/Rules/Classes/UnusedConstructorParametersRule.php index e42a60d5f7..8b38392470 100644 --- a/src/Rules/Classes/UnusedConstructorParametersRule.php +++ b/src/Rules/Classes/UnusedConstructorParametersRule.php @@ -15,7 +15,6 @@ use function array_map; use function array_values; use function count; -use function is_string; use function sprintf; use function strtolower; @@ -56,11 +55,11 @@ public function processNode(Node $node, Scope $scope): array return $this->check->getUnusedParameters( $scope, - array_map(static function (Param $parameter): string { - if (!$parameter->var instanceof Variable || !is_string($parameter->var->name)) { + array_map(static function (Param $parameter): Variable { + if (!$parameter->var instanceof Variable) { throw new ShouldNotHappenException(); } - return $parameter->var->name; + return $parameter->var; }, array_values(array_filter($originalNode->params, static fn (Param $parameter): bool => $parameter->flags === 0))), $originalNode->stmts, $message, diff --git a/src/Rules/Comparison/BooleanAndConstantConditionRule.php b/src/Rules/Comparison/BooleanAndConstantConditionRule.php index 5c05e8ac09..013e6b4b81 100644 --- a/src/Rules/Comparison/BooleanAndConstantConditionRule.php +++ b/src/Rules/Comparison/BooleanAndConstantConditionRule.php @@ -21,7 +21,6 @@ final class BooleanAndConstantConditionRule implements Rule public function __construct( private ConstantConditionRuleHelper $helper, private bool $treatPhpDocTypesAsCertain, - private bool $bleedingEdge, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, ) @@ -40,7 +39,7 @@ public function processNode( { $errors = []; $originalNode = $node->getOriginalNode(); - $nodeText = $this->bleedingEdge ? $originalNode->getOperatorSigil() : '&&'; + $nodeText = $originalNode->getOperatorSigil(); $leftType = $this->helper->getBooleanType($scope, $originalNode->left); $identifierType = $originalNode instanceof Node\Expr\BinaryOp\BooleanAnd ? 'booleanAnd' : 'logicalAnd'; if ($leftType instanceof ConstantBooleanType) { diff --git a/src/Rules/Comparison/BooleanOrConstantConditionRule.php b/src/Rules/Comparison/BooleanOrConstantConditionRule.php index f728505cad..b991f45981 100644 --- a/src/Rules/Comparison/BooleanOrConstantConditionRule.php +++ b/src/Rules/Comparison/BooleanOrConstantConditionRule.php @@ -21,7 +21,6 @@ final class BooleanOrConstantConditionRule implements Rule public function __construct( private ConstantConditionRuleHelper $helper, private bool $treatPhpDocTypesAsCertain, - private bool $bleedingEdge, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, ) @@ -39,7 +38,7 @@ public function processNode( ): array { $originalNode = $node->getOriginalNode(); - $nodeText = $this->bleedingEdge ? $originalNode->getOperatorSigil() : '||'; + $nodeText = $originalNode->getOperatorSigil(); $messages = []; $leftType = $this->helper->getBooleanType($scope, $originalNode->left); $identifierType = $originalNode instanceof Node\Expr\BinaryOp\BooleanOr ? 'booleanOr' : 'logicalOr'; diff --git a/src/Rules/Comparison/ConstantConditionRuleHelper.php b/src/Rules/Comparison/ConstantConditionRuleHelper.php index 9271ef2782..36b2c569d8 100644 --- a/src/Rules/Comparison/ConstantConditionRuleHelper.php +++ b/src/Rules/Comparison/ConstantConditionRuleHelper.php @@ -14,28 +14,15 @@ final class ConstantConditionRuleHelper public function __construct( private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, private bool $treatPhpDocTypesAsCertain, - private bool $looseComparisonRuleEnabled, ) { } - public function shouldReportAlwaysTrueByDefault(Expr $expr): bool - { - return $expr instanceof Expr\BooleanNot - || $expr instanceof Expr\BinaryOp\BooleanOr - || $expr instanceof Expr\BinaryOp\BooleanAnd - || $expr instanceof Expr\Ternary - || $expr instanceof Expr\Isset_ - || $expr instanceof Expr\Empty_; - } - public function shouldSkip(Scope $scope, Expr $expr): bool { if ( - $this->looseComparisonRuleEnabled - && ($expr instanceof Expr\BinaryOp\Equal - || $expr instanceof Expr\BinaryOp\NotEqual - ) + $expr instanceof Expr\BinaryOp\Equal + || $expr instanceof Expr\BinaryOp\NotEqual ) { return true; } diff --git a/src/Rules/Comparison/ConstantLooseComparisonRule.php b/src/Rules/Comparison/ConstantLooseComparisonRule.php index d6fa6c6aac..09961335e7 100644 --- a/src/Rules/Comparison/ConstantLooseComparisonRule.php +++ b/src/Rules/Comparison/ConstantLooseComparisonRule.php @@ -18,7 +18,6 @@ final class ConstantLooseComparisonRule implements Rule { public function __construct( - private bool $checkAlwaysTrueLooseComparison, private bool $treatPhpDocTypesAsCertain, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, @@ -67,28 +66,26 @@ public function processNode(Node $node, Scope $scope): array $scope->getType($node->right)->describe(VerbosityLevel::value()), )))->identifier(sprintf('%s.alwaysFalse', $node instanceof Node\Expr\BinaryOp\Equal ? 'equal' : 'notEqual'))->build(), ]; - } elseif ($this->checkAlwaysTrueLooseComparison) { - $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); - if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { - return []; - } - - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( - 'Loose comparison using %s between %s and %s will always evaluate to true.', - $node->getOperatorSigil(), - $scope->getType($node->left)->describe(VerbosityLevel::value()), - $scope->getType($node->right)->describe(VerbosityLevel::value()), - ))); - if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); - } + } - $errorBuilder->identifier(sprintf('%s.alwaysTrue', $node instanceof Node\Expr\BinaryOp\Equal ? 'equal' : 'notEqual')); + $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); + if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { + return []; + } - return [$errorBuilder->build()]; + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Loose comparison using %s between %s and %s will always evaluate to true.', + $node->getOperatorSigil(), + $scope->getType($node->left)->describe(VerbosityLevel::value()), + $scope->getType($node->right)->describe(VerbosityLevel::value()), + ))); + if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } - return []; + $errorBuilder->identifier(sprintf('%s.alwaysTrue', $node instanceof Node\Expr\BinaryOp\Equal ? 'equal' : 'notEqual')); + + return [$errorBuilder->build()]; } } diff --git a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php index 9c270afa44..0de2772219 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; @@ -48,7 +48,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/ImpossibleCheckTypeFunctionCallRule.php b/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php index 9033aa3865..690307e6fc 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeFunctionCallRule.php @@ -18,7 +18,6 @@ final class ImpossibleCheckTypeFunctionCallRule implements Rule public function __construct( private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, - private bool $checkAlwaysTrueCheckTypeFunctionCall, private bool $treatPhpDocTypesAsCertain, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, @@ -70,27 +69,25 @@ public function processNode(Node $node, Scope $scope): array $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), )))->identifier('function.impossibleType')->build(), ]; - } elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) { - $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); - if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { - return []; - } - - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( - 'Call to function %s()%s will always evaluate to true.', - $functionName, - $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), - ))); - if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); - } + } - $errorBuilder->identifier('function.alreadyNarrowedType'); + $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); + if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { + return []; + } - return [$errorBuilder->build()]; + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Call to function %s()%s will always evaluate to true.', + $functionName, + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + ))); + if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } - return []; + $errorBuilder->identifier('function.alreadyNarrowedType'); + + return [$errorBuilder->build()]; } } diff --git a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php index 39a4da06bd..48eea97d6f 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php @@ -8,11 +8,13 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; +use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\Scope; use PHPStan\Analyser\TypeSpecifier; use PHPStan\Analyser\TypeSpecifierContext; use PHPStan\Reflection\ParametersAcceptorSelector; use PHPStan\Reflection\ReflectionProvider; +use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; @@ -48,7 +50,6 @@ public function __construct( private TypeSpecifier $typeSpecifier, private array $universalObjectCratesClasses, private bool $treatPhpDocTypesAsCertain, - private bool $nullContextForVoidReturningFunctions, ) { } @@ -235,6 +236,10 @@ public function findSpecifiedType( } } + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + $typeSpecifierScope = $this->treatPhpDocTypesAsCertain ? $scope : $scope->doNotTreatPhpDocTypesAsCertain(); $specifiedTypes = $this->typeSpecifier->specifyTypesInCondition($typeSpecifierScope, $node, $this->determineContext($typeSpecifierScope, $node)); @@ -277,7 +282,7 @@ public function findSpecifiedType( /** @var Type $resultType */ $resultType = $sureType[1]; - $results[] = $resultType->isSuperTypeOf($argumentType); + $results[] = $resultType->isSuperTypeOf($argumentType)->result; } foreach ($sureNotTypes as $sureNotType) { @@ -295,7 +300,7 @@ public function findSpecifiedType( /** @var Type $resultType */ $resultType = $sureNotType[1]; - $results[] = $resultType->isSuperTypeOf($argumentType)->negate(); + $results[] = $resultType->isSuperTypeOf($argumentType)->negate()->result; } if (count($results) === 0) { @@ -369,16 +374,11 @@ public function doNotTreatPhpDocTypesAsCertain(): self $this->typeSpecifier, $this->universalObjectCratesClasses, false, - $this->nullContextForVoidReturningFunctions, ); } private function determineContext(Scope $scope, Expr $node): TypeSpecifierContext { - if (!$this->nullContextForVoidReturningFunctions) { - return TypeSpecifierContext::createTruthy(); - } - if ($node instanceof Expr\CallLike && $node->isFirstClassCallable()) { return TypeSpecifierContext::createTruthy(); } diff --git a/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php b/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php index 7bbcecefd7..4b79d98acb 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeMethodCallRule.php @@ -20,7 +20,6 @@ final class ImpossibleCheckTypeMethodCallRule implements Rule public function __construct( private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, - private bool $checkAlwaysTrueCheckTypeFunctionCall, private bool $treatPhpDocTypesAsCertain, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, @@ -70,29 +69,27 @@ public function processNode(Node $node, Scope $scope): array $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), )))->identifier('method.impossibleType')->build(), ]; - } elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) { - $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); - if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { - return []; - } - - $method = $this->getMethod($node->var, $node->name->name, $scope); - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( - 'Call to method %s::%s()%s will always evaluate to true.', - $method->getDeclaringClass()->getDisplayName(), - $method->getName(), - $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), - ))); - if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); - } + } - $errorBuilder->identifier('method.alreadyNarrowedType'); + $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); + if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { + return []; + } - return [$errorBuilder->build()]; + $method = $this->getMethod($node->var, $node->name->name, $scope); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Call to method %s::%s()%s will always evaluate to true.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + ))); + if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } - return []; + $errorBuilder->identifier('method.alreadyNarrowedType'); + + return [$errorBuilder->build()]; } private function getMethod( diff --git a/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php b/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php index df4504cb0e..e4b3721538 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRule.php @@ -20,7 +20,6 @@ final class ImpossibleCheckTypeStaticMethodCallRule implements Rule public function __construct( private ImpossibleCheckTypeHelper $impossibleCheckTypeHelper, - private bool $checkAlwaysTrueCheckTypeFunctionCall, private bool $treatPhpDocTypesAsCertain, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, @@ -71,29 +70,27 @@ public function processNode(Node $node, Scope $scope): array $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), )))->identifier('staticMethod.impossibleType')->build(), ]; - } elseif ($this->checkAlwaysTrueCheckTypeFunctionCall) { - $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); - if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { - return []; - } - - $method = $this->getMethod($node->class, $node->name->name, $scope); - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( - 'Call to static method %s::%s()%s will always evaluate to true.', - $method->getDeclaringClass()->getDisplayName(), - $method->getName(), - $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), - ))); - if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); - } + } - $errorBuilder->identifier('staticMethod.alreadyNarrowedType'); + $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); + if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { + return []; + } - return [$errorBuilder->build()]; + $method = $this->getMethod($node->class, $node->name->name, $scope); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Call to static method %s::%s()%s will always evaluate to true.', + $method->getDeclaringClass()->getDisplayName(), + $method->getName(), + $this->impossibleCheckTypeHelper->getArgumentsDescription($scope, $node->getArgs()), + ))); + if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); } - return []; + $errorBuilder->identifier('staticMethod.alreadyNarrowedType'); + + return [$errorBuilder->build()]; } /** diff --git a/src/Rules/Comparison/MatchExpressionRule.php b/src/Rules/Comparison/MatchExpressionRule.php index 81cfb1f471..6edef9747b 100644 --- a/src/Rules/Comparison/MatchExpressionRule.php +++ b/src/Rules/Comparison/MatchExpressionRule.php @@ -27,8 +27,6 @@ final class MatchExpressionRule implements Rule public function __construct( private ConstantConditionRuleHelper $constantConditionRuleHelper, - private bool $checkAlwaysTrueStrictComparison, - private bool $disableUnreachable, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertain, ) @@ -54,12 +52,6 @@ public function processNode(Node $node, Scope $scope): array $nextArmIsDeadForNativeType || ($nextArmIsDeadForType && $this->treatPhpDocTypesAsCertain) ) { - if (!$this->disableUnreachable) { - $errors[] = RuleErrorBuilder::message('Match arm is unreachable because previous comparison is always true.') - ->identifier('match.unreachable') - ->line($arm->getLine()) - ->build(); - } continue; } $armConditions = $arm->getConditions(); @@ -105,25 +97,24 @@ public function processNode(Node $node, Scope $scope): array $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value()), ))->line($armLine)->identifier('match.alwaysFalse')->build(); - } else { - if ($this->checkAlwaysTrueStrictComparison) { - if ($i === $armsCount - 1 && !$this->reportAlwaysTrueInLastCondition) { - continue; - } - $errorBuilder = RuleErrorBuilder::message(sprintf( - 'Match arm comparison between %s and %s is always true.', - $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), - $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value()), - ))->line($armLine); - if ($i !== $armsCount - 1 && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); - } - - $errorBuilder->identifier('match.alwaysTrue'); - - $errors[] = $errorBuilder->build(); - } + continue; } + + if ($i === $armsCount - 1 && !$this->reportAlwaysTrueInLastCondition) { + continue; + } + $errorBuilder = RuleErrorBuilder::message(sprintf( + 'Match arm comparison between %s and %s is always true.', + $armConditionScope->getType($matchCondition)->describe(VerbosityLevel::value()), + $armConditionScope->getType($armCondition->getCondition())->describe(VerbosityLevel::value()), + ))->line($armLine); + if ($i !== $armsCount - 1 && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->tip('Remove remaining cases below this one and this error will disappear too.'); + } + + $errorBuilder->identifier('match.alwaysTrue'); + + $errors[] = $errorBuilder->build(); } } diff --git a/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php b/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php index d155be352a..9ba6ee4797 100644 --- a/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php +++ b/src/Rules/Comparison/StrictComparisonOfDifferentTypesRule.php @@ -3,11 +3,13 @@ namespace PHPStan\Rules\Comparison; use PhpParser\Node; +use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\RicherScopeGetTypeHelper; use PHPStan\Analyser\Scope; use PHPStan\Parser\LastConditionVisitor; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; +use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\VerbosityLevel; @@ -22,7 +24,6 @@ final class StrictComparisonOfDifferentTypesRule implements Rule public function __construct( private RicherScopeGetTypeHelper $richerScopeGetTypeHelper, - private bool $checkAlwaysTrueStrictComparison, private bool $treatPhpDocTypesAsCertain, private bool $reportAlwaysTrueInLastCondition, private bool $treatPhpDocTypesAsCertainTip, @@ -37,6 +38,10 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } + if ($node instanceof Node\Expr\BinaryOp\Identical) { $nodeTypeResult = $this->richerScopeGetTypeHelper->getIdenticalResult($this->treatPhpDocTypesAsCertain ? $scope : $scope->doNotTreatPhpDocTypesAsCertain(), $node); } elseif ($node instanceof Node\Expr\BinaryOp\NotIdentical) { @@ -109,38 +114,36 @@ public function processNode(Node $node, Scope $scope): array $rightType->describe($verbosity), )))->identifier(sprintf('%s.alwaysFalse', $node instanceof Node\Expr\BinaryOp\Identical ? 'identical' : 'notIdentical'))->build(), ]; - } elseif ($this->checkAlwaysTrueStrictComparison) { - $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); - if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { - return []; - } - - $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( - 'Strict comparison using %s between %s and %s will always evaluate to true.', - $node->getOperatorSigil(), - $leftType->describe($verbosity), - $rightType->describe($verbosity), - ))); - if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { - $errorBuilder->addTip('Remove remaining cases below this one and this error will disappear too.'); - } + } - if ( - $leftType->isEnum()->yes() - && $rightType->isEnum()->yes() - && $node->getAttribute(LastConditionVisitor::ATTRIBUTE_IS_MATCH_NAME, false) !== true - ) { - $errorBuilder->addTip('Use match expression instead. PHPStan will report unhandled enum cases.'); - } + $isLast = $node->getAttribute(LastConditionVisitor::ATTRIBUTE_NAME); + if ($isLast === true && !$this->reportAlwaysTrueInLastCondition) { + return []; + } - $errorBuilder->identifier(sprintf('%s.alwaysTrue', $node instanceof Node\Expr\BinaryOp\Identical ? 'identical' : 'notIdentical')); + $errorBuilder = $addTip(RuleErrorBuilder::message(sprintf( + 'Strict comparison using %s between %s and %s will always evaluate to true.', + $node->getOperatorSigil(), + $leftType->describe($verbosity), + $rightType->describe($verbosity), + ))); + if ($isLast === false && !$this->reportAlwaysTrueInLastCondition) { + $errorBuilder->addTip('Remove remaining cases below this one and this error will disappear too.'); + } - return [ - $errorBuilder->build(), - ]; + if ( + $leftType->isEnum()->yes() + && $rightType->isEnum()->yes() + && $node->getAttribute(LastConditionVisitor::ATTRIBUTE_IS_MATCH_NAME, false) !== true + ) { + $errorBuilder->addTip('Use match expression instead. PHPStan will report unhandled enum cases.'); } - return []; + $errorBuilder->identifier(sprintf('%s.alwaysTrue', $node instanceof Node\Expr\BinaryOp\Identical ? 'identical' : 'notIdentical')); + + return [ + $errorBuilder->build(), + ]; } } diff --git a/src/Rules/Comparison/UnreachableIfBranchesRule.php b/src/Rules/Comparison/UnreachableIfBranchesRule.php deleted file mode 100644 index 5d6b001e88..0000000000 --- a/src/Rules/Comparison/UnreachableIfBranchesRule.php +++ /dev/null @@ -1,84 +0,0 @@ - - */ -final class UnreachableIfBranchesRule implements Rule -{ - - public function __construct( - private ConstantConditionRuleHelper $helper, - private bool $treatPhpDocTypesAsCertain, - private bool $disable, - private bool $treatPhpDocTypesAsCertainTip, - ) - { - } - - public function getNodeType(): string - { - return Node\Stmt\If_::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if ($this->disable) { - return []; - } - - $errors = []; - $condition = $node->cond; - $conditionType = $this->treatPhpDocTypesAsCertain ? $scope->getType($condition) : $scope->getNativeType($condition); - $conditionBooleanType = $conditionType->toBoolean(); - $nextBranchIsDead = $conditionBooleanType->isTrue()->yes() && $this->helper->shouldSkip($scope, $node->cond) && !$this->helper->shouldReportAlwaysTrueByDefault($node->cond); - - $addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, &$condition): RuleErrorBuilder { - if (!$this->treatPhpDocTypesAsCertain) { - return $ruleErrorBuilder; - } - - $booleanNativeType = $scope->getNativeType($condition)->toBoolean(); - if ($booleanNativeType instanceof ConstantBooleanType) { - return $ruleErrorBuilder; - } - if (!$this->treatPhpDocTypesAsCertainTip) { - return $ruleErrorBuilder; - } - - return $ruleErrorBuilder->treatPhpDocTypesAsCertainTip(); - }; - - foreach ($node->elseifs as $elseif) { - if ($nextBranchIsDead) { - $errors[] = $addTip(RuleErrorBuilder::message('Elseif branch is unreachable because previous condition is always true.')) - ->identifier('elseif.unreachable') - ->line($elseif->getStartLine()) - ->build(); - continue; - } - - $condition = $elseif->cond; - $conditionType = $this->treatPhpDocTypesAsCertain ? $scope->getType($condition) : $scope->getNativeType($condition); - $conditionBooleanType = $conditionType->toBoolean(); - $nextBranchIsDead = $conditionBooleanType->isTrue()->yes() && $this->helper->shouldSkip($scope, $elseif->cond) && !$this->helper->shouldReportAlwaysTrueByDefault($elseif->cond); - } - - if ($node->else !== null && $nextBranchIsDead) { - $errors[] = $addTip(RuleErrorBuilder::message('Else branch is unreachable because previous condition is always true.')) - ->identifier('else.unreachable') - ->line($node->else->getStartLine()) - ->build(); - } - - return $errors; - } - -} diff --git a/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php b/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php deleted file mode 100644 index 63ea467ce4..0000000000 --- a/src/Rules/Comparison/UnreachableTernaryElseBranchRule.php +++ /dev/null @@ -1,70 +0,0 @@ - - */ -final class UnreachableTernaryElseBranchRule implements Rule -{ - - public function __construct( - private ConstantConditionRuleHelper $helper, - private bool $treatPhpDocTypesAsCertain, - private bool $disable, - private bool $treatPhpDocTypesAsCertainTip, - ) - { - } - - public function getNodeType(): string - { - return Node\Expr\Ternary::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if ($this->disable) { - return []; - } - - $conditionType = $this->treatPhpDocTypesAsCertain ? $scope->getType($node->cond) : $scope->getNativeType($node->cond); - $conditionBooleanType = $conditionType->toBoolean(); - if ( - $conditionBooleanType->isTrue()->yes() - && $this->helper->shouldSkip($scope, $node->cond) - && !$this->helper->shouldReportAlwaysTrueByDefault($node->cond) - ) { - $addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, $node): RuleErrorBuilder { - if (!$this->treatPhpDocTypesAsCertain) { - return $ruleErrorBuilder; - } - - $booleanNativeType = $scope->getNativeType($node->cond); - if ($booleanNativeType instanceof ConstantBooleanType) { - return $ruleErrorBuilder; - } - if (!$this->treatPhpDocTypesAsCertainTip) { - return $ruleErrorBuilder; - } - - return $ruleErrorBuilder->treatPhpDocTypesAsCertainTip(); - }; - return [ - $addTip(RuleErrorBuilder::message('Else branch is unreachable because ternary operator condition is always true.')) - ->identifier('ternary.elseUnreachable') - ->line($node->else->getStartLine()) - ->build(), - ]; - } - - return []; - } - -} diff --git a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php index 74b46b3d69..8f6a1e3cf0 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; @@ -47,7 +47,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/Constants/AlwaysUsedClassConstantsExtension.php b/src/Rules/Constants/AlwaysUsedClassConstantsExtension.php index 4e3bdcc92d..977bac234b 100644 --- a/src/Rules/Constants/AlwaysUsedClassConstantsExtension.php +++ b/src/Rules/Constants/AlwaysUsedClassConstantsExtension.php @@ -2,7 +2,7 @@ namespace PHPStan\Rules\Constants; -use PHPStan\Reflection\ConstantReflection; +use PHPStan\Reflection\ClassConstantReflection; /** * This is the extension interface to implement if you want to describe @@ -25,6 +25,6 @@ interface AlwaysUsedClassConstantsExtension { - public function isAlwaysUsed(ConstantReflection $constant): bool; + public function isAlwaysUsed(ClassConstantReflection $constant): bool; } diff --git a/src/Rules/Constants/OverridingConstantRule.php b/src/Rules/Constants/OverridingConstantRule.php index ca1a822f99..2b3fa162d1 100644 --- a/src/Rules/Constants/OverridingConstantRule.php +++ b/src/Rules/Constants/OverridingConstantRule.php @@ -6,7 +6,6 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -53,7 +52,7 @@ public function processNode(Node $node, Scope $scope): array private function processSingleConstant(ClassReflection $classReflection, string $constantName): array { $prototype = $this->findPrototype($classReflection, $constantName); - if (!$prototype instanceof ClassConstantReflection) { + if ($prototype === null) { return []; } @@ -145,7 +144,7 @@ private function processSingleConstant(ClassReflection $classReflection, string return $errors; } - private function findPrototype(ClassReflection $classReflection, string $constantName): ?ConstantReflection + private function findPrototype(ClassReflection $classReflection, string $constantName): ?ClassConstantReflection { foreach ($classReflection->getImmediateInterfaces() as $immediateInterface) { if ($immediateInterface->hasConstant($constantName)) { diff --git a/src/Rules/Constants/ValueAssignedToClassConstantRule.php b/src/Rules/Constants/ValueAssignedToClassConstantRule.php index afdbf2c5e7..728b5a039f 100644 --- a/src/Rules/Constants/ValueAssignedToClassConstantRule.php +++ b/src/Rules/Constants/ValueAssignedToClassConstantRule.php @@ -63,7 +63,7 @@ private function processSingleConstant(ClassReflection $classReflection, string return []; } - $accepts = $nativeType->acceptsWithReason($valueExprType, true); + $accepts = $nativeType->accepts($valueExprType, true); if ($accepts->yes()) { return []; } @@ -107,7 +107,7 @@ private function processSingleConstant(ClassReflection $classReflection, string } $type = $constantReflection->getValueType(); - $accepts = $type->acceptsWithReason($valueExprType, true); + $accepts = $type->accepts($valueExprType, true); if ($accepts->yes()) { return []; } diff --git a/src/Rules/DeadCode/BetterNoopRule.php b/src/Rules/DeadCode/BetterNoopRule.php deleted file mode 100644 index 2e246941b7..0000000000 --- a/src/Rules/DeadCode/BetterNoopRule.php +++ /dev/null @@ -1,138 +0,0 @@ - - */ -final class BetterNoopRule implements Rule -{ - - public function __construct(private ExprPrinter $exprPrinter) - { - } - - public function getNodeType(): string - { - return NoopExpressionNode::class; - } - - public function processNode(Node $node, Scope $scope): array - { - $expr = $node->getOriginalExpr(); - if ($expr instanceof Node\Expr\BinaryOp\LogicalXor) { - return [ - RuleErrorBuilder::message( - 'Unused result of "xor" operator.', - )->line($expr->getStartLine()) - ->tip('This operator has unexpected precedence, try disambiguating the logic with parentheses ().') - ->identifier('logicalXor.resultUnused') - ->build(), - ]; - } - - if ($expr instanceof Node\Expr\BinaryOp\LogicalAnd || $expr instanceof Node\Expr\BinaryOp\LogicalOr) { - $identifierType = $expr instanceof Node\Expr\BinaryOp\LogicalAnd ? 'logicalAnd' : 'logicalOr'; - - return [ - RuleErrorBuilder::message(sprintf( - 'Unused result of "%s" operator.', - $expr->getOperatorSigil(), - ))->line($expr->getStartLine()) - ->tip('This operator has unexpected precedence, try disambiguating the logic with parentheses ().') - ->identifier(sprintf('%s.resultUnused', $identifierType)) - ->build(), - ]; - } - - if ($node->hasAssign()) { - return []; - } - - if ($expr instanceof Node\Expr\BinaryOp\BooleanAnd || $expr instanceof Node\Expr\BinaryOp\BooleanOr) { - $identifierType = $expr instanceof Node\Expr\BinaryOp\BooleanAnd ? 'booleanAnd' : 'booleanOr'; - - return [ - RuleErrorBuilder::message(sprintf( - 'Unused result of "%s" operator.', - $expr->getOperatorSigil(), - ))->line($expr->getStartLine()) - ->identifier(sprintf('%s.resultUnused', $identifierType)) - ->build(), - ]; - } - - if ($expr instanceof Node\Expr\Ternary) { - return [ - RuleErrorBuilder::message('Unused result of ternary operator.') - ->line($expr->getStartLine()) - ->identifier('ternary.resultUnused') - ->build(), - ]; - } - - if ($expr instanceof Node\Expr\FuncCall) { - if ($expr->name instanceof Node\Name) { - // handled by CallToFunctionStatementWithoutSideEffectsRule - return []; - } - - $nameType = $scope->getType($expr->name); - if (!$nameType->isCallable()->yes()) { - return []; - } - } - - if ($expr instanceof Node\Expr\New_ && $expr->class instanceof Node\Name) { - // handled by CallToConstructorStatementWithoutSideEffectsRule - return []; - } - - if ( - $expr instanceof Node\Expr\NullsafeMethodCall - || $expr instanceof Node\Expr\MethodCall - || $expr instanceof Node\Expr\StaticCall - ) { - // handled by *WithoutSideEffectsRule rules - return []; - } - - if ( - $expr instanceof Node\Expr\Assign - || $expr instanceof Node\Expr\AssignOp - || $expr instanceof Node\Expr\AssignRef - ) { - return []; - } - - if ($expr instanceof Node\Expr\Closure) { - return []; - } - - $exprString = $this->exprPrinter->printExpr($expr); - $exprStringLines = preg_split('~\R~', $exprString, 2); - if ($exprStringLines !== false && count($exprStringLines) > 1) { - $exprString = $exprStringLines[0] . '…'; - } - - return [ - RuleErrorBuilder::message(sprintf( - 'Expression "%s" on a separate line does not do anything.', - $exprString, - ))->line($expr->getStartLine()) - ->identifier('expr.resultUnused') - ->build(), - ]; - } - -} diff --git a/src/Rules/DeadCode/NoopRule.php b/src/Rules/DeadCode/NoopRule.php index ff0d6eb8e7..abc5200a71 100644 --- a/src/Rules/DeadCode/NoopRule.php +++ b/src/Rules/DeadCode/NoopRule.php @@ -4,70 +4,135 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Node\NoopExpressionNode; use PHPStan\Node\Printer\ExprPrinter; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; +use function count; +use function preg_split; use function sprintf; /** - * @deprecated Replaced by PHPStan\Rules\DeadCode\BetterNoopRule - * @implements Rule + * @implements Rule */ final class NoopRule implements Rule { - public function __construct(private ExprPrinter $exprPrinter, private bool $better) + public function __construct(private ExprPrinter $exprPrinter) { } public function getNodeType(): string { - return Node\Stmt\Expression::class; + return NoopExpressionNode::class; } public function processNode(Node $node, Scope $scope): array { - if ($this->better) { - // disabled in bleeding edge + $expr = $node->getOriginalExpr(); + if ($expr instanceof Node\Expr\BinaryOp\LogicalXor) { + return [ + RuleErrorBuilder::message( + 'Unused result of "xor" operator.', + )->line($expr->getStartLine()) + ->tip('This operator has unexpected precedence, try disambiguating the logic with parentheses ().') + ->identifier('logicalXor.resultUnused') + ->build(), + ]; + } + + if ($expr instanceof Node\Expr\BinaryOp\LogicalAnd || $expr instanceof Node\Expr\BinaryOp\LogicalOr) { + $identifierType = $expr instanceof Node\Expr\BinaryOp\LogicalAnd ? 'logicalAnd' : 'logicalOr'; + + return [ + RuleErrorBuilder::message(sprintf( + 'Unused result of "%s" operator.', + $expr->getOperatorSigil(), + ))->line($expr->getStartLine()) + ->tip('This operator has unexpected precedence, try disambiguating the logic with parentheses ().') + ->identifier(sprintf('%s.resultUnused', $identifierType)) + ->build(), + ]; + } + + if ($node->hasAssign()) { + return []; + } + + if ($expr instanceof Node\Expr\BinaryOp\BooleanAnd || $expr instanceof Node\Expr\BinaryOp\BooleanOr) { + $identifierType = $expr instanceof Node\Expr\BinaryOp\BooleanAnd ? 'booleanAnd' : 'booleanOr'; + + return [ + RuleErrorBuilder::message(sprintf( + 'Unused result of "%s" operator.', + $expr->getOperatorSigil(), + ))->line($expr->getStartLine()) + ->identifier(sprintf('%s.resultUnused', $identifierType)) + ->build(), + ]; + } + + if ($expr instanceof Node\Expr\Ternary) { + return [ + RuleErrorBuilder::message('Unused result of ternary operator.') + ->line($expr->getStartLine()) + ->identifier('ternary.resultUnused') + ->build(), + ]; + } + + if ($expr instanceof Node\Expr\FuncCall) { + if ($expr->name instanceof Node\Name) { + // handled by CallToFunctionStatementWithoutSideEffectsRule + return []; + } + + $nameType = $scope->getType($expr->name); + if (!$nameType->isCallable()->yes()) { + return []; + } + } + + if ($expr instanceof Node\Expr\New_ && $expr->class instanceof Node\Name) { + // handled by CallToConstructorStatementWithoutSideEffectsRule + return []; + } + + if ( + $expr instanceof Node\Expr\NullsafeMethodCall + || $expr instanceof Node\Expr\MethodCall + || $expr instanceof Node\Expr\StaticCall + ) { + // handled by *WithoutSideEffectsRule rules 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 instanceof Node\Expr\Assign + || $expr instanceof Node\Expr\AssignOp + || $expr instanceof Node\Expr\AssignRef ) { - $expr = $expr->expr; + return []; } - if (!$this->isNoopExpr($expr)) { + if ($expr instanceof Node\Expr\Closure) { return []; } + $exprString = $this->exprPrinter->printExpr($expr); + $exprStringLines = preg_split('~\R~', $exprString, 2); + if ($exprStringLines !== false && count($exprStringLines) > 1) { + $exprString = $exprStringLines[0] . '…'; + } + return [ RuleErrorBuilder::message(sprintf( 'Expression "%s" on a separate line does not do anything.', - $this->exprPrinter->printExpr($originalExpr), + $exprString, ))->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/src/Rules/DirectRegistry.php b/src/Rules/DirectRegistry.php index 13c8bfe3a2..8003bef42a 100644 --- a/src/Rules/DirectRegistry.php +++ b/src/Rules/DirectRegistry.php @@ -6,10 +6,7 @@ use function class_implements; use function class_parents; -/** - * @final - */ -class DirectRegistry implements Registry +final class DirectRegistry implements Registry { /** @var Rule[][] */ diff --git a/src/Rules/Exceptions/DefaultExceptionTypeResolver.php b/src/Rules/Exceptions/DefaultExceptionTypeResolver.php index fd6866bc72..75f020fe77 100644 --- a/src/Rules/Exceptions/DefaultExceptionTypeResolver.php +++ b/src/Rules/Exceptions/DefaultExceptionTypeResolver.php @@ -9,9 +9,8 @@ /** * @api - * @final */ -class DefaultExceptionTypeResolver implements ExceptionTypeResolver +final class DefaultExceptionTypeResolver implements ExceptionTypeResolver { /** diff --git a/src/Rules/Exceptions/NoncapturingCatchRule.php b/src/Rules/Exceptions/NoncapturingCatchRule.php index 499b62e154..a4d91a9ba2 100644 --- a/src/Rules/Exceptions/NoncapturingCatchRule.php +++ b/src/Rules/Exceptions/NoncapturingCatchRule.php @@ -4,7 +4,6 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -14,10 +13,6 @@ final class NoncapturingCatchRule implements Rule { - public function __construct(private PhpVersion $phpVersion) - { - } - public function getNodeType(): string { return Node\Stmt\Catch_::class; @@ -28,7 +23,7 @@ public function getNodeType(): string */ public function processNode(Node $node, Scope $scope): array { - if ($this->phpVersion->supportsNoncapturingCatches()) { + if ($scope->getPhpVersion()->supportsNoncapturingCatches()->yes()) { return []; } 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/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') diff --git a/src/Rules/Exceptions/TooWideThrowTypeCheck.php b/src/Rules/Exceptions/TooWideThrowTypeCheck.php index 830d0f9a62..5c5e33c803 100644 --- a/src/Rules/Exceptions/TooWideThrowTypeCheck.php +++ b/src/Rules/Exceptions/TooWideThrowTypeCheck.php @@ -13,6 +13,10 @@ final class TooWideThrowTypeCheck { + public function __construct(private bool $implicitThrows) + { + } + /** * @param ThrowPoint[] $throwPoints * @return string[] @@ -23,8 +27,8 @@ public function check(Type $throwType, array $throwPoints): array return []; } - $throwPointType = TypeCombinator::union(...array_map(static function (ThrowPoint $throwPoint): Type { - if (!$throwPoint->isExplicit()) { + $throwPointType = TypeCombinator::union(...array_map(function (ThrowPoint $throwPoint): Type { + if (!$this->implicitThrows && !$throwPoint->isExplicit()) { return new NeverType(); } diff --git a/src/Rules/FoundTypeResult.php b/src/Rules/FoundTypeResult.php index 4e89ed8ec5..61702c6194 100644 --- a/src/Rules/FoundTypeResult.php +++ b/src/Rules/FoundTypeResult.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class FoundTypeResult +final class FoundTypeResult { /** diff --git a/src/Rules/FunctionCallParametersCheck.php b/src/Rules/FunctionCallParametersCheck.php index 69c8467515..50371ab23c 100644 --- a/src/Rules/FunctionCallParametersCheck.php +++ b/src/Rules/FunctionCallParametersCheck.php @@ -6,14 +6,14 @@ use PhpParser\Node\Expr; use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\Scope; -use PHPStan\Php\PhpVersion; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\ParameterReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\ResolvedFunctionVariant; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\ConditionalType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\ErrorType; @@ -29,6 +29,8 @@ use function array_key_exists; use function count; use function implode; +use function in_array; +use function is_int; use function is_string; use function max; use function sprintf; @@ -39,21 +41,17 @@ final class FunctionCallParametersCheck public function __construct( private RuleLevelHelper $ruleLevelHelper, private NullsafeCheck $nullsafeCheck, - private PhpVersion $phpVersion, private UnresolvableTypeHelper $unresolvableTypeHelper, private PropertyReflectionFinder $propertyReflectionFinder, private bool $checkArgumentTypes, private bool $checkArgumentsPassedByReference, private bool $checkExtraArguments, private bool $checkMissingTypehints, - private bool $checkUnresolvableParameterTypes, ) { } /** - * @param Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall - * @param array{0: string, 1: string, 2: string, 3: string, 4: string, 5: string, 6: string, 7: string, 8: string, 9: string, 10: string, 11: string, 12: string, 13?: string, 14?: string} $messages * @param 'attribute'|'callable'|'method'|'staticMethod'|'function'|'new' $nodeType * @return list */ @@ -61,10 +59,24 @@ public function check( ParametersAcceptor $parametersAcceptor, Scope $scope, bool $isBuiltin, - $funcCall, - array $messages, - string $nodeType = 'function', - bool $acceptsNamedArguments = true, + Node\Expr\FuncCall|Node\Expr\MethodCall|Node\Expr\StaticCall|Node\Expr\New_ $funcCall, + string $nodeType, + TrinaryLogic $acceptsNamedArguments, + string $singleInsufficientParameterMessage, + string $pluralInsufficientParametersMessage, + string $singleInsufficientParameterInVariadicFunctionMessage, + string $pluralInsufficientParametersInVariadicFunctionMessage, + string $singleInsufficientParameterWithOptionalParametersMessage, + string $pluralInsufficientParametersWithOptionalParametersMessage, + string $wrongArgumentTypeMessage, + string $voidReturnTypeUsed, + string $parameterPassedByReferenceMessage, + string $unresolvableTemplateTypeMessage, + string $missingParameterMessage, + string $unknownParameterMessage, + string $unresolvableReturnTypeMessage, + string $unresolvableParameterTypeMessage, + string $namedArgumentMessage, ): array { $functionParametersMinCount = 0; @@ -115,30 +127,32 @@ public function check( $type = $scope->getType($arg->value); $arrays = $type->getConstantArrays(); if (count($arrays) > 0) { - $minKeys = null; + $maxKeys = null; foreach ($arrays as $array) { $countType = $array->getArraySize(); if ($countType instanceof ConstantIntegerType) { $keysCount = $countType->getValue(); } elseif ($countType instanceof IntegerRangeType) { - $keysCount = $countType->getMin(); + $keysCount = $countType->getMax(); if ($keysCount === null) { throw new ShouldNotHappenException(); } } else { throw new ShouldNotHappenException(); } - if ($minKeys !== null && $keysCount >= $minKeys) { + if ($maxKeys !== null && $keysCount >= $maxKeys) { continue; } - $minKeys = $keysCount; + $maxKeys = $keysCount; } - for ($j = 0; $j < $minKeys; $j++) { + for ($j = 0; $j < $maxKeys; $j++) { $types = []; $commonKey = null; + $isOptionalKey = false; foreach ($arrays as $constantArray) { + $isOptionalKey = in_array($j, $constantArray->getOptionalKeys(), true); $types[] = $constantArray->getValueTypes()[$j]; $keyType = $constantArray->getKeyTypes()[$j]; if ($commonKey === null) { @@ -152,6 +166,10 @@ public function check( $keyArgumentName = $commonKey; $hasNamedArguments = true; } + if ($isOptionalKey) { + continue; + } + $arguments[] = [ $arg->value, TypeCombinator::union(...$types), @@ -181,7 +199,7 @@ public function check( ]; } - if ($hasNamedArguments && !$this->phpVersion->supportsNamedArguments() && !(bool) $funcCall->getAttribute('isAttribute', false)) { + if ($hasNamedArguments && !$scope->getPhpVersion()->supportsNamedArguments()->yes() && !(bool) $funcCall->getAttribute('isAttribute', false)) { $errors[] = RuleErrorBuilder::message('Named arguments are supported only on PHP 8.0 and later.') ->identifier('argument.namedNotSupported') ->line($funcCall->getStartLine()) @@ -204,7 +222,7 @@ public function check( ) { if ($functionParametersMinCount === $functionParametersMaxCount) { $errors[] = RuleErrorBuilder::message(sprintf( - $invokedParametersCount === 1 ? $messages[0] : $messages[1], + $invokedParametersCount === 1 ? $singleInsufficientParameterMessage : $pluralInsufficientParametersMessage, $invokedParametersCount, $functionParametersMinCount, )) @@ -213,7 +231,7 @@ public function check( ->build(); } elseif ($functionParametersMaxCount === -1 && $invokedParametersCount < $functionParametersMinCount) { $errors[] = RuleErrorBuilder::message(sprintf( - $invokedParametersCount === 1 ? $messages[2] : $messages[3], + $invokedParametersCount === 1 ? $singleInsufficientParameterInVariadicFunctionMessage : $pluralInsufficientParametersInVariadicFunctionMessage, $invokedParametersCount, $functionParametersMinCount, )) @@ -222,7 +240,7 @@ public function check( ->build(); } elseif ($functionParametersMaxCount !== -1) { $errors[] = RuleErrorBuilder::message(sprintf( - $invokedParametersCount === 1 ? $messages[4] : $messages[5], + $invokedParametersCount === 1 ? $singleInsufficientParameterWithOptionalParametersMessage : $pluralInsufficientParametersWithOptionalParametersMessage, $invokedParametersCount, $functionParametersMinCount, $functionParametersMaxCount, @@ -239,13 +257,13 @@ public function check( && !$scope->isInFirstLevelStatement() && $scope->getKeepVoidType($funcCall)->isVoid()->yes() ) { - $errors[] = RuleErrorBuilder::message($messages[7]) + $errors[] = RuleErrorBuilder::message($voidReturnTypeUsed) ->identifier(sprintf('%s.void', $nodeType)) ->line($funcCall->getStartLine()) ->build(); } - [$addedErrors, $argumentsWithParameters] = $this->processArguments($parametersAcceptor, $funcCall->getStartLine(), $isBuiltin, $arguments, $hasNamedArguments, $messages[10], $messages[11]); + [$addedErrors, $argumentsWithParameters] = $this->processArguments($parametersAcceptor, $funcCall->getStartLine(), $isBuiltin, $arguments, $hasNamedArguments, $missingParameterMessage, $unknownParameterMessage); foreach ($addedErrors as $error) { $errors[] = $error; } @@ -290,9 +308,9 @@ public function check( } } - if (!$acceptsNamedArguments && $this->checkUnresolvableParameterTypes && isset($messages[14])) { + if (!$acceptsNamedArguments->yes()) { if ($argumentName !== null) { - $errors[] = RuleErrorBuilder::message(sprintf($messages[14], sprintf('named argument $%s', $argumentName))) + $errors[] = RuleErrorBuilder::message(sprintf($namedArgumentMessage, sprintf('named argument $%s', $argumentName))) ->identifier('argument.named') ->line($argumentLine) ->build(); @@ -300,7 +318,7 @@ public function check( $unpackedArrayType = $scope->getType($argumentValue); $hasStringKey = $unpackedArrayType->getIterableKeyType()->isString(); if (!$hasStringKey->no()) { - $errors[] = RuleErrorBuilder::message(sprintf($messages[14], sprintf('unpacked array with %s', $hasStringKey->yes() ? 'string key' : 'possibly string key'))) + $errors[] = RuleErrorBuilder::message(sprintf($namedArgumentMessage, sprintf('unpacked array with %s', $hasStringKey->yes() ? 'string key' : 'possibly string key'))) ->identifier('argument.named') ->line($argumentLine) ->build(); @@ -313,19 +331,15 @@ public function check( if ( !$parameter->passedByReference()->createsNewVariable() - || ( - !$isBuiltin - && $this->checkUnresolvableParameterTypes // bleeding edge only - && !$argumentValueType instanceof ErrorType - ) + || (!$isBuiltin && !$argumentValueType instanceof ErrorType) ) { - $accepts = $this->ruleLevelHelper->acceptsWithReason($parameterType, $argumentValueType, $scope->isDeclareStrictTypes()); + $accepts = $this->ruleLevelHelper->accepts($parameterType, $argumentValueType, $scope->isDeclareStrictTypes()); if (!$accepts->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($parameterType, $argumentValueType); $errors[] = RuleErrorBuilder::message(sprintf( - $messages[6], - $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), + $wrongArgumentTypeMessage, + $this->describeParameter($parameter, $argumentName ?? $i + 1), $parameterType->describe($verbosityLevel), $argumentValueType->describe($verbosityLevel), )) @@ -336,26 +350,25 @@ public function check( } } - if ($this->checkUnresolvableParameterTypes - && $originalParameter !== null - && isset($messages[13]) + if ( + $originalParameter !== null && !$this->unresolvableTypeHelper->containsUnresolvableType($originalParameter->getType()) && $this->unresolvableTypeHelper->containsUnresolvableType($parameterType) ) { $errors[] = RuleErrorBuilder::message(sprintf( - $messages[13], + $unresolvableParameterTypeMessage, $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), ))->identifier('argument.unresolvableType')->line($argumentLine)->build(); } if ( - $parameter instanceof ParameterReflectionWithPhpDocs + $parameter instanceof ExtendedParameterReflection && $parameter->getClosureThisType() !== null && ($argumentValue instanceof Expr\Closure || $argumentValue instanceof Expr\ArrowFunction) && $argumentValue->static ) { $errors[] = RuleErrorBuilder::message(sprintf( - $messages[6], + $wrongArgumentTypeMessage, $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), 'bindable closure', 'static closure', @@ -375,7 +388,7 @@ public function check( if ($this->nullsafeCheck->containsNullSafe($argumentValue)) { $errors[] = RuleErrorBuilder::message(sprintf( - $messages[8], + $parameterPassedByReferenceMessage, $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), )) ->identifier('argument.byRef') @@ -404,7 +417,7 @@ public function check( } $errors[] = RuleErrorBuilder::message(sprintf( - 'Parameter %s is passed by reference so it does not accept %s.', + '%s is passed by reference so it does not accept %s.', $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), $propertyDescription, ))->identifier('argument.byRef')->line($argumentLine)->build(); @@ -419,7 +432,7 @@ public function check( } $errors[] = RuleErrorBuilder::message(sprintf( - $messages[8], + $parameterPassedByReferenceMessage, $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), ))->identifier('argument.byRef')->line($argumentLine)->build(); } @@ -476,7 +489,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty continue; } - $errors[] = RuleErrorBuilder::message(sprintf($messages[9], $name)) + $errors[] = RuleErrorBuilder::message(sprintf($unresolvableTemplateTypeMessage, $name)) ->identifier('argument.templateType') ->line($funcCall->getStartLine()) ->tip('See: https://phpstan.org/blog/solving-phpstan-error-unable-to-resolve-template-type') @@ -488,7 +501,7 @@ static function (Type $type, callable $traverse) use (&$returnTemplateTypes): Ty !$this->unresolvableTypeHelper->containsUnresolvableType($originalParametersAcceptor->getReturnType()) && $this->unresolvableTypeHelper->containsUnresolvableType($parametersAcceptor->getReturnType()) ) { - $errors[] = RuleErrorBuilder::message($messages[12]) + $errors[] = RuleErrorBuilder::message($unresolvableReturnTypeMessage) ->identifier(sprintf('%s.unresolvableReturnType', $nodeType)) ->line($funcCall->getStartLine()) ->build(); @@ -620,11 +633,15 @@ private function processArguments( return [$errors, $newArguments]; } - private function describeParameter(ParameterReflection $parameter, ?int $position): string + private function describeParameter(ParameterReflection $parameter, int|string|null $positionOrNamed): string { $parts = []; - if ($position !== null) { - $parts[] = '#' . $position; + if (is_int($positionOrNamed)) { + $parts[] = 'Parameter #' . $positionOrNamed; + } elseif ($parameter->isVariadic() && is_string($positionOrNamed)) { + $parts[] = 'Named argument ' . $positionOrNamed . ' for variadic parameter'; + } else { + $parts[] = 'Parameter'; } $name = $parameter->getName(); diff --git a/src/Rules/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php index 327c0a7be4..6874582743 100644 --- a/src/Rules/FunctionDefinitionCheck.php +++ b/src/Rules/FunctionDefinitionCheck.php @@ -18,10 +18,10 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\Printer\NodeTypePrinter; use PHPStan\Php\PhpVersion; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\ParameterReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Reflection\ParametersAcceptor; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection; use PHPStan\Reflection\Php\PhpMethodFromParserNodeReflection; use PHPStan\Reflection\ReflectionProvider; @@ -54,7 +54,6 @@ public function __construct( private PhpVersion $phpVersion, private bool $checkClassCaseSensitivity, private bool $checkThisOnly, - private bool $absentTypeChecks, ) { } @@ -216,7 +215,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; @@ -268,7 +267,7 @@ public function checkClassMethod( ); $selfOutType = $methodReflection->getSelfOutType(); - if ($selfOutType !== null && $this->absentTypeChecks) { + if ($selfOutType !== null) { $selfOutTypeReferencedClasses = $selfOutType->getReferencedClasses(); foreach ($selfOutTypeReferencedClasses as $class) { @@ -369,7 +368,7 @@ private function checkParametersAcceptor( return $parameterNode; }; - if ($parameter instanceof ParameterReflectionWithPhpDocs) { + if ($parameter instanceof ExtendedParameterReflection) { $parameterVar = $parameterNodeCallback()->var; if (!$parameterVar instanceof Variable || !is_string($parameterVar->name)) { throw new ShouldNotHappenException(); @@ -631,7 +630,7 @@ private function getParameterNode( */ private function getParameterReferencedClasses(ParameterReflection $parameter): array { - if (!$parameter instanceof ParameterReflectionWithPhpDocs) { + if (!$parameter instanceof ExtendedParameterReflection) { return $parameter->getType()->getReferencedClasses(); } @@ -640,13 +639,11 @@ private function getParameterReferencedClasses(ParameterReflection $parameter): } $moreClasses = []; - if ($this->absentTypeChecks) { - if ($parameter->getOutType() !== null) { - $moreClasses = array_merge($moreClasses, $parameter->getOutType()->getReferencedClasses()); - } - if ($parameter->getClosureThisType() !== null) { - $moreClasses = array_merge($moreClasses, $parameter->getClosureThisType()->getReferencedClasses()); - } + if ($parameter->getOutType() !== null) { + $moreClasses = array_merge($moreClasses, $parameter->getOutType()->getReferencedClasses()); + } + if ($parameter->getClosureThisType() !== null) { + $moreClasses = array_merge($moreClasses, $parameter->getClosureThisType()->getReferencedClasses()); } return array_merge( @@ -661,7 +658,7 @@ private function getParameterReferencedClasses(ParameterReflection $parameter): */ private function getReturnTypeReferencedClasses(ParametersAcceptor $parametersAcceptor): array { - if (!$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs) { + if (!$parametersAcceptor instanceof ExtendedParametersAcceptor) { return $parametersAcceptor->getReturnType()->getReferencedClasses(); } @@ -706,18 +703,12 @@ private function checkImplicitlyNullableType( if ($type instanceof Identifier && strtolower($type->name) === 'mixed') { return null; } - if ($type instanceof Name && $type->toLowerString() === 'mixed') { - return null; - } if ($type instanceof UnionType) { foreach ($type->types as $innerType) { if ($innerType instanceof Identifier && strtolower($innerType->name) === 'null') { return null; } - if ($innerType instanceof Name && $innerType->toLowerString() === 'null') { - return null; - } } } diff --git a/src/Rules/FunctionReturnTypeCheck.php b/src/Rules/FunctionReturnTypeCheck.php index be2eb86b1a..994b3943f2 100644 --- a/src/Rules/FunctionReturnTypeCheck.php +++ b/src/Rules/FunctionReturnTypeCheck.php @@ -90,7 +90,7 @@ public function checkReturnType( ]; } - $accepts = $this->ruleLevelHelper->acceptsWithReason($returnType, $returnValueType, $scope->isDeclareStrictTypes()); + $accepts = $this->ruleLevelHelper->accepts($returnType, $returnValueType, $scope->isDeclareStrictTypes()); if (!$accepts->result) { return [ RuleErrorBuilder::message(sprintf( diff --git a/src/Rules/Functions/ArrayValuesRule.php b/src/Rules/Functions/ArrayValuesRule.php index 2b969a42aa..679bcb4d4a 100644 --- a/src/Rules/Functions/ArrayValuesRule.php +++ b/src/Rules/Functions/ArrayValuesRule.php @@ -10,7 +10,6 @@ use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Type\Accessory\AccessoryArrayListType; use PHPStan\Type\VerbosityLevel; use function count; use function sprintf; @@ -40,10 +39,6 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (AccessoryArrayListType::isListTypeEnabled() === false) { - return []; - } - if (!$this->reflectionProvider->hasFunction($node->name, $scope)) { return []; } diff --git a/src/Rules/Functions/ArrowFunctionAttributesRule.php b/src/Rules/Functions/ArrowFunctionAttributesRule.php index b849f968aa..67af9eb5e0 100644 --- a/src/Rules/Functions/ArrowFunctionAttributesRule.php +++ b/src/Rules/Functions/ArrowFunctionAttributesRule.php @@ -5,11 +5,12 @@ use Attribute; use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Node\InArrowFunctionNode; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\Rule; /** - * @implements Rule + * @implements Rule */ final class ArrowFunctionAttributesRule implements Rule { @@ -20,14 +21,14 @@ public function __construct(private AttributesCheck $attributesCheck) public function getNodeType(): string { - return Node\Expr\ArrowFunction::class; + return InArrowFunctionNode::class; } public function processNode(Node $node, Scope $scope): array { return $this->attributesCheck->check( $scope, - $node->attrGroups, + $node->getOriginalNode()->attrGroups, Attribute::TARGET_FUNCTION, 'function', ); diff --git a/src/Rules/Functions/CallCallablesRule.php b/src/Rules/Functions/CallCallablesRule.php index d8fb352e52..162894e266 100644 --- a/src/Rules/Functions/CallCallablesRule.php +++ b/src/Rules/Functions/CallCallablesRule.php @@ -12,6 +12,7 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; +use PHPStan\TrinaryLogic; use PHPStan\Type\ClosureType; use PHPStan\Type\ErrorType; use PHPStan\Type\Type; @@ -79,9 +80,9 @@ public function processNode( $parametersAcceptors = $type->getCallableParametersAcceptors($scope); $messages = []; - $acceptsNamedArguments = true; + $acceptsNamedArguments = TrinaryLogic::createYes(); foreach ($parametersAcceptors as $parametersAcceptor) { - $acceptsNamedArguments = $acceptsNamedArguments && $parametersAcceptor->acceptsNamedArguments(); + $acceptsNamedArguments = $acceptsNamedArguments->and($parametersAcceptor->acceptsNamedArguments()); } if ( @@ -117,25 +118,23 @@ public function processNode( $scope, false, $node, - [ - ucfirst($callableDescription) . ' invoked with %d parameter, %d required.', - ucfirst($callableDescription) . ' invoked with %d parameters, %d required.', - ucfirst($callableDescription) . ' invoked with %d parameter, at least %d required.', - ucfirst($callableDescription) . ' invoked with %d parameters, at least %d required.', - ucfirst($callableDescription) . ' invoked with %d parameter, %d-%d required.', - ucfirst($callableDescription) . ' invoked with %d parameters, %d-%d required.', - 'Parameter %s of ' . $callableDescription . ' expects %s, %s given.', - 'Result of ' . $callableDescription . ' (void) is used.', - 'Parameter %s of ' . $callableDescription . ' is passed by reference, so it expects variables only.', - 'Unable to resolve the template type %s in call to ' . $callableDescription, - 'Missing parameter $%s in call to ' . $callableDescription . '.', - 'Unknown parameter $%s in call to ' . $callableDescription . '.', - 'Return type of call to ' . $callableDescription . ' contains unresolvable type.', - 'Parameter %s of ' . $callableDescription . ' contains unresolvable type.', - ucfirst($callableDescription) . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'callable', $acceptsNamedArguments, + ucfirst($callableDescription) . ' invoked with %d parameter, %d required.', + ucfirst($callableDescription) . ' invoked with %d parameters, %d required.', + ucfirst($callableDescription) . ' invoked with %d parameter, at least %d required.', + ucfirst($callableDescription) . ' invoked with %d parameters, at least %d required.', + ucfirst($callableDescription) . ' invoked with %d parameter, %d-%d required.', + ucfirst($callableDescription) . ' invoked with %d parameters, %d-%d required.', + '%s of ' . $callableDescription . ' expects %s, %s given.', + 'Result of ' . $callableDescription . ' (void) is used.', + '%s of ' . $callableDescription . ' is passed by reference, so it expects variables only.', + 'Unable to resolve the template type %s in call to ' . $callableDescription, + 'Missing parameter $%s in call to ' . $callableDescription . '.', + 'Unknown parameter $%s in call to ' . $callableDescription . '.', + 'Return type of call to ' . $callableDescription . ' contains unresolvable type.', + '%s of ' . $callableDescription . ' contains unresolvable type.', + ucfirst($callableDescription) . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', ), ); } diff --git a/src/Rules/Functions/CallToFunctionParametersRule.php b/src/Rules/Functions/CallToFunctionParametersRule.php index d1ca216791..63e1b93c7a 100644 --- a/src/Rules/Functions/CallToFunctionParametersRule.php +++ b/src/Rules/Functions/CallToFunctionParametersRule.php @@ -49,25 +49,23 @@ public function processNode(Node $node, Scope $scope): array $scope, $function->isBuiltin(), $node, - [ - 'Function ' . $functionName . ' invoked with %d parameter, %d required.', - 'Function ' . $functionName . ' invoked with %d parameters, %d required.', - 'Function ' . $functionName . ' invoked with %d parameter, at least %d required.', - 'Function ' . $functionName . ' invoked with %d parameters, at least %d required.', - 'Function ' . $functionName . ' invoked with %d parameter, %d-%d required.', - 'Function ' . $functionName . ' invoked with %d parameters, %d-%d required.', - 'Parameter %s of function ' . $functionName . ' expects %s, %s given.', - 'Result of function ' . $functionName . ' (void) is used.', - 'Parameter %s of function ' . $functionName . ' is passed by reference, so it expects variables only.', - 'Unable to resolve the template type %s in call to function ' . $functionName, - 'Missing parameter $%s in call to function ' . $functionName . '.', - 'Unknown parameter $%s in call to function ' . $functionName . '.', - 'Return type of call to function ' . $functionName . ' contains unresolvable type.', - 'Parameter %s of function ' . $functionName . ' contains unresolvable type.', - 'Function ' . $functionName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'function', $function->acceptsNamedArguments(), + 'Function ' . $functionName . ' invoked with %d parameter, %d required.', + 'Function ' . $functionName . ' invoked with %d parameters, %d required.', + 'Function ' . $functionName . ' invoked with %d parameter, at least %d required.', + 'Function ' . $functionName . ' invoked with %d parameters, at least %d required.', + 'Function ' . $functionName . ' invoked with %d parameter, %d-%d required.', + 'Function ' . $functionName . ' invoked with %d parameters, %d-%d required.', + '%s of function ' . $functionName . ' expects %s, %s given.', + 'Result of function ' . $functionName . ' (void) is used.', + '%s of function ' . $functionName . ' is passed by reference, so it expects variables only.', + 'Unable to resolve the template type %s in call to function ' . $functionName, + 'Missing parameter $%s in call to function ' . $functionName . '.', + 'Unknown parameter $%s in call to function ' . $functionName . '.', + 'Return type of call to function ' . $functionName . ' contains unresolvable type.', + '%s of function ' . $functionName . ' contains unresolvable type.', + 'Function ' . $functionName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', ); } diff --git a/src/Rules/Functions/CallUserFuncRule.php b/src/Rules/Functions/CallUserFuncRule.php index c4030961cf..5eb21c2128 100644 --- a/src/Rules/Functions/CallUserFuncRule.php +++ b/src/Rules/Functions/CallUserFuncRule.php @@ -60,23 +60,29 @@ public function processNode(Node $node, Scope $scope): array $callableDescription = 'callable passed to call_user_func()'; - return $this->check->check($parametersAcceptor, $scope, false, $funcCall, [ + return $this->check->check( + $parametersAcceptor, + $scope, + false, + $funcCall, + 'function', + $acceptsNamedArguments, ucfirst($callableDescription) . ' invoked with %d parameter, %d required.', ucfirst($callableDescription) . ' invoked with %d parameters, %d required.', ucfirst($callableDescription) . ' invoked with %d parameter, at least %d required.', ucfirst($callableDescription) . ' invoked with %d parameters, at least %d required.', ucfirst($callableDescription) . ' invoked with %d parameter, %d-%d required.', ucfirst($callableDescription) . ' invoked with %d parameters, %d-%d required.', - 'Parameter %s of ' . $callableDescription . ' expects %s, %s given.', + '%s of ' . $callableDescription . ' expects %s, %s given.', 'Result of ' . $callableDescription . ' (void) is used.', - 'Parameter %s of ' . $callableDescription . ' is passed by reference, so it expects variables only.', + '%s of ' . $callableDescription . ' is passed by reference, so it expects variables only.', 'Unable to resolve the template type %s in call to ' . $callableDescription, 'Missing parameter $%s in call to ' . $callableDescription . '.', 'Unknown parameter $%s in call to ' . $callableDescription . '.', 'Return type of call to ' . $callableDescription . ' contains unresolvable type.', - 'Parameter %s of ' . $callableDescription . ' contains unresolvable type.', + '%s of ' . $callableDescription . ' contains unresolvable type.', ucfirst($callableDescription) . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'function', $acceptsNamedArguments); + ); } } diff --git a/src/Rules/Functions/ClosureAttributesRule.php b/src/Rules/Functions/ClosureAttributesRule.php index 841ae2f46c..fc206e19d4 100644 --- a/src/Rules/Functions/ClosureAttributesRule.php +++ b/src/Rules/Functions/ClosureAttributesRule.php @@ -5,11 +5,12 @@ use Attribute; use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Node\InClosureNode; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\Rule; /** - * @implements Rule + * @implements Rule */ final class ClosureAttributesRule implements Rule { @@ -20,14 +21,14 @@ public function __construct(private AttributesCheck $attributesCheck) public function getNodeType(): string { - return Node\Expr\Closure::class; + return InClosureNode::class; } public function processNode(Node $node, Scope $scope): array { return $this->attributesCheck->check( $scope, - $node->attrGroups, + $node->getOriginalNode()->attrGroups, Attribute::TARGET_FUNCTION, 'function', ); diff --git a/src/Rules/Functions/FunctionAttributesRule.php b/src/Rules/Functions/FunctionAttributesRule.php index 153c222091..9c5ad24d73 100644 --- a/src/Rules/Functions/FunctionAttributesRule.php +++ b/src/Rules/Functions/FunctionAttributesRule.php @@ -5,11 +5,12 @@ use Attribute; use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Node\InFunctionNode; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\Rule; /** - * @implements Rule + * @implements Rule */ final class FunctionAttributesRule implements Rule { @@ -20,14 +21,14 @@ public function __construct(private AttributesCheck $attributesCheck) public function getNodeType(): string { - return Node\Stmt\Function_::class; + return InFunctionNode::class; } public function processNode(Node $node, Scope $scope): array { return $this->attributesCheck->check( $scope, - $node->attrGroups, + $node->getOriginalNode()->attrGroups, Attribute::TARGET_FUNCTION, 'function', ); 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/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php b/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php index 7d5967fb2b..80ab58e8bb 100644 --- a/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php +++ b/src/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRule.php @@ -44,7 +44,7 @@ public function processNode(Node $node, Scope $scope): array $parameterType = $parameters[$paramI]->getType(); $parameterType = TemplateTypeHelper::resolveToBounds($parameterType); - $accepts = $parameterType->acceptsWithReason($defaultValueType, true); + $accepts = $parameterType->accepts($defaultValueType, true); if ($accepts->yes()) { continue; } diff --git a/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php b/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php index ab3565a612..f4d3965026 100644 --- a/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php +++ b/src/Rules/Functions/IncompatibleClosureDefaultParameterTypeRule.php @@ -44,7 +44,7 @@ public function processNode(Node $node, Scope $scope): array $parameterType = $parameters[$paramI]->getType(); $parameterType = TemplateTypeHelper::resolveToBounds($parameterType); - $accepts = $parameterType->acceptsWithReason($defaultValueType, true); + $accepts = $parameterType->accepts($defaultValueType, true); if ($accepts->yes()) { continue; } diff --git a/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php b/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php index af9d403b34..68f9fffc6d 100644 --- a/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php +++ b/src/Rules/Functions/IncompatibleDefaultParameterTypeRule.php @@ -43,7 +43,7 @@ public function processNode(Node $node, Scope $scope): array $parameterType = $function->getParameters()[$paramI]->getType(); $parameterType = TemplateTypeHelper::resolveToBounds($parameterType); - $accepts = $parameterType->acceptsWithReason($defaultValueType, true); + $accepts = $parameterType->accepts($defaultValueType, true); if ($accepts->yes()) { continue; } diff --git a/src/Rules/Functions/MissingFunctionParameterTypehintRule.php b/src/Rules/Functions/MissingFunctionParameterTypehintRule.php index c988c70c08..586ce8727c 100644 --- a/src/Rules/Functions/MissingFunctionParameterTypehintRule.php +++ b/src/Rules/Functions/MissingFunctionParameterTypehintRule.php @@ -23,7 +23,6 @@ final class MissingFunctionParameterTypehintRule implements Rule public function __construct( private MissingTypehintCheck $missingTypehintCheck, - private bool $paramOut, ) { } @@ -49,9 +48,6 @@ public function processNode(Node $node, Scope $scope): array } } - if (!$this->paramOut) { - continue; - } if ($parameterReflection->getOutType() === null) { continue; } diff --git a/src/Rules/Functions/ParameterCastableToNumberRule.php b/src/Rules/Functions/ParameterCastableToNumberRule.php new file mode 100644 index 0000000000..640c73a440 --- /dev/null +++ b/src/Rules/Functions/ParameterCastableToNumberRule.php @@ -0,0 +1,84 @@ + + */ +final class ParameterCastableToNumberRule implements Rule +{ + + public function __construct( + private ReflectionProvider $reflectionProvider, + private ParameterCastableToStringCheck $parameterCastableToStringCheck, + ) + { + } + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!($node->name instanceof Node\Name)) { + return []; + } + + if (!$this->reflectionProvider->hasFunction($node->name, $scope)) { + return []; + } + + $functionReflection = $this->reflectionProvider->getFunction($node->name, $scope); + $functionName = $functionReflection->getName(); + + if (!in_array($functionName, ['array_sum', 'array_product'], true)) { + return []; + } + + $origArgs = $node->getArgs(); + + if (count($origArgs) !== 1) { + return []; + } + + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $scope, + $origArgs, + $functionReflection->getVariants(), + $functionReflection->getNamedArgumentsVariants(), + ); + + $errorMessage = 'Parameter %s of function %s expects an array of values castable to number, %s given.'; + $functionParameters = $parametersAcceptor->getParameters(); + $error = $this->parameterCastableToStringCheck->checkParameter( + $origArgs[0], + $scope, + $errorMessage, + static fn (Type $t) => $t->toNumber(), + $functionName, + $this->parameterCastableToStringCheck->getParameterName( + $origArgs[0], + 0, + $functionParameters[0] ?? null, + ), + ); + + return $error !== null + ? [$error] + : []; + } + +} diff --git a/src/Rules/Functions/RandomIntParametersRule.php b/src/Rules/Functions/RandomIntParametersRule.php index ecca6e7d09..e35c21a3ed 100644 --- a/src/Rules/Functions/RandomIntParametersRule.php +++ b/src/Rules/Functions/RandomIntParametersRule.php @@ -5,6 +5,7 @@ use PhpParser\Node; use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -21,7 +22,11 @@ final class RandomIntParametersRule implements Rule { - public function __construct(private ReflectionProvider $reflectionProvider, private bool $reportMaybes) + public function __construct( + private ReflectionProvider $reflectionProvider, + private PhpVersion $phpVersion, + private bool $reportMaybes, + ) { } @@ -55,7 +60,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $isSmaller = $maxType->isSmallerThan($minType); + $isSmaller = $maxType->isSmallerThan($minType, $this->phpVersion); if ($isSmaller->yes() || $isSmaller->maybe() && $this->reportMaybes) { $message = 'Parameter #1 $min (%s) of function random_int expects lower number than parameter #2 $max (%s).'; diff --git a/src/Rules/Functions/UnusedClosureUsesRule.php b/src/Rules/Functions/UnusedClosureUsesRule.php index 1494208b5b..ed9639e41f 100644 --- a/src/Rules/Functions/UnusedClosureUsesRule.php +++ b/src/Rules/Functions/UnusedClosureUsesRule.php @@ -6,10 +6,8 @@ use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; use PHPStan\Rules\UnusedFunctionParametersCheck; -use PHPStan\ShouldNotHappenException; use function array_map; use function count; -use function is_string; /** * @implements Rule @@ -34,12 +32,7 @@ public function processNode(Node $node, Scope $scope): array return $this->check->getUnusedParameters( $scope, - array_map(static function (Node\Expr\ClosureUse $use): string { - if (!is_string($use->var->name)) { - throw new ShouldNotHappenException(); - } - return $use->var->name; - }, $node->uses), + array_map(static fn (Node\ClosureUse $use): Node\Expr\Variable => $use->var, $node->uses), $node->stmts, 'Anonymous function has an unused use $%s.', 'closure.unusedUse', diff --git a/src/Rules/Generators/YieldFromTypeRule.php b/src/Rules/Generators/YieldFromTypeRule.php index b73b5a3509..5bac445f13 100644 --- a/src/Rules/Generators/YieldFromTypeRule.php +++ b/src/Rules/Generators/YieldFromTypeRule.php @@ -78,7 +78,7 @@ public function processNode(Node $node, Scope $scope): array } $messages = []; - $acceptsKey = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableKeyType(), $exprType->getIterableKeyType(), $scope->isDeclareStrictTypes()); + $acceptsKey = $this->ruleLevelHelper->accepts($returnType->getIterableKeyType(), $exprType->getIterableKeyType(), $scope->isDeclareStrictTypes()); if (!$acceptsKey->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableKeyType(), $exprType->getIterableKeyType()); $messages[] = RuleErrorBuilder::message(sprintf( @@ -92,7 +92,7 @@ public function processNode(Node $node, Scope $scope): array ->build(); } - $acceptsValue = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableValueType(), $exprType->getIterableValueType(), $scope->isDeclareStrictTypes()); + $acceptsValue = $this->ruleLevelHelper->accepts($returnType->getIterableValueType(), $exprType->getIterableValueType(), $scope->isDeclareStrictTypes()); if (!$acceptsValue->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableValueType(), $exprType->getIterableValueType()); $messages[] = RuleErrorBuilder::message(sprintf( diff --git a/src/Rules/Generators/YieldTypeRule.php b/src/Rules/Generators/YieldTypeRule.php index c8475e23a8..eccc960d2a 100644 --- a/src/Rules/Generators/YieldTypeRule.php +++ b/src/Rules/Generators/YieldTypeRule.php @@ -53,7 +53,7 @@ public function processNode(Node $node, Scope $scope): array } $messages = []; - $acceptsKey = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableKeyType(), $keyType, $scope->isDeclareStrictTypes()); + $acceptsKey = $this->ruleLevelHelper->accepts($returnType->getIterableKeyType(), $keyType, $scope->isDeclareStrictTypes()); if (!$acceptsKey->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableKeyType(), $keyType); $messages[] = RuleErrorBuilder::message(sprintf( @@ -72,7 +72,7 @@ public function processNode(Node $node, Scope $scope): array $valueType = $scope->getType($node->value); } - $acceptsValue = $this->ruleLevelHelper->acceptsWithReason($returnType->getIterableValueType(), $valueType, $scope->isDeclareStrictTypes()); + $acceptsValue = $this->ruleLevelHelper->accepts($returnType->getIterableValueType(), $valueType, $scope->isDeclareStrictTypes()); if (!$acceptsValue->result) { $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($returnType->getIterableValueType(), $valueType); $messages[] = RuleErrorBuilder::message(sprintf( diff --git a/src/Rules/Generics/GenericAncestorsCheck.php b/src/Rules/Generics/GenericAncestorsCheck.php index c2eaef580e..d55fd57116 100644 --- a/src/Rules/Generics/GenericAncestorsCheck.php +++ b/src/Rules/Generics/GenericAncestorsCheck.php @@ -35,9 +35,8 @@ public function __construct( private GenericObjectTypeCheck $genericObjectTypeCheck, private VarianceCheck $varianceCheck, private UnresolvableTypeHelper $unresolvableTypeHelper, - private bool $checkGenericClassInNonGenericObjectType, private array $skipCheckGenericClasses, - private bool $absentTypeChecks, + private bool $checkMissingTypehints, ) { } @@ -105,12 +104,10 @@ public function check( ); $messages = array_merge($messages, $genericObjectTypeCheckMessages); - if ($this->absentTypeChecks) { - if ($this->unresolvableTypeHelper->containsUnresolvableType($ancestorType)) { - $messages[] = RuleErrorBuilder::message($unresolvableTypeMessage) - ->identifier('generics.unresolvable') - ->build(); - } + if ($this->unresolvableTypeHelper->containsUnresolvableType($ancestorType)) { + $messages[] = RuleErrorBuilder::message($unresolvableTypeMessage) + ->identifier('generics.unresolvable') + ->build(); } foreach ($ancestorType->getReferencedClasses() as $referencedClass) { @@ -121,10 +118,6 @@ public function check( continue; } - if (!$this->absentTypeChecks) { - continue; - } - if ($referencedClass === $ancestorType->getClassName()) { continue; } @@ -161,7 +154,7 @@ public function check( } } - if ($this->checkGenericClassInNonGenericObjectType) { + if ($this->checkMissingTypehints) { foreach (array_keys($unusedNames) as $unusedName) { if (!$this->reflectionProvider->hasClass($unusedName)) { continue; diff --git a/src/Rules/Generics/PropertyVarianceRule.php b/src/Rules/Generics/PropertyVarianceRule.php index 4ddff55f11..f222bd9945 100644 --- a/src/Rules/Generics/PropertyVarianceRule.php +++ b/src/Rules/Generics/PropertyVarianceRule.php @@ -18,7 +18,6 @@ final class PropertyVarianceRule implements Rule public function __construct( private VarianceCheck $varianceCheck, - private bool $readOnlyByPhpDoc, ) { } @@ -42,7 +41,7 @@ public function processNode(Node $node, Scope $scope): array return []; } - $variance = $node->isReadOnly() || ($this->readOnlyByPhpDoc && $node->isReadOnlyByPhpDoc()) + $variance = $node->isReadOnly() || $node->isReadOnlyByPhpDoc() ? TemplateTypeVariance::createCovariant() : TemplateTypeVariance::createInvariant(); diff --git a/src/Rules/Generics/VarianceCheck.php b/src/Rules/Generics/VarianceCheck.php index ca13ca07a6..d01dbf75a3 100644 --- a/src/Rules/Generics/VarianceCheck.php +++ b/src/Rules/Generics/VarianceCheck.php @@ -2,7 +2,7 @@ namespace PHPStan\Rules\Generics; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\Generic\TemplateType; @@ -13,19 +13,12 @@ final class VarianceCheck { - public function __construct( - private bool $checkParamOutVariance, - private bool $strictStaticVariance, - ) - { - } - /** * @param 'function'|'method' $identifier * @return list */ public function checkParametersAcceptor( - ParametersAcceptorWithPhpDocs $parametersAcceptor, + ExtendedParametersAcceptor $parametersAcceptor, string $parameterTypeMessage, string $parameterOutTypeMessage, string $returnTypeMessage, @@ -57,9 +50,7 @@ public function checkParametersAcceptor( } $covariant = TemplateTypeVariance::createCovariant(); - $parameterVariance = $isStatic && !$this->strictStaticVariance - ? TemplateTypeVariance::createStatic() - : TemplateTypeVariance::createContravariant(); + $parameterVariance = TemplateTypeVariance::createContravariant(); foreach ($parametersAcceptor->getParameters() as $parameterReflection) { $type = $parameterReflection->getType(); @@ -68,10 +59,6 @@ public function checkParametersAcceptor( $errors[] = $error; } - if (!$this->checkParamOutVariance) { - continue; - } - $paramOutType = $parameterReflection->getOutType(); if ($paramOutType === null) { continue; diff --git a/src/Rules/IssetCheck.php b/src/Rules/IssetCheck.php index 1a07cb30c7..89433d32ca 100644 --- a/src/Rules/IssetCheck.php +++ b/src/Rules/IssetCheck.php @@ -25,7 +25,6 @@ public function __construct( private PropertyReflectionFinder $propertyReflectionFinder, private bool $checkAdvancedIsset, private bool $treatPhpDocTypesAsCertain, - private bool $strictUnnecessaryNullsafePropertyFetch, ) { } @@ -217,10 +216,6 @@ public function check(Expr $expr, Scope $scope, string $operatorDescription, str } if ($expr instanceof Expr\NullsafePropertyFetch) { - if (!$this->strictUnnecessaryNullsafePropertyFetch) { - return null; - } - if ($expr->name instanceof Node\Identifier) { return RuleErrorBuilder::message(sprintf('Using nullsafe property access "?->%s" %s is unnecessary. Use -> instead.', $expr->name->name, $operatorDescription)) ->identifier('nullsafe.neverNull') 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/Methods/CallMethodsRule.php b/src/Rules/Methods/CallMethodsRule.php index 4f45dbf9fd..19bc52fe80 100644 --- a/src/Rules/Methods/CallMethodsRule.php +++ b/src/Rules/Methods/CallMethodsRule.php @@ -55,25 +55,23 @@ public function processNode(Node $node, Scope $scope): array $scope, $declaringClass->isBuiltin(), $node, - [ - 'Method ' . $messagesMethodName . ' invoked with %d parameter, %d required.', - 'Method ' . $messagesMethodName . ' invoked with %d parameters, %d required.', - 'Method ' . $messagesMethodName . ' invoked with %d parameter, at least %d required.', - 'Method ' . $messagesMethodName . ' invoked with %d parameters, at least %d required.', - 'Method ' . $messagesMethodName . ' invoked with %d parameter, %d-%d required.', - 'Method ' . $messagesMethodName . ' invoked with %d parameters, %d-%d required.', - 'Parameter %s of method ' . $messagesMethodName . ' expects %s, %s given.', - 'Result of method ' . $messagesMethodName . ' (void) is used.', - 'Parameter %s of method ' . $messagesMethodName . ' is passed by reference, so it expects variables only.', - 'Unable to resolve the template type %s in call to method ' . $messagesMethodName, - 'Missing parameter $%s in call to method ' . $messagesMethodName . '.', - 'Unknown parameter $%s in call to method ' . $messagesMethodName . '.', - 'Return type of call to method ' . $messagesMethodName . ' contains unresolvable type.', - 'Parameter %s of method ' . $messagesMethodName . ' contains unresolvable type.', - 'Method ' . $messagesMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'method', $methodReflection->acceptsNamedArguments(), + 'Method ' . $messagesMethodName . ' invoked with %d parameter, %d required.', + 'Method ' . $messagesMethodName . ' invoked with %d parameters, %d required.', + 'Method ' . $messagesMethodName . ' invoked with %d parameter, at least %d required.', + 'Method ' . $messagesMethodName . ' invoked with %d parameters, at least %d required.', + 'Method ' . $messagesMethodName . ' invoked with %d parameter, %d-%d required.', + 'Method ' . $messagesMethodName . ' invoked with %d parameters, %d-%d required.', + '%s of method ' . $messagesMethodName . ' expects %s, %s given.', + 'Result of method ' . $messagesMethodName . ' (void) is used.', + '%s of method ' . $messagesMethodName . ' is passed by reference, so it expects variables only.', + 'Unable to resolve the template type %s in call to method ' . $messagesMethodName, + 'Missing parameter $%s in call to method ' . $messagesMethodName . '.', + 'Unknown parameter $%s in call to method ' . $messagesMethodName . '.', + 'Return type of call to method ' . $messagesMethodName . ' contains unresolvable type.', + '%s of method ' . $messagesMethodName . ' contains unresolvable type.', + 'Method ' . $messagesMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', )); } diff --git a/src/Rules/Methods/CallStaticMethodsRule.php b/src/Rules/Methods/CallStaticMethodsRule.php index 33612ff02c..e6b2c9dbb5 100644 --- a/src/Rules/Methods/CallStaticMethodsRule.php +++ b/src/Rules/Methods/CallStaticMethodsRule.php @@ -63,25 +63,23 @@ public function processNode(Node $node, Scope $scope): array $scope, $method->getDeclaringClass()->isBuiltin(), $node, - [ - $displayMethodName . ' invoked with %d parameter, %d required.', - $displayMethodName . ' invoked with %d parameters, %d required.', - $displayMethodName . ' invoked with %d parameter, at least %d required.', - $displayMethodName . ' invoked with %d parameters, at least %d required.', - $displayMethodName . ' invoked with %d parameter, %d-%d required.', - $displayMethodName . ' invoked with %d parameters, %d-%d required.', - 'Parameter %s of ' . $lowercasedMethodName . ' expects %s, %s given.', - 'Result of ' . $lowercasedMethodName . ' (void) is used.', - 'Parameter %s of ' . $lowercasedMethodName . ' is passed by reference, so it expects variables only.', - 'Unable to resolve the template type %s in call to method ' . $lowercasedMethodName, - 'Missing parameter $%s in call to ' . $lowercasedMethodName . '.', - 'Unknown parameter $%s in call to ' . $lowercasedMethodName . '.', - 'Return type of call to ' . $lowercasedMethodName . ' contains unresolvable type.', - 'Parameter %s of ' . $lowercasedMethodName . ' contains unresolvable type.', - $displayMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', - ], 'staticMethod', $method->acceptsNamedArguments(), + $displayMethodName . ' invoked with %d parameter, %d required.', + $displayMethodName . ' invoked with %d parameters, %d required.', + $displayMethodName . ' invoked with %d parameter, at least %d required.', + $displayMethodName . ' invoked with %d parameters, at least %d required.', + $displayMethodName . ' invoked with %d parameter, %d-%d required.', + $displayMethodName . ' invoked with %d parameters, %d-%d required.', + '%s of ' . $lowercasedMethodName . ' expects %s, %s given.', + 'Result of ' . $lowercasedMethodName . ' (void) is used.', + '%s of ' . $lowercasedMethodName . ' is passed by reference, so it expects variables only.', + 'Unable to resolve the template type %s in call to method ' . $lowercasedMethodName, + 'Missing parameter $%s in call to ' . $lowercasedMethodName . '.', + 'Unknown parameter $%s in call to ' . $lowercasedMethodName . '.', + 'Return type of call to ' . $lowercasedMethodName . ' contains unresolvable type.', + '%s of ' . $lowercasedMethodName . ' contains unresolvable type.', + $displayMethodName . ' invoked with %s, but it\'s not allowed because of @no-named-arguments.', )); return $errors; diff --git a/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php b/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php index c50d21d878..f214edf960 100644 --- a/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php +++ b/src/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRule.php @@ -19,7 +19,6 @@ final class CallToConstructorStatementWithoutSideEffectsRule implements Rule public function __construct( private ReflectionProvider $reflectionProvider, - private bool $reportNoConstructor, ) { } @@ -47,16 +46,12 @@ public function processNode(Node $node, Scope $scope): array $classReflection = $this->reflectionProvider->getClass($className); if (!$classReflection->hasConstructor()) { - if ($this->reportNoConstructor) { - return [ - RuleErrorBuilder::message(sprintf( - 'Call to new %s() on a separate line has no effect.', - $classReflection->getDisplayName(), - ))->identifier('new.resultUnused')->build(), - ]; - } - - return []; + return [ + RuleErrorBuilder::message(sprintf( + 'Call to new %s() on a separate line has no effect.', + $classReflection->getDisplayName(), + ))->identifier('new.resultUnused')->build(), + ]; } $constructor = $classReflection->getConstructor(); diff --git a/src/Rules/Methods/FinalPrivateMethodRule.php b/src/Rules/Methods/FinalPrivateMethodRule.php index b205234dc2..7331e21bc1 100644 --- a/src/Rules/Methods/FinalPrivateMethodRule.php +++ b/src/Rules/Methods/FinalPrivateMethodRule.php @@ -5,7 +5,6 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\InClassMethodNode; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use function sprintf; @@ -14,12 +13,6 @@ final class FinalPrivateMethodRule implements Rule { - public function __construct( - private PhpVersion $phpVersion, - ) - { - } - public function getNodeType(): string { return InClassMethodNode::class; @@ -28,7 +21,7 @@ public function getNodeType(): string public function processNode(Node $node, Scope $scope): array { $method = $node->getMethodReflection(); - if (!$this->phpVersion->producesWarningForFinalPrivateMethods()) { + if ($scope->getPhpVersion()->producesWarningForFinalPrivateMethods()->no()) { return []; } diff --git a/src/Rules/Methods/IllegalConstructorMethodCallRule.php b/src/Rules/Methods/IllegalConstructorMethodCallRule.php deleted file mode 100644 index 1dba6ed6d2..0000000000 --- a/src/Rules/Methods/IllegalConstructorMethodCallRule.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ -final class IllegalConstructorMethodCallRule implements Rule -{ - - public function getNodeType(): string - { - return Node\Expr\MethodCall::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if (!$node->name instanceof Node\Identifier || $node->name->toLowerString() !== '__construct') { - return []; - } - - return [ - RuleErrorBuilder::message('Call to __construct() on an existing object is not allowed.') - ->identifier('constructor.call') - ->build(), - ]; - } - -} diff --git a/src/Rules/Methods/IllegalConstructorStaticCallRule.php b/src/Rules/Methods/IllegalConstructorStaticCallRule.php deleted file mode 100644 index fa747d6a2b..0000000000 --- a/src/Rules/Methods/IllegalConstructorStaticCallRule.php +++ /dev/null @@ -1,92 +0,0 @@ - - */ -final class IllegalConstructorStaticCallRule implements Rule -{ - - public function getNodeType(): string - { - return Node\Expr\StaticCall::class; - } - - public function processNode(Node $node, Scope $scope): array - { - if (!$node->name instanceof Node\Identifier || $node->name->toLowerString() !== '__construct') { - return []; - } - - if ($this->isCollectCallingConstructor($node, $scope)) { - return []; - } - - return [ - RuleErrorBuilder::message('Static call to __construct() is only allowed on a parent class in the constructor.') - ->identifier('constructor.call') - ->build(), - ]; - } - - private function isCollectCallingConstructor(Node\Expr\StaticCall $node, Scope $scope): bool - { - // __construct should be called from inside constructor - if ($scope->getFunction() === null) { - return false; - } - - if ($scope->getFunction()->getName() !== '__construct') { - if (!$this->isInRenamedTraitConstructor($scope)) { - return false; - } - } - - if (!$scope->isInClass()) { - return false; - } - - if (!$node->class instanceof Node\Name) { - return false; - } - - $parentClasses = array_map(static fn (string $name) => strtolower($name), $scope->getClassReflection()->getParentClassesNames()); - - return in_array(strtolower($scope->resolveName($node->class)), $parentClasses, true); - } - - private function isInRenamedTraitConstructor(Scope $scope): bool - { - if (!$scope->isInClass()) { - return false; - } - - if (!$scope->isInTrait()) { - return false; - } - - if ($scope->getFunction() === null) { - return false; - } - - $traitAliases = $scope->getClassReflection()->getNativeReflection()->getTraitAliases(); - $functionName = $scope->getFunction()->getName(); - if (!array_key_exists($functionName, $traitAliases)) { - return false; - } - - return $traitAliases[$functionName] === sprintf('%s::%s', $scope->getTraitReflection()->getName(), '__construct'); - } - -} diff --git a/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php b/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php index d8814af601..85059abcac 100644 --- a/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php +++ b/src/Rules/Methods/IncompatibleDefaultParameterTypeRule.php @@ -44,7 +44,7 @@ public function processNode(Node $node, Scope $scope): array $parameterType = $parameter->getType(); $parameterType = TemplateTypeHelper::resolveToBounds($parameterType); - $accepts = $parameterType->acceptsWithReason($defaultValueType, true); + $accepts = $parameterType->accepts($defaultValueType, true); if ($accepts->yes()) { continue; } diff --git a/src/Rules/Methods/MethodAttributesRule.php b/src/Rules/Methods/MethodAttributesRule.php index fefc7bac89..433931baf3 100644 --- a/src/Rules/Methods/MethodAttributesRule.php +++ b/src/Rules/Methods/MethodAttributesRule.php @@ -5,11 +5,12 @@ use Attribute; use PhpParser\Node; use PHPStan\Analyser\Scope; +use PHPStan\Node\InClassMethodNode; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\Rule; /** - * @implements Rule + * @implements Rule */ final class MethodAttributesRule implements Rule { @@ -20,14 +21,14 @@ public function __construct(private AttributesCheck $attributesCheck) public function getNodeType(): string { - return Node\Stmt\ClassMethod::class; + return InClassMethodNode::class; } public function processNode(Node $node, Scope $scope): array { return $this->attributesCheck->check( $scope, - $node->attrGroups, + $node->getOriginalNode()->attrGroups, Attribute::TARGET_METHOD, 'method', ); diff --git a/src/Rules/Methods/MethodCallCheck.php b/src/Rules/Methods/MethodCallCheck.php index 165f41741c..d20760f847 100644 --- a/src/Rules/Methods/MethodCallCheck.php +++ b/src/Rules/Methods/MethodCallCheck.php @@ -56,7 +56,7 @@ public function check( if ($type instanceof StaticType) { $typeForDescribe = $type->getStaticObjectType(); } - if (!$type->canCallMethods()->yes() || $type->isClassStringType()->yes()) { + if (!$type->canCallMethods()->yes() || $type->isClassString()->yes()) { return [ [ RuleErrorBuilder::message(sprintf( diff --git a/src/Rules/Methods/MethodParameterComparisonHelper.php b/src/Rules/Methods/MethodParameterComparisonHelper.php index d8bb7f1f4f..34f66bb8bb 100644 --- a/src/Rules/Methods/MethodParameterComparisonHelper.php +++ b/src/Rules/Methods/MethodParameterComparisonHelper.php @@ -9,6 +9,7 @@ use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\ArrayType; +use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\IterableType; use PHPStan\Type\MixedType; use PHPStan\Type\Type; @@ -23,14 +24,14 @@ final class MethodParameterComparisonHelper { - public function __construct(private PhpVersion $phpVersion, private bool $genericPrototypeMessage) + public function __construct(private PhpVersion $phpVersion) { } /** * @return list */ - public function compare(ExtendedMethodReflection $prototype, ClassReflection $prototypeDeclaringClass, PhpMethodFromParserNodeReflection $method, bool $ignorable = false): array + public function compare(ExtendedMethodReflection $prototype, ClassReflection $prototypeDeclaringClass, PhpMethodFromParserNodeReflection $method, bool $ignorable): array { /** @var list $messages */ $messages = []; @@ -45,7 +46,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr 'Method %s::%s() overrides method %s::%s() but misses parameter #%d $%s.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), $i + 1, $prototypeParameter->getName(), @@ -71,7 +72,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $method->getName(), $i + 1, $prototypeParameter->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('parameter.byRef'); @@ -90,7 +91,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $method->getName(), $i + 1, $prototypeParameter->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('parameter.notByRef'); @@ -131,7 +132,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $method->getName(), $i + 1, $prototypeParameter->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('parameter.notVariadic'); @@ -176,7 +177,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $i + $j + 1, $remainingPrototypeParameter->getName(), $remainingPrototypeParameter->getNativeType()->describe(VerbosityLevel::typeOnly()), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('method.childParameterType'); @@ -196,7 +197,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $method->getName(), $i + 1, $prototypeParameter->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('parameter.variadic'); @@ -218,7 +219,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $method->getName(), $i + 1, $prototypeParameter->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('parameter.notOptional'); @@ -244,7 +245,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $i + 1, $prototypeParameter->getName(), $prototypeParameterType->describe(VerbosityLevel::typeOnly()), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('method.childParameterType'); @@ -272,7 +273,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $i + 1, $prototypeParameter->getName(), $prototypeParameterType->describe(VerbosityLevel::typeOnly()), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('method.childParameterType'); @@ -292,7 +293,7 @@ public function compare(ExtendedMethodReflection $prototype, ClassReflection $pr $i + 1, $prototypeParameter->getName(), $prototypeParameterType->describe(VerbosityLevel::typeOnly()), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('method.childParameterType'); @@ -392,6 +393,9 @@ private function isTypeCompatible(Type $methodParameterType, Type $prototypePara if ($prototypeParameterType instanceof ArrayType) { return true; } + if ($prototypeParameterType instanceof ConstantArrayType) { + return true; + } if ($prototypeParameterType->isObject()->yes() && $prototypeParameterType->getObjectClassNames() === [Traversable::class]) { return true; } diff --git a/src/Rules/Methods/MethodSignatureRule.php b/src/Rules/Methods/MethodSignatureRule.php index 4cd7fd8277..86b4614133 100644 --- a/src/Rules/Methods/MethodSignatureRule.php +++ b/src/Rules/Methods/MethodSignatureRule.php @@ -7,9 +7,8 @@ use PHPStan\Node\InClassMethodNode; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; -use PHPStan\Reflection\Php\NativeBuiltinMethodReflection; +use PHPStan\Reflection\ExtendedParameterReflection; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\Php\PhpClassReflectionExtension; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; @@ -43,7 +42,6 @@ public function __construct( private PhpClassReflectionExtension $phpClassReflectionExtension, private bool $reportMaybes, private bool $reportStatic, - private bool $abstractTraitMethod, ) { } @@ -166,30 +164,28 @@ private function collectParentMethods(string $methodName, ClassReflection $class $parentMethods[] = [$method, $method->getDeclaringClass()]; } - if ($this->abstractTraitMethod) { - foreach ($class->getTraits(true) as $trait) { - $nativeTraitReflection = $trait->getNativeReflection(); - if (!$nativeTraitReflection->hasMethod($methodName)) { - continue; - } - - $methodReflection = $nativeTraitReflection->getMethod($methodName); - $isAbstract = $methodReflection->isAbstract(); - if (!$isAbstract) { - continue; - } + foreach ($class->getTraits(true) as $trait) { + $nativeTraitReflection = $trait->getNativeReflection(); + if (!$nativeTraitReflection->hasMethod($methodName)) { + continue; + } - $declaringTrait = $trait->getNativeMethod($methodName)->getDeclaringClass(); - $parentMethods[] = [ - $this->phpClassReflectionExtension->createUserlandMethodReflection( - $trait, - $class, - new NativeBuiltinMethodReflection($methodReflection), - $declaringTrait->getName(), - ), - $declaringTrait, - ]; + $methodReflection = $nativeTraitReflection->getMethod($methodName); + $isAbstract = $methodReflection->isAbstract(); + if (!$isAbstract) { + continue; } + + $declaringTrait = $trait->getNativeMethod($methodName)->getDeclaringClass(); + $parentMethods[] = [ + $this->phpClassReflectionExtension->createUserlandMethodReflection( + $trait, + $class, + $methodReflection, + $declaringTrait->getName(), + ), + $declaringTrait, + ]; } return $parentMethods; @@ -200,8 +196,8 @@ private function collectParentMethods(string $methodName, ClassReflection $class */ private function checkReturnTypeCompatibility( ClassReflection $declaringClass, - ParametersAcceptorWithPhpDocs $currentVariant, - ParametersAcceptorWithPhpDocs $parentVariant, + ExtendedParametersAcceptor $currentVariant, + ExtendedParametersAcceptor $parentVariant, ): array { $returnType = TypehintHelper::decideType( @@ -223,15 +219,15 @@ private function checkReturnTypeCompatibility( return [TrinaryLogic::createYes(), $returnType, $parentReturnType]; } - return [$parentReturnType->isSuperTypeOf($returnType), TypehintHelper::decideType( + return [$parentReturnType->isSuperTypeOf($returnType)->result, TypehintHelper::decideType( $currentVariant->getNativeReturnType(), $currentVariant->getPhpDocReturnType(), ), $originalParentReturnType]; } /** - * @param ParameterReflectionWithPhpDocs[] $parameters - * @param ParameterReflectionWithPhpDocs[] $parentParameters + * @param ExtendedParameterReflection[] $parameters + * @param ExtendedParameterReflection[] $parentParameters * @return array */ private function checkParameterTypeCompatibility( @@ -257,7 +253,7 @@ private function checkParameterTypeCompatibility( ); $parentParameterType = $this->transformStaticType($declaringClass, $originalParameterType); - $parameterResults[] = [$parameterType->isSuperTypeOf($parentParameterType), TypehintHelper::decideType( + $parameterResults[] = [$parameterType->isSuperTypeOf($parentParameterType)->result, TypehintHelper::decideType( $parameter->getNativeType(), $parameter->getPhpDocType(), ), $originalParameterType]; diff --git a/src/Rules/Methods/MissingMethodParameterTypehintRule.php b/src/Rules/Methods/MissingMethodParameterTypehintRule.php index 8d5edd7890..5c6c204760 100644 --- a/src/Rules/Methods/MissingMethodParameterTypehintRule.php +++ b/src/Rules/Methods/MissingMethodParameterTypehintRule.php @@ -23,7 +23,6 @@ final class MissingMethodParameterTypehintRule implements Rule public function __construct( private MissingTypehintCheck $missingTypehintCheck, - private bool $paramOut, ) { } @@ -49,9 +48,6 @@ public function processNode(Node $node, Scope $scope): array } } - if (!$this->paramOut) { - continue; - } if ($parameterReflection->getOutType() === null) { continue; } diff --git a/src/Rules/Methods/OverridingMethodRule.php b/src/Rules/Methods/OverridingMethodRule.php index 29a936b35a..38c588f9db 100644 --- a/src/Rules/Methods/OverridingMethodRule.php +++ b/src/Rules/Methods/OverridingMethodRule.php @@ -7,11 +7,10 @@ use PHPStan\Node\InClassMethodNode; use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\ExtendedFunctionVariant; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\FunctionVariantWithPhpDocs; use PHPStan\Reflection\MethodPrototypeReflection; use PHPStan\Reflection\Native\NativeMethodReflection; -use PHPStan\Reflection\Php\NativeBuiltinMethodReflection; use PHPStan\Reflection\Php\PhpClassReflectionExtension; use PHPStan\Reflection\Php\PhpMethodReflection; use PHPStan\Rules\IdentifierRuleError; @@ -37,8 +36,6 @@ public function __construct( private bool $checkPhpDocMethodSignatures, private MethodParameterComparisonHelper $methodParameterComparisonHelper, private PhpClassReflectionExtension $phpClassReflectionExtension, - private bool $genericPrototypeMessage, - private bool $finalByPhpDoc, private bool $checkMissingOverrideMethodAttribute, ) { @@ -64,7 +61,7 @@ public function processNode(Node $node, Scope $scope): array 'Method %s::%s() overrides final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $parent->getDisplayName($this->genericPrototypeMessage), + $parent->getDisplayName(true), $parentConstructor->getName(), )) ->nonIgnorable() @@ -72,13 +69,13 @@ public function processNode(Node $node, Scope $scope): array ->build(), ], $node, $scope); } - if ($parentConstructor->isFinal()->yes() && $this->finalByPhpDoc) { + if ($parentConstructor->isFinal()->yes()) { return $this->addErrors([ RuleErrorBuilder::message(sprintf( 'Method %s::%s() overrides @final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $parent->getDisplayName($this->genericPrototypeMessage), + $parent->getDisplayName(true), $parentConstructor->getName(), ))->identifier('method.parentMethodFinalByPhpDoc') ->build(), @@ -115,7 +112,7 @@ public function processNode(Node $node, Scope $scope): array 'Method %s::%s() overrides method %s::%s() but is missing the #[\Override] attribute.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('method.missingOverride')->build(); } @@ -124,18 +121,18 @@ public function processNode(Node $node, Scope $scope): array 'Method %s::%s() overrides final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() ->identifier('method.parentMethodFinal') ->build(); - } elseif ($prototype->isFinal()->yes() && $this->finalByPhpDoc) { + } elseif ($prototype->isFinal()->yes()) { $messages[] = RuleErrorBuilder::message(sprintf( 'Method %s::%s() overrides @final method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), ))->identifier('method.parentMethodFinalByPhpDoc') ->build(); @@ -147,7 +144,7 @@ public function processNode(Node $node, Scope $scope): array 'Non-static method %s::%s() overrides static method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() @@ -159,7 +156,7 @@ public function processNode(Node $node, Scope $scope): array 'Static method %s::%s() overrides non-static method %s::%s().', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() @@ -175,7 +172,7 @@ public function processNode(Node $node, Scope $scope): array $method->isPrivate() ? 'Private' : 'Protected', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() @@ -187,7 +184,7 @@ public function processNode(Node $node, Scope $scope): array 'Private method %s::%s() overriding protected method %s::%s() should be protected or public.', $method->getDeclaringClass()->getDisplayName(), $method->getName(), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() @@ -221,7 +218,7 @@ public function processNode(Node $node, Scope $scope): array $method->getDeclaringClass()->getDisplayName(), $method->getName(), $realPrototype->getTentativeReturnType()->describe(VerbosityLevel::typeOnly()), - $realPrototype->getDeclaringClass()->getDisplayName($this->genericPrototypeMessage), + $realPrototype->getDeclaringClass()->getDisplayName(true), $realPrototype->getName(), )) ->tip('Make it covariant, or use the #[\ReturnTypeWillChange] attribute to temporarily suppress the error.') @@ -231,9 +228,9 @@ public function processNode(Node $node, Scope $scope): array } } - $messages = array_merge($messages, $this->methodParameterComparisonHelper->compare($prototype, $prototypeDeclaringClass, $method)); + $messages = array_merge($messages, $this->methodParameterComparisonHelper->compare($prototype, $prototypeDeclaringClass, $method, false)); - if (!$prototypeVariant instanceof FunctionVariantWithPhpDocs) { + if (!$prototypeVariant instanceof ExtendedFunctionVariant) { return $this->addErrors($messages, $node, $scope); } @@ -271,7 +268,7 @@ public function processNode(Node $node, Scope $scope): array $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeReturnType->describe(VerbosityLevel::typeOnly()), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() @@ -284,7 +281,7 @@ public function processNode(Node $node, Scope $scope): array $method->getDeclaringClass()->getDisplayName(), $method->getName(), $prototypeReturnType->describe(VerbosityLevel::typeOnly()), - $prototypeDeclaringClass->getDisplayName($this->genericPrototypeMessage), + $prototypeDeclaringClass->getDisplayName(true), $prototype->getName(), )) ->nonIgnorable() @@ -370,7 +367,7 @@ private function findPrototype(ClassReflection $classReflection, string $methodN $this->phpClassReflectionExtension->createUserlandMethodReflection( $trait, $classReflection, - new NativeBuiltinMethodReflection($methodReflection), + $methodReflection, $declaringTrait->getName(), ), $declaringTrait, diff --git a/src/Rules/MissingTypehintCheck.php b/src/Rules/MissingTypehintCheck.php index 3467703921..0bebd83c15 100644 --- a/src/Rules/MissingTypehintCheck.php +++ b/src/Rules/MissingTypehintCheck.php @@ -46,9 +46,6 @@ final class MissingTypehintCheck * @param string[] $skipCheckGenericClasses */ public function __construct( - private bool $disableCheckMissingIterableValueType, - private bool $checkMissingIterableValueType, - private bool $checkGenericClassInNonGenericObjectType, private bool $checkMissingCallableSignature, private array $skipCheckGenericClasses, ) @@ -60,12 +57,6 @@ public function __construct( */ public function getIterableTypesWithMissingValueTypehint(Type $type): array { - if (!$this->checkMissingIterableValueType) { - if (!$this->disableCheckMissingIterableValueType) { - return []; - } - } - $iterablesWithMissingValueTypehint = []; TypeTraverser::map($type, function (Type $type, callable $traverse) use (&$iterablesWithMissingValueTypehint): Type { if ($type instanceof TemplateType) { @@ -107,10 +98,6 @@ public function getIterableTypesWithMissingValueTypehint(Type $type): array */ public function getNonGenericObjectTypesWithGenericClass(Type $type): array { - if (!$this->checkGenericClassInNonGenericObjectType) { - return []; - } - $objectTypes = []; TypeTraverser::map($type, function (Type $type, callable $traverse) use (&$objectTypes): Type { if ($type instanceof GenericObjectType) { 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/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/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/Operators/InvalidBinaryOperationRule.php b/src/Rules/Operators/InvalidBinaryOperationRule.php index 517c41b909..e44b2178d5 100644 --- a/src/Rules/Operators/InvalidBinaryOperationRule.php +++ b/src/Rules/Operators/InvalidBinaryOperationRule.php @@ -10,6 +10,7 @@ use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\ErrorType; use PHPStan\Type\Type; use PHPStan\Type\VerbosityLevel; @@ -26,7 +27,6 @@ final class InvalidBinaryOperationRule implements Rule public function __construct( private ExprPrinter $exprPrinter, private RuleLevelHelper $ruleLevelHelper, - private bool $bleedingEdge, ) { } @@ -45,10 +45,6 @@ public function processNode(Node $node, Scope $scope): array return []; } - if (!$scope->getType($node) instanceof ErrorType && !$this->bleedingEdge) { - return []; - } - $leftName = '__PHPSTAN__LEFT__'; $rightName = '__PHPSTAN__RIGHT__'; $leftVariable = new Node\Expr\Variable($leftName); @@ -104,8 +100,8 @@ public function processNode(Node $node, Scope $scope): array } $scope = $scope - ->assignVariable($leftName, $leftType, $leftType) - ->assignVariable($rightName, $rightType, $rightType); + ->assignVariable($leftName, $leftType, $leftType, TrinaryLogic::createYes()) + ->assignVariable($rightName, $rightType, $rightType, TrinaryLogic::createYes()); if (!$scope->getType($newNode) instanceof ErrorType) { return []; diff --git a/src/Rules/Operators/InvalidIncDecOperationRule.php b/src/Rules/Operators/InvalidIncDecOperationRule.php index 6f3382d829..8283936e73 100644 --- a/src/Rules/Operators/InvalidIncDecOperationRule.php +++ b/src/Rules/Operators/InvalidIncDecOperationRule.php @@ -29,8 +29,6 @@ final class InvalidIncDecOperationRule implements Rule public function __construct( private RuleLevelHelper $ruleLevelHelper, - private bool $bleedingEdge, - private bool $checkThisOnly, ) { } @@ -87,30 +85,16 @@ public function processNode(Node $node, Scope $scope): array ]; } - if (!$this->bleedingEdge) { - if ($this->checkThisOnly) { - return []; - } + $allowedTypes = new UnionType([new BooleanType(), new FloatType(), new IntegerType(), new StringType(), new NullType(), new ObjectType('SimpleXMLElement')]); + $varType = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->var, + '', + static fn (Type $type): bool => $allowedTypes->isSuperTypeOf($type)->yes(), + )->getType(); - $varType = $scope->getType($node->var); - if (!$varType->toString() instanceof ErrorType) { - return []; - } - if (!$varType->toNumber() instanceof ErrorType) { - return []; - } - } else { - $allowedTypes = new UnionType([new BooleanType(), new FloatType(), new IntegerType(), new StringType(), new NullType(), new ObjectType('SimpleXMLElement')]); - $varType = $this->ruleLevelHelper->findTypeToCheck( - $scope, - $node->var, - '', - static fn (Type $type): bool => $allowedTypes->isSuperTypeOf($type)->yes(), - )->getType(); - - if ($varType instanceof ErrorType || $allowedTypes->isSuperTypeOf($varType)->yes()) { - return []; - } + if ($varType instanceof ErrorType || $allowedTypes->isSuperTypeOf($varType)->yes()) { + return []; } return [ diff --git a/src/Rules/Operators/InvalidUnaryOperationRule.php b/src/Rules/Operators/InvalidUnaryOperationRule.php index 9ea9c07342..6600cce4ad 100644 --- a/src/Rules/Operators/InvalidUnaryOperationRule.php +++ b/src/Rules/Operators/InvalidUnaryOperationRule.php @@ -9,6 +9,7 @@ use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\ErrorType; use PHPStan\Type\Type; use PHPStan\Type\VerbosityLevel; @@ -22,7 +23,6 @@ final class InvalidUnaryOperationRule implements Rule public function __construct( private RuleLevelHelper $ruleLevelHelper, - private bool $bleedingEdge, ) { } @@ -42,38 +42,34 @@ public function processNode(Node $node, Scope $scope): array return []; } - if ($this->bleedingEdge) { - $varName = '__PHPSTAN__LEFT__'; - $variable = new Node\Expr\Variable($varName); - $newNode = clone $node; - $newNode->setAttribute('phpstan_cache_printer', null); - $newNode->expr = $variable; + $varName = '__PHPSTAN__LEFT__'; + $variable = new Node\Expr\Variable($varName); + $newNode = clone $node; + $newNode->setAttribute('phpstan_cache_printer', null); + $newNode->expr = $variable; - if ($node instanceof Node\Expr\BitwiseNot) { - $callback = static fn (Type $type): bool => $type->isString()->yes() || $type->isInteger()->yes() || $type->isFloat()->yes(); - } else { - $callback = static fn (Type $type): bool => !$type->toNumber() instanceof ErrorType; - } + if ($node instanceof Node\Expr\BitwiseNot) { + $callback = static fn (Type $type): bool => $type->isString()->yes() || $type->isInteger()->yes() || $type->isFloat()->yes(); + } else { + $callback = static fn (Type $type): bool => !$type->toNumber() instanceof ErrorType; + } - $exprType = $this->ruleLevelHelper->findTypeToCheck( - $scope, - $node->expr, - '', - $callback, - )->getType(); - if ($exprType instanceof ErrorType) { - return []; - } + $exprType = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->expr, + '', + $callback, + )->getType(); + if ($exprType instanceof ErrorType) { + return []; + } - if (!$scope instanceof MutatingScope) { - throw new ShouldNotHappenException(); - } + if (!$scope instanceof MutatingScope) { + throw new ShouldNotHappenException(); + } - $scope = $scope->assignVariable($varName, $exprType, $exprType); - if (!$scope->getType($newNode) instanceof ErrorType) { - return []; - } - } elseif (!$scope->getType($node) instanceof ErrorType) { + $scope = $scope->assignVariable($varName, $exprType, $exprType, TrinaryLogic::createYes()); + if (!$scope->getType($newNode) instanceof ErrorType) { return []; } diff --git a/src/Rules/ParameterCastableToStringCheck.php b/src/Rules/ParameterCastableToStringCheck.php index 2d4dea0dbd..9753863557 100644 --- a/src/Rules/ParameterCastableToStringCheck.php +++ b/src/Rules/ParameterCastableToStringCheck.php @@ -36,11 +36,13 @@ public function checkParameter( $scope, $parameter->value, '', - static fn (Type $type): bool => !$castFn($type->getIterableValueType()) instanceof ErrorType, + static fn (Type $type): bool => $type->isArray()->yes() && !$castFn($type->getIterableValueType()) instanceof ErrorType, ); - if ($typeResult->getType() instanceof ErrorType - || !$castFn($typeResult->getType()->getIterableValueType()) instanceof ErrorType) { + if ( + ! $typeResult->getType()->isArray()->yes() + || !$castFn($typeResult->getType()->getIterableValueType()) instanceof ErrorType + ) { return null; } diff --git a/src/Rules/PhpDoc/AssertRuleHelper.php b/src/Rules/PhpDoc/AssertRuleHelper.php index 0dec8f4d24..1fecf4ffa3 100644 --- a/src/Rules/PhpDoc/AssertRuleHelper.php +++ b/src/Rules/PhpDoc/AssertRuleHelper.php @@ -36,7 +36,6 @@ public function __construct( private ClassNameCheck $classCheck, private MissingTypehintCheck $missingTypehintCheck, private GenericObjectTypeCheck $genericObjectTypeCheck, - private bool $absentTypeChecks, private bool $checkClassCaseSensitivity, private bool $checkMissingTypehints, ) @@ -82,11 +81,9 @@ public function check( $assertedExprType = $this->initializerExprTypeResolver->getType($assertedExpr, $context); $assertedExprString = $assert->getParameter()->describe(); if ($assertedExprType instanceof ErrorType) { - if ($this->absentTypeChecks) { - $errors[] = RuleErrorBuilder::message(sprintf('Assert references unknown %s.', $assertedExprString)) - ->identifier('assert.unknownExpr') - ->build(); - } + $errors[] = RuleErrorBuilder::message(sprintf('Assert references unknown %s.', $assertedExprString)) + ->identifier('assert.unknownExpr') + ->build(); continue; } @@ -98,15 +95,13 @@ public function check( AssertTag::IF_FALSE => '@phpstan-assert-if-false', ][$assert->getIf()]; - if ($this->absentTypeChecks) { - if ($this->unresolvableTypeHelper->containsUnresolvableType($assertedType)) { - $errors[] = RuleErrorBuilder::message(sprintf( - 'PHPDoc tag %s for %s contains unresolvable type.', - $tagName, - $assertedExprString, - ))->identifier('assert.unresolvableType')->build(); - continue; - } + if ($this->unresolvableTypeHelper->containsUnresolvableType($assertedType)) { + $errors[] = RuleErrorBuilder::message(sprintf( + 'PHPDoc tag %s for %s contains unresolvable type.', + $tagName, + $assertedExprString, + ))->identifier('assert.unresolvableType')->build(); + continue; } $isSuperType = $assertedType->isSuperTypeOf($assertedExprType); @@ -130,10 +125,6 @@ public function check( } } - if (!$this->absentTypeChecks) { - continue; - } - foreach ($assertedType->getReferencedClasses() as $class) { if (!$this->reflectionProvider->hasClass($class)) { $errors[] = RuleErrorBuilder::message(sprintf( diff --git a/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php b/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php index eee8ad3281..f48a8abc7a 100644 --- a/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php +++ b/src/Rules/PhpDoc/ConditionalReturnTypeRuleHelper.php @@ -2,7 +2,7 @@ namespace PHPStan\Rules\PhpDoc; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\ConditionalType; @@ -23,7 +23,7 @@ final class ConditionalReturnTypeRuleHelper /** * @return list */ - public function check(ParametersAcceptorWithPhpDocs $acceptor): array + public function check(ExtendedParametersAcceptor $acceptor): array { $conditionalTypes = []; $parametersByName = []; diff --git a/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php b/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php index 184821b5a3..a202f67bcd 100644 --- a/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php +++ b/src/Rules/PhpDoc/IncompatiblePropertyPhpDocTypeRule.php @@ -10,7 +10,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\Generic\TemplateType; -use PHPStan\Type\ParserNodeTypeToPHPStanType; use PHPStan\Type\VerbosityLevel; use function array_merge; use function sprintf; @@ -62,33 +61,35 @@ public function processNode(Node $node, Scope $scope): array ))->identifier('property.unresolvableType')->build(); } - $nativeType = ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection); - $isSuperType = $nativeType->isSuperTypeOf($phpDocType); - if ($isSuperType->no()) { - $messages[] = RuleErrorBuilder::message(sprintf( - '%s for property %s::$%s with type %s is incompatible with native type %s.', - $description, - $classReflection->getDisplayName(), - $propertyName, - $phpDocType->describe(VerbosityLevel::typeOnly()), - $nativeType->describe(VerbosityLevel::typeOnly()), - ))->identifier('property.phpDocType')->build(); - - } elseif ($isSuperType->maybe()) { - $errorBuilder = RuleErrorBuilder::message(sprintf( - '%s for property %s::$%s with type %s is not subtype of native type %s.', - $description, - $classReflection->getDisplayName(), - $propertyName, - $phpDocType->describe(VerbosityLevel::typeOnly()), - $nativeType->describe(VerbosityLevel::typeOnly()), - ))->identifier('property.phpDocType'); - - if ($phpDocType instanceof TemplateType) { - $errorBuilder->tip(sprintf('Write @template %s of %s to fix this.', $phpDocType->getName(), $nativeType->describe(VerbosityLevel::typeOnly()))); + $nativeType = $node->getNativeType(); + if ($nativeType !== null) { + $isSuperType = $nativeType->isSuperTypeOf($phpDocType); + if ($isSuperType->no()) { + $messages[] = RuleErrorBuilder::message(sprintf( + '%s for property %s::$%s with type %s is incompatible with native type %s.', + $description, + $classReflection->getDisplayName(), + $propertyName, + $phpDocType->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.phpDocType')->build(); + + } elseif ($isSuperType->maybe()) { + $errorBuilder = RuleErrorBuilder::message(sprintf( + '%s for property %s::$%s with type %s is not subtype of native type %s.', + $description, + $classReflection->getDisplayName(), + $propertyName, + $phpDocType->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.phpDocType'); + + if ($phpDocType instanceof TemplateType) { + $errorBuilder->tip(sprintf('Write @template %s of %s to fix this.', $phpDocType->getName(), $nativeType->describe(VerbosityLevel::typeOnly()))); + } + + $messages[] = $errorBuilder->build(); } - - $messages[] = $errorBuilder->build(); } $className = SprintfHelper::escapeFormatString($classReflection->getDisplayName()); 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..2caa53394e 100644 --- a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php +++ b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\PhpDoc; -use Nette\Utils\Strings; use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\VirtualNode; @@ -18,7 +17,7 @@ use function str_starts_with; /** - * @implements Rule + * @implements Rule */ final class InvalidPhpDocTagValueRule implements Rule { @@ -26,40 +25,23 @@ final class InvalidPhpDocTagValueRule implements Rule public function __construct( private Lexer $phpDocLexer, private PhpDocParser $phpDocParser, - private bool $checkAllInvalidPhpDocs, - private bool $invalidPhpDocTagLine, ) { } 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 []; } } @@ -88,7 +70,7 @@ public function processNode(Node $node, Scope $scope): array 'PHPDoc tag %s %s has invalid value: %s', $phpDocTag->name, $phpDocTag->value->alias, - $this->trimExceptionMessage($phpDocTag->value->type->getException()->getMessage()), + $phpDocTag->value->type->getException()->getMessage(), )) ->line(PhpDocLineHelper::detectLine($node, $phpDocTag)) ->identifier('phpDoc.parseError')->build(); @@ -102,7 +84,7 @@ public function processNode(Node $node, Scope $scope): array 'PHPDoc tag %s has invalid value (%s): %s', $phpDocTag->name, $phpDocTag->value->value, - $this->trimExceptionMessage($phpDocTag->value->exception->getMessage()), + $phpDocTag->value->exception->getMessage(), )) ->line(PhpDocLineHelper::detectLine($node, $phpDocTag)) ->identifier('phpDoc.parseError')->build(); @@ -111,13 +93,4 @@ public function processNode(Node $node, Scope $scope): array return $errors; } - private function trimExceptionMessage(string $message): string - { - if ($this->invalidPhpDocTagLine) { - return $message; - } - - return Strings::replace($message, '~( on line \d+)$~', ''); - } - } diff --git a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php index 53d4c4e6a6..3815a963aa 100644 --- a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php +++ b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php @@ -47,7 +47,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_ ) { @@ -97,6 +96,17 @@ public function processNode(Node $node, Scope $scope): array ->identifier('missingType.iterableValue') ->build(); } + + foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($varTagType) as [$innerName, $genericTypeNames]) { + $errors[] = RuleErrorBuilder::message(sprintf( + '%s contains generic %s but does not specify its types: %s', + $identifier, + $innerName, + $genericTypeNames, + )) + ->identifier('missingType.generics') + ->build(); + } } $escapedIdentifier = SprintfHelper::escapeFormatString($identifier); @@ -110,17 +120,6 @@ public function processNode(Node $node, Scope $scope): array sprintf('Call-site variance of %%s in generic type %%s in %s is redundant, template type %%s of %%s %%s has the same variance.', $escapedIdentifier), )); - foreach ($this->missingTypehintCheck->getNonGenericObjectTypesWithGenericClass($varTagType) as [$innerName, $genericTypeNames]) { - $errors[] = RuleErrorBuilder::message(sprintf( - '%s contains generic %s but does not specify its types: %s', - $identifier, - $innerName, - $genericTypeNames, - )) - ->identifier('missingType.generics') - ->build(); - } - $referencedClasses = $varTagType->getReferencedClasses(); foreach ($referencedClasses as $referencedClass) { if ($this->reflectionProvider->hasClass($referencedClass)) { 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/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/Rules/PhpDoc/WrongVariableNameInVarTagRule.php b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php index 9e4fc3ebf1..72e61ffdb6 100644 --- a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php +++ b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php @@ -37,7 +37,6 @@ final class WrongVariableNameInVarTagRule implements Rule public function __construct( private FileTypeMapper $fileTypeMapper, private VarTagTypeRuleHelper $varTagTypeRuleHelper, - private bool $checkTypeAgainstNativeType, ) { } @@ -51,7 +50,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) @@ -90,10 +88,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); } @@ -136,11 +137,6 @@ private function processAssign(Scope $scope, Node\Expr $var, Node\Expr $expr, ar $errors = []; $hasMultipleMessage = false; $assignedVariables = $this->getAssignedVariables($var); - if ($this->checkTypeAgainstNativeType) { - foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var, $expr, $varTags, $assignedVariables) as $error) { - $errors[] = $error; - } - } foreach (array_keys($varTags) as $key) { if (is_int($key)) { if (count($varTags) !== 1) { @@ -179,6 +175,12 @@ private function processAssign(Scope $scope, Node\Expr $var, Node\Expr $expr, ar } } + if (count($errors) === 0) { + foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var, $expr, $varTags, $assignedVariables) as $error) { + $errors[] = $error; + } + } + return $errors; } @@ -195,7 +197,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) { @@ -249,19 +251,17 @@ private function processForeach(Scope $scope, Node\Expr $iterateeExpr, ?Node\Exp ))->identifier('varTag.differentVariable')->build(); } - if ($this->checkTypeAgainstNativeType) { - foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $iterateeExpr, $iterateeExpr, $varTags, $variableNames) as $error) { - $errors[] = $error; - } - if ($keyVar !== null) { - foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $keyVar, new GetIterableKeyTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) { - $errors[] = $error; - } - } - foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $valueVar, new GetIterableValueTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) { + foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $iterateeExpr, $iterateeExpr, $varTags, $variableNames) as $error) { + $errors[] = $error; + } + if ($keyVar !== null) { + foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $keyVar, new GetIterableKeyTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) { $errors[] = $error; } } + foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $valueVar, new GetIterableValueTypeExpr($iterateeExpr), $varTags, $variableNames) as $error) { + $errors[] = $error; + } return $errors; } @@ -319,14 +319,12 @@ private function processStatic(Scope $scope, array $vars, array $varTags): array ))->identifier('varTag.differentVariable')->build(); } - if ($this->checkTypeAgainstNativeType) { - foreach ($vars as $var) { - if ($var->default === null) { - continue; - } - foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var->var, $var->default, $varTags, $variableNames) as $error) { - $errors[] = $error; - } + foreach ($vars as $var) { + if ($var->default === null) { + continue; + } + foreach ($this->varTagTypeRuleHelper->checkVarType($scope, $var->var, $var->default, $varTags, $variableNames) as $error) { + $errors[] = $error; } } 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; } diff --git a/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php b/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php index 3076d2d3d8..63cd185b7a 100644 --- a/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php +++ b/src/Rules/Properties/DefaultValueTypesAssignedToPropertiesRule.php @@ -44,7 +44,7 @@ public function processNode(Node $node, Scope $scope): array } } $defaultValueType = $scope->getType($default); - $accepts = $this->ruleLevelHelper->acceptsWithReason($propertyType, $defaultValueType, true); + $accepts = $this->ruleLevelHelper->accepts($propertyType, $defaultValueType, true); if ($accepts->result) { return []; } diff --git a/src/Rules/Properties/OverridingPropertyRule.php b/src/Rules/Properties/OverridingPropertyRule.php index be6a9fca4f..5767635e27 100644 --- a/src/Rules/Properties/OverridingPropertyRule.php +++ b/src/Rules/Properties/OverridingPropertyRule.php @@ -9,7 +9,6 @@ use PHPStan\Reflection\Php\PhpPropertyReflection; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; -use PHPStan\Type\ParserNodeTypeToPHPStanType; use PHPStan\Type\VerbosityLevel; use function array_merge; use function count; @@ -104,8 +103,9 @@ public function processNode(Node $node, Scope $scope): array } $typeErrors = []; + $nativeType = $node->getNativeType(); if ($prototype->hasNativeType()) { - if ($node->getNativeType() === null) { + if ($nativeType === null) { $typeErrors[] = RuleErrorBuilder::message(sprintf( 'Property %s::$%s overriding property %s::$%s (%s) should also have native type %s.', $classReflection->getDisplayName(), @@ -116,7 +116,6 @@ public function processNode(Node $node, Scope $scope): array $prototype->getNativeType()->describe(VerbosityLevel::typeOnly()), ))->identifier('property.missingNativeType')->nonIgnorable()->build(); } else { - $nativeType = ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection); if (!$prototype->getNativeType()->equals($nativeType)) { $typeErrors[] = RuleErrorBuilder::message(sprintf( 'Type %s of property %s::$%s is not the same as type %s of overridden property %s::$%s.', @@ -129,12 +128,12 @@ public function processNode(Node $node, Scope $scope): array ))->identifier('property.nativeType')->nonIgnorable()->build(); } } - } elseif ($node->getNativeType() !== null) { + } elseif ($nativeType !== null) { $typeErrors[] = RuleErrorBuilder::message(sprintf( 'Property %s::$%s (%s) overriding property %s::$%s should not have a native type.', $classReflection->getDisplayName(), $node->getName(), - ParserNodeTypeToPHPStanType::resolve($node->getNativeType(), $classReflection)->describe(VerbosityLevel::typeOnly()), + $nativeType->describe(VerbosityLevel::typeOnly()), $prototype->getDeclaringClass()->getDisplayName(), $node->getName(), ))->identifier('property.extraNativeType')->nonIgnorable()->build(); diff --git a/src/Rules/Properties/PropertiesInInterfaceRule.php b/src/Rules/Properties/PropertiesInInterfaceRule.php index d9f62fa618..df5354adb3 100644 --- a/src/Rules/Properties/PropertiesInInterfaceRule.php +++ b/src/Rules/Properties/PropertiesInInterfaceRule.php @@ -5,6 +5,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Node\ClassPropertyNode; +use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -14,6 +15,10 @@ final class PropertiesInInterfaceRule implements Rule { + public function __construct(private PhpVersion $phpVersion) + { + } + public function getNodeType(): string { return ClassPropertyNode::class; @@ -25,12 +30,54 @@ public function processNode(Node $node, Scope $scope): array return []; } - return [ - RuleErrorBuilder::message('Interfaces may not include properties.') - ->nonIgnorable() - ->identifier('property.inInterface') - ->build(), - ]; + if (!$this->phpVersion->supportsPropertyHooks()) { + return [ + RuleErrorBuilder::message('Interfaces cannot include properties.') + ->nonIgnorable() + ->identifier('property.inInterface') + ->build(), + ]; + } + + if (!$node->hasHooks()) { + return [ + RuleErrorBuilder::message('Interfaces can only include hooked properties.') + ->nonIgnorable() + ->identifier('property.nonHookedInInterface') + ->build(), + ]; + } + + if (!$node->isPublic()) { + return [ + RuleErrorBuilder::message('Interfaces cannot include non-public properties.') + ->nonIgnorable() + ->identifier('property.nonPublicInInterface') + ->build(), + ]; + } + + if ($this->hasAnyHookBody($node)) { + return [ + RuleErrorBuilder::message('Interfaces cannot include property hooks with bodies.') + ->nonIgnorable() + ->identifier('property.hookBodyInInterface') + ->build(), + ]; + } + + return []; + } + + private function hasAnyHookBody(ClassPropertyNode $node): bool + { + foreach ($node->getHooks() as $hook) { + if ($hook->body !== null) { + return true; + } + } + + return false; } } diff --git a/src/Rules/Properties/PropertyInClassRule.php b/src/Rules/Properties/PropertyInClassRule.php new file mode 100644 index 0000000000..3500959541 --- /dev/null +++ b/src/Rules/Properties/PropertyInClassRule.php @@ -0,0 +1,113 @@ + + */ +final class PropertyInClassRule implements Rule +{ + + public function __construct(private PhpVersion $phpVersion) + { + } + + public function getNodeType(): string + { + return ClassPropertyNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $classReflection = $node->getClassReflection(); + + if (!$classReflection->isClass()) { + return []; + } + + if (!$this->phpVersion->supportsPropertyHooks()) { + if ($node->hasHooks()) { + return [ + RuleErrorBuilder::message('Property hooks are supported only on PHP 8.4 and later.') + ->nonIgnorable() + ->identifier('property.hooksNotSupported') + ->build(), + ]; + } + + return []; + } + + if ($node->isAbstract()) { + if (!$node->hasHooks()) { + return [ + RuleErrorBuilder::message('Only hooked properties can be declared abstract.') + ->nonIgnorable() + ->identifier('property.abstractNonHooked') + ->build(), + ]; + } + + if (!$this->isAtLeastOneHookBodyEmpty($node)) { + return [ + RuleErrorBuilder::message('Abstract properties must specify at least one abstract hook.') + ->nonIgnorable() + ->identifier('property.abstractWithoutAbstractHook') + ->build(), + ]; + } + + if (!$classReflection->isAbstract()) { + return [ + RuleErrorBuilder::message('Non-abstract classes cannot include abstract properties.') + ->nonIgnorable() + ->identifier('property.abstract') + ->build(), + ]; + } + + return []; + } + + if (!$this->doAllHooksHaveBody($node)) { + return [ + RuleErrorBuilder::message('Non-abstract properties cannot include hooks without bodies.') + ->nonIgnorable() + ->identifier('property.hookWithoutBody') + ->build(), + ]; + } + + return []; + } + + private function doAllHooksHaveBody(ClassPropertyNode $node): bool + { + foreach ($node->getHooks() as $hook) { + if ($hook->body === null) { + return false; + } + } + + return true; + } + + private function isAtLeastOneHookBodyEmpty(ClassPropertyNode $node): bool + { + foreach ($node->getHooks() as $hook) { + if ($hook->body === null) { + return true; + } + } + + return false; + } + +} diff --git a/src/Rules/Properties/ReadWritePropertiesExtension.php b/src/Rules/Properties/ReadWritePropertiesExtension.php index 1b1c695ef9..804619781c 100644 --- a/src/Rules/Properties/ReadWritePropertiesExtension.php +++ b/src/Rules/Properties/ReadWritePropertiesExtension.php @@ -2,7 +2,7 @@ namespace PHPStan\Rules\Properties; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; /** * This is the extension interface to implement if you want to describe @@ -25,10 +25,10 @@ interface ReadWritePropertiesExtension { - public function isAlwaysRead(PropertyReflection $property, string $propertyName): bool; + public function isAlwaysRead(ExtendedPropertyReflection $property, string $propertyName): bool; - public function isAlwaysWritten(PropertyReflection $property, string $propertyName): bool; + public function isAlwaysWritten(ExtendedPropertyReflection $property, string $propertyName): bool; - public function isInitialized(PropertyReflection $property, string $propertyName): bool; + public function isInitialized(ExtendedPropertyReflection $property, string $propertyName): bool; } diff --git a/src/Rules/Properties/TypesAssignedToPropertiesRule.php b/src/Rules/Properties/TypesAssignedToPropertiesRule.php index bb2c2e83c0..f043cf3c3e 100644 --- a/src/Rules/Properties/TypesAssignedToPropertiesRule.php +++ b/src/Rules/Properties/TypesAssignedToPropertiesRule.php @@ -63,7 +63,7 @@ private function processSingleProperty( $scope = $propertyReflection->getScope(); $assignedValueType = $scope->getType($assignedExpr); - $accepts = $this->ruleLevelHelper->acceptsWithReason($propertyType, $assignedValueType, $scope->isDeclareStrictTypes()); + $accepts = $this->ruleLevelHelper->accepts($propertyType, $assignedValueType, $scope->isDeclareStrictTypes()); if (!$accepts->result) { $propertyDescription = $this->describePropertyByName($propertyReflection, $propertyReflection->getName()); $verbosityLevel = VerbosityLevel::getRecommendedLevelByType($propertyType, $assignedValueType); diff --git a/src/Rules/Pure/FunctionPurityCheck.php b/src/Rules/Pure/FunctionPurityCheck.php index e70d2eb292..13d0c1fc93 100644 --- a/src/Rules/Pure/FunctionPurityCheck.php +++ b/src/Rules/Pure/FunctionPurityCheck.php @@ -8,8 +8,8 @@ use PHPStan\Analyser\ImpurePoint; use PHPStan\Analyser\ThrowPoint; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Rules\Functions\CallToFunctionStatementWithoutSideEffectsRule; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleErrorBuilder; @@ -25,7 +25,7 @@ final class FunctionPurityCheck /** * @param 'Function'|'Method' $identifier - * @param ParameterReflectionWithPhpDocs[] $parameters + * @param ExtendedParameterReflection[] $parameters * @param ImpurePoint[] $impurePoints * @param ThrowPoint[] $throwPoints * @param Stmt[] $statements diff --git a/src/Rules/Rule.php b/src/Rules/Rule.php index f0ebf3be85..e42e6ccc52 100644 --- a/src/Rules/Rule.php +++ b/src/Rules/Rule.php @@ -32,7 +32,7 @@ public function getNodeType(): string; /** * @param TNodeType $node - * @return (string|RuleError)[] errors + * @return list */ public function processNode(Node $node, Scope $scope): array; diff --git a/src/Rules/RuleErrorBuilder.php b/src/Rules/RuleErrorBuilder.php index bf673c0fe8..cb714dfd2c 100644 --- a/src/Rules/RuleErrorBuilder.php +++ b/src/Rules/RuleErrorBuilder.php @@ -13,10 +13,9 @@ /** * @api - * @final * @template-covariant T of RuleError */ -class RuleErrorBuilder +final class RuleErrorBuilder { private const TYPE_MESSAGE = 1; diff --git a/src/Rules/RuleLevelHelper.php b/src/Rules/RuleLevelHelper.php index 71c348f7ec..9ad1805c77 100644 --- a/src/Rules/RuleLevelHelper.php +++ b/src/Rules/RuleLevelHelper.php @@ -15,16 +15,12 @@ use PHPStan\Type\NeverType; use PHPStan\Type\NullType; use PHPStan\Type\ObjectType; -use PHPStan\Type\ObjectWithoutClassType; -use PHPStan\Type\StaticType; use PHPStan\Type\StrictMixedType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\TypeTraverser; use PHPStan\Type\TypeUtils; use PHPStan\Type\UnionType; -use PHPStan\Type\VerbosityLevel; -use function array_merge; use function count; use function sprintf; @@ -38,7 +34,6 @@ public function __construct( private bool $checkUnionTypes, private bool $checkExplicitMixed, private bool $checkImplicitMixed, - private bool $newRuleLevelHelper, private bool $checkBenevolentUnionTypes, ) { @@ -50,12 +45,6 @@ public function isThis(Expr $expression): bool return $expression instanceof Expr\Variable && $expression->name === 'this'; } - /** @api */ - public function accepts(Type $acceptingType, Type $acceptedType, bool $strictTypes): bool - { - return $this->acceptsWithReason($acceptingType, $acceptedType, $strictTypes)->result; - } - private function transformCommonType(Type $type): Type { if (!$this->checkExplicitMixed && !$this->checkImplicitMixed) { @@ -64,10 +53,6 @@ private function transformCommonType(Type $type): Type return TypeTraverser::map($type, function (Type $type, callable $traverse) { if ($type instanceof TemplateMixedType) { - if (!$this->newRuleLevelHelper) { - return $type->toStrictMixedType(); - } - if ($this->checkExplicitMixed) { return $type->toStrictMixedType(); } @@ -106,6 +91,7 @@ private function transformAcceptedType(Type $acceptingType, Type $acceptedType): $acceptedType->getResolvedTemplateTypeMap(), $acceptedType->getTemplateTags(), $acceptedType->isPure(), + $acceptedType->isDeprecated(), ); } @@ -127,6 +113,7 @@ private function transformAcceptedType(Type $acceptingType, Type $acceptedType): $acceptedType->getInvalidateExpressions(), $acceptedType->getUsedVariables(), $acceptedType->acceptsNamedArguments(), + $acceptedType->isDeprecated(), ); } @@ -152,150 +139,13 @@ private function transformAcceptedType(Type $acceptingType, Type $acceptedType): return [$acceptedType, $checkForUnion]; } - public function acceptsWithReason(Type $acceptingType, Type $acceptedType, bool $strictTypes): RuleLevelHelperAcceptsResult + /** @api */ + public function accepts(Type $acceptingType, Type $acceptedType, bool $strictTypes): RuleLevelHelperAcceptsResult { - if ($this->newRuleLevelHelper) { - [$acceptedType, $checkForUnion] = $this->transformAcceptedType($acceptingType, $acceptedType); - $acceptingType = $this->transformCommonType($acceptingType); - - $accepts = $acceptingType->acceptsWithReason($acceptedType, $strictTypes); - - return new RuleLevelHelperAcceptsResult( - $checkForUnion ? $accepts->yes() : !$accepts->no(), - $accepts->reasons, - ); - } - - $checkForUnion = $this->checkUnionTypes; - - if ($this->checkBenevolentUnionTypes) { - $traverse = static function (Type $type, callable $traverse) use (&$checkForUnion): Type { - if ($type instanceof BenevolentUnionType) { - $checkForUnion = true; - return TypeUtils::toStrictUnion($type); - } - - return $traverse($type); - }; - - $acceptedType = TypeTraverser::map($acceptedType, $traverse); - } - - if ( - $this->checkExplicitMixed - ) { - $traverse = static function (Type $type, callable $traverse): Type { - if ($type instanceof TemplateMixedType) { - return $type->toStrictMixedType(); - } - if ( - $type instanceof MixedType - && $type->isExplicitMixed() - ) { - return new StrictMixedType(); - } - - return $traverse($type); - }; - $acceptingType = TypeTraverser::map($acceptingType, $traverse); - $acceptedType = TypeTraverser::map($acceptedType, $traverse); - } - - if ( - $this->checkImplicitMixed - ) { - $traverse = static function (Type $type, callable $traverse): Type { - if ($type instanceof TemplateMixedType) { - return $type->toStrictMixedType(); - } - if ( - $type instanceof MixedType - && !$type->isExplicitMixed() - ) { - return new StrictMixedType(); - } - - return $traverse($type); - }; - $acceptingType = TypeTraverser::map($acceptingType, $traverse); - $acceptedType = TypeTraverser::map($acceptedType, $traverse); - } - - if ( - !$this->checkNullables - && !$acceptingType instanceof NullType - && !$acceptedType instanceof NullType - && !$acceptedType instanceof BenevolentUnionType - ) { - $acceptedType = TypeCombinator::removeNull($acceptedType); - } - - $accepts = $acceptingType->acceptsWithReason($acceptedType, $strictTypes); - if ($accepts->yes()) { - return new RuleLevelHelperAcceptsResult(true, $accepts->reasons); - } - if ($acceptingType instanceof UnionType) { - $reasons = []; - foreach ($acceptingType->getTypes() as $innerType) { - $accepts = self::acceptsWithReason($innerType, $acceptedType, $strictTypes); - if ($accepts->result) { - return $accepts; - } - - $reasons = array_merge($reasons, $accepts->reasons); - } - - return new RuleLevelHelperAcceptsResult(false, $reasons); - } - - if ( - $acceptedType->isArray()->yes() - && $acceptingType->isArray()->yes() - && ( - $acceptedType->isConstantArray()->no() - || !$acceptedType->isIterableAtLeastOnce()->no() - ) - && $acceptingType->isConstantArray()->no() - ) { - if ($acceptingType->isIterableAtLeastOnce()->yes() && !$acceptedType->isIterableAtLeastOnce()->yes()) { - $verbosity = VerbosityLevel::getRecommendedLevelByType($acceptingType, $acceptedType); - return new RuleLevelHelperAcceptsResult(false, [ - sprintf( - '%s %s empty.', - $acceptedType->describe($verbosity), - $acceptedType->isIterableAtLeastOnce()->no() ? 'is' : 'might be', - ), - ]); - } - - if ( - $acceptingType->isList()->yes() - && !$acceptedType->isList()->yes() - ) { - $report = $checkForUnion || $acceptedType->isList()->no(); - - if ($report) { - $verbosity = VerbosityLevel::getRecommendedLevelByType($acceptingType, $acceptedType); - return new RuleLevelHelperAcceptsResult(false, [ - sprintf( - '%s %s a list.', - $acceptedType->describe($verbosity), - $acceptedType->isList()->no() ? 'is not' : 'might not be', - ), - ]); - } - } + [$acceptedType, $checkForUnion] = $this->transformAcceptedType($acceptingType, $acceptedType); + $acceptingType = $this->transformCommonType($acceptingType); - return self::acceptsWithReason( - $acceptingType->getIterableKeyType(), - $acceptedType->getIterableKeyType(), - $strictTypes, - )->and(self::acceptsWithReason( - $acceptingType->getIterableValueType(), - $acceptedType->getIterableValueType(), - $strictTypes, - )); - } + $accepts = $acceptingType->accepts($acceptedType, $strictTypes); return new RuleLevelHelperAcceptsResult( $checkForUnion ? $accepts->yes() : !$accepts->no(), @@ -336,49 +186,24 @@ private function findTypeToCheckImplementation( $type = TypeCombinator::removeNull($type); } - if ($this->newRuleLevelHelper) { - if ( - ($this->checkExplicitMixed || $this->checkImplicitMixed) - && $type instanceof MixedType - && ($type->isExplicitMixed() ? $this->checkExplicitMixed : $this->checkImplicitMixed) - ) { - return new FoundTypeResult( - $type instanceof TemplateMixedType - ? $type->toStrictMixedType() - : new StrictMixedType(), - [], - [], - null, - ); - } - } else { - if ( - $this->checkExplicitMixed - && $type instanceof MixedType - && !$type instanceof TemplateMixedType - && $type->isExplicitMixed() - ) { - return new FoundTypeResult(new StrictMixedType(), [], [], null); - } - - if ( - $this->checkImplicitMixed - && $type instanceof MixedType - && !$type instanceof TemplateMixedType - && !$type->isExplicitMixed() - ) { - return new FoundTypeResult(new StrictMixedType(), [], [], null); - } + if ( + ($this->checkExplicitMixed || $this->checkImplicitMixed) + && $type instanceof MixedType + && ($type->isExplicitMixed() ? $this->checkExplicitMixed : $this->checkImplicitMixed) + ) { + return new FoundTypeResult( + $type instanceof TemplateMixedType + ? $type->toStrictMixedType() + : new StrictMixedType(), + [], + [], + null, + ); } if ($type instanceof MixedType || $type instanceof NeverType) { return new FoundTypeResult(new ErrorType(), [], [], null); } - if (!$this->newRuleLevelHelper) { - if ($isTopLevel && $type instanceof StaticType) { - $type = $type->getStaticObjectType(); - } - } $errors = []; $hasClassExistsClass = false; @@ -411,88 +236,69 @@ private function findTypeToCheckImplementation( return new FoundTypeResult(new ErrorType(), [], $errors, null); } - if (!$this->checkUnionTypes && $type instanceof ObjectWithoutClassType) { + if (!$this->checkUnionTypes && $type->isObject()->yes() && count($type->getObjectClassNames()) === 0) { return new FoundTypeResult(new ErrorType(), [], [], null); } - if ($this->newRuleLevelHelper) { - if ($type instanceof UnionType) { - $shouldFilterUnion = ( - !$this->checkUnionTypes - && !$type instanceof BenevolentUnionType - ) || ( - !$this->checkBenevolentUnionTypes - && $type instanceof BenevolentUnionType - ); - - $newTypes = []; + if ($type instanceof UnionType) { + $shouldFilterUnion = ( + !$this->checkUnionTypes + && !$type instanceof BenevolentUnionType + ) || ( + !$this->checkBenevolentUnionTypes + && $type instanceof BenevolentUnionType + ); - foreach ($type->getTypes() as $innerType) { - if ($shouldFilterUnion && !$unionTypeCriteriaCallback($innerType)) { - continue; - } + $newTypes = []; - $newTypes[] = $this->findTypeToCheckImplementation( - $scope, - $var, - $innerType, - $unknownClassErrorPattern, - $unionTypeCriteriaCallback, - )->getType(); + foreach ($type->getTypes() as $innerType) { + if ($shouldFilterUnion && !$unionTypeCriteriaCallback($innerType)) { + continue; } - if (count($newTypes) > 0) { - $newUnion = TypeCombinator::union(...$newTypes); - if ( - !$this->checkBenevolentUnionTypes - && $type instanceof BenevolentUnionType - ) { - $newUnion = TypeUtils::toBenevolentUnion($newUnion); - } + $newTypes[] = $this->findTypeToCheckImplementation( + $scope, + $var, + $innerType, + $unknownClassErrorPattern, + $unionTypeCriteriaCallback, + )->getType(); + } - return new FoundTypeResult($newUnion, $directClassNames, [], null); + if (count($newTypes) > 0) { + $newUnion = TypeCombinator::union(...$newTypes); + if ( + !$this->checkBenevolentUnionTypes + && $type instanceof BenevolentUnionType + ) { + $newUnion = TypeUtils::toBenevolentUnion($newUnion); } + + return new FoundTypeResult($newUnion, $directClassNames, [], null); } + } - if ($type instanceof IntersectionType) { - $newTypes = []; + if ($type instanceof IntersectionType) { + $newTypes = []; - foreach ($type->getTypes() as $innerType) { + $changed = false; + foreach ($type->getTypes() as $innerType) { + if ($innerType instanceof TemplateMixedType) { + $changed = true; $newTypes[] = $this->findTypeToCheckImplementation( $scope, $var, - $innerType, + $innerType->toStrictMixedType(), $unknownClassErrorPattern, $unionTypeCriteriaCallback, )->getType(); + continue; } - - return new FoundTypeResult(TypeCombinator::intersect(...$newTypes), $directClassNames, [], null); + $newTypes[] = $innerType; } - } else { - if ( - ( - !$this->checkUnionTypes - && $type instanceof UnionType - && !$type instanceof BenevolentUnionType - ) || ( - !$this->checkBenevolentUnionTypes - && $type instanceof BenevolentUnionType - ) - ) { - $newTypes = []; - foreach ($type->getTypes() as $innerType) { - if (!$unionTypeCriteriaCallback($innerType)) { - continue; - } - - $newTypes[] = $innerType; - } - - if (count($newTypes) > 0) { - return new FoundTypeResult(TypeCombinator::union(...$newTypes), $directClassNames, [], null); - } + if ($changed) { + return new FoundTypeResult(TypeCombinator::intersect(...$newTypes), $directClassNames, [], null); } } diff --git a/src/Rules/RuleLevelHelperAcceptsResult.php b/src/Rules/RuleLevelHelperAcceptsResult.php index e33db8f0da..1b421c60a4 100644 --- a/src/Rules/RuleLevelHelperAcceptsResult.php +++ b/src/Rules/RuleLevelHelperAcceptsResult.php @@ -4,6 +4,9 @@ use function array_merge; +/** + * @api + */ final class RuleLevelHelperAcceptsResult { diff --git a/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php b/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php index 92084ea3a0..1c40c4a9ce 100644 --- a/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php +++ b/src/Rules/TooWideTypehints/TooWideMethodReturnTypehintRule.php @@ -22,7 +22,7 @@ final class TooWideMethodReturnTypehintRule implements Rule { - public function __construct(private bool $checkProtectedAndPublicMethods, private bool $alwaysCheckFinal) + public function __construct(private bool $checkProtectedAndPublicMethods) { } @@ -39,20 +39,14 @@ public function processNode(Node $node, Scope $scope): array $method = $node->getMethodReflection(); $isFirstDeclaration = $method->getPrototype()->getDeclaringClass() === $method->getDeclaringClass(); if (!$method->isPrivate()) { - if ($this->alwaysCheckFinal) { - if (!$method->getDeclaringClass()->isFinal() && !$method->isFinal()->yes()) { - if (!$this->checkProtectedAndPublicMethods) { - return []; - } + if (!$method->getDeclaringClass()->isFinal() && !$method->isFinal()->yes()) { + if (!$this->checkProtectedAndPublicMethods) { + return []; + } - if ($isFirstDeclaration) { - return []; - } + if ($isFirstDeclaration) { + return []; } - } elseif (!$this->checkProtectedAndPublicMethods) { - return []; - } elseif ($isFirstDeclaration && !$method->getDeclaringClass()->isFinal() && !$method->isFinal()->yes()) { - return []; } } diff --git a/src/Rules/TooWideTypehints/TooWideParameterOutTypeCheck.php b/src/Rules/TooWideTypehints/TooWideParameterOutTypeCheck.php index ceeb071238..e891b65fb6 100644 --- a/src/Rules/TooWideTypehints/TooWideParameterOutTypeCheck.php +++ b/src/Rules/TooWideTypehints/TooWideParameterOutTypeCheck.php @@ -6,7 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\ExecutionEndNode; use PHPStan\Node\ReturnStatement; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\TypeUtils; @@ -20,7 +20,7 @@ final class TooWideParameterOutTypeCheck /** * @param list $executionEnds * @param list $returnStatements - * @param ParameterReflectionWithPhpDocs[] $parameters + * @param ExtendedParameterReflection[] $parameters * @return list */ public function check( @@ -74,7 +74,7 @@ public function check( private function processSingleParameter( Scope $scope, string $functionDescription, - ParameterReflectionWithPhpDocs $parameter, + ExtendedParameterReflection $parameter, ): array { $isParamOutType = true; diff --git a/src/Rules/Traits/ConflictingTraitConstantsRule.php b/src/Rules/Traits/ConflictingTraitConstantsRule.php index 4dd23f32bd..4e38e44bcb 100644 --- a/src/Rules/Traits/ConflictingTraitConstantsRule.php +++ b/src/Rules/Traits/ConflictingTraitConstantsRule.php @@ -8,6 +8,7 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\InitializerExprContext; use PHPStan\Reflection\InitializerExprTypeResolver; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -22,7 +23,10 @@ final class ConflictingTraitConstantsRule implements Rule { - public function __construct(private InitializerExprTypeResolver $initializerExprTypeResolver) + public function __construct( + private InitializerExprTypeResolver $initializerExprTypeResolver, + private ReflectionProvider $reflectionProvider, + ) { } @@ -186,7 +190,7 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect ->build(); } } elseif ($constantNativeType === null) { - $traitNativeTypeType = TypehintHelper::decideTypeFromReflection($traitNativeType, null, $traitDeclaringClass->getName()); + $traitNativeTypeType = TypehintHelper::decideTypeFromReflection($traitNativeType, null, $this->reflectionProvider->getClass($traitDeclaringClass->getName())); $errors[] = RuleErrorBuilder::message(sprintf( 'Constant %s::%s overriding constant %s::%s (%s) should also have native type %s.', $classReflection->getDisplayName(), @@ -200,7 +204,7 @@ private function processSingleConstant(ClassReflection $classReflection, Reflect ->identifier('classConstant.missingNativeType') ->build(); } else { - $traitNativeTypeType = TypehintHelper::decideTypeFromReflection($traitNativeType, null, $traitDeclaringClass->getName()); + $traitNativeTypeType = TypehintHelper::decideTypeFromReflection($traitNativeType, null, $this->reflectionProvider->getClass($traitDeclaringClass->getName())); $constantNativeTypeType = ParserNodeTypeToPHPStanType::resolve($constantNativeType, $classReflection); if (!$traitNativeTypeType->equals($constantNativeTypeType)) { $errors[] = RuleErrorBuilder::message(sprintf( diff --git a/src/Rules/Traits/TraitAttributesRule.php b/src/Rules/Traits/TraitAttributesRule.php new file mode 100644 index 0000000000..2b9fa768d0 --- /dev/null +++ b/src/Rules/Traits/TraitAttributesRule.php @@ -0,0 +1,51 @@ + + */ +final class TraitAttributesRule implements Rule +{ + + public function __construct( + private AttributesCheck $attributesCheck, + ) + { + } + + public function getNodeType(): string + { + return InTraitNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $originalNode = $node->getOriginalNode(); + $errors = $this->attributesCheck->check( + $scope, + $originalNode->attrGroups, + Attribute::TARGET_CLASS, + 'class', + ); + + if (count($node->getTraitReflection()->getNativeReflection()->getAttributes('AllowDynamicProperties')) > 0) { + $errors[] = RuleErrorBuilder::message('Attribute class AllowDynamicProperties cannot be used with trait.') + ->identifier('trait.allowDynamicProperties') + ->nonIgnorable() + ->build(); + } + + return $errors; + } + +} diff --git a/src/Rules/Types/InvalidTypesInUnionRule.php b/src/Rules/Types/InvalidTypesInUnionRule.php index ba53111760..39379b6663 100644 --- a/src/Rules/Types/InvalidTypesInUnionRule.php +++ b/src/Rules/Types/InvalidTypesInUnionRule.php @@ -69,11 +69,11 @@ private function processFunctionLikeNode(Node\FunctionLike $functionLike): array */ private function processClassPropertyNode(ClassPropertyNode $classPropertyNode): array { - if (!$classPropertyNode->getNativeType() instanceof Node\ComplexType) { + if (!$classPropertyNode->getNativeTypeNode() instanceof Node\ComplexType) { return []; } - return $this->processComplexType($classPropertyNode->getNativeType()); + return $this->processComplexType($classPropertyNode->getNativeTypeNode()); } /** diff --git a/src/Rules/UnusedFunctionParametersCheck.php b/src/Rules/UnusedFunctionParametersCheck.php index b85150e267..628041a032 100644 --- a/src/Rules/UnusedFunctionParametersCheck.php +++ b/src/Rules/UnusedFunctionParametersCheck.php @@ -3,11 +3,13 @@ namespace PHPStan\Rules; use PhpParser\Node; +use PhpParser\Node\Expr\Variable; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; +use PHPStan\ShouldNotHappenException; use PHPStan\Type\Constant\ConstantStringType; -use function array_fill_keys; -use function array_keys; +use function array_combine; +use function array_map; use function array_merge; use function is_array; use function is_string; @@ -16,25 +18,34 @@ final class UnusedFunctionParametersCheck { - public function __construct(private ReflectionProvider $reflectionProvider) + public function __construct( + private ReflectionProvider $reflectionProvider, + private bool $reportExactLine, + ) { } /** - * @param string[] $parameterNames + * @param Variable[] $parameterVars * @param Node[] $statements * @param 'constructor.unusedParameter'|'closure.unusedUse' $identifier * @return list */ public function getUnusedParameters( Scope $scope, - array $parameterNames, + array $parameterVars, array $statements, string $unusedParameterMessage, string $identifier, ): array { - $unusedParameters = array_fill_keys($parameterNames, true); + $parameterNames = array_map(static function (Variable $variable): string { + if (!is_string($variable->name)) { + throw new ShouldNotHappenException(); + } + return $variable->name; + }, $parameterVars); + $unusedParameters = array_combine($parameterNames, $parameterVars); foreach ($this->getUsedVariables($scope, $statements) as $variableName) { if (!isset($unusedParameters[$variableName])) { continue; @@ -43,10 +54,12 @@ public function getUnusedParameters( unset($unusedParameters[$variableName]); } $errors = []; - foreach (array_keys($unusedParameters) as $name) { - $errors[] = RuleErrorBuilder::message( - sprintf($unusedParameterMessage, $name), - )->identifier($identifier)->build(); + foreach ($unusedParameters as $name => $variable) { + $errorBuilder = RuleErrorBuilder::message(sprintf($unusedParameterMessage, $name))->identifier($identifier); + if ($this->reportExactLine) { + $errorBuilder->line($variable->getStartLine()); + } + $errors[] = $errorBuilder->build(); } return $errors; @@ -66,10 +79,10 @@ private function getUsedVariables(Scope $scope, $node): array return $scope->getDefinedVariables(); } } - if ($node instanceof Node\Expr\Variable && is_string($node->name) && $node->name !== 'this') { + if ($node instanceof 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/Rules/Variables/ParameterOutExecutionEndTypeRule.php b/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php index b87573b8ff..d8337c97a0 100644 --- a/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php +++ b/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php @@ -7,8 +7,8 @@ use PHPStan\Node\ExecutionEndNode; use PHPStan\Node\Expr\ParameterVariableOriginalValueExpr; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Reflection\ParameterReflectionWithPhpDocs; use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; @@ -56,9 +56,6 @@ public function processNode(Node $node, Scope $scope): array return []; } } - if ($endNode instanceof Node\Stmt\Throw_) { - return []; - } $parameters = $inFunction->getParameters(); $errors = []; @@ -81,7 +78,7 @@ public function processNode(Node $node, Scope $scope): array private function processSingleParameter( Scope $scope, FunctionReflection|ExtendedMethodReflection $inFunction, - ParameterReflectionWithPhpDocs $parameter, + ExtendedParameterReflection $parameter, ): array { $outType = $parameter->getOutType(); 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/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; } /** diff --git a/src/Testing/LevelsTestCase.php b/src/Testing/LevelsTestCase.php index 7d0b1998a9..499277dc8b 100644 --- a/src/Testing/LevelsTestCase.php +++ b/src/Testing/LevelsTestCase.php @@ -30,7 +30,7 @@ abstract class LevelsTestCase extends TestCase /** * @return array> */ - abstract public function dataTopics(): array; + abstract public static function dataTopics(): array; abstract public function getDataPath(): string; @@ -71,7 +71,7 @@ public function testLevels( putenv('__PHPSTAN_FORCE_VALIDATE_STUB_FILES=1'); - foreach (range(0, 9) as $level) { + foreach (range(0, 10) as $level) { unset($outputLines); exec(sprintf('%s %s analyse --no-progress --error-format=prettyJson --level=%d %s %s %s', escapeshellarg(PHP_BINARY), $command, $level, $configPath !== null ? '--configuration ' . escapeshellarg($configPath) : '', $this->shouldAutoloadAnalysedFile() ? sprintf('--autoload-file %s', escapeshellarg($file)) : '', escapeshellarg($file)), $outputLines); diff --git a/src/Testing/PHPStanTestCase.php b/src/Testing/PHPStanTestCase.php index 8f9fdfd44f..849fbfac11 100644 --- a/src/Testing/PHPStanTestCase.php +++ b/src/Testing/PHPStanTestCase.php @@ -5,16 +5,11 @@ use PHPStan\Analyser\ConstantResolver; use PHPStan\Analyser\DirectInternalScopeFactory; use PHPStan\Analyser\Error; -use PHPStan\Analyser\MutatingScope; use PHPStan\Analyser\NodeScopeResolver; use PHPStan\Analyser\RicherScopeGetTypeHelper; use PHPStan\Analyser\ScopeFactory; use PHPStan\Analyser\TypeSpecifier; -use PHPStan\BetterReflection\Reflector\ClassReflector; -use PHPStan\BetterReflection\Reflector\ConstantReflector; -use PHPStan\BetterReflection\Reflector\FunctionReflector; use PHPStan\BetterReflection\Reflector\Reflector; -use PHPStan\Broker\Broker; use PHPStan\DependencyInjection\Container; use PHPStan\DependencyInjection\ContainerFactory; use PHPStan\DependencyInjection\Reflection\ClassReflectionExtensionRegistryProvider; @@ -26,6 +21,7 @@ use PHPStan\Internal\DirectoryCreatorException; use PHPStan\Node\Printer\ExprPrinter; use PHPStan\Parser\Parser; +use PHPStan\Php\ComposerPhpVersionFactory; use PHPStan\Php\PhpVersion; use PHPStan\PhpDoc\TypeNodeResolver; use PHPStan\PhpDoc\TypeStringResolver; @@ -52,9 +48,6 @@ abstract class PHPStanTestCase extends TestCase { - /** @deprecated */ - public static bool $useStaticReflectionProvider = true; - /** @var array */ private static array $containers = []; @@ -117,15 +110,6 @@ public static function getParser(): Parser return $parser; } - /** - * @api - * @deprecated Use createReflectionProvider() instead - */ - public function createBroker(): Broker - { - return self::getContainer()->getByType(Broker::class); - } - /** @api */ public static function createReflectionProvider(): ReflectionProvider { @@ -137,19 +121,6 @@ public static function getReflector(): Reflector return self::getContainer()->getService('betterReflectionReflector'); } - /** - * @deprecated Use getReflector() instead. - * @return array{ClassReflector, FunctionReflector, ConstantReflector} - */ - public static function getReflectors(): array - { - return [ - self::getContainer()->getService('betterReflectionClassReflector'), - self::getContainer()->getService('betterReflectionFunctionReflector'), - self::getContainer()->getService('betterReflectionConstantReflector'), - ]; - } - public static function getClassReflectionExtensionRegistryProvider(): ClassReflectionExtensionRegistryProvider { return self::getContainer()->getByType(ClassReflectionExtensionRegistryProvider::class); @@ -167,7 +138,8 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider } $reflectionProviderProvider = new DirectReflectionProviderProvider($reflectionProvider); - $constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames); + $composerPhpVersionFactory = $container->getByType(ComposerPhpVersionFactory::class); + $constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames, null, $composerPhpVersionFactory); $initializerExprTypeResolver = new InitializerExprTypeResolver( $constantResolver, @@ -180,7 +152,6 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider return new ScopeFactory( new DirectInternalScopeFactory( - MutatingScope::class, $reflectionProvider, $initializerExprTypeResolver, $container->getByType(DynamicReturnTypeExtensionRegistryProvider::class), @@ -192,8 +163,7 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider $container->getByType(NodeScopeResolver::class), new RicherScopeGetTypeHelper($initializerExprTypeResolver), $container->getByType(PhpVersion::class), - $container->getParameter('featureToggles')['explicitMixedInUnknownGenericNew'], - $container->getParameter('featureToggles')['explicitMixedForGlobalVariables'], + $container->getParameter('phpVersion'), $constantResolver, ), ); diff --git a/src/Testing/RuleTestCase.php b/src/Testing/RuleTestCase.php index b3ff058c11..8018b44181 100644 --- a/src/Testing/RuleTestCase.php +++ b/src/Testing/RuleTestCase.php @@ -99,15 +99,12 @@ private function getAnalyser(DirectRuleRegistry $ruleRegistry): Analyser self::createScopeFactory($reflectionProvider, $typeSpecifier), $this->shouldPolluteScopeWithLoopInitialAssignments(), $this->shouldPolluteScopeWithAlwaysIterableForeach(), + self::getContainer()->getParameter('polluteScopeWithBlock'), [], [], self::getContainer()->getParameter('universalObjectCratesClasses'), self::getContainer()->getParameter('exceptions')['implicitThrows'], $this->shouldTreatPhpDocTypesAsCertain(), - self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch'], - self::getContainer()->getParameter('featureToggles')['paramOutType'], - self::getContainer()->getParameter('featureToggles')['preciseMissingReturn'], - self::getContainer()->getParameter('featureToggles')['explicitThrow'], ); $fileAnalyser = new FileAnalyser( $this->createScopeFactory($reflectionProvider, $typeSpecifier), diff --git a/src/Testing/TestCase.neon b/src/Testing/TestCase.neon index cfa21959b9..c5ef275d1f 100644 --- a/src/Testing/TestCase.neon +++ b/src/Testing/TestCase.neon @@ -1,7 +1,5 @@ parameters: inferPrivatePropertyTypeFromConstructor: true - featureToggles: - checkUnresolvableParameterTypes: true services: - @@ -10,7 +8,6 @@ services: phpParser: @phpParserDecorator php8Parser: @php8PhpParser fileExtensions: %fileExtensions% - obsoleteExcludesAnalyse: %excludes_analyse% excludePaths: %excludePaths% cacheStorage: diff --git a/src/Testing/TestCaseSourceLocatorFactory.php b/src/Testing/TestCaseSourceLocatorFactory.php index a4921c9201..724380955e 100644 --- a/src/Testing/TestCaseSourceLocatorFactory.php +++ b/src/Testing/TestCaseSourceLocatorFactory.php @@ -31,7 +31,6 @@ final class TestCaseSourceLocatorFactory /** * @param string[] $fileExtensions - * @param string[] $obsoleteExcludesAnalyse * @param array{analyse?: array, analyseAndScan?: array}|null $excludePaths */ public function __construct( @@ -43,7 +42,6 @@ public function __construct( private ReflectionSourceStubber $reflectionSourceStubber, private PhpVersion $phpVersion, private array $fileExtensions, - private array $obsoleteExcludesAnalyse, private ?array $excludePaths, ) { @@ -56,7 +54,6 @@ public function create(): SourceLocator $cacheKey = sha1(serialize([ $this->phpVersion->getVersionId(), $this->fileExtensions, - $this->obsoleteExcludesAnalyse, $this->excludePaths, ])); if ($classLoaderReflection->hasProperty('vendorDir') && ! isset(self::$composerSourceLocatorsCache[$cacheKey])) { diff --git a/src/Testing/TypeInferenceTestCase.php b/src/Testing/TypeInferenceTestCase.php index 2b8d8e855c..614db4f0c5 100644 --- a/src/Testing/TypeInferenceTestCase.php +++ b/src/Testing/TypeInferenceTestCase.php @@ -79,15 +79,12 @@ public static function processFile( self::createScopeFactory($reflectionProvider, $typeSpecifier), self::getContainer()->getParameter('polluteScopeWithLoopInitialAssignments'), self::getContainer()->getParameter('polluteScopeWithAlwaysIterableForeach'), + self::getContainer()->getParameter('polluteScopeWithBlock'), static::getEarlyTerminatingMethodCalls(), static::getEarlyTerminatingFunctionCalls(), self::getContainer()->getParameter('universalObjectCratesClasses'), self::getContainer()->getParameter('exceptions')['implicitThrows'], self::getContainer()->getParameter('treatPhpDocTypesAsCertain'), - self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch'], - self::getContainer()->getParameter('featureToggles')['paramOutType'], - self::getContainer()->getParameter('featureToggles')['preciseMissingReturn'], - self::getContainer()->getParameter('featureToggles')['explicitThrow'], ); $resolver->setAnalysedFiles(array_map(static fn (string $file): string => $fileHelper->normalizePath($file), array_merge([$file], static::getAdditionalAnalysedFiles()))); @@ -178,7 +175,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 +187,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/TrinaryLogic.php b/src/TrinaryLogic.php index 7e387901e0..a587099844 100644 --- a/src/TrinaryLogic.php +++ b/src/TrinaryLogic.php @@ -10,10 +10,9 @@ /** * @api - * @final * @see https://phpstan.org/developing-extensions/trinary-logic */ -class TrinaryLogic +final class TrinaryLogic { private const YES = 1; @@ -252,12 +251,4 @@ public function describe(): string return $labels[$this->value]; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return self::create($properties['value']); - } - } diff --git a/src/Type/AcceptsResult.php b/src/Type/AcceptsResult.php index 2548f3dd44..2358285f16 100644 --- a/src/Type/AcceptsResult.php +++ b/src/Type/AcceptsResult.php @@ -11,9 +11,8 @@ /** * @api - * @final */ -class AcceptsResult +final class AcceptsResult { /** diff --git a/src/Type/Accessory/AccessoryArrayListType.php b/src/Type/Accessory/AccessoryArrayListType.php index c2eea34349..750466a271 100644 --- a/src/Type/Accessory/AccessoryArrayListType.php +++ b/src/Type/Accessory/AccessoryArrayListType.php @@ -40,8 +40,7 @@ class AccessoryArrayListType implements CompoundType, AccessoryType use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - private static bool $enabled = false; - + /** @api */ public function __construct() { } @@ -76,15 +75,10 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } $isArray = $type->isArray(); @@ -93,47 +87,32 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return new AcceptsResult($isArray->and($isList), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($this->equals($type)) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return new IsSuperTypeOfResult($type->isArray()->and($type->isList()), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isArray()->and($otherType->isList()), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -158,7 +137,7 @@ public function isOffsetAccessLegal(): TrinaryLogic public function hasOffsetValueType(Type $offsetType): TrinaryLogic { - return $this->getIterableKeyType()->isSuperTypeOf($offsetType)->and(TrinaryLogic::createMaybe()); + return $this->getIterableKeyType()->isSuperTypeOf($offsetType)->result->and(TrinaryLogic::createMaybe()); } public function getOffsetValueType(Type $offsetType): Type @@ -414,12 +393,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -500,30 +479,6 @@ public function traverseSimultaneously(Type $right, callable $cb): Type return $this; } - public static function __set_state(array $properties): Type - { - return new self(); - } - - public static function setListTypeEnabled(bool $enabled): void - { - self::$enabled = $enabled; - } - - public static function isListTypeEnabled(): bool - { - return self::$enabled; - } - - public static function intersectWith(Type $type): Type - { - if (self::$enabled) { - return TypeCombinator::intersect($type, new self()); - } - - return $type; - } - public function exponentiate(Type $exponent): Type { return new ErrorType(); diff --git a/src/Type/Accessory/AccessoryLiteralStringType.php b/src/Type/Accessory/AccessoryLiteralStringType.php index d0970ba346..967c58d690 100644 --- a/src/Type/Accessory/AccessoryLiteralStringType.php +++ b/src/Type/Accessory/AccessoryLiteralStringType.php @@ -68,32 +68,22 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof MixedType) { return AcceptsResult::createNo(); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isLiteralString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($this->equals($type)) { @@ -103,29 +93,19 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isLiteralString(), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isLiteralString(), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -313,12 +293,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -368,11 +348,6 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function exponentiate(Type $exponent): Type { return new BenevolentUnionType([ diff --git a/src/Type/Accessory/AccessoryLowercaseStringType.php b/src/Type/Accessory/AccessoryLowercaseStringType.php index 672998fdb8..c4b8b0b364 100644 --- a/src/Type/Accessory/AccessoryLowercaseStringType.php +++ b/src/Type/Accessory/AccessoryLowercaseStringType.php @@ -67,29 +67,19 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isLowercaseString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($this->equals($type)) { @@ -99,29 +89,19 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isLowercaseString(), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isLowercaseString(), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -309,12 +289,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createYes(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -364,11 +344,6 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function exponentiate(Type $exponent): Type { return new BenevolentUnionType([ diff --git a/src/Type/Accessory/AccessoryNonEmptyStringType.php b/src/Type/Accessory/AccessoryNonEmptyStringType.php index 117779e376..08f4790001 100644 --- a/src/Type/Accessory/AccessoryNonEmptyStringType.php +++ b/src/Type/Accessory/AccessoryNonEmptyStringType.php @@ -69,29 +69,19 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isNonEmptyString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($this->equals($type)) { @@ -105,29 +95,19 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isNonEmptyString(), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isNonEmptyString(), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -310,12 +290,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -360,11 +340,6 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function tryRemove(Type $typeToRemove): ?Type { if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') { diff --git a/src/Type/Accessory/AccessoryNonFalsyStringType.php b/src/Type/Accessory/AccessoryNonFalsyStringType.php index 4bfb46f436..04fd4fb60e 100644 --- a/src/Type/Accessory/AccessoryNonFalsyStringType.php +++ b/src/Type/Accessory/AccessoryNonFalsyStringType.php @@ -69,29 +69,19 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isNonFalsyString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($this->equals($type)) { @@ -101,15 +91,10 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isNonFalsyString(), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } if ($otherType instanceof AccessoryNonEmptyStringType) { @@ -120,14 +105,9 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -310,12 +290,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -360,11 +340,6 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function exponentiate(Type $exponent): Type { return new BenevolentUnionType([ diff --git a/src/Type/Accessory/AccessoryNumericStringType.php b/src/Type/Accessory/AccessoryNumericStringType.php index 79c83c7b0f..e0f4964c93 100644 --- a/src/Type/Accessory/AccessoryNumericStringType.php +++ b/src/Type/Accessory/AccessoryNumericStringType.php @@ -68,29 +68,19 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isNumericString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($this->equals($type)) { @@ -100,27 +90,17 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isNumericString(), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isNumericString(), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { if ($acceptingType->isNonFalsyString()->yes()) { return AcceptsResult::createMaybe(); @@ -130,7 +110,7 @@ public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): return AcceptsResult::createYes(); } - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -317,7 +297,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -362,11 +342,6 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function tryRemove(Type $typeToRemove): ?Type { if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') { diff --git a/src/Type/Accessory/AccessoryUppercaseStringType.php b/src/Type/Accessory/AccessoryUppercaseStringType.php index 3ce287d614..f9ae03d0ac 100644 --- a/src/Type/Accessory/AccessoryUppercaseStringType.php +++ b/src/Type/Accessory/AccessoryUppercaseStringType.php @@ -67,29 +67,19 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isUppercaseString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($this->equals($type)) { @@ -99,29 +89,19 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isUppercaseString(), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isUppercaseString(), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -314,7 +294,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createYes(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -364,11 +344,6 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function exponentiate(Type $exponent): Type { return new BenevolentUnionType([ diff --git a/src/Type/Accessory/HasMethodType.php b/src/Type/Accessory/HasMethodType.php index 1ced070eb5..94364bb21f 100644 --- a/src/Type/Accessory/HasMethodType.php +++ b/src/Type/Accessory/HasMethodType.php @@ -62,39 +62,24 @@ private function getCanonicalMethodName(): string return strtolower($this->methodName); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createFromBoolean($this->equals($type)); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { return new IsSuperTypeOfResult($type->hasMethod($this->methodName), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } if ($this->isCallable()->yes() && $otherType->isCallable()->yes()) { @@ -110,14 +95,9 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult return $limit->and(new IsSuperTypeOfResult($otherType->hasMethod($this->methodName), [])); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -211,11 +191,6 @@ public function getFiniteTypes(): array return []; } - public static function __set_state(array $properties): Type - { - return new self($properties['methodName']); - } - public function toPhpDocNode(): TypeNode { return new IdentifierTypeNode(''); // no PHPDoc representation diff --git a/src/Type/Accessory/HasOffsetType.php b/src/Type/Accessory/HasOffsetType.php index 23650ed8d3..492bd1ba27 100644 --- a/src/Type/Accessory/HasOffsetType.php +++ b/src/Type/Accessory/HasOffsetType.php @@ -47,9 +47,8 @@ class HasOffsetType implements CompoundType, AccessoryType /** * @api - * @param ConstantStringType|ConstantIntegerType $offsetType */ - public function __construct(private Type $offsetType) + public function __construct(private ConstantStringType|ConstantIntegerType $offsetType) { } @@ -81,26 +80,16 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isOffsetAccessible()->and($type->hasOffsetValueType($this->offsetType)), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($this->equals($type)) { return IsSuperTypeOfResult::createYes(); @@ -108,15 +97,10 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return new IsSuperTypeOfResult($type->isOffsetAccessible()->and($type->hasOffsetValueType($this->offsetType)), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } $result = new IsSuperTypeOfResult($otherType->isOffsetAccessible()->and($otherType->hasOffsetValueType($this->offsetType)), []); @@ -125,14 +109,9 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -329,12 +308,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -434,11 +413,6 @@ public function getFiniteTypes(): array return []; } - public static function __set_state(array $properties): Type - { - return new self($properties['offsetType']); - } - public function toPhpDocNode(): TypeNode { return new IdentifierTypeNode(''); // no PHPDoc representation diff --git a/src/Type/Accessory/HasOffsetValueType.php b/src/Type/Accessory/HasOffsetValueType.php index b673a3e7eb..296c5b7308 100644 --- a/src/Type/Accessory/HasOffsetValueType.php +++ b/src/Type/Accessory/HasOffsetValueType.php @@ -81,28 +81,21 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } - $result = new AcceptsResult($type->isOffsetAccessible()->and($type->hasOffsetValueType($this->offsetType)), []); - - return $result->and($this->valueType->acceptsWithReason($type->getOffsetValueType($this->offsetType), $strictTypes)); + return new AcceptsResult( + $type->isOffsetAccessible() + ->and($type->hasOffsetValueType($this->offsetType)) + ->and($this->valueType->accepts($type->getOffsetValueType($this->offsetType), $strictTypes)->result), + [], + ); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($this->equals($type)) { return IsSuperTypeOfResult::createYes(); @@ -111,35 +104,25 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult $result = new IsSuperTypeOfResult($type->isOffsetAccessible()->and($type->hasOffsetValueType($this->offsetType)), []); return $result - ->and($this->valueType->isSuperTypeOfWithReason($type->getOffsetValueType($this->offsetType))); - } - - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; + ->and($this->valueType->isSuperTypeOf($type->getOffsetValueType($this->offsetType))); } - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } $result = new IsSuperTypeOfResult($otherType->isOffsetAccessible()->and($otherType->hasOffsetValueType($this->offsetType)), []); return $result - ->and($otherType->getOffsetValueType($this->offsetType)->isSuperTypeOfWithReason($this->valueType)) + ->and($otherType->getOffsetValueType($this->offsetType)->isSuperTypeOf($this->valueType)) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -390,7 +373,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -490,11 +473,6 @@ public function getFiniteTypes(): array return []; } - public static function __set_state(array $properties): Type - { - return new self($properties['offsetType'], $properties['valueType']); - } - public function toPhpDocNode(): TypeNode { return new IdentifierTypeNode(''); // no PHPDoc representation diff --git a/src/Type/Accessory/HasPropertyType.php b/src/Type/Accessory/HasPropertyType.php index 372bcf70f1..71b6b42759 100644 --- a/src/Type/Accessory/HasPropertyType.php +++ b/src/Type/Accessory/HasPropertyType.php @@ -36,9 +36,6 @@ public function __construct(private string $propertyName) { } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -64,39 +61,24 @@ public function getPropertyName(): string return $this->propertyName; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createFromBoolean($this->equals($type)); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { return new IsSuperTypeOfResult($type->hasProperty($this->propertyName), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } if ($otherType instanceof self) { @@ -108,14 +90,9 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult return $limit->and(new IsSuperTypeOfResult($otherType->hasProperty($this->propertyName), [])); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -173,11 +150,6 @@ public function getFiniteTypes(): array return []; } - public static function __set_state(array $properties): Type - { - return new self($properties['propertyName']); - } - public function toPhpDocNode(): TypeNode { return new IdentifierTypeNode(''); // no PHPDoc representation diff --git a/src/Type/Accessory/NonEmptyArrayType.php b/src/Type/Accessory/NonEmptyArrayType.php index 7b9312e6c5..e99bb4cbaa 100644 --- a/src/Type/Accessory/NonEmptyArrayType.php +++ b/src/Type/Accessory/NonEmptyArrayType.php @@ -73,15 +73,10 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } $isArray = $type->isArray(); @@ -90,47 +85,32 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return new AcceptsResult($isArray->and($isIterableAtLeastOnce), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($this->equals($type)) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return new IsSuperTypeOfResult($type->isArray()->and($type->isIterableAtLeastOnce()), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isArray()->and($otherType->isIterableAtLeastOnce()), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -390,12 +370,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -480,11 +460,6 @@ public function getFiniteTypes(): array return []; } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function toPhpDocNode(): TypeNode { return new IdentifierTypeNode('non-empty-array'); diff --git a/src/Type/Accessory/OversizedArrayType.php b/src/Type/Accessory/OversizedArrayType.php index 3de317ba0e..70ba480a7e 100644 --- a/src/Type/Accessory/OversizedArrayType.php +++ b/src/Type/Accessory/OversizedArrayType.php @@ -72,61 +72,41 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isArray()->and($type->isIterableAtLeastOnce()), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($this->equals($type)) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return new IsSuperTypeOfResult($type->isArray()->and($type->isOversizedArray()), []); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isArray()->and($otherType->isOversizedArray()), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -379,12 +359,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -469,11 +449,6 @@ public function getFiniteTypes(): array return []; } - public static function __set_state(array $properties): Type - { - return new self(); - } - public function toPhpDocNode(): TypeNode { return new IdentifierTypeNode(''); // no PHPDoc representation diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 74b47dea0b..402c985b0e 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -11,7 +11,6 @@ use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryArrayListType; -use PHPStan\Type\Accessory\HasOffsetType; use PHPStan\Type\Accessory\HasOffsetValueType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\Constant\ConstantArrayType; @@ -24,6 +23,7 @@ use PHPStan\Type\Generic\TemplateStrictMixedType; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Generic\TemplateTypeVariance; +use PHPStan\Type\Traits\ArrayTypeTrait; use PHPStan\Type\Traits\MaybeCallableTypeTrait; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; use PHPStan\Type\Traits\NonObjectTypeTrait; @@ -37,6 +37,7 @@ class ArrayType implements Type { + use ArrayTypeTrait; use MaybeCallableTypeTrait; use NonObjectTypeTrait; use UndecidedBooleanTypeTrait; @@ -68,9 +69,6 @@ public function getItemType(): Type return $this->itemType; } - /** - * @return string[] - */ public function getReferencedClasses(): array { return array_merge( @@ -79,35 +77,15 @@ public function getReferencedClasses(): array ); } - public function getObjectClassNames(): array - { - return []; - } - - public function getObjectClassReflections(): array - { - return []; - } - - public function getArrays(): array - { - return [$this]; - } - public function getConstantArrays(): array { return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if ($type instanceof ConstantArrayType) { @@ -116,8 +94,8 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $itemType = $this->getItemType(); foreach ($type->getKeyTypes() as $i => $keyType) { $valueType = $type->getValueTypes()[$i]; - $acceptsKey = $thisKeyType->acceptsWithReason($keyType, $strictTypes); - $acceptsValue = $itemType->acceptsWithReason($valueType, $strictTypes); + $acceptsKey = $thisKeyType->accepts($keyType, $strictTypes); + $acceptsValue = $itemType->accepts($valueType, $strictTypes); $result = $result->and($acceptsKey)->and($acceptsValue); } @@ -125,27 +103,22 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult } if ($type instanceof ArrayType) { - return $this->getItemType()->acceptsWithReason($type->getItemType(), $strictTypes) - ->and($this->keyType->acceptsWithReason($type->keyType, $strictTypes)); + return $this->getItemType()->accepts($type->getItemType(), $strictTypes) + ->and($this->keyType->accepts($type->keyType, $strictTypes)); } return AcceptsResult::createNo(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { - if ($type instanceof self) { - return $this->getItemType()->isSuperTypeOfWithReason($type->getItemType()) - ->and($this->getIterableKeyType()->isSuperTypeOfWithReason($type->getIterableKeyType())); + if ($type instanceof self || $type instanceof ConstantArrayType) { + return $this->getItemType()->isSuperTypeOf($type->getItemType()) + ->and($this->getIterableKeyType()->isSuperTypeOf($type->getIterableKeyType())); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -154,15 +127,14 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult public function equals(Type $type): bool { return $type instanceof self - && $type->isConstantArray()->no() && $this->getItemType()->equals($type->getIterableValueType()) && $this->keyType->equals($type->keyType); } public function describe(VerbosityLevel $level): string { - $isMixedKeyType = $this->keyType instanceof MixedType && $this->keyType->describe(VerbosityLevel::precise()) === 'mixed'; - $isMixedItemType = $this->itemType instanceof MixedType && $this->itemType->describe(VerbosityLevel::precise()) === 'mixed'; + $isMixedKeyType = $this->keyType instanceof MixedType && $this->keyType->describe(VerbosityLevel::precise()) === 'mixed' && !$this->keyType->isExplicitMixed(); + $isMixedItemType = $this->itemType instanceof MixedType && $this->itemType->describe(VerbosityLevel::precise()) === 'mixed' && !$this->itemType->isExplicitMixed(); $valueHandler = function () use ($level, $isMixedKeyType, $isMixedItemType): string { if ($isMixedKeyType || $this->keyType instanceof NeverType) { @@ -193,14 +165,6 @@ function () use ($level, $isMixedKeyType, $isMixedItemType): string { ); } - /** - * @deprecated - */ - public function generalizeKeys(): self - { - return new self($this->keyType->generalize(GeneralizePrecision::lessSpecific()), $this->itemType); - } - public function generalizeValues(): self { return new self($this->keyType, $this->itemType->generalize(GeneralizePrecision::lessSpecific())); @@ -208,17 +172,12 @@ public function generalizeValues(): self public function getKeysArray(): Type { - return AccessoryArrayListType::intersectWith(new self(new IntegerType(), $this->getIterableKeyType())); + return TypeCombinator::intersect(new self(new IntegerType(), $this->getIterableKeyType()), new AccessoryArrayListType()); } public function getValuesArray(): Type { - return AccessoryArrayListType::intersectWith(new self(new IntegerType(), $this->itemType)); - } - - public function isIterable(): TrinaryLogic - { - return TrinaryLogic::createYes(); + return TypeCombinator::intersect(new self(new IntegerType(), $this->itemType), new AccessoryArrayListType()); } public function isIterableAtLeastOnce(): TrinaryLogic @@ -269,21 +228,11 @@ public function getLastIterableValueType(): Type return $this->getItemType(); } - public function isArray(): TrinaryLogic - { - return TrinaryLogic::createYes(); - } - public function isConstantArray(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isOversizedArray(): TrinaryLogic - { - return TrinaryLogic::createMaybe(); - } - public function isList(): TrinaryLogic { if (IntegerRangeType::fromInterval(0, null)->isSuperTypeOf($this->getKeyType())->no()) { @@ -293,131 +242,16 @@ public function isList(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isNull(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - public function isConstantValue(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isConstantScalarValue(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function getConstantScalarTypes(): array - { - return []; - } - - public function getConstantScalarValues(): array - { - return []; - } - - public function isTrue(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isFalse(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isBoolean(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isFloat(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isInteger(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isNumericString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isNonEmptyString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isNonFalsyString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isLiteralString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isLowercaseString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isUppercaseString(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isClassStringType(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function getClassStringObjectType(): Type - { - return new ErrorType(); - } - - public function getObjectTypeOrClassStringObjectType(): Type - { - return new ErrorType(); - } - - public function isVoid(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - - public function isScalar(): TrinaryLogic - { - return TrinaryLogic::createNo(); - } - public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType { return new BooleanType(); } - public function isOffsetAccessible(): TrinaryLogic - { - return TrinaryLogic::createYes(); - } - - public function isOffsetAccessLegal(): TrinaryLogic - { - return TrinaryLogic::createYes(); - } - public function hasOffsetValueType(Type $offsetType): TrinaryLogic { $offsetType = $offsetType->toArrayKey(); @@ -533,20 +367,6 @@ public function unsetOffset(Type $offsetType): Type return $this; } - public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type - { - $chunkType = $preserveKeys->yes() - ? $this - : AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $this->getIterableValueType())); - $chunkType = TypeCombinator::intersect($chunkType, new NonEmptyArrayType()); - - $arrayType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $chunkType)); - - return $this->isIterableAtLeastOnce()->yes() - ? TypeCombinator::intersect($arrayType, new NonEmptyArrayType()) - : $arrayType; - } - public function fillKeysArray(Type $valueType): Type { $itemType = $this->getItemType(); @@ -603,7 +423,7 @@ public function shiftArray(): Type public function shuffleArray(): Type { - return AccessoryArrayListType::intersectWith(new self(new IntegerType(), $this->itemType)); + return TypeCombinator::intersect(new self(new IntegerType(), $this->itemType), new AccessoryArrayListType()); } public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type @@ -625,21 +445,6 @@ public function getCallableParametersAcceptors(ClassMemberAccessAnswerer $scope) return [new TrivialParametersAcceptor()]; } - public function toNumber(): Type - { - return new ErrorType(); - } - - public function toAbsoluteNumber(): Type - { - return new ErrorType(); - } - - public function toString(): Type - { - return new ErrorType(); - } - public function toInteger(): Type { return TypeCombinator::union( @@ -656,28 +461,6 @@ public function toFloat(): Type ); } - public function toArray(): Type - { - return $this; - } - - public function toArrayKey(): Type - { - return new ErrorType(); - } - - /** @deprecated Use getArraySize() instead */ - public function count(): Type - { - return $this->getArraySize(); - } - - /** @deprecated Use $offsetType->toArrayKey() instead */ - public static function castToArrayKeyType(Type $offsetType): Type - { - return $offsetType->toArrayKey(); - } - public function inferTemplateTypes(Type $receivedType): TemplateTypeMap { if ($receivedType instanceof UnionType || $receivedType instanceof IntersectionType) { @@ -722,8 +505,8 @@ public function traverse(callable $cb): Type public function toPhpDocNode(): TypeNode { - $isMixedKeyType = $this->keyType instanceof MixedType && $this->keyType->describe(VerbosityLevel::precise()) === 'mixed'; - $isMixedItemType = $this->itemType instanceof MixedType && $this->itemType->describe(VerbosityLevel::precise()) === 'mixed'; + $isMixedKeyType = $this->keyType instanceof MixedType && $this->keyType->describe(VerbosityLevel::precise()) === 'mixed' && !$this->keyType->isExplicitMixed(); + $isMixedItemType = $this->itemType instanceof MixedType && $this->itemType->describe(VerbosityLevel::precise()) === 'mixed' && !$this->itemType->isExplicitMixed(); if ($isMixedKeyType) { if ($isMixedItemType) { @@ -773,36 +556,12 @@ public function tryRemove(Type $typeToRemove): ?Type return new ConstantArrayType([], []); } - if ($this->isConstantArray()->yes() && $typeToRemove instanceof HasOffsetType) { - return $this->unsetOffset($typeToRemove->getOffsetType()); - } - - if ($this->isConstantArray()->yes() && $typeToRemove instanceof HasOffsetValueType) { - return $this->unsetOffset($typeToRemove->getOffsetType()); - } - return null; } - public function exponentiate(Type $exponent): Type - { - return new ErrorType(); - } - public function getFiniteTypes(): array { return []; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['keyType'], - $properties['itemType'], - ); - } - } diff --git a/src/Type/BenevolentUnionType.php b/src/Type/BenevolentUnionType.php index d6b43fbd85..6a2d28dc1c 100644 --- a/src/Type/BenevolentUnionType.php +++ b/src/Type/BenevolentUnionType.php @@ -97,16 +97,11 @@ protected function unionResults(callable $getResult): TrinaryLogic return TrinaryLogic::createNo()->lazyOr($this->getTypes(), $getResult); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { $result = AcceptsResult::createNo(); foreach ($this->getTypes() as $innerType) { - $result = $result->or($acceptingType->acceptsWithReason($innerType, $strictTypes)); + $result = $result->or($acceptingType->accepts($innerType, $strictTypes)); } return $result; @@ -183,12 +178,4 @@ public function traverseSimultaneously(Type $right, callable $cb): Type return $this; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['types']); - } - } diff --git a/src/Type/BooleanType.php b/src/Type/BooleanType.php index 72be662c95..df059481e6 100644 --- a/src/Type/BooleanType.php +++ b/src/Type/BooleanType.php @@ -163,12 +163,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('bool'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/CallableType.php b/src/Type/CallableType.php index f182372fc0..9ea353c5d6 100644 --- a/src/Type/CallableType.php +++ b/src/Type/CallableType.php @@ -52,7 +52,7 @@ class CallableType implements CompoundType, CallableParametersAcceptor use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - /** @var array */ + /** @var list */ private array $parameters; private Type $returnType; @@ -65,9 +65,11 @@ class CallableType implements CompoundType, CallableParametersAcceptor private TrinaryLogic $isPure; + private TrinaryLogic $isDeprecated; + /** * @api - * @param array|null $parameters + * @param list|null $parameters * @param array $templateTags */ public function __construct( @@ -78,6 +80,7 @@ public function __construct( ?TemplateTypeMap $resolvedTemplateTypeMap = null, private array $templateTags = [], ?TrinaryLogic $isPure = null, + ?TrinaryLogic $isDeprecated = null, ) { $this->parameters = $parameters ?? []; @@ -86,6 +89,7 @@ public function __construct( $this->templateTypeMap = $templateTypeMap ?? TemplateTypeMap::createEmpty(); $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap ?? TemplateTypeMap::createEmpty(); $this->isPure = $isPure ?? TrinaryLogic::createMaybe(); + $this->isDeprecated = $isDeprecated ?? TrinaryLogic::createNo(); } /** @@ -101,8 +105,13 @@ public function isPure(): TrinaryLogic return $this->isPure; } + public function isDeprecated(): TrinaryLogic + { + return $this->isDeprecated; + } + /** - * @return string[] + * @return list */ public function getReferencedClasses(): array { @@ -129,29 +138,19 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType && !$type instanceof self) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return $this->isSuperTypeOfInternal($type, true)->toAcceptsResult(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType && !$type instanceof self) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return $this->isSuperTypeOfInternal($type, false); @@ -199,29 +198,19 @@ private function isSuperTypeOfInternal(Type $type, bool $treatMixedAsAny): IsSup return $isCallable->and($variantsResult); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof IntersectionType || $otherType instanceof UnionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return (new IsSuperTypeOfResult($otherType->isCallable(), [])) ->and($otherType instanceof self ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createMaybe()); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -254,6 +243,7 @@ function (): string { $this->resolvedTemplateTypeMap, $this->templateTags, $this->isPure, + $this->isDeprecated, ); return $printer->print($selfWithoutParameterNames->toPhpDocNode()); @@ -304,9 +294,9 @@ public function getUsedVariables(): array return []; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { - return true; + return TrinaryLogic::createYes(); } public function toNumber(): Type @@ -365,7 +355,7 @@ public function getCallSiteVarianceMap(): TemplateTypeVarianceMap } /** - * @return array + * @return list */ public function getParameters(): array { @@ -468,6 +458,7 @@ public function traverse(callable $cb): Type $this->resolvedTemplateTypeMap, $this->templateTags, $this->isPure, + $this->isDeprecated, ); } @@ -518,6 +509,7 @@ public function traverseSimultaneously(Type $right, callable $cb): Type $this->resolvedTemplateTypeMap, $this->templateTags, $this->isPure, + $this->isDeprecated, ); } @@ -606,12 +598,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -695,20 +687,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - (bool) $properties['isCommonCallable'] ? null : $properties['parameters'], - (bool) $properties['isCommonCallable'] ? null : $properties['returnType'], - $properties['variadic'], - $properties['templateTypeMap'], - $properties['resolvedTemplateTypeMap'], - $properties['templateTags'], - $properties['isPure'], - ); - } - } diff --git a/src/Type/CallableTypeHelper.php b/src/Type/CallableTypeHelper.php index aa28e59fff..4e99e94cc9 100644 --- a/src/Type/CallableTypeHelper.php +++ b/src/Type/CallableTypeHelper.php @@ -72,10 +72,10 @@ public static function isParametersAcceptorSuperTypeOf( } if ($treatMixedAsAny) { - $isSuperType = $theirParameter->getType()->acceptsWithReason($ourParameterType, true); + $isSuperType = $theirParameter->getType()->accepts($ourParameterType, true); $isSuperType = new IsSuperTypeOfResult($isSuperType->result, $isSuperType->reasons); } else { - $isSuperType = $theirParameter->getType()->isSuperTypeOfWithReason($ourParameterType); + $isSuperType = $theirParameter->getType()->isSuperTypeOf($ourParameterType); } if ($isSuperType->maybe()) { @@ -99,10 +99,10 @@ public static function isParametersAcceptorSuperTypeOf( $theirReturnType = $theirs->getReturnType(); if ($treatMixedAsAny) { - $isReturnTypeSuperType = $ours->getReturnType()->acceptsWithReason($theirReturnType, true); + $isReturnTypeSuperType = $ours->getReturnType()->accepts($theirReturnType, true); $isReturnTypeSuperType = new IsSuperTypeOfResult($isReturnTypeSuperType->result, $isReturnTypeSuperType->reasons); } else { - $isReturnTypeSuperType = $ours->getReturnType()->isSuperTypeOfWithReason($theirReturnType); + $isReturnTypeSuperType = $ours->getReturnType()->isSuperTypeOf($theirReturnType); } $pure = $ours->isPure(); diff --git a/src/Type/ClassStringType.php b/src/Type/ClassStringType.php index 30e761b660..c5dae4f195 100644 --- a/src/Type/ClassStringType.php +++ b/src/Type/ClassStringType.php @@ -21,32 +21,22 @@ public function describe(VerbosityLevel $level): string return 'class-string'; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } - return new AcceptsResult($type->isClassStringType(), []); + return new AcceptsResult($type->isClassString(), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } - return new IsSuperTypeOfResult($type->isClassStringType(), []); + return new IsSuperTypeOfResult($type->isClassString(), []); } public function isString(): TrinaryLogic @@ -84,7 +74,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createYes(); } @@ -104,12 +94,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('class-string'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/ClosureType.php b/src/Type/ClosureType.php index d12dda936e..03caa373d5 100644 --- a/src/Type/ClosureType.php +++ b/src/Type/ClosureType.php @@ -16,17 +16,17 @@ use PHPStan\Reflection\Callables\CallableParametersAcceptor; use PHPStan\Reflection\Callables\SimpleImpurePoint; use PHPStan\Reflection\Callables\SimpleThrowPoint; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Native\NativeParameterReflection; use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; use PHPStan\Reflection\PassedByReference; use PHPStan\Reflection\Php\ClosureCallUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Php\DummyParameter; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\TrinaryLogic; @@ -59,7 +59,7 @@ class ClosureType implements TypeWithClassName, CallableParametersAcceptor use NonRemoveableTypeTrait; use NonGeneralizableTypeTrait; - /** @var array */ + /** @var list */ private array $parameters; private Type $returnType; @@ -77,9 +77,13 @@ class ClosureType implements TypeWithClassName, CallableParametersAcceptor /** @var SimpleImpurePoint[] */ private array $impurePoints; + private TrinaryLogic $acceptsNamedArguments; + + private TrinaryLogic $isDeprecated; + /** * @api - * @param array|null $parameters + * @param list|null $parameters * @param array $templateTags * @param SimpleThrowPoint[] $throwPoints * @param ?SimpleImpurePoint[] $impurePoints @@ -98,9 +102,15 @@ public function __construct( ?array $impurePoints = null, private array $invalidateExpressions = [], private array $usedVariables = [], - private bool $acceptsNamedArguments = true, + ?TrinaryLogic $acceptsNamedArguments = null, + ?TrinaryLogic $isDeprecated = null, ) { + if ($acceptsNamedArguments === null) { + $acceptsNamedArguments = TrinaryLogic::createYes(); + } + $this->acceptsNamedArguments = $acceptsNamedArguments; + $this->parameters = $parameters ?? []; $this->returnType = $returnType ?? new MixedType(); $this->isCommonCallable = $parameters === null && $returnType === null; @@ -109,6 +119,7 @@ public function __construct( $this->resolvedTemplateTypeMap = $resolvedTemplateTypeMap ?? TemplateTypeMap::createEmpty(); $this->callSiteVarianceMap = $callSiteVarianceMap ?? TemplateTypeVarianceMap::createEmpty(); $this->impurePoints = $impurePoints ?? [new SimpleImpurePoint('functionCall', 'call to an unknown Closure', false)]; + $this->isDeprecated = $isDeprecated ?? TrinaryLogic::createNo(); } /** @@ -143,6 +154,11 @@ public function isPure(): TrinaryLogic return $certainCount > 0 ? TrinaryLogic::createNo() : TrinaryLogic::createMaybe(); } + public function isDeprecated(): TrinaryLogic + { + return $this->isDeprecated; + } + public function getClassName(): string { return $this->objectType->getClassName(); @@ -158,9 +174,6 @@ public function getAncestorWithClassName(string $className): ?TypeWithClassName return $this->objectType->getAncestorWithClassName($className); } - /** - * @return string[] - */ public function getReferencedClasses(): array { $classes = $this->objectType->getReferencedClasses(); @@ -181,33 +194,23 @@ public function getObjectClassReflections(): array return $this->objectType->getObjectClassReflections(); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if (!$type instanceof ClosureType) { - return $this->objectType->acceptsWithReason($type, $strictTypes); + return $this->objectType->accepts($type, $strictTypes); } return $this->isSuperTypeOfInternal($type, true)->toAcceptsResult(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return $this->isSuperTypeOfInternal($type, false); @@ -227,7 +230,7 @@ private function isSuperTypeOfInternal(Type $type, bool $treatMixedAsAny): IsSup return IsSuperTypeOfResult::createMaybe(); } - return $this->objectType->isSuperTypeOfWithReason($type); + return $this->objectType->isSuperTypeOf($type); } public function equals(Type $type): bool @@ -268,6 +271,7 @@ function (): string { $this->impurePoints, $this->invalidateExpressions, $this->usedVariables, + $this->isDeprecated, ); return $printer->print($selfWithoutParameterNames->toPhpDocNode()); @@ -305,7 +309,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return $this->objectType->hasProperty($propertyName); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->objectType->getProperty($propertyName, $scope); } @@ -352,7 +356,7 @@ public function hasConstant(string $constantName): TrinaryLogic return $this->objectType->hasConstant($constantName); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { return $this->objectType->getConstant($constantName); } @@ -412,7 +416,7 @@ public function getUsedVariables(): array return $this->usedVariables; } - public function acceptsNamedArguments(): bool + public function acceptsNamedArguments(): TrinaryLogic { return $this->acceptsNamedArguments; } @@ -484,7 +488,7 @@ public function getCallSiteVarianceMap(): TemplateTypeVarianceMap } /** - * @return array + * @return list */ public function getParameters(): array { @@ -590,6 +594,7 @@ public function traverse(callable $cb): Type $this->invalidateExpressions, $this->usedVariables, $this->acceptsNamedArguments, + $this->isDeprecated, ); } @@ -640,6 +645,7 @@ public function traverseSimultaneously(Type $right, callable $cb): Type $this->invalidateExpressions, $this->usedVariables, $this->acceptsNamedArguments, + $this->isDeprecated, ); } @@ -723,12 +729,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -802,25 +808,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['parameters'], - $properties['returnType'], - $properties['variadic'], - $properties['templateTypeMap'], - $properties['resolvedTemplateTypeMap'], - $properties['callSiteVarianceMap'], - $properties['templateTags'], - $properties['throwPoints'], - $properties['impurePoints'], - $properties['invalidateExpressions'], - $properties['usedVariables'], - $properties['acceptsNamedArguments'], - ); - } - } diff --git a/src/Type/ClosureTypeFactory.php b/src/Type/ClosureTypeFactory.php index a0e82946ff..b5c7983288 100644 --- a/src/Type/ClosureTypeFactory.php +++ b/src/Type/ClosureTypeFactory.php @@ -18,6 +18,7 @@ use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\PassedByReference; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use ReflectionFunction; use function array_map; use function count; @@ -25,9 +26,8 @@ /** * @api - * @final */ -class ClosureTypeFactory +final class ClosureTypeFactory { public function __construct( @@ -114,7 +114,21 @@ public function getDefaultValue(): ?Type }, $betterReflectionFunction->getParameters()); - return new ClosureType($parameters, TypehintHelper::decideTypeFromReflection(ReflectionType::fromTypeOrNull($betterReflectionFunction->getReturnType())), $betterReflectionFunction->isVariadic()); + return new ClosureType( + $parameters, + TypehintHelper::decideTypeFromReflection(ReflectionType::fromTypeOrNull($betterReflectionFunction->getReturnType())), + $betterReflectionFunction->isVariadic(), + null, + null, + null, + [], + [], + null, + [], + [], + null, + TrinaryLogic::createFromBoolean($betterReflectionFunction->isDeprecated()), + ); } } diff --git a/src/Type/CompoundType.php b/src/Type/CompoundType.php index b3080ceb91..f66e10c091 100644 --- a/src/Type/CompoundType.php +++ b/src/Type/CompoundType.php @@ -2,29 +2,19 @@ namespace PHPStan\Type; +use PHPStan\Php\PhpVersion; use PHPStan\TrinaryLogic; /** @api */ interface CompoundType extends Type { - public function isSubTypeOf(Type $otherType): TrinaryLogic; + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult; - /** - * This is like isSubTypeOf() but gives reasons - * why the type was not/might not be accepted in some non-intuitive scenarios. - * - * In PHPStan 2.0 this method will be removed and the return type of isSubTypeOf() - * will change to IsSuperTypeOfResult. - */ - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult; + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult; - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic; + public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic; - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult; - - public function isGreaterThan(Type $otherType): TrinaryLogic; - - public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic; + public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic; } diff --git a/src/Type/ConditionalType.php b/src/Type/ConditionalType.php index f69d3633f7..f154fb5368 100644 --- a/src/Type/ConditionalType.php +++ b/src/Type/ConditionalType.php @@ -4,7 +4,6 @@ use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\Traits\LateResolvableTypeTrait; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; @@ -61,16 +60,11 @@ public function isNegated(): bool return $this->negated; } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { - return $this->if->isSuperTypeOfWithReason($type->if) - ->and($this->else->isSuperTypeOfWithReason($type->else)); + return $this->if->isSuperTypeOf($type->if) + ->and($this->else->isSuperTypeOf($type->else)); } return $this->isSuperTypeOfDefault($type); @@ -193,20 +187,6 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['subject'], - $properties['target'], - $properties['if'], - $properties['else'], - $properties['negated'], - ); - } - private function getNormalizedIf(): Type { return $this->normalizedIf ??= TypeTraverser::map( diff --git a/src/Type/ConditionalTypeForParameter.php b/src/Type/ConditionalTypeForParameter.php index 72d7f0f5a2..0fd8cf4475 100644 --- a/src/Type/ConditionalTypeForParameter.php +++ b/src/Type/ConditionalTypeForParameter.php @@ -4,7 +4,6 @@ use PHPStan\PhpDocParser\Ast\Type\ConditionalTypeForParameterNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\Traits\LateResolvableTypeTrait; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; @@ -75,16 +74,11 @@ public function toConditional(Type $subject): Type ); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { - return $this->if->isSuperTypeOfWithReason($type->if) - ->and($this->else->isSuperTypeOfWithReason($type->else)); + return $this->if->isSuperTypeOf($type->if) + ->and($this->else->isSuperTypeOf($type->else)); } return $this->isSuperTypeOfDefault($type); @@ -180,18 +174,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['parameterName'], - $properties['target'], - $properties['if'], - $properties['else'], - $properties['negated'], - ); - } - } diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index 1b770d6889..1514781d0f 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -4,7 +4,6 @@ use Nette\Utils\Strings; use PHPStan\Analyser\OutOfClassScope; -use PHPStan\DependencyInjection\BleedingEdgeToggle; use PHPStan\Internal\CombinationsHelper; use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; @@ -24,14 +23,13 @@ use PHPStan\TrinaryLogic; use PHPStan\Type\AcceptsResult; use PHPStan\Type\Accessory\AccessoryArrayListType; +use PHPStan\Type\Accessory\HasOffsetType; use PHPStan\Type\Accessory\HasOffsetValueType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\BooleanType; use PHPStan\Type\CompoundType; use PHPStan\Type\ConstantScalarType; -use PHPStan\Type\ConstantType; -use PHPStan\Type\ConstantTypeHelper; use PHPStan\Type\ErrorType; use PHPStan\Type\GeneralizePrecision; use PHPStan\Type\Generic\TemplateTypeMap; @@ -42,6 +40,9 @@ use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; use PHPStan\Type\NullType; +use PHPStan\Type\Traits\ArrayTypeTrait; +use PHPStan\Type\Traits\NonObjectTypeTrait; +use PHPStan\Type\Traits\UndecidedComparisonTypeTrait; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use PHPStan\Type\UnionType; @@ -58,8 +59,6 @@ use function count; use function implode; use function in_array; -use function is_bool; -use function is_int; use function is_string; use function min; use function pow; @@ -71,9 +70,15 @@ /** * @api */ -class ConstantArrayType extends ArrayType implements ConstantType +class ConstantArrayType implements Type { + use ArrayTypeTrait { + chunkArray as traitChunkArray; + } + use NonObjectTypeTrait; + use UndecidedComparisonTypeTrait; + private const DESCRIBE_LIMIT = 8; private const CHUNK_FINITE_TYPES_LIMIT = 5; @@ -82,67 +87,101 @@ class ConstantArrayType extends ArrayType implements ConstantType /** @var self[]|null */ private ?array $allArrays = null; - /** @var non-empty-list */ - private array $nextAutoIndexes; + private ?Type $iterableKeyType = null; + + private ?Type $iterableValueType = null; /** * @api * @param array $keyTypes * @param array $valueTypes - * @param non-empty-list|int $nextAutoIndexes + * @param non-empty-list $nextAutoIndexes * @param int[] $optionalKeys */ public function __construct( private array $keyTypes, private array $valueTypes, - int|array $nextAutoIndexes = [0], + private array $nextAutoIndexes = [0], private array $optionalKeys = [], - bool|TrinaryLogic $isList = false, + ?TrinaryLogic $isList = null, ) { assert(count($keyTypes) === count($valueTypes)); - if (is_int($nextAutoIndexes)) { - $nextAutoIndexes = [$nextAutoIndexes]; + $keyTypesCount = count($this->keyTypes); + if ($keyTypesCount === 0) { + $isList = TrinaryLogic::createYes(); } - $this->nextAutoIndexes = $nextAutoIndexes; + if ($isList === null) { + $isList = TrinaryLogic::createNo(); + } + $this->isList = $isList; + } + + public function getConstantArrays(): array + { + return [$this]; + } + + public function getReferencedClasses(): array + { + $referencedClasses = []; + foreach ($this->getKeyTypes() as $keyType) { + foreach ($keyType->getReferencedClasses() as $referencedClass) { + $referencedClasses[] = $referencedClass; + } + } + + foreach ($this->getValueTypes() as $valueType) { + foreach ($valueType->getReferencedClasses() as $referencedClass) { + $referencedClasses[] = $referencedClass; + } + } + + return $referencedClasses; + } + + public function getIterableKeyType(): Type + { + if ($this->iterableKeyType !== null) { + return $this->iterableKeyType; + } $keyTypesCount = count($this->keyTypes); if ($keyTypesCount === 0) { $keyType = new NeverType(true); - $isList = TrinaryLogic::createYes(); } elseif ($keyTypesCount === 1) { $keyType = $this->keyTypes[0]; } else { $keyType = new UnionType($this->keyTypes); } - if (is_bool($isList)) { - $isList = TrinaryLogic::createFromBoolean($isList); + return $this->iterableKeyType = $keyType; + } + + public function getIterableValueType(): Type + { + if ($this->iterableValueType !== null) { + return $this->iterableValueType; } - $this->isList = $isList; - parent::__construct( - $keyType, - count($valueTypes) > 0 ? TypeCombinator::union(...$valueTypes) : new NeverType(true), - ); + return $this->iterableValueType = count($this->valueTypes) > 0 ? TypeCombinator::union(...$this->valueTypes) : new NeverType(true); } - public function getConstantArrays(): array + public function getKeyType(): Type { - return [$this]; + return $this->getIterableKeyType(); } - public function isConstantValue(): TrinaryLogic + public function getItemType(): Type { - return TrinaryLogic::createYes(); + return $this->getIterableValueType(); } - /** @deprecated Use isIterableAtLeastOnce()->no() instead */ - public function isEmpty(): bool + public function isConstantValue(): TrinaryLogic { - return count($this->keyTypes) === 0; + return TrinaryLogic::createYes(); } /** @@ -153,14 +192,6 @@ public function getNextAutoIndexes(): array return $this->nextAutoIndexes; } - /** - * @deprecated - */ - public function getNextAutoIndex(): int - { - return $this->nextAutoIndexes[count($this->nextAutoIndexes) - 1]; - } - /** * @return int[] */ @@ -210,7 +241,7 @@ public function getAllArrays(): array } $array = $builder->getArray(); - if (!$array instanceof ConstantArrayType) { + if (!$array instanceof self) { throw new ShouldNotHappenException(); } @@ -254,18 +285,6 @@ public function getKeyTypes(): array return $this->keyTypes; } - /** @deprecated Use getFirstIterableKeyType() instead */ - public function getFirstKeyType(): Type - { - return $this->getFirstIterableKeyType(); - } - - /** @deprecated Use getLastIterableKeyType() instead */ - public function getLastKeyType(): Type - { - return $this->getLastIterableKeyType(); - } - /** * @return array */ @@ -274,32 +293,15 @@ public function getValueTypes(): array return $this->valueTypes; } - /** @deprecated Use getFirstIterableValueType() instead */ - public function getFirstValueType(): Type - { - return $this->getFirstIterableValueType(); - } - - /** @deprecated Use getLastIterableValueType() instead */ - public function getLastValueType(): Type - { - return $this->getLastIterableValueType(); - } - public function isOptionalKey(int $i): bool { return in_array($i, $this->optionalKeys, true); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType && !$type instanceof IntersectionType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if ($type instanceof self && count($this->keyTypes) === 0) { @@ -327,7 +329,7 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $result = $result->and($hasOffset); $otherValueType = $type->getOffsetValueType($keyType); $verbosity = VerbosityLevel::getRecommendedLevelByType($valueType, $otherValueType); - $acceptsValue = $valueType->acceptsWithReason($otherValueType, $strictTypes)->decorateReasons( + $acceptsValue = $valueType->accepts($otherValueType, $strictTypes)->decorateReasons( static fn (string $reason) => sprintf( 'Offset %s (%s) does not accept type %s: %s', $keyType->describe(VerbosityLevel::precise()), @@ -362,12 +364,7 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return $result; } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { if (count($this->keyTypes) === 0) { @@ -388,7 +385,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult $results[] = IsSuperTypeOfResult::createMaybe(); } - $isValueSuperType = $this->valueTypes[$i]->isSuperTypeOfWithReason($type->getOffsetValueType($keyType)); + $isValueSuperType = $this->valueTypes[$i]->isSuperTypeOf($type->getOffsetValueType($keyType)); if ($isValueSuperType->no()) { return $isValueSuperType->decorateReasons(static fn (string $reason) => sprintf('Offset %s: %s', $keyType->describe(VerbosityLevel::value()), $reason)); } @@ -404,16 +401,16 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return $result; } - $isKeySuperType = $this->getKeyType()->isSuperTypeOfWithReason($type->getKeyType()); + $isKeySuperType = $this->getKeyType()->isSuperTypeOf($type->getKeyType()); if ($isKeySuperType->no()) { return $isKeySuperType; } - return $result->and($isKeySuperType, $this->getItemType()->isSuperTypeOfWithReason($type->getItemType())); + return $result->and($isKeySuperType, $this->getItemType()->isSuperTypeOf($type->getItemType())); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -530,36 +527,6 @@ private function getClassOrObjectAndMethods(): array return [$classOrObject, $method]; } - /** @deprecated Use findTypeAndMethodNames() instead */ - public function findTypeAndMethodName(): ?ConstantArrayTypeAndMethod - { - $callableArray = $this->getClassOrObjectAndMethods(); - if ($callableArray === []) { - return null; - } - - [$classOrObject, $method] = $callableArray; - if (!$method instanceof ConstantStringType) { - return ConstantArrayTypeAndMethod::createUnknown(); - } - - $type = $classOrObject->getObjectTypeOrClassStringObjectType(); - if (!$type->isObject()->yes()) { - return ConstantArrayTypeAndMethod::createUnknown(); - } - - $has = $type->hasMethod($method->getValue()); - if (!$has->no()) { - if ($this->isOptionalKey(0) || $this->isOptionalKey(1)) { - $has = $has->and(TrinaryLogic::createMaybe()); - } - - return ConstantArrayTypeAndMethod::createConcrete($type, $method->getValue(), $has); - } - - return null; - } - /** @return ConstantArrayTypeAndMethod[] */ public function findTypeAndMethodNames(): array { @@ -587,8 +554,7 @@ public function findTypeAndMethodNames(): array } if ( - BleedingEdgeToggle::isBleedingEdge() - && $has->yes() + $has->yes() && !$phpVersion->supportsCallableInstanceMethods() ) { $methodReflection = $type->getMethod($method->getValue(), new OutOfClassScope()); @@ -810,7 +776,7 @@ public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type $results = []; foreach ($finiteTypes as $finiteType) { if (!$finiteType instanceof ConstantIntegerType || $finiteType->getValue() < 1) { - return parent::chunkArray($lengthType, $preserveKeys); + return $this->traitChunkArray($lengthType, $preserveKeys); } $length = $finiteType->getValue(); @@ -829,7 +795,7 @@ public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type return TypeCombinator::union(...$results); } - return parent::chunkArray($lengthType, $preserveKeys); + return $this->traitChunkArray($lengthType, $preserveKeys); } public function fillKeysArray(Type $valueType): Type @@ -949,13 +915,13 @@ public function shuffleArray(): Type return $valuesArray; } - $generalizedArray = new ArrayType($valuesArray->getIterableKeyType(), $valuesArray->getItemType()); + $generalizedArray = new ArrayType($valuesArray->getIterableKeyType(), $valuesArray->getIterableValueType()); if ($isIterableAtLeastOnce->yes()) { $generalizedArray = TypeCombinator::intersect($generalizedArray, new NonEmptyArrayType()); } if ($valuesArray->isList->yes()) { - $generalizedArray = AccessoryArrayListType::intersectWith($generalizedArray); + $generalizedArray = TypeCombinator::intersect($generalizedArray, new AccessoryArrayListType()); } return $generalizedArray; @@ -1029,15 +995,14 @@ public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $pre $isOptional = true; } - $builder->setOffsetValueType($this->keyTypes[$i], $this->valueTypes[$i], $isOptional); - } + $offsetType = $preserveKeys->yes() || $this->keyTypes[$i]->isInteger()->no() + ? $this->keyTypes[$i] + : null; - $slice = $builder->getArray(); - if (!$slice instanceof self) { - throw new ShouldNotHappenException(); + $builder->setOffsetValueType($offsetType, $this->valueTypes[$i], $isOptional); } - return $preserveKeys->yes() ? $slice : $slice->reindex(); + return $builder->getArray(); } public function isIterableAtLeastOnce(): TrinaryLogic @@ -1128,12 +1093,6 @@ public function isList(): TrinaryLogic return $this->isList; } - /** @deprecated Use popArray() instead */ - public function removeLast(): self - { - return $this->removeLastElements(1); - } - /** @param positive-int $length */ private function removeLastElements(int $length): self { @@ -1145,7 +1104,7 @@ private function removeLastElements(int $length): self $keyTypes = $this->keyTypes; $valueTypes = $this->valueTypes; $optionalKeys = $this->optionalKeys; - $nextAutoindex = $this->nextAutoIndexes; + $nextAutoindexes = $this->nextAutoIndexes; $optionalKeysRemoved = 0; $newLength = $keyTypesCount - $length; @@ -1165,9 +1124,9 @@ private function removeLastElements(int $length): self $removedKeyType = array_pop($keyTypes); array_pop($valueTypes); - $nextAutoindex = $removedKeyType instanceof ConstantIntegerType - ? $removedKeyType->getValue() - : $this->getNextAutoIndex(); // @phpstan-ignore method.deprecated + $nextAutoindexes = $removedKeyType instanceof ConstantIntegerType + ? [$removedKeyType->getValue()] + : $this->nextAutoIndexes; continue; } @@ -1182,20 +1141,14 @@ private function removeLastElements(int $length): self return new self( $keyTypes, $valueTypes, - $nextAutoindex, + $nextAutoindexes, array_values($optionalKeys), $this->isList, ); } - /** @deprecated Use shiftArray() instead */ - public function removeFirst(): self - { - return $this->removeFirstElements(1); - } - /** @param positive-int $length */ - private function removeFirstElements(int $length, bool $reindex = true): self + private function removeFirstElements(int $length, bool $reindex = true): Type { $builder = ConstantArrayTypeBuilder::createEmpty(); @@ -1222,78 +1175,7 @@ private function removeFirstElements(int $length, bool $reindex = true): self $builder->setOffsetValueType($keyType, $valueType, $isOptional); } - $array = $builder->getArray(); - if (!$array instanceof self) { - throw new ShouldNotHappenException(); - } - - return $array; - } - - /** @deprecated Use sliceArray() instead */ - public function slice(int $offset, ?int $limit, bool $preserveKeys = false): self - { - $array = $this->sliceArray( - ConstantTypeHelper::getTypeFromValue($offset), - ConstantTypeHelper::getTypeFromValue($limit), - TrinaryLogic::createFromBoolean($preserveKeys), - ); - if (!$array instanceof self) { - throw new ShouldNotHappenException(); - } - - return $array; - } - - /** @deprecated Use reverseArray() instead */ - public function reverse(bool $preserveKeys = false): self - { - $array = $this->reverseArray(TrinaryLogic::createFromBoolean($preserveKeys)); - if (!$array instanceof self) { - throw new ShouldNotHappenException(); - } - - return $array; - } - - /** - * @deprecated Use chunkArray() instead - * @param positive-int $length - */ - public function chunk(int $length, bool $preserveKeys = false): self - { - $builder = ConstantArrayTypeBuilder::createEmpty(); - - $keyTypesCount = count($this->keyTypes); - for ($i = 0; $i < $keyTypesCount; $i += $length) { - $chunk = $this->slice($i, $length, true); - $builder->setOffsetValueType(null, $preserveKeys ? $chunk : $chunk->getValuesArray()); - } - - $chunks = $builder->getArray(); - if (!$chunks instanceof self) { - throw new ShouldNotHappenException(); - } - - return $chunks; - } - - private function reindex(): self - { - $keyTypes = []; - $autoIndex = 0; - - foreach ($this->keyTypes as $keyType) { - if (!$keyType instanceof ConstantIntegerType) { - $keyTypes[] = $keyType; - continue; - } - - $keyTypes[] = new ConstantIntegerType($autoIndex); - $autoIndex++; - } - - return new self($keyTypes, $this->valueTypes, [$autoIndex], $this->optionalKeys, TrinaryLogic::createYes()); + return $builder->getArray(); } public function toBoolean(): BooleanType @@ -1323,7 +1205,7 @@ public function generalize(GeneralizePrecision $precision): Type $arrayType = new ArrayType( $this->getIterableKeyType()->generalize($precision), - $this->getItemType()->generalize($precision), + $this->getIterableValueType()->generalize($precision), ); $keyTypesCount = count($this->keyTypes); @@ -1343,7 +1225,7 @@ public function generalize(GeneralizePrecision $precision): Type } if ($this->isList()->yes()) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); + $arrayType = TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } if (count($accessoryTypes) > 0) { @@ -1353,10 +1235,7 @@ public function generalize(GeneralizePrecision $precision): Type return $arrayType; } - /** - * @return self - */ - public function generalizeValues(): ArrayType + public function generalizeValues(): self { $valueTypes = []; foreach ($this->valueTypes as $valueType) { @@ -1366,38 +1245,12 @@ public function generalizeValues(): ArrayType return new self($this->keyTypes, $valueTypes, $this->nextAutoIndexes, $this->optionalKeys, $this->isList); } - /** @deprecated */ - public function generalizeToArray(): Type - { - $isIterableAtLeastOnce = $this->isIterableAtLeastOnce(); - if ($isIterableAtLeastOnce->no()) { - return $this; - } - - $arrayType = new ArrayType($this->getIterableKeyType(), $this->getItemType()); - - if ($isIterableAtLeastOnce->yes()) { - $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); - } - if ($this->isList->yes()) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); - } - - return $arrayType; - } - - /** - * @return self - */ - public function getKeysArray(): Type + public function getKeysArray(): self { return $this->getKeysOrValuesArray($this->keyTypes); } - /** - * @return self - */ - public function getValuesArray(): Type + public function getValuesArray(): self { return $this->getKeysOrValuesArray($this->valueTypes); } @@ -1449,12 +1302,6 @@ private function getKeysOrValuesArray(array $types): self return new self($keyTypes, $valueTypes, $autoIndexes, $optionalKeys, TrinaryLogic::createYes()); } - /** @deprecated Use getArraySize() instead */ - public function count(): Type - { - return $this->getArraySize(); - } - public function describe(VerbosityLevel $level): string { $describeValue = function (bool $truncate) use ($level): string { @@ -1500,7 +1347,7 @@ public function describe(VerbosityLevel $level): string ); }; return $level->handle( - fn (): string => parent::describe($level), + fn (): string => $this->isIterableAtLeastOnce()->no() ? 'array' : sprintf('array<%s, %s>', $this->getIterableKeyType()->describe($level), $this->getIterableValueType()->describe($level)), static fn (): string => $describeValue(true), static fn (): string => $describeValue(false), ); @@ -1526,7 +1373,14 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap return $typeMap; } - return parent::inferTemplateTypes($receivedType); + if ($receivedType->isArray()->yes()) { + $keyTypeMap = $this->getIterableKeyType()->inferTemplateTypes($receivedType->getIterableKeyType()); + $itemTypeMap = $this->getIterableValueType()->inferTemplateTypes($receivedType->getIterableValueType()); + + return $keyTypeMap->union($itemTypeMap); + } + + return TemplateTypeMap::createEmpty(); } public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array @@ -1549,6 +1403,27 @@ public function getReferencedTemplateTypes(TemplateTypeVariance $positionVarianc return $references; } + public function tryRemove(Type $typeToRemove): ?Type + { + if ($typeToRemove->isConstantArray()->yes() && $typeToRemove->isIterableAtLeastOnce()->no()) { + return TypeCombinator::intersect($this, new NonEmptyArrayType()); + } + + if ($typeToRemove instanceof NonEmptyArrayType) { + return new ConstantArrayType([], []); + } + + if ($typeToRemove instanceof HasOffsetType) { + return $this->unsetOffset($typeToRemove->getOffsetType()); + } + + if ($typeToRemove instanceof HasOffsetValueType) { + return $this->unsetOffset($typeToRemove->getOffsetType()); + } + + return null; + } + public function traverse(callable $cb): Type { $valueTypes = []; @@ -1759,7 +1634,7 @@ public function toPhpDocNode(): TypeNode ); } - return new ArrayShapeNode($exportValuesOnly ? $values : $items); + return ArrayShapeNode::createSealed($exportValuesOnly ? $values : $items); } public static function isValidIdentifier(string $value): bool @@ -1808,12 +1683,4 @@ public function getFiniteTypes(): array return $finiteTypes; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['keyTypes'], $properties['valueTypes'], $properties['nextAutoIndexes'] ?? $properties['nextAutoIndex'], $properties['optionalKeys'] ?? [], $properties['isList'] ?? TrinaryLogic::createNo()); - } - } diff --git a/src/Type/Constant/ConstantArrayTypeAndMethod.php b/src/Type/Constant/ConstantArrayTypeAndMethod.php index 01e735d949..07f4156550 100644 --- a/src/Type/Constant/ConstantArrayTypeAndMethod.php +++ b/src/Type/Constant/ConstantArrayTypeAndMethod.php @@ -8,9 +8,8 @@ /** * @api - * @final */ -class ConstantArrayTypeAndMethod +final class ConstantArrayTypeAndMethod { private function __construct( diff --git a/src/Type/Constant/ConstantArrayTypeBuilder.php b/src/Type/Constant/ConstantArrayTypeBuilder.php index e5caa1117a..4f1e558254 100644 --- a/src/Type/Constant/ConstantArrayTypeBuilder.php +++ b/src/Type/Constant/ConstantArrayTypeBuilder.php @@ -24,9 +24,8 @@ /** * @api - * @final */ -class ConstantArrayTypeBuilder +final class ConstantArrayTypeBuilder { public const ARRAY_COUNT_LIMIT = 256; @@ -308,7 +307,7 @@ public function getArray(): Type } if ($this->isList->yes()) { - $array = AccessoryArrayListType::intersectWith($array); + $array = TypeCombinator::intersect($array, new AccessoryArrayListType()); } return $array; diff --git a/src/Type/Constant/ConstantBooleanType.php b/src/Type/Constant/ConstantBooleanType.php index db5328d0d2..a01321c138 100644 --- a/src/Type/Constant/ConstantBooleanType.php +++ b/src/Type/Constant/ConstantBooleanType.php @@ -40,7 +40,7 @@ public function describe(VerbosityLevel $level): string return $this->value ? 'true' : 'false'; } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { if ($this->value) { return StaticTypeFactory::falsey(); @@ -48,7 +48,7 @@ public function getSmallerType(): Type return new NeverType(); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { if ($this->value) { return new MixedType(); @@ -56,7 +56,7 @@ public function getSmallerOrEqualType(): Type return StaticTypeFactory::falsey(); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { if ($this->value) { return new NeverType(); @@ -64,7 +64,7 @@ public function getGreaterType(): Type return StaticTypeFactory::truthy(); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { if ($this->value) { return StaticTypeFactory::truthy(); @@ -127,14 +127,6 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode($this->value ? 'true' : 'false'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['value']); - } - public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType { if ($type->isObject()->yes()) { diff --git a/src/Type/Constant/ConstantFloatType.php b/src/Type/Constant/ConstantFloatType.php index 3aeb1e2e18..0ac763af76 100644 --- a/src/Type/Constant/ConstantFloatType.php +++ b/src/Type/Constant/ConstantFloatType.php @@ -100,12 +100,4 @@ public function toPhpDocNode(): TypeNode return new ConstTypeNode(new ConstExprFloatNode($this->castFloatToString($this->value))); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['value']); - } - } diff --git a/src/Type/Constant/ConstantIntegerType.php b/src/Type/Constant/ConstantIntegerType.php index 603281d734..52f29d37a2 100644 --- a/src/Type/Constant/ConstantIntegerType.php +++ b/src/Type/Constant/ConstantIntegerType.php @@ -5,7 +5,6 @@ use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; -use PHPStan\TrinaryLogic; use PHPStan\Type\CompoundType; use PHPStan\Type\ConstantScalarType; use PHPStan\Type\GeneralizePrecision; @@ -38,12 +37,7 @@ public function getValue(): int return $this->value; } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return $this->value === $type->value ? IsSuperTypeOfResult::createYes() : IsSuperTypeOfResult::createNo(); @@ -64,7 +58,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -111,12 +105,4 @@ public function toPhpDocNode(): TypeNode return new ConstTypeNode(new ConstExprIntegerNode((string) $this->value)); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['value']); - } - } diff --git a/src/Type/Constant/ConstantStringType.php b/src/Type/Constant/ConstantStringType.php index f0e78cf903..19cfe07e7d 100644 --- a/src/Type/Constant/ConstantStringType.php +++ b/src/Type/Constant/ConstantStringType.php @@ -6,13 +6,13 @@ use Nette\Utils\Strings; use PhpParser\Node\Name; use PHPStan\Analyser\OutOfClassScope; -use PHPStan\DependencyInjection\BleedingEdgeToggle; -use PHPStan\PhpDocParser\Ast\ConstExpr\QuoteAwareConstExprStringNode; +use PHPStan\Php\PhpVersion; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\Callables\FunctionCallableVariant; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\InaccessibleMethod; use PHPStan\Reflection\PhpVersionStaticAccessor; use PHPStan\Reflection\ReflectionProviderStaticAccessor; @@ -85,7 +85,7 @@ public function getConstantStrings(): array return [$this]; } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { if ($this->isClassString) { return TrinaryLogic::createYes(); @@ -98,7 +98,7 @@ public function isClassStringType(): TrinaryLogic public function getClassStringObjectType(): Type { - if ($this->isClassStringType()->yes()) { + if ($this->isClassString()->yes()) { return new ObjectType($this->value); } @@ -110,14 +110,6 @@ public function getObjectTypeOrClassStringObjectType(): Type return $this->getClassStringObjectType(); } - /** - * @deprecated use isClassStringType() instead - */ - public function isClassString(): bool - { - return $this->isClassStringType()->yes(); - } - public function describe(VerbosityLevel $level): string { return $level->handle( @@ -149,12 +141,7 @@ private function export(string $value): string return "'" . addcslashes($value, '\\\'') . "'"; } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof GenericClassStringType) { $genericType = $type->getGenericType(); @@ -172,9 +159,9 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult // Do not use TemplateType's isSuperTypeOf handling directly because it takes ObjectType // uncertainty into account. if ($genericType instanceof TemplateType) { - $isSuperType = $genericType->getBound()->isSuperTypeOfWithReason($objectType); + $isSuperType = $genericType->getBound()->isSuperTypeOf($objectType); } else { - $isSuperType = $genericType->isSuperTypeOfWithReason($objectType); + $isSuperType = $genericType->isSuperTypeOf($objectType); } // Explicitly handle the uncertainty for Yes & Maybe. @@ -184,7 +171,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return IsSuperTypeOfResult::createNo(); } if ($type instanceof ClassStringType) { - return $this->isClassStringType()->yes() ? IsSuperTypeOfResult::createMaybe() : IsSuperTypeOfResult::createNo(); + return $this->isClassString()->yes() ? IsSuperTypeOfResult::createMaybe() : IsSuperTypeOfResult::createNo(); } if ($type instanceof self) { @@ -196,7 +183,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -227,8 +214,7 @@ public function isCallable(): TrinaryLogic if ($classRef->hasMethod($matches[2])) { $method = $classRef->getMethod($matches[2], new OutOfClassScope()); if ( - BleedingEdgeToggle::isBleedingEdge() - && !$phpVersion->supportsCallableInstanceMethods() + !$phpVersion->supportsCallableInstanceMethods() && !$method->isStatic() ) { return TrinaryLogic::createNo(); @@ -367,7 +353,7 @@ public function hasOffsetValueType(Type $offsetType): TrinaryLogic { if ($offsetType->isInteger()->yes()) { $strLenType = IntegerRangeType::fromInterval(0, strlen($this->value) - 1); - return $strLenType->isSuperTypeOf($offsetType); + return $strLenType->isSuperTypeOf($offsetType)->result; } return parent::hasOffsetValueType($offsetType); @@ -491,7 +477,7 @@ public function generalize(GeneralizePrecision $precision): Type return new StringType(); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { $subtractedTypes = [ new ConstantBooleanType(true), @@ -510,7 +496,7 @@ public function getSmallerType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { $subtractedTypes = [ IntegerRangeType::createAllGreaterThan((float) $this->value), @@ -523,7 +509,7 @@ public function getSmallerOrEqualType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { $subtractedTypes = [ new ConstantBooleanType(false), @@ -537,7 +523,7 @@ public function getGreaterType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { $subtractedTypes = [ IntegerRangeType::createAllSmallerThan((float) $this->value), @@ -552,7 +538,7 @@ public function getGreaterOrEqualType(): Type public function canAccessConstants(): TrinaryLogic { - return $this->isClassStringType(); + return $this->isClassString(); } public function hasConstant(string $constantName): TrinaryLogic @@ -560,7 +546,7 @@ public function hasConstant(string $constantName): TrinaryLogic return $this->getObjectType()->hasConstant($constantName); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { return $this->getObjectType()->getConstant($constantName); } @@ -576,15 +562,7 @@ public function toPhpDocNode(): TypeNode return $this->generalize(GeneralizePrecision::moreSpecific())->toPhpDocNode(); } - return new ConstTypeNode(new QuoteAwareConstExprStringNode($this->value, QuoteAwareConstExprStringNode::SINGLE_QUOTED)); - } - - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['value'], $properties['isClassString'] ?? false); + return new ConstTypeNode(new ConstExprStringNode($this->value, ConstExprStringNode::SINGLE_QUOTED)); } } diff --git a/src/Type/Constant/OversizedArrayBuilder.php b/src/Type/Constant/OversizedArrayBuilder.php index 02e1115e1d..026e305361 100644 --- a/src/Type/Constant/OversizedArrayBuilder.php +++ b/src/Type/Constant/OversizedArrayBuilder.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Constant; +use PhpParser\Node\ArrayItem; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; use PHPStan\Node\Expr\TypeExpr; @@ -33,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; } @@ -50,22 +48,19 @@ public function build(Array_ $expr, callable $getTypeCallback): Type } else { $keyExpr = new TypeExpr($innerKeyType); } - array_splice($items, $i++, 0, [new Expr\ArrayItem( + array_splice($items, $i++, 0, [new ArrayItem( new TypeExpr($innerValueType), $keyExpr, )]); } } else { - array_splice($items, $i, 1, [new Expr\ArrayItem( + array_splice($items, $i, 1, [new ArrayItem( new TypeExpr($valueType->getIterableValueType()), new TypeExpr($valueType->getIterableKeyType()), )]); } } foreach ($items as $item) { - if ($item === null) { - continue; - } if ($item->unpack) { throw new ShouldNotHappenException(); } @@ -97,7 +92,7 @@ public function build(Array_ $expr, callable $getTypeCallback): Type $arrayType = new ArrayType($keyType, $valueType); if ($isList) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); + $arrayType = TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } return TypeCombinator::intersect($arrayType, new NonEmptyArrayType(), new OversizedArrayType()); diff --git a/src/Type/ConstantScalarType.php b/src/Type/ConstantScalarType.php index f44e18333b..b84b381717 100644 --- a/src/Type/ConstantScalarType.php +++ b/src/Type/ConstantScalarType.php @@ -3,7 +3,7 @@ namespace PHPStan\Type; /** @api */ -interface ConstantScalarType extends ConstantType +interface ConstantScalarType extends Type { /** diff --git a/src/Type/ConstantType.php b/src/Type/ConstantType.php deleted file mode 100644 index d5fab2b652..0000000000 --- a/src/Type/ConstantType.php +++ /dev/null @@ -1,9 +0,0 @@ -setBroker($broker); - } } /** diff --git a/src/Type/DynamicStaticMethodReturnTypeExtension.php b/src/Type/DynamicStaticMethodReturnTypeExtension.php index 87b74c9af4..e74f69460f 100644 --- a/src/Type/DynamicStaticMethodReturnTypeExtension.php +++ b/src/Type/DynamicStaticMethodReturnTypeExtension.php @@ -26,6 +26,7 @@ interface DynamicStaticMethodReturnTypeExtension { + /** @return class-string */ public function getClass(): string; public function isStaticMethodSupported(MethodReflection $methodReflection): bool; diff --git a/src/Type/Enum/EnumCaseObjectType.php b/src/Type/Enum/EnumCaseObjectType.php index cf91e6e2d9..5e803a6af9 100644 --- a/src/Type/Enum/EnumCaseObjectType.php +++ b/src/Type/Enum/EnumCaseObjectType.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Enum; +use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; @@ -59,22 +60,12 @@ public function equals(Type $type): bool $this->getClassName() === $type->getClassName(); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic + public function accepts(Type $type, bool $strictTypes): AcceptsResult { - return $this->acceptsWithReason($type, $strictTypes)->result; + return $this->isSuperTypeOf($type)->toAcceptsResult(); } - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult - { - return $this->isSuperTypeOfWithReason($type)->toAcceptsResult(); - } - - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createFromBoolean( @@ -83,14 +74,14 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ( $type instanceof SubtractableType && $type->getSubtractedType() !== null ) { - $isSuperType = $type->getSubtractedType()->isSuperTypeOfWithReason($this); + $isSuperType = $type->getSubtractedType()->isSuperTypeOf($this); if ($isSuperType->yes()) { return IsSuperTypeOfResult::createNo(); } @@ -98,7 +89,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult $parent = new parent($this->getClassName(), $this->getSubtractedType(), $this->getClassReflection()); - return $parent->isSuperTypeOfWithReason($type)->and(IsSuperTypeOfResult::createMaybe()); + return $parent->isSuperTypeOf($type)->and(IsSuperTypeOfResult::createMaybe()); } public function subtract(Type $type): Type @@ -185,12 +176,12 @@ public function generalize(GeneralizePrecision $precision): Type return new parent($this->getClassName(), null, $this->getClassReflection()); } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -210,12 +201,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['className'], $properties['enumCaseName'], null); - } - } diff --git a/src/Type/ErrorType.php b/src/Type/ErrorType.php index 345465b306..751271aef3 100644 --- a/src/Type/ErrorType.php +++ b/src/Type/ErrorType.php @@ -41,12 +41,4 @@ public function equals(Type $type): bool return $type instanceof self; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/FileTypeMapper.php b/src/Type/FileTypeMapper.php index edd8d3eef6..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]; @@ -519,9 +515,7 @@ 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 && !$node instanceof Node\Stmt\TraitUse && !$node instanceof Node\Stmt\TraitUseAdaptation diff --git a/src/Type/FloatType.php b/src/Type/FloatType.php index d086024868..880006af90 100644 --- a/src/Type/FloatType.php +++ b/src/Type/FloatType.php @@ -42,9 +42,6 @@ public function __construct() { } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -65,37 +62,27 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof self || $type->isInteger()->yes()) { return AcceptsResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createNo(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -241,12 +228,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -301,12 +288,4 @@ public function getFiniteTypes(): array return []; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/Generic/GenericClassStringType.php b/src/Type/Generic/GenericClassStringType.php index 893c13d2c5..4e04a9df28 100644 --- a/src/Type/Generic/GenericClassStringType.php +++ b/src/Type/Generic/GenericClassStringType.php @@ -6,7 +6,6 @@ use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\ReflectionProviderStaticAccessor; -use PHPStan\TrinaryLogic; use PHPStan\Type\AcceptsResult; use PHPStan\Type\ClassStringType; use PHPStan\Type\CompoundType; @@ -61,14 +60,14 @@ public function describe(VerbosityLevel $level): string return sprintf('%s<%s>', parent::describe($level), $this->type->describe($level)); } - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if ($type instanceof ConstantStringType) { - if (!$type->isClassStringType()->yes()) { + if (!$type->isClassString()->yes()) { return AcceptsResult::createNo(); } @@ -83,18 +82,13 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return AcceptsResult::createNo(); } - return $this->type->acceptsWithReason($objectType, $strictTypes); + return $this->type->accepts($objectType, $strictTypes); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($type instanceof ConstantStringType) { @@ -114,18 +108,18 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult // Do not use TemplateType's isSuperTypeOf handling directly because it takes ObjectType // uncertainty into account. if ($genericType instanceof TemplateType) { - $isSuperType = $genericType->getBound()->isSuperTypeOfWithReason($objectType); + $isSuperType = $genericType->getBound()->isSuperTypeOf($objectType); } else { - $isSuperType = $genericType->isSuperTypeOfWithReason($objectType); + $isSuperType = $genericType->isSuperTypeOf($objectType); } - if (!$type->isClassStringType()->yes()) { + if (!$type->isClassString()->yes()) { $isSuperType = $isSuperType->and(IsSuperTypeOfResult::createMaybe()); } return $isSuperType; } elseif ($type instanceof self) { - return $this->type->isSuperTypeOfWithReason($type->type); + return $this->type->isSuperTypeOf($type->type); } elseif ($type instanceof StringType) { return IsSuperTypeOfResult::createMaybe(); } @@ -163,7 +157,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap $typeToInfer = new ObjectType($receivedType->getValue()); } elseif ($receivedType instanceof self) { $typeToInfer = $receivedType->type; - } elseif ($receivedType->isClassStringType()->yes()) { + } elseif ($receivedType->isClassString()->yes()) { $typeToInfer = $this->type; if ($typeToInfer instanceof TemplateType) { $typeToInfer = $typeToInfer->getBound(); @@ -201,14 +195,6 @@ public function equals(Type $type): bool return true; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['type']); - } - public function toPhpDocNode(): TypeNode { return new GenericTypeNode( @@ -221,7 +207,7 @@ public function toPhpDocNode(): TypeNode public function tryRemove(Type $typeToRemove): ?Type { - if ($typeToRemove instanceof ConstantStringType && $typeToRemove->isClassStringType()->yes()) { + if ($typeToRemove instanceof ConstantStringType && $typeToRemove->isClassString()->yes()) { $generic = $this->getGenericType(); $genericObjectClassNames = $generic->getObjectClassNames(); diff --git a/src/Type/Generic/GenericObjectType.php b/src/Type/Generic/GenericObjectType.php index 6945ccaf40..a2bdadd7ae 100644 --- a/src/Type/Generic/GenericObjectType.php +++ b/src/Type/Generic/GenericObjectType.php @@ -8,12 +8,11 @@ use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\ReflectionProviderStaticAccessor; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\ShouldNotHappenException; -use PHPStan\TrinaryLogic; use PHPStan\Type\AcceptsResult; use PHPStan\Type\CompoundType; use PHPStan\Type\ErrorType; @@ -92,9 +91,6 @@ public function equals(Type $type): bool return true; } - /** - * @return string[] - */ public function getReferencedClasses(): array { $classes = parent::getReferencedClasses(); @@ -119,29 +115,19 @@ public function getVariances(): array return $this->variances; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return $this->isSuperTypeOfInternal($type, true)->toAcceptsResult(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return $this->isSuperTypeOfInternal($type, false); @@ -149,7 +135,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult private function isSuperTypeOfInternal(Type $type, bool $acceptsContext): IsSuperTypeOfResult { - $nakedSuperTypeOf = parent::isSuperTypeOfWithReason($type); + $nakedSuperTypeOf = parent::isSuperTypeOf($type); if ($nakedSuperTypeOf->no()) { return $nakedSuperTypeOf; } @@ -198,11 +184,9 @@ private function isSuperTypeOfInternal(Type $type, bool $acceptsContext): IsSupe $thisVariance = $this->variances[$i] ?? TemplateTypeVariance::createInvariant(); $ancestorVariance = $ancestor->variances[$i] ?? TemplateTypeVariance::createInvariant(); if (!$thisVariance->invariant()) { - $result = $thisVariance->isValidVarianceWithReason($templateType, $this->types[$i], $ancestor->types[$i]); - $results[] = new IsSuperTypeOfResult($result->result, $result->reasons); + $results[] = $thisVariance->isValidVariance($templateType, $this->types[$i], $ancestor->types[$i]); } else { - $result = $templateType->isValidVarianceWithReason($this->types[$i], $ancestor->types[$i]); - $results[] = new IsSuperTypeOfResult($result->result, $result->reasons); + $results[] = $templateType->isValidVariance($this->types[$i], $ancestor->types[$i]); } $results[] = IsSuperTypeOfResult::createFromBoolean($thisVariance->validPosition($ancestorVariance)); @@ -236,7 +220,7 @@ public function getClassReflection(): ?ClassReflection ->withVariances($this->variances); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -406,18 +390,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['className'], - $properties['types'], - $properties['subtractedType'] ?? null, - null, - $properties['variances'] ?? [], - ); - } - } diff --git a/src/Type/Generic/TemplateMixedType.php b/src/Type/Generic/TemplateMixedType.php index c06b082d52..8160633fc3 100644 --- a/src/Type/Generic/TemplateMixedType.php +++ b/src/Type/Generic/TemplateMixedType.php @@ -2,8 +2,8 @@ namespace PHPStan\Type\Generic; -use PHPStan\TrinaryLogic; use PHPStan\Type\AcceptsResult; +use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\MixedType; use PHPStan\Type\StrictMixedType; use PHPStan\Type\Type; @@ -37,19 +37,14 @@ public function __construct( $this->default = $default; } - public function isSuperTypeOfMixed(MixedType $type): TrinaryLogic + public function isSuperTypeOfMixed(MixedType $type): IsSuperTypeOfResult { return $this->isSuperTypeOf($type); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - $isSuperType = $this->isSuperTypeOfWithReason($acceptingType)->toAcceptsResult(); + $isSuperType = $this->isSuperTypeOf($acceptingType)->toAcceptsResult(); if ($isSuperType->no()) { return $isSuperType; } diff --git a/src/Type/Generic/TemplateStrictMixedType.php b/src/Type/Generic/TemplateStrictMixedType.php index fa204aade2..6feefd8696 100644 --- a/src/Type/Generic/TemplateStrictMixedType.php +++ b/src/Type/Generic/TemplateStrictMixedType.php @@ -2,8 +2,8 @@ namespace PHPStan\Type\Generic; -use PHPStan\TrinaryLogic; use PHPStan\Type\AcceptsResult; +use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\MixedType; use PHPStan\Type\StrictMixedType; use PHPStan\Type\Type; @@ -35,19 +35,14 @@ public function __construct( $this->default = $default; } - public function isSuperTypeOfMixed(MixedType $type): TrinaryLogic + public function isSuperTypeOfMixed(MixedType $type): IsSuperTypeOfResult { return $this->isSuperTypeOf($type); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } } diff --git a/src/Type/Generic/TemplateType.php b/src/Type/Generic/TemplateType.php index 8374c6c0ac..2dfa5dafbd 100644 --- a/src/Type/Generic/TemplateType.php +++ b/src/Type/Generic/TemplateType.php @@ -2,9 +2,8 @@ namespace PHPStan\Type\Generic; -use PHPStan\TrinaryLogic; -use PHPStan\Type\AcceptsResult; use PHPStan\Type\CompoundType; +use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\Type; /** @api */ @@ -24,9 +23,7 @@ public function toArgument(): TemplateType; public function isArgument(): bool; - public function isValidVariance(Type $a, Type $b): TrinaryLogic; - - public function isValidVarianceWithReason(Type $a, Type $b): AcceptsResult; + public function isValidVariance(Type $a, Type $b): IsSuperTypeOfResult; public function getVariance(): TemplateTypeVariance; diff --git a/src/Type/Generic/TemplateTypeArgumentStrategy.php b/src/Type/Generic/TemplateTypeArgumentStrategy.php index deeb9b6ddd..0e8f59cf5e 100644 --- a/src/Type/Generic/TemplateTypeArgumentStrategy.php +++ b/src/Type/Generic/TemplateTypeArgumentStrategy.php @@ -18,9 +18,9 @@ final class TemplateTypeArgumentStrategy implements TemplateTypeStrategy public function accepts(TemplateType $left, Type $right, bool $strictTypes): AcceptsResult { if ($right instanceof CompoundType) { - $accepts = $right->isAcceptedWithReasonBy($left, $strictTypes); + $accepts = $right->isAcceptedBy($left, $strictTypes); } else { - $accepts = $left->getBound()->acceptsWithReason($right, $strictTypes) + $accepts = $left->getBound()->accepts($right, $strictTypes) ->and(AcceptsResult::createMaybe()); if ($accepts->maybe()) { $verbosity = VerbosityLevel::getRecommendedLevelByType($left, $right); @@ -43,12 +43,4 @@ public function isArgument(): bool return true; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self(); - } - } diff --git a/src/Type/Generic/TemplateTypeMap.php b/src/Type/Generic/TemplateTypeMap.php index 30cd0e52c0..49f3a08496 100644 --- a/src/Type/Generic/TemplateTypeMap.php +++ b/src/Type/Generic/TemplateTypeMap.php @@ -12,9 +12,8 @@ /** * @api - * @final */ -class TemplateTypeMap +final class TemplateTypeMap { private static ?TemplateTypeMap $empty = null; @@ -218,15 +217,4 @@ public function resolveToBounds(): self )); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self( - $properties['types'], - $properties['lowerBoundTypes'] ?? [], - ); - } - } diff --git a/src/Type/Generic/TemplateTypeParameterStrategy.php b/src/Type/Generic/TemplateTypeParameterStrategy.php index 1ec43f153a..3e18bccf2d 100644 --- a/src/Type/Generic/TemplateTypeParameterStrategy.php +++ b/src/Type/Generic/TemplateTypeParameterStrategy.php @@ -15,10 +15,10 @@ final class TemplateTypeParameterStrategy implements TemplateTypeStrategy public function accepts(TemplateType $left, Type $right, bool $strictTypes): AcceptsResult { if ($right instanceof CompoundType) { - return $right->isAcceptedWithReasonBy($left, $strictTypes); + return $right->isAcceptedBy($left, $strictTypes); } - return $left->getBound()->acceptsWithReason($right, $strictTypes); + return $left->getBound()->accepts($right, $strictTypes); } public function isArgument(): bool @@ -26,12 +26,4 @@ public function isArgument(): bool return false; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self(); - } - } diff --git a/src/Type/Generic/TemplateTypeScope.php b/src/Type/Generic/TemplateTypeScope.php index 8cc0e54e5e..f362ecadd4 100644 --- a/src/Type/Generic/TemplateTypeScope.php +++ b/src/Type/Generic/TemplateTypeScope.php @@ -68,15 +68,4 @@ public function describe(): string return sprintf('method %s::%s()', $this->className, $this->functionName); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self - { - return new self( - $properties['className'], - $properties['functionName'], - ); - } - } diff --git a/src/Type/Generic/TemplateTypeTrait.php b/src/Type/Generic/TemplateTypeTrait.php index 9a0fa73a59..c26509b017 100644 --- a/src/Type/Generic/TemplateTypeTrait.php +++ b/src/Type/Generic/TemplateTypeTrait.php @@ -2,12 +2,10 @@ namespace PHPStan\Type\Generic; -use PHPStan\DependencyInjection\BleedingEdgeToggle; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\TrinaryLogic; use PHPStan\Type\AcceptsResult; -use PHPStan\Type\GeneralizePrecision; use PHPStan\Type\IntersectionType; use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\MixedType; @@ -104,14 +102,9 @@ public function toArgument(): TemplateType ); } - public function isValidVariance(Type $a, Type $b): TrinaryLogic + public function isValidVariance(Type $a, Type $b): IsSuperTypeOfResult { - return $this->isValidVarianceWithReason($a, $b)->result; - } - - public function isValidVarianceWithReason(Type $a, Type $b): AcceptsResult - { - return $this->variance->isValidVarianceWithReason($this, $a, $b); + return $this->variance->isValidVariance($this, $a, $b); } public function subtract(Type $typeToRemove): Type @@ -183,12 +176,7 @@ public function equals(Type $type): bool ); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { /** @var TBound $bound */ $bound = $this->getBound(); @@ -198,56 +186,41 @@ public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): && !$acceptingType instanceof TemplateType && ($acceptingType instanceof UnionType || $acceptingType instanceof IntersectionType) ) { - return $acceptingType->acceptsWithReason($this, $strictTypes); + return $acceptingType->accepts($this, $strictTypes); } if (!$acceptingType instanceof TemplateType) { - return $acceptingType->acceptsWithReason($this->getBound(), $strictTypes); + return $acceptingType->accepts($this->getBound(), $strictTypes); } if ($this->getScope()->equals($acceptingType->getScope()) && $this->getName() === $acceptingType->getName()) { - return $acceptingType->getBound()->acceptsWithReason($this->getBound(), $strictTypes); + return $acceptingType->getBound()->accepts($this->getBound(), $strictTypes); } - return $acceptingType->getBound()->acceptsWithReason($this->getBound(), $strictTypes) + return $acceptingType->getBound()->accepts($this->getBound(), $strictTypes) ->and(new AcceptsResult(TrinaryLogic::createMaybe(), [])); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { return $this->strategy->accepts($this, $type, $strictTypes); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof TemplateType || $type instanceof IntersectionType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($type instanceof NeverType) { return IsSuperTypeOfResult::createYes(); } - return $this->getBound()->isSuperTypeOfWithReason($type) + return $this->getBound()->isSuperTypeOf($type) ->and(IsSuperTypeOfResult::createMaybe()); } - public function isSubTypeOf(Type $type): TrinaryLogic - { - return $this->isSubTypeOfWithReason($type)->result; - } - - public function isSubTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSubTypeOf(Type $type): IsSuperTypeOfResult { /** @var TBound $bound */ $bound = $this->getBound(); @@ -257,18 +230,18 @@ public function isSubTypeOfWithReason(Type $type): IsSuperTypeOfResult && !$type instanceof TemplateType && ($type instanceof UnionType || $type instanceof IntersectionType) ) { - return $type->isSuperTypeOfWithReason($this); + return $type->isSuperTypeOf($this); } if (!$type instanceof TemplateType) { - return $type->isSuperTypeOfWithReason($this->getBound()); + return $type->isSuperTypeOf($this->getBound()); } if ($this->getScope()->equals($type->getScope()) && $this->getName() === $type->getName()) { - return $type->getBound()->isSuperTypeOfWithReason($this->getBound()); + return $type->getBound()->isSuperTypeOf($this->getBound()); } - return $type->getBound()->isSuperTypeOfWithReason($this->getBound()) + return $type->getBound()->isSuperTypeOf($this->getBound()) ->and(IsSuperTypeOfResult::createMaybe()); } @@ -296,13 +269,6 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap TemplateTypeVariance::createStatic(), )); if ($resolvedBound->isSuperTypeOf($receivedType)->yes()) { - if (!BleedingEdgeToggle::isBleedingEdge() && $this->shouldGeneralizeInferredType()) { - $generalizedType = $receivedType->generalize(GeneralizePrecision::templateArgument()); - if ($resolvedBound->isSuperTypeOf($generalizedType)->yes()) { - $receivedType = $generalizedType; - } - } - return (new TemplateTypeMap([ $this->name => $receivedType, ]))->union($map); @@ -395,19 +361,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode($this->name); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['scope'], - $properties['strategy'], - $properties['variance'], - $properties['name'], - $properties['bound'], - $properties['default'] ?? null, - ); - } - } diff --git a/src/Type/Generic/TemplateTypeVariance.php b/src/Type/Generic/TemplateTypeVariance.php index a426d29f21..a630895bed 100644 --- a/src/Type/Generic/TemplateTypeVariance.php +++ b/src/Type/Generic/TemplateTypeVariance.php @@ -5,8 +5,8 @@ use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\ShouldNotHappenException; use PHPStan\TrinaryLogic; -use PHPStan\Type\AcceptsResult; use PHPStan\Type\BenevolentUnionType; +use PHPStan\Type\IsSuperTypeOfResult; use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; use PHPStan\Type\Type; @@ -14,9 +14,8 @@ /** * @api - * @final */ -class TemplateTypeVariance +final class TemplateTypeVariance { private const INVARIANT = 1; @@ -28,8 +27,6 @@ class TemplateTypeVariance /** @var self[] */ private static array $registry; - private static bool $invarianceCompositionEnabled = false; - private function __construct(private int $value) { } @@ -118,7 +115,7 @@ public function compose(self $other): self return self::createInvariant(); } - if (self::$invarianceCompositionEnabled && $this->invariant()) { + if ($this->invariant()) { return self::createInvariant(); } @@ -129,35 +126,30 @@ public function compose(self $other): self return $other; } - public function isValidVariance(Type $a, Type $b): TrinaryLogic - { - return $this->isValidVarianceWithReason(null, $a, $b)->result; - } - - public function isValidVarianceWithReason(?TemplateType $templateType, Type $a, Type $b): AcceptsResult + public function isValidVariance(TemplateType $templateType, Type $a, Type $b): IsSuperTypeOfResult { if ($b instanceof NeverType) { - return AcceptsResult::createYes(); + return IsSuperTypeOfResult::createYes(); } if ($a instanceof MixedType && !$a instanceof TemplateType) { - return AcceptsResult::createYes(); + return IsSuperTypeOfResult::createYes(); } if ($a instanceof BenevolentUnionType) { if (!$a->isSuperTypeOf($b)->no()) { - return AcceptsResult::createYes(); + return IsSuperTypeOfResult::createYes(); } } if ($b instanceof BenevolentUnionType) { if (!$b->isSuperTypeOf($a)->no()) { - return AcceptsResult::createYes(); + return IsSuperTypeOfResult::createYes(); } } if ($b instanceof MixedType && !$b instanceof TemplateType) { - return AcceptsResult::createYes(); + return IsSuperTypeOfResult::createYes(); } if ($this->invariant()) { @@ -165,8 +157,7 @@ public function isValidVarianceWithReason(?TemplateType $templateType, Type $a, $reasons = []; if (!$result) { if ( - $templateType !== null - && $templateType->getScope()->getClassName() !== null + $templateType->getScope()->getClassName() !== null && $a->isSuperTypeOf($b)->yes() ) { $reasons[] = sprintf( @@ -177,19 +168,19 @@ public function isValidVarianceWithReason(?TemplateType $templateType, Type $a, } } - return new AcceptsResult(TrinaryLogic::createFromBoolean($result), $reasons); + return new IsSuperTypeOfResult(TrinaryLogic::createFromBoolean($result), $reasons); } if ($this->covariant()) { - return $a->isSuperTypeOfWithReason($b)->toAcceptsResult(); + return $a->isSuperTypeOf($b); } if ($this->contravariant()) { - return $b->isSuperTypeOfWithReason($a)->toAcceptsResult(); + return $b->isSuperTypeOf($a); } if ($this->bivariant()) { - return AcceptsResult::createYes(); + return IsSuperTypeOfResult::createYes(); } throw new ShouldNotHappenException(); @@ -245,17 +236,4 @@ public function toPhpDocNodeVariance(): string throw new ShouldNotHappenException(); } - /** - * @param array{value: int} $properties - */ - public static function __set_state(array $properties): self - { - return new self($properties['value']); - } - - public static function setInvarianceCompositionEnabled(bool $enabled): void - { - self::$invarianceCompositionEnabled = $enabled; - } - } diff --git a/src/Type/Generic/TemplateTypeVarianceMap.php b/src/Type/Generic/TemplateTypeVarianceMap.php index bcbb23ea42..072c7952e5 100644 --- a/src/Type/Generic/TemplateTypeVarianceMap.php +++ b/src/Type/Generic/TemplateTypeVarianceMap.php @@ -6,9 +6,8 @@ /** * @api - * @final */ -class TemplateTypeVarianceMap +final class TemplateTypeVarianceMap { private static ?TemplateTypeVarianceMap $empty = null; diff --git a/src/Type/GenericTypeVariableResolver.php b/src/Type/GenericTypeVariableResolver.php deleted file mode 100644 index eee42d0f1b..0000000000 --- a/src/Type/GenericTypeVariableResolver.php +++ /dev/null @@ -1,53 +0,0 @@ -getClassReflection(); - if ($classReflection === null) { - return null; - } - $ancestorClassReflection = $classReflection->getAncestorWithClassName($genericClassName); - if ($ancestorClassReflection === null) { - return null; - } - - $activeTemplateTypeMap = $ancestorClassReflection->getPossiblyIncompleteActiveTemplateTypeMap(); - - $type = $activeTemplateTypeMap->getType($typeVariableName); - if ($type instanceof ErrorType) { - $templateTypeMap = $ancestorClassReflection->getTemplateTypeMap(); - $templateType = $templateTypeMap->getType($typeVariableName); - if ($templateType === null) { - return $type; - } - - $bound = TemplateTypeHelper::resolveToBounds($templateType); - if ($bound instanceof MixedType && $bound->isExplicitMixed()) { - return new MixedType(false); - } - - return TemplateTypeHelper::resolveToDefaults($templateType); - } - - return $type; - } - -} diff --git a/src/Type/Helper/GetTemplateTypeType.php b/src/Type/Helper/GetTemplateTypeType.php index 12e03fe1b0..c45a7be5fa 100644 --- a/src/Type/Helper/GetTemplateTypeType.php +++ b/src/Type/Helper/GetTemplateTypeType.php @@ -2,7 +2,7 @@ namespace PHPStan\Type\Helper; -use PHPStan\PhpDocParser\Ast\ConstExpr\QuoteAwareConstExprStringNode; +use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; @@ -98,21 +98,9 @@ public function toPhpDocNode(): TypeNode [ $this->type->toPhpDocNode(), new IdentifierTypeNode($this->ancestorClassName), - new ConstTypeNode(new QuoteAwareConstExprStringNode($this->templateTypeName, QuoteAwareConstExprStringNode::SINGLE_QUOTED)), + new ConstTypeNode(new ConstExprStringNode($this->templateTypeName, ConstExprStringNode::SINGLE_QUOTED)), ], ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['type'], - $properties['ancestorClassName'], - $properties['templateTypeName'], - ); - } - } diff --git a/src/Type/IntegerRangeType.php b/src/Type/IntegerRangeType.php index 9d8e735f35..b90f4d31a7 100644 --- a/src/Type/IntegerRangeType.php +++ b/src/Type/IntegerRangeType.php @@ -204,30 +204,20 @@ public function shift(int $amount): Type return self::fromInterval($min, $max); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof parent) { - return $this->isSuperTypeOfWithReason($type)->toAcceptsResult(); + return $this->isSuperTypeOf($type)->toAcceptsResult(); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createNo(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self || $type instanceof ConstantIntegerType) { if ($type instanceof self) { @@ -257,21 +247,16 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof parent) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } if ($otherType instanceof UnionType) { @@ -279,7 +264,7 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult } if ($otherType instanceof IntersectionType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -298,17 +283,12 @@ private function isSubTypeOfUnionWithReason(UnionType $otherType): IsSuperTypeOf } } - return IsSuperTypeOfResult::createNo()->or(...array_map(fn (Type $innerType) => $this->isSubTypeOfWithReason($innerType), $otherType->getTypes())); + return IsSuperTypeOfResult::createNo()->or(...array_map(fn (Type $innerType) => $this->isSubTypeOf($innerType), $otherType->getTypes())); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -321,75 +301,75 @@ public function generalize(GeneralizePrecision $precision): Type return new IntegerType(); } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($this->min === null) { $minIsSmaller = TrinaryLogic::createYes(); } else { - $minIsSmaller = (new ConstantIntegerType($this->min))->isSmallerThan($otherType); + $minIsSmaller = (new ConstantIntegerType($this->min))->isSmallerThan($otherType, $phpVersion); } if ($this->max === null) { $maxIsSmaller = TrinaryLogic::createNo(); } else { - $maxIsSmaller = (new ConstantIntegerType($this->max))->isSmallerThan($otherType); + $maxIsSmaller = (new ConstantIntegerType($this->max))->isSmallerThan($otherType, $phpVersion); } return TrinaryLogic::extremeIdentity($minIsSmaller, $maxIsSmaller); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($this->min === null) { $minIsSmaller = TrinaryLogic::createYes(); } else { - $minIsSmaller = (new ConstantIntegerType($this->min))->isSmallerThanOrEqual($otherType); + $minIsSmaller = (new ConstantIntegerType($this->min))->isSmallerThanOrEqual($otherType, $phpVersion); } if ($this->max === null) { $maxIsSmaller = TrinaryLogic::createNo(); } else { - $maxIsSmaller = (new ConstantIntegerType($this->max))->isSmallerThanOrEqual($otherType); + $maxIsSmaller = (new ConstantIntegerType($this->max))->isSmallerThanOrEqual($otherType, $phpVersion); } return TrinaryLogic::extremeIdentity($minIsSmaller, $maxIsSmaller); } - public function isGreaterThan(Type $otherType): TrinaryLogic + public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($this->min === null) { $minIsSmaller = TrinaryLogic::createNo(); } else { - $minIsSmaller = $otherType->isSmallerThan((new ConstantIntegerType($this->min))); + $minIsSmaller = $otherType->isSmallerThan((new ConstantIntegerType($this->min)), $phpVersion); } if ($this->max === null) { $maxIsSmaller = TrinaryLogic::createYes(); } else { - $maxIsSmaller = $otherType->isSmallerThan((new ConstantIntegerType($this->max))); + $maxIsSmaller = $otherType->isSmallerThan((new ConstantIntegerType($this->max)), $phpVersion); } return TrinaryLogic::extremeIdentity($minIsSmaller, $maxIsSmaller); } - public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic + public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($this->min === null) { $minIsSmaller = TrinaryLogic::createNo(); } else { - $minIsSmaller = $otherType->isSmallerThanOrEqual((new ConstantIntegerType($this->min))); + $minIsSmaller = $otherType->isSmallerThanOrEqual((new ConstantIntegerType($this->min)), $phpVersion); } if ($this->max === null) { $maxIsSmaller = TrinaryLogic::createYes(); } else { - $maxIsSmaller = $otherType->isSmallerThanOrEqual((new ConstantIntegerType($this->max))); + $maxIsSmaller = $otherType->isSmallerThanOrEqual((new ConstantIntegerType($this->max)), $phpVersion); } return TrinaryLogic::extremeIdentity($minIsSmaller, $maxIsSmaller); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { $subtractedTypes = [ new ConstantBooleanType(true), @@ -402,7 +382,7 @@ public function getSmallerType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { $subtractedTypes = []; @@ -413,7 +393,7 @@ public function getSmallerOrEqualType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { $subtractedTypes = [ new NullType(), @@ -431,7 +411,7 @@ public function getGreaterType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { $subtractedTypes = []; @@ -714,19 +694,11 @@ public function toPhpDocNode(): TypeNode public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType { - if ($this->isSmallerThan($type)->yes() || $this->isGreaterThan($type)->yes()) { + if ($this->isSmallerThan($type, $phpVersion)->yes() || $this->isGreaterThan($type, $phpVersion)->yes()) { return new ConstantBooleanType(false); } return parent::looseCompare($type, $phpVersion); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['min'], $properties['max']); - } - } diff --git a/src/Type/IntegerType.php b/src/Type/IntegerType.php index 535928c045..31ef751715 100644 --- a/src/Type/IntegerType.php +++ b/src/Type/IntegerType.php @@ -51,14 +51,6 @@ public function getConstantStrings(): array return []; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - public function toNumber(): Type { return $this; diff --git a/src/Type/IntersectionType.php b/src/Type/IntersectionType.php index 519649a384..255f56dd7a 100644 --- a/src/Type/IntersectionType.php +++ b/src/Type/IntersectionType.php @@ -3,15 +3,16 @@ namespace PHPStan\Type; use PHPStan\Php\PhpVersion; +use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode; use PHPStan\PhpDocParser\Ast\Type\GenericTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\InitializerExprTypeResolver; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\TrivialParametersAcceptor; use PHPStan\Reflection\Type\IntersectionTypeUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\IntersectionTypeUnresolvedPropertyPrototypeReflection; @@ -28,6 +29,7 @@ use PHPStan\Type\Accessory\AccessoryType; use PHPStan\Type\Accessory\AccessoryUppercaseStringType; use PHPStan\Type\Accessory\NonEmptyArrayType; +use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\Generic\TemplateType; @@ -46,9 +48,10 @@ use function ksort; use function md5; use function sprintf; -use function str_starts_with; +use function strcasecmp; use function strlen; use function substr; +use function usort; /** @api */ class IntersectionType implements CompoundType @@ -181,16 +184,11 @@ public function getConstantStrings(): array return $strings; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $otherType, bool $strictTypes): AcceptsResult + public function accepts(Type $otherType, bool $strictTypes): AcceptsResult { $result = AcceptsResult::createYes(); foreach ($this->types as $type) { - $result = $result->and($type->acceptsWithReason($otherType, $strictTypes)); + $result = $result->and($type->accepts($otherType, $strictTypes)); } if (!$result->yes()) { @@ -222,12 +220,7 @@ public function acceptsWithReason(Type $otherType, bool $strictTypes): AcceptsRe return $result; } - public function isSuperTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($otherType)->result; - } - - public function isSuperTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSuperTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof IntersectionType && $this->equals($otherType)) { return IsSuperTypeOfResult::createYes(); @@ -237,21 +230,16 @@ public function isSuperTypeOfWithReason(Type $otherType): IsSuperTypeOfResult return IsSuperTypeOfResult::createYes(); } - return IsSuperTypeOfResult::createYes()->and(...array_map(static fn (Type $innerType) => $innerType->isSuperTypeOfWithReason($otherType), $this->types)); + return IsSuperTypeOfResult::createYes()->and(...array_map(static fn (Type $innerType) => $innerType->isSuperTypeOf($otherType), $this->types)); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if (($otherType instanceof self || $otherType instanceof UnionType) && !$otherType instanceof TemplateType) { - return $otherType->isSuperTypeOfWithReason($this); + return $otherType->isSuperTypeOf($this); } - $result = IsSuperTypeOfResult::maxMin(...array_map(static fn (Type $innerType) => $otherType->isSuperTypeOfWithReason($innerType), $this->types)); + $result = IsSuperTypeOfResult::maxMin(...array_map(static fn (Type $innerType) => $otherType->isSuperTypeOf($innerType), $this->types)); if ($this->isOversizedArray()->yes()) { if (!$result->no()) { return IsSuperTypeOfResult::createYes(); @@ -261,14 +249,9 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult return $result; } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - $result = AcceptsResult::maxMin(...array_map(static fn (Type $innerType) => $acceptingType->acceptsWithReason($innerType, $strictTypes), $this->types)); + $result = AcceptsResult::maxMin(...array_map(static fn (Type $innerType) => $acceptingType->accepts($innerType, $strictTypes), $this->types)); if ($this->isOversizedArray()->yes()) { if (!$result->no()) { return AcceptsResult::createYes(); @@ -314,13 +297,43 @@ public function describe(VerbosityLevel $level): string return $level->handle( function () use ($level): string { $typeNames = []; + $isList = $this->isList()->yes(); + $valueType = null; foreach ($this->getSortedTypes() as $type) { + if ($isList) { + if ($type instanceof ArrayType || $type instanceof ConstantArrayType) { + $valueType = $type->getIterableValueType(); + continue; + } + if ($type instanceof NonEmptyArrayType) { + continue; + } + } if ($type instanceof AccessoryType) { continue; } $typeNames[] = $type->generalize(GeneralizePrecision::lessSpecific())->describe($level); } + if ($isList) { + $isMixedValueType = $valueType instanceof MixedType && $valueType->describe(VerbosityLevel::precise()) === 'mixed' && !$valueType->isExplicitMixed(); + $innerType = ''; + if ($valueType !== null && !$isMixedValueType) { + $innerType = sprintf('<%s>', $valueType->describe($level)); + } + + $typeNames[] = 'list' . $innerType; + } + + usort($typeNames, static function ($a, $b) { + $cmp = strcasecmp($a, $b); + if ($cmp !== 0) { + return $cmp; + } + + return $a <=> $b; + }); + return implode('&', $typeNames); }, fn (): string => $this->describeItself($level, true), @@ -336,6 +349,10 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes) $nonEmptyStr = false; $nonFalsyStr = false; + $isList = $this->isList()->yes(); + $isArray = $this->isArray()->yes(); + $isNonEmptyArray = $this->isIterableAtLeastOnce()->yes(); + $describedTypes = []; foreach ($this->getSortedTypes() as $i => $type) { if ($type instanceof AccessoryNonEmptyStringType || $type instanceof AccessoryLiteralStringType @@ -371,10 +388,45 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes) $skipTypeNames[] = 'string'; continue; } - if ($type instanceof NonEmptyArrayType || $type instanceof AccessoryArrayListType) { - $typesToDescribe[$i] = $type; - $skipTypeNames[] = 'array'; - continue; + if ($isList || $isArray) { + if ($type instanceof ArrayType) { + $keyType = $type->getKeyType(); + $valueType = $type->getItemType(); + if ($isList) { + $isMixedValueType = $valueType instanceof MixedType && $valueType->describe(VerbosityLevel::precise()) === 'mixed' && !$valueType->isExplicitMixed(); + $valueTypeDescription = ''; + if (!$isMixedValueType) { + $valueTypeDescription = sprintf('<%s>', $valueType->describe($level)); + } + + $describedTypes[$i] = ($isNonEmptyArray ? 'non-empty-list' : 'list') . $valueTypeDescription; + } else { + $isMixedKeyType = $keyType instanceof MixedType && $keyType->describe(VerbosityLevel::precise()) === 'mixed' && !$keyType->isExplicitMixed(); + $isMixedValueType = $valueType instanceof MixedType && $valueType->describe(VerbosityLevel::precise()) === 'mixed' && !$valueType->isExplicitMixed(); + $typeDescription = ''; + if (!$isMixedKeyType) { + $typeDescription = sprintf('<%s, %s>', $keyType->describe($level), $valueType->describe($level)); + } elseif (!$isMixedValueType) { + $typeDescription = sprintf('<%s>', $valueType->describe($level)); + } + + $describedTypes[$i] = ($isNonEmptyArray ? 'non-empty-array' : 'array') . $typeDescription; + } + continue; + } elseif ($type instanceof ConstantArrayType) { + $description = $type->describe($level); + $descriptionWithoutKind = substr($description, strlen('array')); + $begin = $isList ? 'list' : 'array'; + if ($isNonEmptyArray && !$type->isIterableAtLeastOnce()->yes()) { + $begin = 'non-empty-' . $begin; + } + + $describedTypes[$i] = $begin . $descriptionWithoutKind; + continue; + } + if ($type instanceof NonEmptyArrayType || $type instanceof AccessoryArrayListType) { + continue; + } } if ($type instanceof CallableType && $type->isCommonCallable()) { @@ -396,7 +448,6 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes) $typesToDescribe[$i] = $type; } - $describedTypes = []; foreach ($baseTypes as $i => $type) { $typeDescription = $type->describe($level); @@ -410,36 +461,6 @@ private function describeItself(VerbosityLevel $level, bool $skipAccessoryTypes) } } - if ( - str_starts_with($typeDescription, 'array<') - && in_array('array', $skipTypeNames, true) - ) { - $nonEmpty = false; - $typeName = 'array'; - foreach ($typesToDescribe as $j => $typeToDescribe) { - if ( - $typeToDescribe instanceof AccessoryArrayListType - && substr($typeDescription, 0, strlen('array, ')) === 'array, ' - ) { - $typeName = 'list'; - $typeDescription = 'array<' . substr($typeDescription, strlen('array, ')); - } elseif ($typeToDescribe instanceof NonEmptyArrayType) { - $nonEmpty = true; - } else { - continue; - } - - unset($typesToDescribe[$j]); - } - - if ($nonEmpty) { - $typeName = 'non-empty-' . $typeName; - } - - $describedTypes[$i] = $typeName . '<' . substr($typeDescription, strlen('array<')); - continue; - } - if (in_array($typeDescription, $skipTypeNames, true)) { continue; } @@ -481,7 +502,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasProperty($propertyName)); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -557,7 +578,7 @@ public function hasConstant(string $constantName): TrinaryLogic return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->hasConstant($constantName)); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { foreach ($this->types as $type) { if ($type->hasConstant($constantName)->yes()) { @@ -668,9 +689,9 @@ public function isUppercaseString(): TrinaryLogic return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isUppercaseString()); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { - return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isClassStringType()); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isClassString()); } public function getClassStringObjectType(): Type @@ -760,7 +781,7 @@ public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $uni $result = $this->intersectTypes(static fn (Type $type): Type => $type->setOffsetValueType($offsetType, $valueType, $unionValues)); if ($offsetType !== null && $this->isList()->yes() && $this->isIterableAtLeastOnce()->yes() && (new ConstantIntegerType(1))->isSuperTypeOf($offsetType)->yes()) { - $result = AccessoryArrayListType::intersectWith($result); + $result = TypeCombinator::intersect($result, new AccessoryArrayListType()); } return $result; @@ -869,14 +890,14 @@ public function isCloneable(): TrinaryLogic return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isCloneable()); } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThan($otherType)); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThan($otherType, $phpVersion)); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThanOrEqual($otherType)); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThanOrEqual($otherType, $phpVersion)); } public function isNull(): TrinaryLogic @@ -943,34 +964,34 @@ public function isInteger(): TrinaryLogic return $this->intersectResults(static fn (Type $type): TrinaryLogic => $type->isInteger()); } - public function isGreaterThan(Type $otherType): TrinaryLogic + public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->intersectResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThan($type)); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThan($type, $phpVersion)); } - public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic + public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->intersectResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThanOrEqual($type)); + return $this->intersectResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThanOrEqual($type, $phpVersion)); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { - return $this->intersectTypes(static fn (Type $type): Type => $type->getSmallerType()); + return $this->intersectTypes(static fn (Type $type): Type => $type->getSmallerType($phpVersion)); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { - return $this->intersectTypes(static fn (Type $type): Type => $type->getSmallerOrEqualType()); + return $this->intersectTypes(static fn (Type $type): Type => $type->getSmallerOrEqualType($phpVersion)); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { - return $this->intersectTypes(static fn (Type $type): Type => $type->getGreaterType()); + return $this->intersectTypes(static fn (Type $type): Type => $type->getGreaterType($phpVersion)); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { - return $this->intersectTypes(static fn (Type $type): Type => $type->getGreaterOrEqualType()); + return $this->intersectTypes(static fn (Type $type): Type => $type->getGreaterOrEqualType($phpVersion)); } public function toBoolean(): BooleanType @@ -1142,14 +1163,6 @@ public function getFiniteTypes(): array return $result; } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['types']); - } - /** * @param callable(Type $type): TrinaryLogic $getResult */ @@ -1175,6 +1188,10 @@ public function toPhpDocNode(): TypeNode $nonEmptyStr = false; $nonFalsyStr = false; + $isList = $this->isList()->yes(); + $isArray = $this->isArray()->yes(); + $isNonEmptyArray = $this->isIterableAtLeastOnce()->yes(); + $describedTypes = []; foreach ($this->getSortedTypes() as $i => $type) { if ($type instanceof AccessoryNonEmptyStringType @@ -1205,11 +1222,70 @@ public function toPhpDocNode(): TypeNode $skipTypeNames[] = 'string'; continue; } - if ($type instanceof NonEmptyArrayType || $type instanceof AccessoryArrayListType) { - $typesToDescribe[$i] = $type; - $skipTypeNames[] = 'array'; - continue; + + if ($isList || $isArray) { + if ($type instanceof ArrayType) { + $keyType = $type->getKeyType(); + $valueType = $type->getItemType(); + if ($isList) { + $isMixedValueType = $valueType instanceof MixedType && $valueType->describe(VerbosityLevel::precise()) === 'mixed' && !$valueType->isExplicitMixed(); + $identifierTypeNode = new IdentifierTypeNode($isNonEmptyArray ? 'non-empty-list' : 'list'); + if (!$isMixedValueType) { + $describedTypes[$i] = new GenericTypeNode($identifierTypeNode, [ + $valueType->toPhpDocNode(), + ]); + } else { + $describedTypes[$i] = $identifierTypeNode; + } + } else { + $isMixedKeyType = $keyType instanceof MixedType && $keyType->describe(VerbosityLevel::precise()) === 'mixed' && !$keyType->isExplicitMixed(); + $isMixedValueType = $valueType instanceof MixedType && $valueType->describe(VerbosityLevel::precise()) === 'mixed' && !$valueType->isExplicitMixed(); + $identifierTypeNode = new IdentifierTypeNode($isNonEmptyArray ? 'non-empty-array' : 'array'); + if (!$isMixedKeyType) { + $describedTypes[$i] = new GenericTypeNode($identifierTypeNode, [ + $keyType->toPhpDocNode(), + $valueType->toPhpDocNode(), + ]); + } elseif (!$isMixedValueType) { + $describedTypes[$i] = new GenericTypeNode($identifierTypeNode, [ + $valueType->toPhpDocNode(), + ]); + } else { + $describedTypes[$i] = $identifierTypeNode; + } + } + continue; + } elseif ($type instanceof ConstantArrayType) { + $constantArrayTypeNode = $type->toPhpDocNode(); + if ($constantArrayTypeNode instanceof ArrayShapeNode) { + $newKind = $constantArrayTypeNode->kind; + if ($isList) { + if ($isNonEmptyArray && !$type->isIterableAtLeastOnce()->yes()) { + $newKind = ArrayShapeNode::KIND_NON_EMPTY_LIST; + } else { + $newKind = ArrayShapeNode::KIND_LIST; + } + } elseif ($isNonEmptyArray && !$type->isIterableAtLeastOnce()->yes()) { + $newKind = ArrayShapeNode::KIND_NON_EMPTY_ARRAY; + } + + if ($newKind !== $constantArrayTypeNode->kind) { + if ($constantArrayTypeNode->sealed) { + $constantArrayTypeNode = ArrayShapeNode::createSealed($constantArrayTypeNode->items, $newKind); + } else { + $constantArrayTypeNode = ArrayShapeNode::createUnsealed($constantArrayTypeNode->items, $constantArrayTypeNode->unsealedType, $newKind); + } + } + + $describedTypes[$i] = $constantArrayTypeNode; + continue; + } + } + if ($type instanceof NonEmptyArrayType || $type instanceof AccessoryArrayListType) { + continue; + } } + if (!$type instanceof AccessoryType) { $baseTypes[$i] = $type; continue; @@ -1223,7 +1299,6 @@ public function toPhpDocNode(): TypeNode $typesToDescribe[$i] = $type; } - $describedTypes = []; foreach ($baseTypes as $i => $type) { $typeNode = $type->toPhpDocNode(); if ($typeNode instanceof GenericTypeNode && $typeNode->type->name === 'array') { diff --git a/src/Type/IsSuperTypeOfResult.php b/src/Type/IsSuperTypeOfResult.php index dd28cec78f..c1decae155 100644 --- a/src/Type/IsSuperTypeOfResult.php +++ b/src/Type/IsSuperTypeOfResult.php @@ -139,6 +139,11 @@ public function negate(): self return new self($this->result->negate(), $this->reasons); } + public function describe(): string + { + return $this->result->describe(); + } + /** * @param array $operands * diff --git a/src/Type/IterableType.php b/src/Type/IterableType.php index 2d0c632298..502fb6330a 100644 --- a/src/Type/IterableType.php +++ b/src/Type/IterableType.php @@ -52,9 +52,6 @@ public function getItemType(): Type return $this->itemType; } - /** - * @return string[] - */ public function getReferencedClasses(): array { return array_merge( @@ -78,52 +75,42 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type->isConstantArray()->yes() && $type->isIterableAtLeastOnce()->no()) { return AcceptsResult::createYes(); } if ($type->isIterable()->yes()) { - return $this->getIterableValueType()->acceptsWithReason($type->getIterableValueType(), $strictTypes) - ->and($this->getIterableKeyType()->acceptsWithReason($type->getIterableKeyType(), $strictTypes)); + return $this->getIterableValueType()->accepts($type->getIterableValueType(), $strictTypes) + ->and($this->getIterableKeyType()->accepts($type->getIterableKeyType(), $strictTypes)); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createNo(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return (new IsSuperTypeOfResult($type->isIterable(), [])) - ->and($this->getIterableValueType()->isSuperTypeOfWithReason($type->getIterableValueType())) - ->and($this->getIterableKeyType()->isSuperTypeOfWithReason($type->getIterableKeyType())); + ->and($this->getIterableValueType()->isSuperTypeOf($type->getIterableValueType())) + ->and($this->getIterableKeyType()->isSuperTypeOf($type->getIterableKeyType())); } - public function isSuperTypeOfMixed(Type $type): TrinaryLogic + public function isSuperTypeOfMixed(Type $type): IsSuperTypeOfResult { - return $type->isIterable() + return (new IsSuperTypeOfResult($type->isIterable(), [])) ->and($this->isNestedTypeSuperTypeOf($this->getIterableValueType(), $type->getIterableValueType())) ->and($this->isNestedTypeSuperTypeOf($this->getIterableKeyType(), $type->getIterableKeyType())); } - private function isNestedTypeSuperTypeOf(Type $a, Type $b): TrinaryLogic + private function isNestedTypeSuperTypeOf(Type $a, Type $b): IsSuperTypeOfResult { if (!$a instanceof MixedType || !$b instanceof MixedType) { return $a->isSuperTypeOf($b); @@ -135,24 +122,19 @@ private function isNestedTypeSuperTypeOf(Type $a, Type $b): TrinaryLogic if ($a->isExplicitMixed()) { if ($b->isExplicitMixed()) { - return TrinaryLogic::createYes(); + return IsSuperTypeOfResult::createYes(); } - return TrinaryLogic::createMaybe(); + return IsSuperTypeOfResult::createMaybe(); } - return TrinaryLogic::createYes(); - } - - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; + return IsSuperTypeOfResult::createYes(); } - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof IntersectionType || $otherType instanceof UnionType) { - return $otherType->isSuperTypeOfWithReason(new UnionType([ + return $otherType->isSuperTypeOf(new UnionType([ new ArrayType($this->keyType, $this->itemType), new IntersectionType([ new ObjectType(Traversable::class), @@ -173,19 +155,14 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult return $limit->and( new IsSuperTypeOfResult($otherType->isIterable(), []), - $otherType->getIterableValueType()->isSuperTypeOfWithReason($this->itemType), - $otherType->getIterableKeyType()->isSuperTypeOfWithReason($this->keyType), + $otherType->getIterableValueType()->isSuperTypeOf($this->itemType), + $otherType->getIterableKeyType()->isSuperTypeOf($this->keyType), ); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function equals(Type $type): bool @@ -387,12 +364,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -532,12 +509,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['keyType'], $properties['itemType']); - } - } diff --git a/src/Type/JustNullableTypeTrait.php b/src/Type/JustNullableTypeTrait.php index 9545fff1da..5435c540ff 100644 --- a/src/Type/JustNullableTypeTrait.php +++ b/src/Type/JustNullableTypeTrait.php @@ -8,9 +8,6 @@ trait JustNullableTypeTrait { - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -26,37 +23,27 @@ public function getObjectClassReflections(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof static) { return AcceptsResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createNo(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -157,12 +144,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } diff --git a/src/Type/KeyOfType.php b/src/Type/KeyOfType.php index 32eab8b019..10a4cb2ea5 100644 --- a/src/Type/KeyOfType.php +++ b/src/Type/KeyOfType.php @@ -91,14 +91,4 @@ public function toPhpDocNode(): TypeNode return new GenericTypeNode(new IdentifierTypeNode('key-of'), [$this->type->toPhpDocNode()]); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['type'], - ); - } - } diff --git a/src/Type/MethodTypeSpecifyingExtension.php b/src/Type/MethodTypeSpecifyingExtension.php index 9e56ea330f..f0f11de2f4 100644 --- a/src/Type/MethodTypeSpecifyingExtension.php +++ b/src/Type/MethodTypeSpecifyingExtension.php @@ -28,6 +28,7 @@ interface MethodTypeSpecifyingExtension { + /** @return class-string */ public function getClass(): string; public function isMethodSupported(MethodReflection $methodReflection, MethodCall $node, TypeSpecifierContext $context): bool; diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index 6ca4e4bad8..c63c78f214 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -6,13 +6,13 @@ use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; -use PHPStan\Reflection\Dummy\DummyConstantReflection; +use PHPStan\Reflection\Dummy\DummyClassConstantReflection; use PHPStan\Reflection\Dummy\DummyMethodReflection; use PHPStan\Reflection\Dummy\DummyPropertyReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\TrivialParametersAcceptor; use PHPStan\Reflection\Type\CallbackUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\CallbackUnresolvedPropertyPrototypeReflection; @@ -62,9 +62,6 @@ public function __construct( $this->subtractedType = $subtractedType; } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -95,54 +92,44 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { return AcceptsResult::createYes(); } - public function isSuperTypeOfMixed(MixedType $type): TrinaryLogic + public function isSuperTypeOfMixed(MixedType $type): IsSuperTypeOfResult { if ($this->subtractedType === null) { if ($this->isExplicitMixed) { if ($type->isExplicitMixed) { - return TrinaryLogic::createYes(); + return IsSuperTypeOfResult::createYes(); } - return TrinaryLogic::createMaybe(); + return IsSuperTypeOfResult::createMaybe(); } - return TrinaryLogic::createYes(); + return IsSuperTypeOfResult::createYes(); } if ($type->subtractedType === null) { - return TrinaryLogic::createMaybe(); + return IsSuperTypeOfResult::createMaybe(); } $isSuperType = $type->subtractedType->isSuperTypeOf($this->subtractedType); if ($isSuperType->yes()) { if ($this->isExplicitMixed) { if ($type->isExplicitMixed) { - return TrinaryLogic::createYes(); + return IsSuperTypeOfResult::createYes(); } - return TrinaryLogic::createMaybe(); + return IsSuperTypeOfResult::createMaybe(); } - return TrinaryLogic::createYes(); + return IsSuperTypeOfResult::createYes(); } - return TrinaryLogic::createMaybe(); - } - - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; + return IsSuperTypeOfResult::createMaybe(); } - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($this->subtractedType === null || $type instanceof NeverType) { return IsSuperTypeOfResult::createYes(); @@ -152,7 +139,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult if ($type->subtractedType === null) { return IsSuperTypeOfResult::createMaybe(); } - $isSuperType = $type->subtractedType->isSuperTypeOfWithReason($this->subtractedType); + $isSuperType = $type->subtractedType->isSuperTypeOf($this->subtractedType); if ($isSuperType->yes()) { return $isSuperType; } @@ -160,7 +147,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return IsSuperTypeOfResult::createMaybe(); } - $result = $this->subtractedType->isSuperTypeOfWithReason($type)->negate(); + $result = $this->subtractedType->isSuperTypeOf($type)->negate(); if ($result->no()) { return IsSuperTypeOfResult::createNo([ sprintf( @@ -198,7 +185,7 @@ public function getKeysArray(): Type return new ErrorType(); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new UnionType([new IntegerType(), new StringType()]))); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new UnionType([new IntegerType(), new StringType()])), new AccessoryArrayListType()); } public function getValuesArray(): Type @@ -207,7 +194,7 @@ public function getValuesArray(): Type return new ErrorType(); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed))); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed)), new AccessoryArrayListType()); } public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type @@ -216,7 +203,7 @@ public function chunkArray(Type $lengthType, TrinaryLogic $preserveKeys): Type return new ErrorType(); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed))); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed)), new AccessoryArrayListType()); } public function fillKeysArray(Type $valueType): Type @@ -288,7 +275,7 @@ public function shuffleArray(): Type return new ErrorType(); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed))); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new MixedType($this->isExplicitMixed)), new AccessoryArrayListType()); } public function sliceArray(Type $offsetType, Type $lengthType, TrinaryLogic $preserveKeys): Type @@ -342,19 +329,14 @@ public function equals(Type $type): bool return $this->subtractedType->equals($type->subtractedType); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof self && !$otherType instanceof TemplateMixedType) { return IsSuperTypeOfResult::createYes(); } if ($this->subtractedType !== null) { - $isSuperType = $this->subtractedType->isSuperTypeOfWithReason($otherType); + $isSuperType = $this->subtractedType->isSuperTypeOf($otherType); if ($isSuperType->yes()) { return IsSuperTypeOfResult::createNo(); } @@ -363,14 +345,9 @@ public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult return IsSuperTypeOfResult::createMaybe(); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult - { - $isSuperType = $this->isSuperTypeOfWithReason($acceptingType)->toAcceptsResult(); + $isSuperType = $this->isSuperTypeOf($acceptingType)->toAcceptsResult(); if ($isSuperType->no()) { return $isSuperType; } @@ -412,7 +389,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createYes(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -464,9 +441,9 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createYes(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { - return new DummyConstantReflection($constantName); + return new DummyClassConstantReflection($constantName); } public function isCloneable(): TrinaryLogic @@ -980,7 +957,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { if ($this->subtractedType !== null) { if ($this->subtractedType->isSuperTypeOf(new StringType())->yes()) { @@ -996,7 +973,7 @@ public function isClassStringType(): TrinaryLogic public function getClassStringObjectType(): Type { - if (!$this->isClassStringType()->no()) { + if (!$this->isClassString()->no()) { return new ObjectWithoutClassType(); } @@ -1070,15 +1047,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('mixed'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['isExplicitMixed'], - $properties['subtractedType'] ?? null, - ); - } - } diff --git a/src/Type/NeverType.php b/src/Type/NeverType.php index a3d8daf1fe..eab6009abb 100644 --- a/src/Type/NeverType.php +++ b/src/Type/NeverType.php @@ -5,10 +5,10 @@ use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\ShouldNotHappenException; @@ -39,9 +39,6 @@ public function isExplicit(): bool return $this->isExplicit; } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -72,22 +69,12 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { return AcceptsResult::createYes(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createYes(); @@ -101,24 +88,14 @@ public function equals(Type $type): bool return $type instanceof self; } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { return IsSuperTypeOfResult::createYes(); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return $this->isSubTypeOfWithReason($acceptingType)->toAcceptsResult(); + return $this->isSubTypeOf($acceptingType)->toAcceptsResult(); } public function describe(VerbosityLevel $level): string @@ -151,7 +128,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { throw new ShouldNotHappenException(); } @@ -191,7 +168,7 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { throw new ShouldNotHappenException(); } @@ -501,7 +478,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -551,12 +528,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('never'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['isExplicit']); - } - } diff --git a/src/Type/NewObjectType.php b/src/Type/NewObjectType.php index 57b932a398..93d14c6936 100644 --- a/src/Type/NewObjectType.php +++ b/src/Type/NewObjectType.php @@ -91,14 +91,4 @@ public function toPhpDocNode(): TypeNode return new GenericTypeNode(new IdentifierTypeNode('new'), [$this->type->toPhpDocNode()]); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['type'], - ); - } - } diff --git a/src/Type/NonAcceptingNeverType.php b/src/Type/NonAcceptingNeverType.php index 861165cdf2..dd14d3f9d2 100644 --- a/src/Type/NonAcceptingNeverType.php +++ b/src/Type/NonAcceptingNeverType.php @@ -2,8 +2,6 @@ namespace PHPStan\Type; -use PHPStan\TrinaryLogic; - /** @api */ class NonAcceptingNeverType extends NeverType { @@ -14,12 +12,7 @@ public function __construct() parent::__construct(true); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createYes(); @@ -31,7 +24,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return IsSuperTypeOfResult::createNo(); } - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof NeverType) { return AcceptsResult::createYes(); diff --git a/src/Type/NonexistentParentClassType.php b/src/Type/NonexistentParentClassType.php index bbf9dceec8..f52c5ea8de 100644 --- a/src/Type/NonexistentParentClassType.php +++ b/src/Type/NonexistentParentClassType.php @@ -5,10 +5,10 @@ use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\ShouldNotHappenException; @@ -67,7 +67,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { throw new ShouldNotHappenException(); } @@ -107,7 +107,7 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { throw new ShouldNotHappenException(); } @@ -192,12 +192,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('parent'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/NullType.php b/src/Type/NullType.php index 2bd76023f8..7d66fa7e79 100644 --- a/src/Type/NullType.php +++ b/src/Type/NullType.php @@ -36,9 +36,6 @@ public function __construct() { } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -72,37 +69,27 @@ public function generalize(GeneralizePrecision $precision): Type return $this; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof self) { return AcceptsResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createNo(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -113,27 +100,27 @@ public function equals(Type $type): bool return $type instanceof self; } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($otherType instanceof ConstantScalarType) { return TrinaryLogic::createFromBoolean(null < $otherType->getValue()); } if ($otherType instanceof CompoundType) { - return $otherType->isGreaterThan($this); + return $otherType->isGreaterThan($this, $phpVersion); } return TrinaryLogic::createMaybe(); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($otherType instanceof ConstantScalarType) { return TrinaryLogic::createFromBoolean(null <= $otherType->getValue()); } if ($otherType instanceof CompoundType) { - return $otherType->isGreaterThanOrEqual($this); + return $otherType->isGreaterThanOrEqual($this, $phpVersion); } return TrinaryLogic::createMaybe(); @@ -310,7 +297,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -353,12 +340,12 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType return new BooleanType(); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { return new NeverType(); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { // All falsey types except '0' return new UnionType([ @@ -371,7 +358,7 @@ public function getSmallerOrEqualType(): Type ]); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { // All truthy types, but also '0' return new MixedType(false, new UnionType([ @@ -384,7 +371,7 @@ public function getGreaterType(): Type ])); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { return new MixedType(); } @@ -409,12 +396,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('null'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/ObjectShapeType.php b/src/Type/ObjectShapeType.php index af1e4d67d4..1a1beed6c0 100644 --- a/src/Type/ObjectShapeType.php +++ b/src/Type/ObjectShapeType.php @@ -3,7 +3,6 @@ namespace PHPStan\Type; use PHPStan\Analyser\OutOfClassScope; -use PHPStan\Broker\Broker; use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode; use PHPStan\PhpDocParser\Ast\Type\ConstTypeNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; @@ -11,9 +10,9 @@ use PHPStan\PhpDocParser\Ast\Type\ObjectShapeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\ClassMemberAccessAnswerer; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\MissingPropertyFromReflectionException; use PHPStan\Reflection\Php\UniversalObjectCratesClassReflectionExtension; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\ReflectionProviderStaticAccessor; use PHPStan\Reflection\Type\CallbackUnresolvedPropertyPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; @@ -103,7 +102,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createYes(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -123,22 +122,16 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember ); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); foreach ($type->getObjectClassReflections() as $classReflection) { if (!UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( $reflectionProvider, - Broker::getInstance()->getUniversalObjectCratesClasses(), $classReflection, )) { continue; @@ -209,7 +202,7 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult $otherPropertyType = $otherProperty->getReadableType(); $verbosity = VerbosityLevel::getRecommendedLevelByType($propertyType, $otherPropertyType); - $acceptsValue = $propertyType->acceptsWithReason($otherPropertyType, $strictTypes)->decorateReasons( + $acceptsValue = $propertyType->accepts($otherPropertyType, $strictTypes)->decorateReasons( static fn (string $reason) => sprintf( 'Property ($%s) type %s does not accept type %s: %s', $propertyName, @@ -237,15 +230,10 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return $result->and(new AcceptsResult($type->isObject(), [])); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($type instanceof ObjectWithoutClassType) { @@ -256,7 +244,6 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult foreach ($type->getObjectClassReflections() as $classReflection) { if (!UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( $reflectionProvider, - Broker::getInstance()->getUniversalObjectCratesClasses(), $classReflection, )) { continue; @@ -300,7 +287,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } $otherPropertyType = $otherProperty->getReadableType(); - $isSuperType = $propertyType->isSuperTypeOfWithReason($otherPropertyType); + $isSuperType = $propertyType->isSuperTypeOf($otherPropertyType); if ($isSuperType->no()) { return $isSuperType; } @@ -535,12 +522,4 @@ public function toPhpDocNode(): TypeNode return new ObjectShapeNode($items); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['properties'], $properties['optionalProperties']); - } - } diff --git a/src/Type/ObjectType.php b/src/Type/ObjectType.php index fab7c056b0..9294fa2078 100644 --- a/src/Type/ObjectType.php +++ b/src/Type/ObjectType.php @@ -5,25 +5,20 @@ use ArrayAccess; use Closure; use Countable; -use DateTime; -use DateTimeImmutable; -use DateTimeInterface; -use Error; -use Exception; use Iterator; use IteratorAggregate; use PHPStan\Analyser\OutOfClassScope; -use PHPStan\Broker\Broker; use PHPStan\Broker\ClassNotFoundException; use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\Callables\CallableParametersAcceptor; use PHPStan\Reflection\Callables\FunctionCallableVariant; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Php\UniversalObjectCratesClassReflectionExtension; use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\ReflectionProviderStaticAccessor; @@ -46,7 +41,6 @@ use PHPStan\Type\Traits\NonGeneralizableTypeTrait; use PHPStan\Type\Traits\NonGenericTypeTrait; use PHPStan\Type\Traits\UndecidedComparisonTypeTrait; -use Throwable; use Traversable; use function array_key_exists; use function array_map; @@ -173,7 +167,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -264,9 +258,6 @@ public function getPropertyWithoutTransformingStatic(string $propertyName, Class return $classReflection->getProperty($propertyName, $scope); } - /** - * @return string[] - */ public function getReferencedClasses(): array { return [$this->className]; @@ -290,19 +281,14 @@ public function getObjectClassReflections(): array return [$classReflection]; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof StaticType) { return $this->checkSubclassAcceptability($type->getClassName()); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if ($type instanceof ClosureType) { @@ -325,12 +311,7 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult return $this->checkSubclassAcceptability($thatClassNames[0]); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { $thatClassNames = $type->getObjectClassNames(); if (!$type instanceof CompoundType && $thatClassNames === [] && !$type instanceof ObjectWithoutClassType) { @@ -350,7 +331,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return self::$superTypes[$thisDescription][$description] = $type->isSubTypeOfWithReason($this); + return self::$superTypes[$thisDescription][$description] = $type->isSubTypeOf($this); } if ($type instanceof ClosureType) { @@ -369,7 +350,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult $transformResult = static fn (IsSuperTypeOfResult $result) => $result; if ($this->subtractedType !== null) { - $isSuperType = $this->subtractedType->isSuperTypeOfWithReason($type); + $isSuperType = $this->subtractedType->isSuperTypeOf($type); if ($isSuperType->yes()) { return self::$superTypes[$thisDescription][$description] = IsSuperTypeOfResult::createNo(); } @@ -382,7 +363,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult $type instanceof SubtractableType && $type->getSubtractedType() !== null ) { - $isSuperType = $type->getSubtractedType()->isSuperTypeOfWithReason($this); + $isSuperType = $type->getSubtractedType()->isSuperTypeOf($this); if ($isSuperType->yes()) { return self::$superTypes[$thisDescription][$description] = IsSuperTypeOfResult::createNo(); } @@ -636,7 +617,6 @@ public function toArray(): Type !$classReflection->getNativeReflection()->isUserDefined() || UniversalObjectCratesClassReflectionExtension::isUniversalObjectCrate( $reflectionProvider, - Broker::getInstance()->getUniversalObjectCratesClasses(), $classReflection, ) ) { @@ -814,7 +794,7 @@ public function hasConstant(string $constantName): TrinaryLogic ); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { $class = $this->getClassReflection(); if ($class === null) { @@ -1058,12 +1038,12 @@ public function isLowercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isUppercaseString(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isUppercaseString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -1343,17 +1323,6 @@ public function isCloneable(): TrinaryLogic return TrinaryLogic::createYes(); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['className'], - $properties['subtractedType'] ?? null, - ); - } - public function isInstanceOf(string $className): TrinaryLogic { $classReflection = $this->getClassReflection(); @@ -1509,10 +1478,7 @@ public function getClassReflection(): ?ClassReflection return $classReflection; } - /** - * @return self|null - */ - public function getAncestorWithClassName(string $className): ?TypeWithClassName + public function getAncestorWithClassName(string $className): ?self { if ($this->className === $className) { return $this; @@ -1600,23 +1566,21 @@ private function getInterfaces(): array public function tryRemove(Type $typeToRemove): ?Type { - if ($this->getClassName() === DateTimeInterface::class) { - if ($typeToRemove instanceof ObjectType && $typeToRemove->getClassName() === DateTimeImmutable::class) { - return new ObjectType(DateTime::class); - } - - if ($typeToRemove instanceof ObjectType && $typeToRemove->getClassName() === DateTime::class) { - return new ObjectType(DateTimeImmutable::class); - } - } + if ($typeToRemove instanceof ObjectType) { + foreach (UnionType::EQUAL_UNION_CLASSES as $baseClass => $classes) { + if ($this->getClassName() !== $baseClass) { + continue; + } - if ($this->getClassName() === Throwable::class) { - if ($typeToRemove instanceof ObjectType && $typeToRemove->getClassName() === Error::class) { - return new ObjectType(Exception::class); // phpcs:ignore SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException - } + foreach ($classes as $index => $class) { + if ($typeToRemove->getClassName() === $class) { + unset($classes[$index]); - if ($typeToRemove instanceof ObjectType && $typeToRemove->getClassName() === Exception::class) { // phpcs:ignore SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException - return new ObjectType(Error::class); + return TypeCombinator::union( + ...array_map(static fn (string $objectClass): Type => new ObjectType($objectClass), $classes), + ); + } + } } } diff --git a/src/Type/ObjectWithoutClassType.php b/src/Type/ObjectWithoutClassType.php index 52dd0e7a21..3abe064e3f 100644 --- a/src/Type/ObjectWithoutClassType.php +++ b/src/Type/ObjectWithoutClassType.php @@ -34,9 +34,6 @@ public function __construct( $this->subtractedType = $subtractedType; } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -52,15 +49,10 @@ public function getObjectClassReflections(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return AcceptsResult::createFromBoolean( @@ -68,15 +60,10 @@ public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult ); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } if ($type instanceof self) { @@ -84,7 +71,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return IsSuperTypeOfResult::createYes(); } if ($type->subtractedType !== null) { - $isSuperType = $type->subtractedType->isSuperTypeOfWithReason($this->subtractedType); + $isSuperType = $type->subtractedType->isSuperTypeOf($this->subtractedType); if ($isSuperType->yes()) { return $isSuperType; } @@ -105,7 +92,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return IsSuperTypeOfResult::createYes(); } - return $this->subtractedType->isSuperTypeOfWithReason($type)->negate(); + return $this->subtractedType->isSuperTypeOf($type)->negate(); } public function equals(Type $type): bool @@ -235,12 +222,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('object'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['subtractedType'] ?? null); - } - } diff --git a/src/Type/OffsetAccessType.php b/src/Type/OffsetAccessType.php index 430d38332c..5e4ef1aec3 100644 --- a/src/Type/OffsetAccessType.php +++ b/src/Type/OffsetAccessType.php @@ -114,15 +114,4 @@ public function toPhpDocNode(): TypeNode ); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['type'], - $properties['offset'], - ); - } - } diff --git a/src/Type/OperatorTypeSpecifyingExtensionRegistry.php b/src/Type/OperatorTypeSpecifyingExtensionRegistry.php index 809ba5bd20..7b84648f28 100644 --- a/src/Type/OperatorTypeSpecifyingExtensionRegistry.php +++ b/src/Type/OperatorTypeSpecifyingExtensionRegistry.php @@ -2,8 +2,6 @@ namespace PHPStan\Type; -use PHPStan\Broker\Broker; -use PHPStan\Reflection\BrokerAwareExtension; use function array_filter; use function array_values; @@ -14,21 +12,9 @@ final class OperatorTypeSpecifyingExtensionRegistry * @param OperatorTypeSpecifyingExtension[] $extensions */ public function __construct( - ?Broker $broker, private array $extensions, ) { - if ($broker === null) { - return; - } - - foreach ($extensions as $extension) { - if (!$extension instanceof BrokerAwareExtension) { - continue; - } - - $extension->setBroker($broker); - } } /** diff --git a/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php b/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php index 7bca91ccd9..51d8999c2f 100644 --- a/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php @@ -99,7 +99,7 @@ private function handleAnyArray(Type $arrayType, Type $columnType, ?Type $indexT $returnType = TypeCombinator::intersect($returnType, new NonEmptyArrayType()); } if ($indexType === null) { - $returnType = AccessoryArrayListType::intersectWith($returnType); + $returnType = TypeCombinator::intersect($returnType, new AccessoryArrayListType()); } return $returnType; diff --git a/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php b/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php index 33ff1509e0..fbadbac593 100644 --- a/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayFillFunctionReturnTypeExtension.php @@ -78,7 +78,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $resultType = new ArrayType(new IntegerType(), $valueType); if ((new ConstantIntegerType(0))->isSuperTypeOf($startIndexType)->yes()) { - $resultType = AccessoryArrayListType::intersectWith($resultType); + $resultType = TypeCombinator::intersect($resultType, new AccessoryArrayListType()); } if (IntegerRangeType::fromInterval(1, null)->isSuperTypeOf($numberType)->yes()) { $resultType = TypeCombinator::intersect($resultType, new NonEmptyArrayType()); diff --git a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php index 5291652129..dc31159355 100644 --- a/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php +++ b/src/Type/Php/ArrayFilterFunctionReturnTypeHelper.php @@ -17,6 +17,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; use PHPStan\ShouldNotHappenException; +use PHPStan\TrinaryLogic; use PHPStan\Type\ArrayType; use PHPStan\Type\BenevolentUnionType; use PHPStan\Type\Constant\ConstantArrayType; @@ -233,7 +234,7 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type throw new ShouldNotHappenException(); } $itemVarName = $itemVar->name; - $scope = $scope->assignVariable($itemVarName, $itemType, new MixedType()); + $scope = $scope->assignVariable($itemVarName, $itemType, new MixedType(), TrinaryLogic::createYes()); } $keyVarName = null; @@ -242,7 +243,7 @@ private function processKeyAndItemType(MutatingScope $scope, Type $keyType, Type throw new ShouldNotHappenException(); } $keyVarName = $keyVar->name; - $scope = $scope->assignVariable($keyVarName, $keyType, new MixedType()); + $scope = $scope->assignVariable($keyVarName, $keyType, new MixedType(), TrinaryLogic::createYes()); } $booleanResult = $scope->getType($expr)->toBoolean(); diff --git a/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php index d255aa8c15..7d2eb3b2a4 100644 --- a/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php @@ -14,6 +14,7 @@ use PHPStan\Analyser\TypeSpecifierContext; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Accessory\HasOffsetType; +use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\ArrayType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; @@ -58,10 +59,20 @@ public function specifyTypes( $keyType = $scope->getType($key); $arrayType = $scope->getType($array); - if (!$keyType instanceof ConstantIntegerType + if ( + !$keyType instanceof ConstantIntegerType && !$keyType instanceof ConstantStringType - && !$arrayType->isIterableAtLeastOnce()->no()) { + ) { if ($context->true()) { + if ($arrayType->isIterableAtLeastOnce()->no()) { + return $this->typeSpecifier->create( + $array, + new NonEmptyArrayType(), + $context, + $scope, + ); + } + $arrayKeyType = $arrayType->getIterableKeyType(); if ($keyType->isString()->yes()) { $arrayKeyType = $arrayKeyType->toString(); @@ -73,7 +84,6 @@ public function specifyTypes( $key, $arrayKeyType, $context, - false, $scope, ); @@ -86,10 +96,8 @@ public function specifyTypes( $arrayDimFetch, $arrayType->getIterableValueType(), $context, - false, $scope, - new Identical($arrayDimFetch, new ConstFetch(new Name('__PHPSTAN_FAUX_CONSTANT'))), - )); + ))->setRootExpr(new Identical($arrayDimFetch, new ConstFetch(new Name('__PHPSTAN_FAUX_CONSTANT')))); } return new SpecifiedTypes(); @@ -108,7 +116,6 @@ public function specifyTypes( $array, $type, $context, - false, $scope, ); } diff --git a/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php b/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php index 31c239af58..145756b971 100644 --- a/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php @@ -144,7 +144,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } $returnedArray = $returnedArrayBuilder->getArray(); if ($constantArray->isList()->yes()) { - $returnedArray = AccessoryArrayListType::intersectWith($returnedArray); + $returnedArray = TypeCombinator::intersect($returnedArray, new AccessoryArrayListType()); } $arrayTypes[] = $returnedArray; } @@ -168,12 +168,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ); } } else { - $mappedArrayType = AccessoryArrayListType::intersectWith( - TypeCombinator::intersect(new ArrayType( - new IntegerType(), - $valueType, - ), ...TypeUtils::getAccessoryTypes($arrayType)), - ); + $mappedArrayType = TypeCombinator::intersect(new ArrayType( + new IntegerType(), + $valueType, + ), new AccessoryArrayListType(), ...TypeUtils::getAccessoryTypes($arrayType)); } if ($arrayType->isIterableAtLeastOnce()->yes()) { diff --git a/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php index 5b177a9f68..58bb5fe1ad 100644 --- a/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayMergeFunctionDynamicReturnTypeExtension.php @@ -132,7 +132,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $arrayType = TypeCombinator::intersect($arrayType, new NonEmptyArrayType()); } if ($isList) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); + $arrayType = TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } return $arrayType; diff --git a/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php b/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php index 4b974bbe1d..68f2992096 100644 --- a/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/ArraySearchFunctionTypeSpecifyingExtension.php @@ -10,10 +10,7 @@ use PHPStan\Analyser\TypeSpecifierContext; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Accessory\NonEmptyArrayType; -use PHPStan\Type\ArrayType; use PHPStan\Type\FunctionTypeSpecifyingExtension; -use PHPStan\Type\MixedType; -use PHPStan\Type\TypeCombinator; use function strtolower; final class ArraySearchFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtension, TypeSpecifierAwareExtension @@ -45,9 +42,8 @@ public function specifyTypes( return $this->typeSpecifier->create( $arrayArg, - TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new NonEmptyArrayType()), + new NonEmptyArrayType(), $context, - false, $scope, ); } 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)) { diff --git a/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php index 8cf3d88c19..e10e74a53e 100644 --- a/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/ClassExistsFunctionTypeSpecifyingExtension.php @@ -50,7 +50,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ]), new ConstantBooleanType(true), $context, - false, $scope, ); } @@ -64,7 +63,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[0]->value, $narrowedType, $context, - false, $scope, ); } diff --git a/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php b/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php index 17e293973b..df1b7022ab 100644 --- a/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php +++ b/src/Type/Php/ClassImplementsFunctionReturnTypeExtension.php @@ -57,7 +57,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $variant->getReturnType(); } - if ($firstArgType->isClassStringType()->no()) { + if ($firstArgType->isClassString()->no()) { return new ConstantBooleanType(false); } diff --git a/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php b/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php index d392b20500..f8421d109e 100644 --- a/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php +++ b/src/Type/Php/ClosureFromCallableDynamicReturnTypeExtension.php @@ -5,8 +5,8 @@ use Closure; use PhpParser\Node\Expr\StaticCall; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ExtendedParametersAcceptor; use PHPStan\Reflection\MethodReflection; -use PHPStan\Reflection\ParametersAcceptorWithPhpDocs; use PHPStan\Type\ClosureType; use PHPStan\Type\DynamicStaticMethodReturnTypeExtension; use PHPStan\Type\ErrorType; @@ -47,13 +47,14 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, $variant->isVariadic(), $variant->getTemplateTypeMap(), $variant->getResolvedTemplateTypeMap(), - $variant instanceof ParametersAcceptorWithPhpDocs ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), + $variant instanceof ExtendedParametersAcceptor ? $variant->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(), [], $variant->getThrowPoints(), $variant->getImpurePoints(), $variant->getInvalidateExpressions(), $variant->getUsedVariables(), $variant->acceptsNamedArguments(), + $variant->isDeprecated(), ); } diff --git a/src/Type/Php/CountCharsFunctionDynamicReturnTypeExtension.php b/src/Type/Php/CountCharsFunctionDynamicReturnTypeExtension.php new file mode 100644 index 0000000000..e798af6bbd --- /dev/null +++ b/src/Type/Php/CountCharsFunctionDynamicReturnTypeExtension.php @@ -0,0 +1,62 @@ +getName() === 'count_chars'; + } + + public function getTypeFromFunctionCall( + FunctionReflection $functionReflection, + FuncCall $functionCall, + Scope $scope, + ): ?Type + { + $args = $functionCall->getArgs(); + + if (count($args) < 1) { + return null; + } + + $modeType = count($args) === 2 ? $scope->getType($args[1]->value) : new ConstantIntegerType(0); + + if (IntegerRangeType::fromInterval(0, 2)->isSuperTypeOf($modeType)->yes()) { + $arrayType = new ArrayType(new IntegerType(), new IntegerType()); + + return $this->phpVersion->throwsValueErrorForInternalFunctions() + ? $arrayType + : TypeUtils::toBenevolentUnion(new UnionType([$arrayType, new ConstantBooleanType(false)])); + } + + $stringType = new StringType(); + + return $this->phpVersion->throwsValueErrorForInternalFunctions() + ? $stringType + : TypeUtils::toBenevolentUnion(new UnionType([$stringType, new ConstantBooleanType(false)])); + } + +} diff --git a/src/Type/Php/CountFunctionTypeSpecifyingExtension.php b/src/Type/Php/CountFunctionTypeSpecifyingExtension.php index 03d938a7e4..b109b13f91 100644 --- a/src/Type/Php/CountFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/CountFunctionTypeSpecifyingExtension.php @@ -41,7 +41,7 @@ public function specifyTypes( return new SpecifiedTypes([], []); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, new NonEmptyArrayType(), $context, false, $scope); + return $this->typeSpecifier->create($node->getArgs()[0]->value, new NonEmptyArrayType(), $context, $scope); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php b/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php index 7e70566044..837c3fb890 100644 --- a/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/CtypeDigitFunctionTypeSpecifyingExtension.php @@ -59,7 +59,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n } $unionType = TypeCombinator::union(...$types); - $specifiedTypes = $this->typeSpecifier->create($exprArg, $unionType, $context, false, $scope); + $specifiedTypes = $this->typeSpecifier->create($exprArg, $unionType, $context, $scope); if ($exprArg instanceof Cast\String_) { $castedType = new UnionType([ @@ -71,7 +71,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n new ConstantBooleanType(true), ]); $specifiedTypes = $specifiedTypes->unionWith( - $this->typeSpecifier->create($exprArg->expr, $castedType, $context, false, $scope), + $this->typeSpecifier->create($exprArg->expr, $castedType, $context, $scope), ); } diff --git a/src/Type/Php/DateTimeModifyReturnTypeExtension.php b/src/Type/Php/DateTimeModifyReturnTypeExtension.php index 6ab34811e5..0ed2933856 100644 --- a/src/Type/Php/DateTimeModifyReturnTypeExtension.php +++ b/src/Type/Php/DateTimeModifyReturnTypeExtension.php @@ -22,7 +22,7 @@ final class DateTimeModifyReturnTypeExtension implements DynamicMethodReturnType /** @param class-string $dateTimeClass */ public function __construct( private PhpVersion $phpVersion, - private string $dateTimeClass = DateTime::class, + private string $dateTimeClass, ) { } diff --git a/src/Type/Php/DefineConstantTypeSpecifyingExtension.php b/src/Type/Php/DefineConstantTypeSpecifyingExtension.php index 81a836f620..9d4ac3d682 100644 --- a/src/Type/Php/DefineConstantTypeSpecifyingExtension.php +++ b/src/Type/Php/DefineConstantTypeSpecifyingExtension.php @@ -56,9 +56,8 @@ public function specifyTypes( ), $scope->getType($node->getArgs()[1]->value), TypeSpecifierContext::createTruthy(), - true, $scope, - ); + )->setAlwaysOverwriteTypes(); } } diff --git a/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php b/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php index 880a3c8c21..01c310459b 100644 --- a/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php +++ b/src/Type/Php/DefinedConstantTypeSpecifyingExtension.php @@ -63,7 +63,6 @@ public function specifyTypes( $expr, new MixedType(), $context, - false, $scope, ); } diff --git a/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php b/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php index d675eee45c..d43c328df5 100644 --- a/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/ExplodeFunctionDynamicReturnTypeExtension.php @@ -72,8 +72,7 @@ public function getTypeFromFunctionCall( $returnValueType = new StringType(); } - $returnType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $returnValueType)); - + $returnType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $returnValueType), new AccessoryArrayListType()); if ( !isset($args[2]) || IntegerRangeType::fromInterval(0, null)->isSuperTypeOf($scope->getType($args[2]->value))->yes() diff --git a/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php b/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php index 2eaa4308b4..9f9a51cad3 100644 --- a/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php +++ b/src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php @@ -88,7 +88,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ); $arrayType = new ArrayType($inputArgType->getIterableKeyType(), $valueType); - return $isList ? AccessoryArrayListType::intersectWith($arrayType) : $arrayType; + return $isList ? TypeCombinator::intersect($arrayType, new AccessoryArrayListType()) : $arrayType; } // Override $add_empty option @@ -116,7 +116,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $addEmpty ? TypeCombinator::addNull($valueType) : $valueType, ); - return $isList ? AccessoryArrayListType::intersectWith($arrayType) : $arrayType; + return $isList ? TypeCombinator::intersect($arrayType, new AccessoryArrayListType()) : $arrayType; } return null; diff --git a/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php b/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php index 51bc6c4b2d..5d320104a7 100644 --- a/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/FunctionExistsFunctionTypeSpecifyingExtension.php @@ -42,7 +42,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n ]), new ConstantBooleanType(true), $context, - false, $scope, ); } @@ -51,7 +50,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[0]->value, new CallableType(), $context, - false, $scope, ); } diff --git a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php index df1bf3499a..997cfea752 100644 --- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php @@ -18,7 +18,6 @@ use PHPStan\Type\FunctionTypeSpecifyingExtension; use PHPStan\Type\MixedType; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; use function strtolower; @@ -65,18 +64,15 @@ 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; } if ($isStrictComparison) { - $itemTypes = $this->typeSpecifier->resolveIdentical(new Identical($needleExpr, $item->value), $scope, $context, null); + $itemTypes = $this->typeSpecifier->resolveIdentical(new Identical($needleExpr, $item->value), $scope, $context); } else { - $itemTypes = $this->typeSpecifier->resolveEqual(new Equal($needleExpr, $item->value), $scope, $context, null); + $itemTypes = $this->typeSpecifier->resolveEqual(new Equal($needleExpr, $item->value), $scope, $context); } if ($types === null) { @@ -102,7 +98,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[1]->value, TypeCombinator::intersect($arrayType, new NonEmptyArrayType()), $context, - false, $scope, ); } @@ -115,17 +110,15 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $context->true() || ( $context->false() - && ( - count(TypeUtils::getConstantScalars($arrayValueType)) > 0 - || count(TypeUtils::getEnumCaseObjects($arrayValueType)) > 0 - ) + && count($arrayValueType->getFiniteTypes()) > 0 + && count($needleType->getFiniteTypes()) > 0 + && $arrayType->isIterableAtLeastOnce()->yes() ) ) { $specifiedTypes = $this->typeSpecifier->create( $needleExpr, $arrayValueType, $context, - false, $scope, ); if ($needleExpr instanceof AlwaysRememberedExpr) { @@ -133,7 +126,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $needleExpr->getExpr(), $arrayValueType, $context, - false, $scope, )); } @@ -143,10 +135,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $context->true() || ( $context->false() - && ( - count(TypeUtils::getConstantScalars($needleType)) === 1 - || count(TypeUtils::getEnumCaseObjects($needleType)) === 1 - ) + && count($needleType->getFiniteTypes()) === 1 ) ) { if ($context->true()) { @@ -159,7 +148,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[1]->value, new ArrayType(new MixedType(), $arrayValueType), TypeSpecifierContext::createTrue(), - false, $scope, )); } @@ -169,7 +157,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[1]->value, TypeCombinator::intersect($arrayType, new NonEmptyArrayType()), $context, - false, $scope, )); } diff --git a/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php index c4000b9aff..fe6048dbb9 100644 --- a/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php @@ -51,7 +51,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[0]->value, $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, true), $context, - false, $scope, ); } diff --git a/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php index 20ca925c1c..e31033185e 100644 --- a/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsArrayFunctionTypeSpecifyingExtension.php @@ -20,10 +20,6 @@ final class IsArrayFunctionTypeSpecifyingExtension implements FunctionTypeSpecif private TypeSpecifier $typeSpecifier; - public function __construct(private bool $explicitMixed) - { - } - public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool { return strtolower($functionReflection->getName()) === 'is_array' @@ -39,7 +35,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n throw new ShouldNotHappenException(); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, new ArrayType(new MixedType($this->explicitMixed), new MixedType($this->explicitMixed)), $context, false, $scope); + return $this->typeSpecifier->create($node->getArgs()[0]->value, new ArrayType(new MixedType(true), new MixedType(true)), $context, $scope); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php index 472683ffb1..42c5fe8505 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), @@ -62,7 +58,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return $this->methodExistsExtension->specifyTypes($functionReflection, $functionCall, $scope, $context); } - return $this->typeSpecifier->create($value, new CallableType(), $context, false, $scope); + return $this->typeSpecifier->create($value, new CallableType(), $context, $scope); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php index c523fde243..a8404ef99f 100644 --- a/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsIterableFunctionTypeSpecifyingExtension.php @@ -36,7 +36,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return new SpecifiedTypes(); } - return $this->typeSpecifier->create($node->getArgs()[0]->value, new IterableType(new MixedType(), new MixedType()), $context, false, $scope); + return $this->typeSpecifier->create($node->getArgs()[0]->value, new IterableType(new MixedType(), new MixedType()), $context, $scope); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php index 2d52ee99e1..5bf3d9df9b 100644 --- a/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php @@ -52,7 +52,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $node->getArgs()[0]->value, $this->isAFunctionTypeSpecifyingHelper->determineType($objectOrClassType, $classType, $allowString, false), $context, - false, $scope, ); } diff --git a/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php b/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php index d1dc17f176..618fdb1fdc 100644 --- a/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php +++ b/src/Type/Php/IteratorToArrayFunctionReturnTypeExtension.php @@ -12,6 +12,7 @@ use PHPStan\Type\IntegerType; use PHPStan\Type\NeverType; use PHPStan\Type\Type; +use PHPStan\Type\TypeCombinator; use function strtolower; final class IteratorToArrayFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -36,10 +37,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $preserveKeysType = $scope->getType($arguments[1]->value); if ($preserveKeysType->isFalse()->yes()) { - return AccessoryArrayListType::intersectWith(new ArrayType( + return TypeCombinator::intersect(new ArrayType( new IntegerType(), $traversableType->getIterableValueType(), - )); + ), new AccessoryArrayListType()); } } diff --git a/src/Type/Php/LtrimFunctionReturnTypeExtension.php b/src/Type/Php/LtrimFunctionReturnTypeExtension.php index b8b5b38c6f..284be58a82 100644 --- a/src/Type/Php/LtrimFunctionReturnTypeExtension.php +++ b/src/Type/Php/LtrimFunctionReturnTypeExtension.php @@ -29,7 +29,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $string = $scope->getType($functionCall->getArgs()[0]->value); $trimChars = $scope->getType($functionCall->getArgs()[1]->value); - if ($trimChars instanceof ConstantStringType && $trimChars->getValue() === '\\' && $string->isClassStringType()->yes()) { + if ($trimChars instanceof ConstantStringType && $trimChars->getValue() === '\\' && $string->isClassString()->yes()) { if ($string instanceof ConstantStringType) { return new ConstantStringType(ltrim($string->getValue(), $trimChars->getValue()), true); } diff --git a/src/Type/Php/MethodExistsTypeSpecifyingExtension.php b/src/Type/Php/MethodExistsTypeSpecifyingExtension.php index bdff31b842..ba67e53322 100644 --- a/src/Type/Php/MethodExistsTypeSpecifyingExtension.php +++ b/src/Type/Php/MethodExistsTypeSpecifyingExtension.php @@ -53,7 +53,7 @@ public function specifyTypes( $objectType = $scope->getType($node->getArgs()[0]->value); if ($objectType->isString()->yes()) { - if ($objectType->isClassStringType()->yes()) { + if ($objectType->isClassString()->yes()) { return $this->typeSpecifier->create( $node->getArgs()[0]->value, new IntersectionType([ @@ -61,7 +61,6 @@ public function specifyTypes( new HasMethodType($methodNameType->getValue()), ]), $context, - false, $scope, ); } @@ -79,7 +78,6 @@ public function specifyTypes( new ClassStringType(), ]), $context, - false, $scope, ); } diff --git a/src/Type/Php/MinMaxFunctionReturnTypeExtension.php b/src/Type/Php/MinMaxFunctionReturnTypeExtension.php index 20128f0a92..c10150b748 100644 --- a/src/Type/Php/MinMaxFunctionReturnTypeExtension.php +++ b/src/Type/Php/MinMaxFunctionReturnTypeExtension.php @@ -11,7 +11,6 @@ use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\ConstantScalarType; -use PHPStan\Type\ConstantType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\ErrorType; use PHPStan\Type\Type; @@ -152,16 +151,19 @@ private function processType( { $resultType = null; foreach ($types as $type) { - if (!$type instanceof ConstantType) { + if (!$type->isConstantValue()->yes()) { return TypeCombinator::union(...$types); } - if ($resultType === null) { $resultType = $type; continue; } $compareResult = $this->compareTypes($resultType, $type); + if ($compareResult === null) { + return TypeCombinator::union(...$types); + } + if ($functionName === 'min') { if ($compareResult === $type) { $resultType = $type; diff --git a/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php b/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php index 083914085a..893627aae2 100644 --- a/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php +++ b/src/Type/Php/NonEmptyStringFunctionsReturnTypeExtension.php @@ -2,17 +2,20 @@ namespace PHPStan\Type\Php; +use PhpParser\Node\Arg; use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\Accessory\AccessoryNonEmptyStringType; use PHPStan\Type\Accessory\AccessoryNonFalsyStringType; +use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\IntersectionType; use PHPStan\Type\StringType; use PHPStan\Type\Type; use function count; use function in_array; +use const ENT_SUBSTITUTE; final class NonEmptyStringFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension { @@ -45,6 +48,15 @@ public function getTypeFromFunctionCall( return null; } + if (in_array($functionReflection->getName(), [ + 'htmlspecialchars', + 'htmlentities', + ], true)) { + if (!$this->isSubstituteFlagSet($args, $scope)) { + return new StringType(); + } + } + $argType = $scope->getType($args[0]->value); if ($argType->isNonFalsyString()->yes()) { return new IntersectionType([ @@ -62,4 +74,22 @@ public function getTypeFromFunctionCall( return new StringType(); } + /** + * @param Arg[] $args + */ + private function isSubstituteFlagSet( + array $args, + Scope $scope, + ): bool + { + if (!isset($args[1])) { + return true; + } + $flagsType = $scope->getType($args[1]->value); + if (!$flagsType instanceof ConstantIntegerType) { + return false; + } + return (bool) ($flagsType->getValue() & ENT_SUBSTITUTE); + } + } diff --git a/src/Type/Php/PregMatchTypeSpecifyingExtension.php b/src/Type/Php/PregMatchTypeSpecifyingExtension.php index 2c7cad49be..09606087f1 100644 --- a/src/Type/Php/PregMatchTypeSpecifyingExtension.php +++ b/src/Type/Php/PregMatchTypeSpecifyingExtension.php @@ -68,14 +68,17 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $context = $context->negate(); } - return $this->typeSpecifier->create( + $types = $this->typeSpecifier->create( $matchesArg->value, $matchedType, $context, - $overwrite, $scope, - $node, - ); + )->setRootExpr($node); + if ($overwrite) { + $types = $types->setAlwaysOverwriteTypes(); + } + + return $types; } } diff --git a/src/Type/Php/PregSplitDynamicReturnTypeExtension.php b/src/Type/Php/PregSplitDynamicReturnTypeExtension.php index d898085584..d51b5314b0 100644 --- a/src/Type/Php/PregSplitDynamicReturnTypeExtension.php +++ b/src/Type/Php/PregSplitDynamicReturnTypeExtension.php @@ -43,7 +43,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, new IntegerType(), new ConstantArrayType([new ConstantIntegerType(0), new ConstantIntegerType(1)], [new StringType(), IntegerRangeType::fromInterval(0, null)], [2], [], TrinaryLogic::createYes()), ); - return TypeCombinator::union(AccessoryArrayListType::intersectWith($type), new ConstantBooleanType(false)); + return TypeCombinator::union(TypeCombinator::intersect($type, new AccessoryArrayListType()), new ConstantBooleanType(false)); } return null; diff --git a/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php b/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php index 70d08b9098..38592e632e 100644 --- a/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php +++ b/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php @@ -82,7 +82,6 @@ public function specifyTypes( new HasPropertyType($propertyNameType->getValue()), ]), $context, - false, $scope, ); } diff --git a/src/Type/Php/RangeFunctionReturnTypeExtension.php b/src/Type/Php/RangeFunctionReturnTypeExtension.php index aceaebf670..175370be90 100644 --- a/src/Type/Php/RangeFunctionReturnTypeExtension.php +++ b/src/Type/Php/RangeFunctionReturnTypeExtension.php @@ -89,27 +89,28 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $startConstant = $endConstant; $endConstant = $tmp; } - - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + return TypeCombinator::intersect( new ArrayType( new IntegerType(), IntegerRangeType::fromInterval($startConstant->getValue(), $endConstant->getValue()), ), new NonEmptyArrayType(), - )); + new AccessoryArrayListType(), + ); } if ($stepType->isFloat()->yes()) { - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + return TypeCombinator::intersect( new ArrayType( new IntegerType(), new FloatType(), ), new NonEmptyArrayType(), - )); + new AccessoryArrayListType(), + ); } - return AccessoryArrayListType::intersectWith(TypeCombinator::intersect( + return TypeCombinator::intersect( new ArrayType( new IntegerType(), TypeCombinator::union( @@ -119,7 +120,8 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, ), ), new NonEmptyArrayType(), - )); + new AccessoryArrayListType(), + ); } $arrayBuilder = ConstantArrayTypeBuilder::createEmpty(); foreach ($rangeValues as $value) { @@ -141,30 +143,30 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($isInteger && $isStepInteger) { if ($argType instanceof IntegerRangeType) { - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $argType)); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), $argType), new AccessoryArrayListType()); } - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new IntegerType())); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new IntegerType()), new AccessoryArrayListType()); } if ($argType->isFloat()->yes()) { - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new FloatType())); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new FloatType()), new AccessoryArrayListType()); } $numberType = new UnionType([new IntegerType(), new FloatType()]); $isNumber = $numberType->isSuperTypeOf($argType)->yes(); $isNumericString = $argType->isNumericString()->yes(); if ($isNumber || $isNumericString) { - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $numberType)); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), $numberType), new AccessoryArrayListType()); } if ($argType->isString()->yes()) { - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new StringType()), new AccessoryArrayListType()); } - return AccessoryArrayListType::intersectWith(new ArrayType( + return TypeCombinator::intersect(new ArrayType( new IntegerType(), new BenevolentUnionType([new IntegerType(), new FloatType(), new StringType()]), - )); + ), new AccessoryArrayListType()); } } diff --git a/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php b/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php index fb3e577d38..df49f7cb16 100644 --- a/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php +++ b/src/Type/Php/ReflectionClassIsSubclassOfTypeSpecifyingExtension.php @@ -50,7 +50,6 @@ public function specifyTypes(MethodReflection $methodReflection, MethodCall $nod new ObjectType($valueType->getValue()), ]), $context, - false, $scope, ); } diff --git a/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php b/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php index 04454c63b2..493ec0e9c3 100644 --- a/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php +++ b/src/Type/Php/ReflectionGetAttributesMethodReturnTypeExtension.php @@ -11,6 +11,7 @@ use PHPStan\Type\Generic\GenericObjectType; use PHPStan\Type\IntegerType; use PHPStan\Type\Type; +use PHPStan\Type\TypeCombinator; use ReflectionAttribute; use function count; @@ -43,7 +44,7 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method $argType = $scope->getType($methodCall->getArgs()[0]->value); $classType = $argType->getClassStringObjectType(); - return AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new GenericObjectType(ReflectionAttribute::class, [$classType]))); + return TypeCombinator::intersect(new ArrayType(new IntegerType(), new GenericObjectType(ReflectionAttribute::class, [$classType])), new AccessoryArrayListType()); } } diff --git a/src/Type/Php/RegexArrayShapeMatcher.php b/src/Type/Php/RegexArrayShapeMatcher.php index 64bdf2d605..cd91c0aa80 100644 --- a/src/Type/Php/RegexArrayShapeMatcher.php +++ b/src/Type/Php/RegexArrayShapeMatcher.php @@ -60,14 +60,6 @@ public function matchExpr(Expr $patternExpr, ?Type $flagsType, TrinaryLogic $was return $this->matchPatternType($this->getPatternType($patternExpr, $scope), $flagsType, $wasMatched, false); } - /** - * @deprecated use matchExpr() instead for a more precise result - */ - public function matchType(Type $patternType, ?Type $flagsType, TrinaryLogic $wasMatched): ?Type - { - return $this->matchPatternType($patternType, $flagsType, $wasMatched, false); - } - private function matchPatternType(Type $patternType, ?Type $flagsType, TrinaryLogic $wasMatched, bool $matchesAll): ?Type { if ($wasMatched->no()) { @@ -157,7 +149,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched if (!$this->containsUnmatchedAsNull($flags, $matchesAll)) { // positive match has a subject but not any capturing group $combiType = TypeCombinator::union( - new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [1], [], true), + new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [1], [], TrinaryLogic::createYes()), $combiType, ); } @@ -222,7 +214,7 @@ private function matchRegex(string $regex, ?int $flags, TrinaryLogic $wasMatched ) ) { // positive match has a subject but not any capturing group - $combiTypes[] = new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [1], [], true); + $combiTypes[] = new ConstantArrayType([new ConstantIntegerType(0)], [$this->createSubjectValueType($flags, $matchesAll)], [1], [], TrinaryLogic::createYes()); } return TypeCombinator::union(...$combiTypes); @@ -354,7 +346,7 @@ private function buildArrayType( } if ($matchesAll && $this->containsSetOrder($flags)) { - $arrayType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $builder->getArray())); + $arrayType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $builder->getArray()), new AccessoryArrayListType()); if (!$wasMatched->yes()) { $arrayType = TypeCombinator::union( new ConstantArrayType([], []), @@ -382,7 +374,7 @@ private function createSubjectValueType(int $flags, bool $matchesAll): Type if ($matchesAll) { if ($this->containsPatternOrder($flags)) { - $subjectValueType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $subjectValueType)); + $subjectValueType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $subjectValueType), new AccessoryArrayListType()); } } @@ -446,7 +438,7 @@ private function createGroupValueType(RegexCapturingGroup $captureGroup, Trinary } if ($this->containsPatternOrder($flags)) { - $groupValueType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), $groupValueType)); + $groupValueType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $groupValueType), new AccessoryArrayListType()); } return $groupValueType; diff --git a/src/Type/Php/SetTypeFunctionTypeSpecifyingExtension.php b/src/Type/Php/SetTypeFunctionTypeSpecifyingExtension.php index 934aece46e..a9134026ea 100644 --- a/src/Type/Php/SetTypeFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/SetTypeFunctionTypeSpecifyingExtension.php @@ -78,9 +78,8 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $value, TypeCombinator::union(...$types), TypeSpecifierContext::createTruthy(), - true, $scope, - ); + )->setAlwaysOverwriteTypes(); } public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void diff --git a/src/Type/Php/StrContainingTypeSpecifyingExtension.php b/src/Type/Php/StrContainingTypeSpecifyingExtension.php index 8cf678ae56..af5f0e55b7 100644 --- a/src/Type/Php/StrContainingTypeSpecifyingExtension.php +++ b/src/Type/Php/StrContainingTypeSpecifyingExtension.php @@ -90,18 +90,16 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n $args[$hackstackArg]->value, new IntersectionType($accessories), $context, - false, $scope, - new BooleanAnd( - new NotIdentical( - $args[$needleArg]->value, - new String_(''), - ), - new FuncCall(new Name('FAUX_FUNCTION'), [ - new Arg($args[$needleArg]->value), - ]), + )->setRootExpr(new BooleanAnd( + new NotIdentical( + $args[$needleArg]->value, + new String_(''), ), - ); + new FuncCall(new Name('FAUX_FUNCTION'), [ + new Arg($args[$needleArg]->value), + ]), + )); } } diff --git a/src/Type/Php/StrSplitFunctionReturnTypeExtension.php b/src/Type/Php/StrSplitFunctionReturnTypeExtension.php index 34d58152dc..9c28bc3c69 100644 --- a/src/Type/Php/StrSplitFunctionReturnTypeExtension.php +++ b/src/Type/Php/StrSplitFunctionReturnTypeExtension.php @@ -103,7 +103,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return TypeCombinator::union(...$results); } - $returnType = AccessoryArrayListType::intersectWith(new ArrayType(new IntegerType(), new StringType())); + $returnType = TypeCombinator::intersect(new ArrayType(new IntegerType(), new StringType()), new AccessoryArrayListType()); return $encoding === null && !$this->phpVersion->strSplitReturnsEmptyArray() ? TypeCombinator::intersect($returnType, new NonEmptyArrayType()) diff --git a/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php b/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php index 1f715dad2c..a6ab212328 100644 --- a/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php +++ b/src/Type/Php/TypeSpecifyingFunctionsDynamicReturnTypeExtension.php @@ -25,7 +25,7 @@ final class TypeSpecifyingFunctionsDynamicReturnTypeExtension implements Dynamic /** * @param string[] $universalObjectCratesClasses */ - public function __construct(private ReflectionProvider $reflectionProvider, private bool $treatPhpDocTypesAsCertain, private array $universalObjectCratesClasses, private bool $nullContextForVoidReturningFunctions) + public function __construct(private ReflectionProvider $reflectionProvider, private bool $treatPhpDocTypesAsCertain, private array $universalObjectCratesClasses) { } @@ -68,7 +68,7 @@ public function getTypeFromFunctionCall( private function getHelper(): ImpossibleCheckTypeHelper { if ($this->helper === null) { - $this->helper = new ImpossibleCheckTypeHelper($this->reflectionProvider, $this->typeSpecifier, $this->universalObjectCratesClasses, $this->treatPhpDocTypesAsCertain, $this->nullContextForVoidReturningFunctions); + $this->helper = new ImpossibleCheckTypeHelper($this->reflectionProvider, $this->typeSpecifier, $this->universalObjectCratesClasses, $this->treatPhpDocTypesAsCertain); } return $this->helper; diff --git a/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php b/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php index 9a5592bf40..7ca5d8bac9 100644 --- a/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php +++ b/src/Type/Php/VersionCompareFunctionDynamicReturnTypeExtension.php @@ -2,22 +2,37 @@ namespace PHPStan\Type\Php; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; +use PHPStan\Php\ComposerPhpVersionFactory; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\FunctionReflection; use PHPStan\Type\BooleanType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantIntegerType; +use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; use function array_filter; use function count; +use function is_array; use function version_compare; final class VersionCompareFunctionDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension { + /** + * @param int|array{min: int, max: int}|null $configPhpVersion + */ + public function __construct( + private int|array|null $configPhpVersion, + private ComposerPhpVersionFactory $composerPhpVersionFactory, + ) + { + } + public function isFunctionSupported(FunctionReflection $functionReflection): bool { return $functionReflection->getName() === 'version_compare'; @@ -29,19 +44,20 @@ public function getTypeFromFunctionCall( Scope $scope, ): ?Type { - if (count($functionCall->getArgs()) < 2) { + $args = $functionCall->getArgs(); + if (count($args) < 2) { return null; } - $version1Strings = $scope->getType($functionCall->getArgs()[0]->value)->getConstantStrings(); - $version2Strings = $scope->getType($functionCall->getArgs()[1]->value)->getConstantStrings(); + $version1Strings = $this->getVersionStrings($args[0]->value, $scope); + $version2Strings = $this->getVersionStrings($args[1]->value, $scope); $counts = [ count($version1Strings), count($version2Strings), ]; - if (isset($functionCall->getArgs()[2])) { - $operatorStrings = $scope->getType($functionCall->getArgs()[2]->value)->getConstantStrings(); + if (isset($args[2])) { + $operatorStrings = $scope->getType($args[2]->value)->getConstantStrings(); $counts[] = count($operatorStrings); $returnType = new BooleanType(); } else { @@ -77,4 +93,32 @@ public function getTypeFromFunctionCall( return TypeCombinator::union(...$types); } + /** + * @return ConstantStringType[] + */ + private function getVersionStrings(Expr $expr, Scope $scope): array + { + if ( + $expr instanceof Expr\ConstFetch + && $expr->name->toString() === 'PHP_VERSION' + ) { + if (is_array($this->configPhpVersion)) { + $minVersion = new PhpVersion($this->configPhpVersion['min']); + $maxVersion = new PhpVersion($this->configPhpVersion['max']); + } else { + $minVersion = $this->composerPhpVersionFactory->getMinVersion(); + $maxVersion = $this->composerPhpVersionFactory->getMaxVersion(); + } + + if ($minVersion !== null && $maxVersion !== null) { + return [ + new ConstantStringType($minVersion->getVersionString()), + new ConstantStringType($maxVersion->getVersionString()), + ]; + } + } + + return $scope->getType($expr)->getConstantStrings(); + } + } diff --git a/src/Type/ResourceType.php b/src/Type/ResourceType.php index 4327f30bde..f62023f2c6 100644 --- a/src/Type/ResourceType.php +++ b/src/Type/ResourceType.php @@ -121,12 +121,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('resource'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/StaticMethodTypeSpecifyingExtension.php b/src/Type/StaticMethodTypeSpecifyingExtension.php index dbb6a49ffa..7421f3b896 100644 --- a/src/Type/StaticMethodTypeSpecifyingExtension.php +++ b/src/Type/StaticMethodTypeSpecifyingExtension.php @@ -28,6 +28,7 @@ interface StaticMethodTypeSpecifyingExtension { + /** @return class-string */ public function getClass(): string; public function isStaticMethodSupported(MethodReflection $staticMethodReflection, StaticCall $node, TypeSpecifierContext $context): bool; diff --git a/src/Type/StaticType.php b/src/Type/StaticType.php index 7056fc5901..8885972a66 100644 --- a/src/Type/StaticType.php +++ b/src/Type/StaticType.php @@ -5,12 +5,11 @@ use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; -use PHPStan\Reflection\ReflectionProviderStaticAccessor; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\CallbackUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\CallbackUnresolvedPropertyPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; @@ -100,9 +99,6 @@ public function getStaticObjectType(): ObjectType return $this->staticObjectType; } - /** - * @return string[] - */ public function getReferencedClasses(): array { return $this->getStaticObjectType()->getReferencedClasses(); @@ -133,33 +129,23 @@ public function getConstantStrings(): array return $this->getStaticObjectType()->getConstantStrings(); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if (!$type instanceof static) { return AcceptsResult::createNo(); } - return $this->getStaticObjectType()->acceptsWithReason($type->getStaticObjectType(), $strictTypes); - } - - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; + return $this->getStaticObjectType()->accepts($type->getStaticObjectType(), $strictTypes); } - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { - return $this->getStaticObjectType()->isSuperTypeOfWithReason($type); + return $this->getStaticObjectType()->isSuperTypeOf($type); } if ($type instanceof ObjectWithoutClassType) { @@ -167,7 +153,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof ObjectType) { - $result = $this->getStaticObjectType()->isSuperTypeOfWithReason($type); + $result = $this->getStaticObjectType()->isSuperTypeOf($type); if ($result->yes()) { $classReflection = $type->getClassReflection(); if ($classReflection !== null && $classReflection->isFinal()) { @@ -179,7 +165,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -224,7 +210,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return $this->getStaticObjectType()->hasProperty($propertyName); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -320,7 +306,7 @@ public function hasConstant(string $constantName): TrinaryLogic return $this->getStaticObjectType()->hasConstant($constantName); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { return $this->getStaticObjectType()->getConstant($constantName); } @@ -585,9 +571,9 @@ public function isUppercaseString(): TrinaryLogic return $this->getStaticObjectType()->isUppercaseString(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { - return $this->getStaticObjectType()->isClassStringType(); + return $this->getStaticObjectType()->isClassString(); } public function getClassStringObjectType(): Type @@ -752,17 +738,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('static'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); - if ($reflectionProvider->hasClass($properties['baseClass'])) { - return new self($reflectionProvider->getClass($properties['baseClass']), $properties['subtractedType'] ?? null); - } - - return new ErrorType(); - } - } diff --git a/src/Type/StrictMixedType.php b/src/Type/StrictMixedType.php index c839779a55..355d186986 100644 --- a/src/Type/StrictMixedType.php +++ b/src/Type/StrictMixedType.php @@ -5,10 +5,10 @@ use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\ShouldNotHappenException; @@ -51,22 +51,12 @@ public function getConstantStrings(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { return AcceptsResult::createYes(); } - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; - } - - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { if ($acceptingType instanceof self) { return AcceptsResult::createYes(); @@ -78,22 +68,12 @@ public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): return AcceptsResult::createMaybe(); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { return IsSuperTypeOfResult::createYes(); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { if ($otherType instanceof self) { return IsSuperTypeOfResult::createYes(); @@ -145,7 +125,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { throw new ShouldNotHappenException(); } @@ -185,7 +165,7 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { throw new ShouldNotHappenException(); } @@ -295,7 +275,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -455,12 +435,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('mixed'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/StringAlwaysAcceptingObjectWithToStringType.php b/src/Type/StringAlwaysAcceptingObjectWithToStringType.php index 24a88696cb..feb18e97d6 100644 --- a/src/Type/StringAlwaysAcceptingObjectWithToStringType.php +++ b/src/Type/StringAlwaysAcceptingObjectWithToStringType.php @@ -3,25 +3,19 @@ namespace PHPStan\Type; use PHPStan\Reflection\ReflectionProviderStaticAccessor; -use PHPStan\TrinaryLogic; class StringAlwaysAcceptingObjectWithToStringType extends StringType { - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } $thatClassNames = $type->getObjectClassNames(); if ($thatClassNames === []) { - return parent::isSuperTypeOfWithReason($type); + return parent::isSuperTypeOf($type); } $result = IsSuperTypeOfResult::createNo(); @@ -38,11 +32,11 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult return $result; } - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { $thatClassNames = $type->getObjectClassNames(); if ($thatClassNames === []) { - return parent::acceptsWithReason($type, $strictTypes); + return parent::accepts($type, $strictTypes); } $result = AcceptsResult::createNo(); diff --git a/src/Type/StringType.php b/src/Type/StringType.php index c49cf7823c..4605c92efe 100644 --- a/src/Type/StringType.php +++ b/src/Type/StringType.php @@ -109,19 +109,14 @@ public function unsetOffset(Type $offsetType): Type return new ErrorType(); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof self) { return AcceptsResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } $thatClassNames = $type->getObjectClassNames(); @@ -250,7 +245,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createMaybe(); } @@ -277,7 +272,7 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType public function hasMethod(string $methodName): TrinaryLogic { - if ($this->isClassStringType()->yes()) { + if ($this->isClassString()->yes()) { return TrinaryLogic::createMaybe(); } return TrinaryLogic::createNo(); @@ -311,12 +306,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('string'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/src/Type/ThisType.php b/src/Type/ThisType.php index 3eb3eb845a..39d4949ca8 100644 --- a/src/Type/ThisType.php +++ b/src/Type/ThisType.php @@ -5,8 +5,6 @@ use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ReflectionProviderStaticAccessor; -use PHPStan\TrinaryLogic; use function sprintf; /** @api */ @@ -34,24 +32,19 @@ public function describe(VerbosityLevel $level): string return sprintf('$this(%s)', $this->getStaticObjectType()->describe($level)); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { - return $this->getStaticObjectType()->isSuperTypeOfWithReason($type); + return $this->getStaticObjectType()->isSuperTypeOf($type); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } $parent = new parent($this->getClassReflection(), $this->getSubtractedType()); - return $parent->isSuperTypeOfWithReason($type)->and(IsSuperTypeOfResult::createMaybe()); + return $parent->isSuperTypeOf($type)->and(IsSuperTypeOfResult::createMaybe()); } public function changeSubtractedType(?Type $subtractedType): Type @@ -92,17 +85,4 @@ public function toPhpDocNode(): TypeNode return new ThisTypeNode(); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - $reflectionProvider = ReflectionProviderStaticAccessor::getInstance(); - if ($reflectionProvider->hasClass($properties['baseClass'])) { - return new self($reflectionProvider->getClass($properties['baseClass']), $properties['subtractedType'] ?? null); - } - - return new ErrorType(); - } - } diff --git a/src/Type/Traits/ArrayTypeTrait.php b/src/Type/Traits/ArrayTypeTrait.php new file mode 100644 index 0000000000..ddc501d022 --- /dev/null +++ b/src/Type/Traits/ArrayTypeTrait.php @@ -0,0 +1,206 @@ +yes() + ? $this + : TypeCombinator::intersect(new ArrayType(new IntegerType(), $this->getIterableValueType()), new AccessoryArrayListType()); + $chunkType = TypeCombinator::intersect($chunkType, new NonEmptyArrayType()); + + $arrayType = TypeCombinator::intersect(new ArrayType(new IntegerType(), $chunkType), new AccessoryArrayListType()); + + return $this->isIterableAtLeastOnce()->yes() + ? TypeCombinator::intersect($arrayType, new NonEmptyArrayType()) + : $arrayType; + } + +} diff --git a/src/Type/Traits/ConstantNumericComparisonTypeTrait.php b/src/Type/Traits/ConstantNumericComparisonTypeTrait.php index 2b3b4a45c5..c6efe96950 100644 --- a/src/Type/Traits/ConstantNumericComparisonTypeTrait.php +++ b/src/Type/Traits/ConstantNumericComparisonTypeTrait.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Traits; +use PHPStan\Php\PhpVersion; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\IntegerRangeType; @@ -13,7 +14,7 @@ trait ConstantNumericComparisonTypeTrait { - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { $subtractedTypes = [ new ConstantBooleanType(true), @@ -29,7 +30,7 @@ public function getSmallerType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { $subtractedTypes = [ IntegerRangeType::createAllGreaterThan($this->value), @@ -43,7 +44,7 @@ public function getSmallerOrEqualType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { $subtractedTypes = [ new NullType(), @@ -59,7 +60,7 @@ public function getGreaterType(): Type return TypeCombinator::remove(new MixedType(), TypeCombinator::union(...$subtractedTypes)); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { $subtractedTypes = [ IntegerRangeType::createAllSmallerThan($this->value), diff --git a/src/Type/Traits/ConstantScalarTypeTrait.php b/src/Type/Traits/ConstantScalarTypeTrait.php index 4c8c6a7294..b4757aaac2 100644 --- a/src/Type/Traits/ConstantScalarTypeTrait.php +++ b/src/Type/Traits/ConstantScalarTypeTrait.php @@ -17,30 +17,20 @@ trait ConstantScalarTypeTrait { - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof self) { return AcceptsResult::createFromBoolean($this->equals($type)); } if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } - return parent::acceptsWithReason($type, $strictTypes)->and(AcceptsResult::createMaybe()); - } - - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; + return parent::accepts($type, $strictTypes)->and(AcceptsResult::createMaybe()); } - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createFromBoolean($this->equals($type)); @@ -51,7 +41,7 @@ public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -84,27 +74,27 @@ public function equals(Type $type): bool return $type instanceof self && $this->value === $type->value; } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($otherType instanceof ConstantScalarType) { return TrinaryLogic::createFromBoolean($this->value < $otherType->getValue()); } if ($otherType instanceof CompoundType) { - return $otherType->isGreaterThan($this); + return $otherType->isGreaterThan($this, $phpVersion); } return TrinaryLogic::createMaybe(); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { if ($otherType instanceof ConstantScalarType) { return TrinaryLogic::createFromBoolean($this->value <= $otherType->getValue()); } if ($otherType instanceof CompoundType) { - return $otherType->isGreaterThanOrEqual($this); + return $otherType->isGreaterThanOrEqual($this, $phpVersion); } return TrinaryLogic::createMaybe(); diff --git a/src/Type/Traits/LateResolvableTypeTrait.php b/src/Type/Traits/LateResolvableTypeTrait.php index e6355875ca..3c5a4e5b5f 100644 --- a/src/Type/Traits/LateResolvableTypeTrait.php +++ b/src/Type/Traits/LateResolvableTypeTrait.php @@ -3,10 +3,10 @@ namespace PHPStan\Type\Traits; use PHPStan\Php\PhpVersion; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\TrinaryLogic; @@ -49,22 +49,12 @@ public function getConstantStrings(): array return $this->resolve()->getConstantStrings(); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic + public function accepts(Type $type, bool $strictTypes): AcceptsResult { return $this->resolve()->accepts($type, $strictTypes); } - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult - { - return $this->resolve()->acceptsWithReason($type, $strictTypes); - } - - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { return $this->isSuperTypeOfDefault($type); } @@ -79,7 +69,7 @@ private function isSuperTypeOfDefault(Type $type): IsSuperTypeOfResult $type = $type->resolve(); } - $isSuperType = $this->resolve()->isSuperTypeOfWithReason($type); + $isSuperType = $this->resolve()->isSuperTypeOf($type); if (!$this->isResolvable()) { $isSuperType = $isSuperType->and(IsSuperTypeOfResult::createMaybe()); @@ -113,7 +103,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return $this->resolve()->hasProperty($propertyName); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->resolve()->getProperty($propertyName, $scope); } @@ -153,7 +143,7 @@ public function hasConstant(string $constantName): TrinaryLogic return $this->resolve()->hasConstant($constantName); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { return $this->resolve()->getConstant($constantName); } @@ -378,14 +368,14 @@ public function toArrayKey(): Type return $this->resolve()->toArrayKey(); } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->resolve()->isSmallerThan($otherType); + return $this->resolve()->isSmallerThan($otherType, $phpVersion); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->resolve()->isSmallerThanOrEqual($otherType); + return $this->resolve()->isSmallerThanOrEqual($otherType, $phpVersion); } public function isNull(): TrinaryLogic @@ -473,9 +463,9 @@ public function isUppercaseString(): TrinaryLogic return $this->resolve()->isUppercaseString(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { - return $this->resolve()->isClassStringType(); + return $this->resolve()->isClassString(); } public function getClassStringObjectType(): Type @@ -503,24 +493,24 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType return new BooleanType(); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { - return $this->resolve()->getSmallerType(); + return $this->resolve()->getSmallerType($phpVersion); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { - return $this->resolve()->getSmallerOrEqualType(); + return $this->resolve()->getSmallerOrEqualType($phpVersion); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { - return $this->resolve()->getGreaterType(); + return $this->resolve()->getGreaterType($phpVersion); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { - return $this->resolve()->getGreaterOrEqualType(); + return $this->resolve()->getGreaterOrEqualType($phpVersion); } public function inferTemplateTypes(Type $receivedType): TemplateTypeMap @@ -533,58 +523,48 @@ public function tryRemove(Type $typeToRemove): ?Type return $this->resolve()->tryRemove($typeToRemove); } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { $result = $this->resolve(); if ($result instanceof CompoundType) { - return $result->isSubTypeOfWithReason($otherType); + return $result->isSubTypeOf($otherType); } - return $otherType->isSuperTypeOfWithReason($result); - } - - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic - { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; + return $otherType->isSuperTypeOf($result); } - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { $result = $this->resolve(); if ($result instanceof CompoundType) { - return $result->isAcceptedWithReasonBy($acceptingType, $strictTypes); + return $result->isAcceptedBy($acceptingType, $strictTypes); } - return $acceptingType->acceptsWithReason($result, $strictTypes); + return $acceptingType->accepts($result, $strictTypes); } - public function isGreaterThan(Type $otherType): TrinaryLogic + public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { $result = $this->resolve(); if ($result instanceof CompoundType) { - return $result->isGreaterThan($otherType); + return $result->isGreaterThan($otherType, $phpVersion); } - return $otherType->isSmallerThan($result); + return $otherType->isSmallerThan($result, $phpVersion); } - public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic + public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { $result = $this->resolve(); if ($result instanceof CompoundType) { - return $result->isGreaterThanOrEqual($otherType); + return $result->isGreaterThanOrEqual($otherType, $phpVersion); } - return $otherType->isSmallerThanOrEqual($result); + return $otherType->isSmallerThanOrEqual($result, $phpVersion); } public function exponentiate(Type $exponent): Type diff --git a/src/Type/Traits/MaybeObjectTypeTrait.php b/src/Type/Traits/MaybeObjectTypeTrait.php index b8097947b4..ff50c721d3 100644 --- a/src/Type/Traits/MaybeObjectTypeTrait.php +++ b/src/Type/Traits/MaybeObjectTypeTrait.php @@ -2,13 +2,13 @@ namespace PHPStan\Type\Traits; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; -use PHPStan\Reflection\Dummy\DummyConstantReflection; +use PHPStan\Reflection\Dummy\DummyClassConstantReflection; use PHPStan\Reflection\Dummy\DummyMethodReflection; use PHPStan\Reflection\Dummy\DummyPropertyReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\CallbackUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\CallbackUnresolvedPropertyPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; @@ -45,7 +45,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -97,9 +97,9 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { - return new DummyConstantReflection($constantName); + return new DummyClassConstantReflection($constantName); } public function isCloneable(): TrinaryLogic diff --git a/src/Type/Traits/NonObjectTypeTrait.php b/src/Type/Traits/NonObjectTypeTrait.php index 3cba4b5bca..d16b86c9b1 100644 --- a/src/Type/Traits/NonObjectTypeTrait.php +++ b/src/Type/Traits/NonObjectTypeTrait.php @@ -2,10 +2,10 @@ namespace PHPStan\Type\Traits; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\ShouldNotHappenException; @@ -36,7 +36,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { throw new ShouldNotHappenException(); } @@ -76,7 +76,7 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createNo(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { throw new ShouldNotHappenException(); } diff --git a/src/Type/Traits/ObjectTypeTrait.php b/src/Type/Traits/ObjectTypeTrait.php index 7cf3659a50..70f7d2c007 100644 --- a/src/Type/Traits/ObjectTypeTrait.php +++ b/src/Type/Traits/ObjectTypeTrait.php @@ -3,13 +3,13 @@ namespace PHPStan\Type\Traits; use PHPStan\Php\PhpVersion; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; -use PHPStan\Reflection\Dummy\DummyConstantReflection; +use PHPStan\Reflection\Dummy\DummyClassConstantReflection; use PHPStan\Reflection\Dummy\DummyMethodReflection; use PHPStan\Reflection\Dummy\DummyPropertyReflection; use PHPStan\Reflection\ExtendedMethodReflection; -use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\Type\CallbackUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\CallbackUnresolvedPropertyPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; @@ -56,7 +56,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -108,9 +108,9 @@ public function hasConstant(string $constantName): TrinaryLogic return TrinaryLogic::createMaybe(); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { - return new DummyConstantReflection($constantName); + return new DummyClassConstantReflection($constantName); } public function getConstantStrings(): array @@ -208,7 +208,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } diff --git a/src/Type/Traits/UndecidedComparisonCompoundTypeTrait.php b/src/Type/Traits/UndecidedComparisonCompoundTypeTrait.php index e40b72fad4..6adf571d54 100644 --- a/src/Type/Traits/UndecidedComparisonCompoundTypeTrait.php +++ b/src/Type/Traits/UndecidedComparisonCompoundTypeTrait.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Traits; +use PHPStan\Php\PhpVersion; use PHPStan\TrinaryLogic; use PHPStan\Type\Type; @@ -10,12 +11,12 @@ trait UndecidedComparisonCompoundTypeTrait use UndecidedComparisonTypeTrait; - public function isGreaterThan(Type $otherType): TrinaryLogic + public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic + public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { return TrinaryLogic::createMaybe(); } diff --git a/src/Type/Traits/UndecidedComparisonTypeTrait.php b/src/Type/Traits/UndecidedComparisonTypeTrait.php index e5c6d2c891..6761274cf1 100644 --- a/src/Type/Traits/UndecidedComparisonTypeTrait.php +++ b/src/Type/Traits/UndecidedComparisonTypeTrait.php @@ -2,6 +2,7 @@ namespace PHPStan\Type\Traits; +use PHPStan\Php\PhpVersion; use PHPStan\TrinaryLogic; use PHPStan\Type\MixedType; use PHPStan\Type\Type; @@ -9,32 +10,32 @@ trait UndecidedComparisonTypeTrait { - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { return TrinaryLogic::createMaybe(); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { return new MixedType(); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { return new MixedType(); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { return new MixedType(); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { return new MixedType(); } diff --git a/src/Type/Type.php b/src/Type/Type.php index 6562ba2005..0badf2930c 100644 --- a/src/Type/Type.php +++ b/src/Type/Type.php @@ -5,12 +5,11 @@ use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Reflection\Callables\CallableParametersAcceptor; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ClassReflection; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\ExtendedPropertyReflection; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\TrinaryLogic; @@ -29,7 +28,7 @@ interface Type { /** - * @return string[] + * @return list */ public function getReferencedClasses(): array; @@ -56,7 +55,7 @@ public function isObject(): TrinaryLogic; public function isEnum(): TrinaryLogic; - /** @return list */ + /** @return list */ public function getArrays(): array; /** @return list */ @@ -65,27 +64,9 @@ public function getConstantArrays(): array; /** @return list */ public function getConstantStrings(): array; - public function accepts(Type $type, bool $strictTypes): TrinaryLogic; + public function accepts(Type $type, bool $strictTypes): AcceptsResult; - /** - * This is like accepts() but gives reasons - * why the type was not/might not be accepted in some non-intuitive scenarios. - * - * In PHPStan 2.0 this method will be removed and the return type of accepts() - * will change to AcceptsResult. - */ - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult; - - public function isSuperTypeOf(Type $type): TrinaryLogic; - - /** - * This is like isSuperTypeOf() but gives reasons - * why the type was not/might not be accepted in some non-intuitive scenarios. - * - * In PHPStan 2.0 this method will be removed and the return type of isSuperTypeOf() - * will change to IsSuperTypeOfResult. - */ - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult; + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult; public function equals(Type $type): bool; @@ -95,10 +76,7 @@ public function canAccessProperties(): TrinaryLogic; public function hasProperty(string $propertyName): TrinaryLogic; - /** - * @return ExtendedPropertyReflection - */ - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection; + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection; public function getUnresolvedPropertyPrototype(string $propertyName, ClassMemberAccessAnswerer $scope): UnresolvedPropertyPrototypeReflection; @@ -114,7 +92,7 @@ public function canAccessConstants(): TrinaryLogic; public function hasConstant(string $constantName): TrinaryLogic; - public function getConstant(string $constantName): ConstantReflection; + public function getConstant(string $constantName): ClassConstantReflection; public function isIterable(): TrinaryLogic; @@ -226,9 +204,9 @@ public function toArray(): Type; public function toArrayKey(): Type; - public function isSmallerThan(Type $otherType): TrinaryLogic; + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic; - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic; + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic; /** * Is Type of a known constant value? Includes literal strings, integers, floats, true, false, null, and array shapes. @@ -276,7 +254,7 @@ public function isLowercaseString(): TrinaryLogic; public function isUppercaseString(): TrinaryLogic; - public function isClassStringType(): TrinaryLogic; + public function isClassString(): TrinaryLogic; public function isVoid(): TrinaryLogic; @@ -284,13 +262,13 @@ public function isScalar(): TrinaryLogic; public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType; - public function getSmallerType(): Type; + public function getSmallerType(PhpVersion $phpVersion): Type; - public function getSmallerOrEqualType(): Type; + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type; - public function getGreaterType(): Type; + public function getGreaterType(PhpVersion $phpVersion): Type; - public function getGreaterOrEqualType(): Type; + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type; /** * Returns actual template type for a given object. @@ -332,7 +310,7 @@ public function inferTemplateTypes(Type $receivedType): TemplateTypeMap; * which the receiver type was * found. * - * @return TemplateTypeReference[] + * @return list */ public function getReferencedTemplateTypes(TemplateTypeVariance $positionVariance): array; @@ -366,9 +344,4 @@ public function tryRemove(Type $typeToRemove): ?Type; public function generalize(GeneralizePrecision $precision): Type; - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): self; - } diff --git a/src/Type/TypeCombinator.php b/src/Type/TypeCombinator.php index 03ddffd988..8add1bd481 100644 --- a/src/Type/TypeCombinator.php +++ b/src/Type/TypeCombinator.php @@ -38,9 +38,8 @@ /** * @api - * @final */ -class TypeCombinator +final class TypeCombinator { public static function addNull(Type $type): Type @@ -615,7 +614,7 @@ private static function processArrayAccessoryTypes(array $arrayTypes): array $constantArrays = $arrayType->getConstantArrays(); foreach ($constantArrays as $constantArray) { - if ($constantArray->isList()->yes() && AccessoryArrayListType::isListTypeEnabled()) { + if ($constantArray->isList()->yes()) { $list = new AccessoryArrayListType(); $accessoryTypes[$list->describe(VerbosityLevel::cache())][$i] = $list; } @@ -813,7 +812,7 @@ private static function optimizeConstantArrays(array $types): array $innerValueType = $type->getValueTypes()[$i]; $generalizedValueType = TypeTraverser::map($innerValueType, static function (Type $type) use ($traverse): Type { - if ($type instanceof ArrayType) { + if ($type instanceof ArrayType || $type instanceof ConstantArrayType) { return TypeCombinator::intersect($type, new OversizedArrayType()); } @@ -827,7 +826,7 @@ private static function optimizeConstantArrays(array $types): array $arrayType = new ArrayType($keyType, $valueType); if ($isList) { - $arrayType = AccessoryArrayListType::intersectWith($arrayType); + $arrayType = TypeCombinator::intersect($arrayType, new AccessoryArrayListType()); } return TypeCombinator::intersect($arrayType, new NonEmptyArrayType(), new OversizedArrayType()); @@ -1244,7 +1243,7 @@ public static function intersect(Type ...$types): Type continue 2; } - if ($types[$i] instanceof ConstantArrayType && $types[$j] instanceof ArrayType) { + if ($types[$i] instanceof ConstantArrayType && ($types[$j] instanceof ArrayType || $types[$j] instanceof ConstantArrayType)) { $newArray = ConstantArrayTypeBuilder::createEmpty(); $valueTypes = $types[$i]->getValueTypes(); foreach ($types[$i]->getKeyTypes() as $k => $keyType) { @@ -1260,7 +1259,7 @@ public static function intersect(Type ...$types): Type continue 2; } - if ($types[$j] instanceof ConstantArrayType && $types[$i] instanceof ArrayType) { + if ($types[$j] instanceof ConstantArrayType && ($types[$i] instanceof ArrayType || $types[$i] instanceof ConstantArrayType)) { $newArray = ConstantArrayTypeBuilder::createEmpty(); $valueTypes = $types[$j]->getValueTypes(); foreach ($types[$j]->getKeyTypes() as $k => $keyType) { @@ -1277,8 +1276,8 @@ public static function intersect(Type ...$types): Type } if ( - ($types[$i] instanceof ArrayType || $types[$i] instanceof IterableType) && - ($types[$j] instanceof ArrayType || $types[$j] instanceof IterableType) + ($types[$i] instanceof ArrayType || $types[$i] instanceof ConstantArrayType || $types[$i] instanceof IterableType) && + ($types[$j] instanceof ArrayType || $types[$j] instanceof ConstantArrayType || $types[$j] instanceof IterableType) ) { $keyType = self::intersect($types[$i]->getIterableKeyType(), $types[$j]->getKeyType()); $itemType = self::intersect($types[$i]->getItemType(), $types[$j]->getItemType()); diff --git a/src/Type/TypeUtils.php b/src/Type/TypeUtils.php index 9998d64422..7213a8140f 100644 --- a/src/Type/TypeUtils.php +++ b/src/Type/TypeUtils.php @@ -6,108 +6,19 @@ use PHPStan\Type\Accessory\HasPropertyType; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantIntegerType; -use PHPStan\Type\Constant\ConstantStringType; -use PHPStan\Type\Enum\EnumCaseObjectType; use PHPStan\Type\Generic\TemplateBenevolentUnionType; use PHPStan\Type\Generic\TemplateType; use PHPStan\Type\Generic\TemplateUnionType; use function array_merge; -use function array_unique; -use function array_values; /** * @api - * @final */ -class TypeUtils +final class TypeUtils { /** - * @return ArrayType[] - * - * @deprecated Use PHPStan\Type\Type::getArrays() instead and handle optional ConstantArrayType keys if necessary. - */ - public static function getArrays(Type $type): array - { - if ($type instanceof ConstantArrayType) { - return $type->getAllArrays(); - } - - if ($type instanceof ArrayType) { - return [$type]; - } - - if ($type instanceof UnionType) { - $matchingTypes = []; - foreach ($type->getTypes() as $innerType) { - if (!$innerType instanceof ArrayType) { - return []; - } - foreach (self::getArrays($innerType) as $innerInnerType) { - $matchingTypes[] = $innerInnerType; - } - } - - return $matchingTypes; - } - - if ($type instanceof IntersectionType) { - $matchingTypes = []; - foreach ($type->getTypes() as $innerType) { - if (!$innerType instanceof ArrayType) { - continue; - } - foreach (self::getArrays($innerType) as $innerInnerType) { - $matchingTypes[] = $innerInnerType; - } - } - - return $matchingTypes; - } - - return []; - } - - /** - * @return ConstantArrayType[] - * - * @deprecated Use PHPStan\Type\Type::getConstantArrays() instead and handle optional keys if necessary. - */ - public static function getConstantArrays(Type $type): array - { - if ($type instanceof ConstantArrayType) { - return $type->getAllArrays(); - } - - if ($type instanceof UnionType) { - $matchingTypes = []; - foreach ($type->getTypes() as $innerType) { - if (!$innerType instanceof ConstantArrayType) { - return []; - } - foreach (self::getConstantArrays($innerType) as $innerInnerType) { - $matchingTypes[] = $innerInnerType; - } - } - - return $matchingTypes; - } - - return []; - } - - /** - * @return ConstantStringType[] - * - * @deprecated Use PHPStan\Type\Type::getConstantStrings() instead - */ - public static function getConstantStrings(Type $type): array - { - return self::map(ConstantStringType::class, $type, false); - } - - /** - * @return ConstantIntegerType[] + * @return list */ public static function getConstantIntegers(Type $type): array { @@ -115,68 +26,7 @@ public static function getConstantIntegers(Type $type): array } /** - * @deprecated Use Type::isConstantValue() or Type::generalize() - * @return ConstantType[] - */ - public static function getConstantTypes(Type $type): array - { - return self::map(ConstantType::class, $type, false); - } - - /** - * @deprecated Use Type::isConstantValue() or Type::generalize() - * @return ConstantType[] - */ - public static function getAnyConstantTypes(Type $type): array - { - return self::map(ConstantType::class, $type, false, false); - } - - /** - * @return ArrayType[] - * - * @deprecated Use PHPStan\Type\Type::getArrays() instead. - */ - public static function getAnyArrays(Type $type): array - { - return self::map(ArrayType::class, $type, true, false); - } - - /** - * @deprecated Use PHPStan\Type\Type::generalize() instead. - */ - public static function generalizeType(Type $type, GeneralizePrecision $precision): Type - { - return $type->generalize($precision); - } - - /** - * @return list - * - * @deprecated Use Type::getObjectClassNames() instead. - */ - public static function getDirectClassNames(Type $type): array - { - if ($type instanceof TypeWithClassName) { - return [$type->getClassName()]; - } - - if ($type instanceof UnionType || $type instanceof IntersectionType) { - $classNames = []; - foreach ($type->getTypes() as $innerType) { - foreach (self::getDirectClassNames($innerType) as $n) { - $classNames[] = $n; - } - } - - return array_values(array_unique($classNames)); - } - - return []; - } - - /** - * @return IntegerRangeType[] + * @return list */ public static function getIntegerRanges(Type $type): array { @@ -184,36 +34,7 @@ public static function getIntegerRanges(Type $type): array } /** - * @deprecated Use Type::isConstantScalarValue() or Type::getConstantScalarTypes() or Type::getConstantScalarValues() - * @return ConstantScalarType[] - */ - public static function getConstantScalars(Type $type): array - { - return self::map(ConstantScalarType::class, $type, false); - } - - /** - * @deprecated Use Type::getEnumCases() - * @return EnumCaseObjectType[] - */ - public static function getEnumCaseObjects(Type $type): array - { - return self::map(EnumCaseObjectType::class, $type, false); - } - - /** - * @internal - * @return ConstantArrayType[] - * - * @deprecated Use PHPStan\Type\Type::getConstantArrays(). - */ - public static function getOldConstantArrays(Type $type): array - { - return self::map(ConstantArrayType::class, $type, false); - } - - /** - * @return mixed[] + * @return list */ private static function map( string $typeClass, @@ -378,24 +199,6 @@ public static function getAccessoryTypes(Type $type): array return self::map(AccessoryType::class, $type, true, false); } - /** @deprecated Use PHPStan\Type\Type::isCallable() instead. */ - public static function containsCallable(Type $type): bool - { - if ($type->isCallable()->yes()) { - return true; - } - - if ($type instanceof UnionType) { - foreach ($type->getTypes() as $innerType) { - if ($innerType->isCallable()->yes()) { - return true; - } - } - } - - return false; - } - public static function containsTemplateType(Type $type): bool { $containsTemplateType = false; diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php index 8f9f5616f3..333d9de4a7 100644 --- a/src/Type/TypehintHelper.php +++ b/src/Type/TypehintHelper.php @@ -2,106 +2,34 @@ 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\Constant\ConstantArrayType; 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 str_ends_with; -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, ?Type $phpDocType = null, - ClassReflection|string|null $selfClass = null, + ClassReflection|null $selfClass = null, bool $isVariadic = false, ): Type { if ($reflectionType === null) { - if ($isVariadic && $phpDocType instanceof ArrayType) { + if ($isVariadic && ($phpDocType instanceof ArrayType || $phpDocType instanceof ConstantArrayType)) { $phpDocType = $phpDocType->getItemType(); } return $phpDocType ?? new MixedType(); @@ -131,23 +59,13 @@ public static function decideTypeFromReflection( throw new ShouldNotHappenException(sprintf('Unexpected type: %s', get_class($reflectionType))); } - $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'; + if ($reflectionType->isIdentifier()) { + $typeNode = new Identifier($reflectionType->getName()); + } else { + $typeNode = new FullyQualified($reflectionType->getName()); } - $type = self::getTypeObjectFromTypehint($reflectionTypeString, $selfClass); + $type = ParserNodeTypeToPHPStanType::resolve($typeNode, $selfClass); if ($reflectionType->allowsNull()) { $type = TypeCombinator::addNull($type); } elseif ($phpDocType !== null) { @@ -182,7 +100,7 @@ public static function decideType( if ($phpDocType instanceof UnionType) { $innerTypes = []; foreach ($phpDocType->getTypes() as $innerType) { - if ($innerType instanceof ArrayType) { + if ($innerType instanceof ArrayType || $innerType instanceof ConstantArrayType) { $innerTypes[] = new IterableType( $innerType->getIterableKeyType(), $innerType->getItemType(), @@ -192,7 +110,7 @@ public static function decideType( } } $phpDocType = new UnionType($innerTypes); - } elseif ($phpDocType instanceof ArrayType) { + } elseif ($phpDocType instanceof ArrayType || $phpDocType instanceof ConstantArrayType) { $phpDocType = new IterableType( $phpDocType->getKeyType(), $phpDocType->getItemType(), diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index 14eb812267..c69888cf30 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -5,14 +5,16 @@ use DateTime; use DateTimeImmutable; use DateTimeInterface; +use Error; +use Exception; use PHPStan\Php\PhpVersion; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\PhpDocParser\Ast\Type\UnionTypeNode; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Reflection\ClassMemberAccessAnswerer; -use PHPStan\Reflection\ConstantReflection; use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ExtendedPropertyReflection; use PHPStan\Reflection\InitializerExprTypeResolver; -use PHPStan\Reflection\PropertyReflection; use PHPStan\Reflection\Type\UnionTypeUnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnionTypeUnresolvedPropertyPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; @@ -26,6 +28,7 @@ use PHPStan\Type\Generic\TemplateTypeVariance; use PHPStan\Type\Generic\TemplateUnionType; use PHPStan\Type\Traits\NonGeneralizableTypeTrait; +use Throwable; use function array_diff_assoc; use function array_fill_keys; use function array_map; @@ -45,6 +48,11 @@ class UnionType implements CompoundType use NonGeneralizableTypeTrait; + public const EQUAL_UNION_CLASSES = [ + DateTimeInterface::class => [DateTimeImmutable::class, DateTime::class], + Throwable::class => [Error::class, Exception::class], // phpcs:ignore SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException + ]; + private bool $sortedTypes = false; /** @var array */ @@ -129,9 +137,6 @@ protected function getSortedTypes(): array return $this->types; } - /** - * @return string[] - */ public function getReferencedClasses(): array { $classes = []; @@ -184,55 +189,49 @@ public function getConstantStrings(): array ); } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic + public function accepts(Type $type, bool $strictTypes): AcceptsResult { - return $this->acceptsWithReason($type, $strictTypes)->result; - } + foreach (self::EQUAL_UNION_CLASSES as $baseClass => $classes) { + if (!$type->equals(new ObjectType($baseClass))) { + continue; + } - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult - { - if ( - $type->equals(new ObjectType(DateTimeInterface::class)) - && $this->accepts( - new UnionType([new ObjectType(DateTime::class), new ObjectType(DateTimeImmutable::class)]), - $strictTypes, - )->yes() - ) { - return AcceptsResult::createYes(); + $union = TypeCombinator::union( + ...array_map(static fn (string $objectClass): Type => new ObjectType($objectClass), $classes), + ); + if ($this->accepts($union, $strictTypes)->yes()) { + return AcceptsResult::createYes(); + } + break; } $result = AcceptsResult::createNo(); foreach ($this->getSortedTypes() as $i => $innerType) { - $result = $result->or($innerType->acceptsWithReason($type, $strictTypes)->decorateReasons(static fn (string $reason) => sprintf('Type #%d from the union: %s', $i + 1, $reason))); + $result = $result->or($innerType->accepts($type, $strictTypes)->decorateReasons(static fn (string $reason) => sprintf('Type #%d from the union: %s', $i + 1, $reason))); } if ($result->yes()) { return $result; } if ($type instanceof CompoundType && !$type instanceof CallableType && !$type instanceof TemplateType && !$type instanceof IntersectionType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } if ($type instanceof TemplateUnionType) { - return $result->or($type->isAcceptedWithReasonBy($this, $strictTypes)); + return $result->or($type->isAcceptedBy($this, $strictTypes)); } if ($type->isEnum()->yes() && !$this->isEnum()->no()) { $enumCasesUnion = TypeCombinator::union(...$type->getEnumCases()); if (!$type->equals($enumCasesUnion)) { - return $this->acceptsWithReason($enumCasesUnion, $strictTypes); + return $this->accepts($enumCasesUnion, $strictTypes); } } return $result; } - public function isSuperTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($otherType)->result; - } - - public function isSuperTypeOfWithReason(Type $otherType): IsSuperTypeOfResult + public function isSuperTypeOf(Type $otherType): IsSuperTypeOfResult { if ( ($otherType instanceof self && !$otherType instanceof TemplateUnionType) @@ -242,12 +241,12 @@ public function isSuperTypeOfWithReason(Type $otherType): IsSuperTypeOfResult || $otherType instanceof ConditionalTypeForParameter || $otherType instanceof IntegerRangeType ) { - return $otherType->isSubTypeOfWithReason($this); + return $otherType->isSubTypeOf($this); } $results = []; foreach ($this->types as $innerType) { - $result = $innerType->isSuperTypeOfWithReason($otherType); + $result = $innerType->isSuperTypeOf($otherType); if ($result->yes()) { return $result; } @@ -256,30 +255,20 @@ public function isSuperTypeOfWithReason(Type $otherType): IsSuperTypeOfResult $result = IsSuperTypeOfResult::createNo()->or(...$results); if ($otherType instanceof TemplateUnionType) { - return $result->or($otherType->isSubTypeOfWithReason($this)); + return $result->or($otherType->isSubTypeOf($this)); } return $result; } - public function isSubTypeOf(Type $otherType): TrinaryLogic - { - return $this->isSubTypeOfWithReason($otherType)->result; - } - - public function isSubTypeOfWithReason(Type $otherType): IsSuperTypeOfResult - { - return IsSuperTypeOfResult::extremeIdentity(...array_map(static fn (Type $innerType) => $otherType->isSuperTypeOfWithReason($innerType), $this->types)); - } - - public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic + public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult { - return $this->isAcceptedWithReasonBy($acceptingType, $strictTypes)->result; + return IsSuperTypeOfResult::extremeIdentity(...array_map(static fn (Type $innerType) => $otherType->isSuperTypeOf($innerType), $this->types)); } - public function isAcceptedWithReasonBy(Type $acceptingType, bool $strictTypes): AcceptsResult + public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult { - return AcceptsResult::extremeIdentity(...array_map(static fn (Type $innerType) => $acceptingType->acceptsWithReason($innerType, $strictTypes), $this->types)); + return AcceptsResult::extremeIdentity(...array_map(static fn (Type $innerType) => $acceptingType->accepts($innerType, $strictTypes), $this->types)); } public function equals(Type $type): bool @@ -473,7 +462,7 @@ public function hasProperty(string $propertyName): TrinaryLogic return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->hasProperty($propertyName)); } - public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): PropertyReflection + public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection { return $this->getUnresolvedPropertyPrototype($propertyName, $scope)->getTransformedProperty(); } @@ -552,11 +541,11 @@ public function hasConstant(string $constantName): TrinaryLogic ); } - public function getConstant(string $constantName): ConstantReflection + public function getConstant(string $constantName): ClassConstantReflection { return $this->getInternal( static fn (Type $type): TrinaryLogic => $type->hasConstant($constantName), - static fn (Type $type): ConstantReflection => $type->getConstant($constantName), + static fn (Type $type): ClassConstantReflection => $type->getConstant($constantName), ); } @@ -660,9 +649,9 @@ public function isUppercaseString(): TrinaryLogic return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isUppercaseString()); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { - return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isClassStringType()); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isClassString()); } public function getClassStringObjectType(): Type @@ -836,14 +825,14 @@ public function isCloneable(): TrinaryLogic return $this->unionResults(static fn (Type $type): TrinaryLogic => $type->isCloneable()); } - public function isSmallerThan(Type $otherType): TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThan($otherType)); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThan($otherType, $phpVersion)); } - public function isSmallerThanOrEqual(Type $otherType): TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThanOrEqual($otherType)); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isSmallerThanOrEqual($otherType, $phpVersion)); } public function isNull(): TrinaryLogic @@ -896,34 +885,34 @@ public function isInteger(): TrinaryLogic return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $type->isInteger()); } - public function getSmallerType(): Type + public function getSmallerType(PhpVersion $phpVersion): Type { - return $this->unionTypes(static fn (Type $type): Type => $type->getSmallerType()); + return $this->unionTypes(static fn (Type $type): Type => $type->getSmallerType($phpVersion)); } - public function getSmallerOrEqualType(): Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): Type { - return $this->unionTypes(static fn (Type $type): Type => $type->getSmallerOrEqualType()); + return $this->unionTypes(static fn (Type $type): Type => $type->getSmallerOrEqualType($phpVersion)); } - public function getGreaterType(): Type + public function getGreaterType(PhpVersion $phpVersion): Type { - return $this->unionTypes(static fn (Type $type): Type => $type->getGreaterType()); + return $this->unionTypes(static fn (Type $type): Type => $type->getGreaterType($phpVersion)); } - public function getGreaterOrEqualType(): Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): Type { - return $this->unionTypes(static fn (Type $type): Type => $type->getGreaterOrEqualType()); + return $this->unionTypes(static fn (Type $type): Type => $type->getGreaterOrEqualType($phpVersion)); } - public function isGreaterThan(Type $otherType): TrinaryLogic + public function isGreaterThan(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThan($type)); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThan($type, $phpVersion)); } - public function isGreaterThanOrEqual(Type $otherType): TrinaryLogic + public function isGreaterThanOrEqual(Type $otherType, PhpVersion $phpVersion): TrinaryLogic { - return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThanOrEqual($type)); + return $this->notBenevolentUnionResults(static fn (Type $type): TrinaryLogic => $otherType->isSmallerThanOrEqual($type, $phpVersion)); } public function toBoolean(): BooleanType @@ -1121,14 +1110,6 @@ public function getFiniteTypes(): array return array_values($uniquedTypes); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self($properties['types'], $properties['normalized']); - } - /** * @param callable(Type $type): TrinaryLogic $getResult */ @@ -1153,18 +1134,6 @@ protected function unionTypes(callable $getType): Type return TypeCombinator::union(...array_map($getType, $this->types)); } - /** - * @template T of Type - * @param callable(Type $type): list $getTypes - * @return list - * - * @deprecated Use pickFromTypes() instead. - */ - protected function pickTypes(callable $getTypes): array - { - return $this->pickFromTypes($getTypes, static fn () => false); - } - /** * @template T * @param callable(Type $type): list $getValues diff --git a/src/Type/ValueOfType.php b/src/Type/ValueOfType.php index 9df5411c47..d02b7d11f7 100644 --- a/src/Type/ValueOfType.php +++ b/src/Type/ValueOfType.php @@ -100,14 +100,4 @@ public function toPhpDocNode(): TypeNode return new GenericTypeNode(new IdentifierTypeNode('value-of'), [$this->type->toPhpDocNode()]); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self( - $properties['type'], - ); - } - } diff --git a/src/Type/VoidType.php b/src/Type/VoidType.php index 18b3d719c1..b6bac5908c 100644 --- a/src/Type/VoidType.php +++ b/src/Type/VoidType.php @@ -37,9 +37,6 @@ public function __construct() { } - /** - * @return string[] - */ public function getReferencedClasses(): array { return []; @@ -55,33 +52,23 @@ public function getObjectClassReflections(): array return []; } - public function accepts(Type $type, bool $strictTypes): TrinaryLogic - { - return $this->acceptsWithReason($type, $strictTypes)->result; - } - - public function acceptsWithReason(Type $type, bool $strictTypes): AcceptsResult + public function accepts(Type $type, bool $strictTypes): AcceptsResult { if ($type instanceof CompoundType) { - return $type->isAcceptedWithReasonBy($this, $strictTypes); + return $type->isAcceptedBy($this, $strictTypes); } return new AcceptsResult($type->isVoid()->or($type->isNull()), []); } - public function isSuperTypeOf(Type $type): TrinaryLogic - { - return $this->isSuperTypeOfWithReason($type)->result; - } - - public function isSuperTypeOfWithReason(Type $type): IsSuperTypeOfResult + public function isSuperTypeOf(Type $type): IsSuperTypeOfResult { if ($type instanceof self) { return IsSuperTypeOfResult::createYes(); } if ($type instanceof CompoundType) { - return $type->isSubTypeOfWithReason($this); + return $type->isSubTypeOf($this); } return IsSuperTypeOfResult::createNo(); @@ -222,7 +209,7 @@ public function isUppercaseString(): TrinaryLogic return TrinaryLogic::createNo(); } - public function isClassStringType(): TrinaryLogic + public function isClassString(): TrinaryLogic { return TrinaryLogic::createNo(); } @@ -277,12 +264,4 @@ public function toPhpDocNode(): TypeNode return new IdentifierTypeNode('void'); } - /** - * @param mixed[] $properties - */ - public static function __set_state(array $properties): Type - { - return new self(); - } - } diff --git a/stubs/Countable.stub b/stubs/Countable.stub index c69c9dba43..2491db1ce5 100644 --- a/stubs/Countable.stub +++ b/stubs/Countable.stub @@ -3,7 +3,7 @@ interface Countable { /** - * @return int + * @return 0|positive-int */ public function count(): int; } diff --git a/stubs/ReflectionClass.stub b/stubs/ReflectionClass.stub index 65b02ffaac..06f8e08a2e 100644 --- a/stubs/ReflectionClass.stub +++ b/stubs/ReflectionClass.stub @@ -7,6 +7,7 @@ class ReflectionClass { /** + * @readonly * @var class-string */ public $name; diff --git a/stubs/arrayFunctions.stub b/stubs/arrayFunctions.stub index 8124ffe56a..9b29ddff0b 100644 --- a/stubs/arrayFunctions.stub +++ b/stubs/arrayFunctions.stub @@ -72,6 +72,6 @@ function array_udiff( /** * @param array $value - * @return ($value is __always-list ? true : false) + * @return ($value is list ? true : false) */ function array_is_list(array $value): bool {} diff --git a/stubs/bleedingEdge/Countable.stub b/stubs/bleedingEdge/Countable.stub deleted file mode 100644 index 2491db1ce5..0000000000 --- a/stubs/bleedingEdge/Countable.stub +++ /dev/null @@ -1,9 +0,0 @@ - - */ - public function getNodeType(): string; - - /** - * @param TNodeType $node - * @return list - */ - public function processNode(Node $node, Scope $scope): array; - -} diff --git a/stubs/core.stub b/stubs/core.stub index d6c1463c81..f2b72c235b 100644 --- a/stubs/core.stub +++ b/stubs/core.stub @@ -222,9 +222,9 @@ function preg_match_all($pattern, $subject, &$matches = [], int $flags = 1, int function preg_match($pattern, $subject, &$matches = [], int $flags = 0, int $offset = 0) {} /** - * @param string|array $pattern - * @param callable(array):string $callback - * @param string|array $subject + * @param string|string[] $pattern + * @param callable(string[]):string $callback + * @param string|array $subject * @param int $count * @param-out 0|positive-int $count * @return ($subject is array ? list|null : string|null) @@ -232,9 +232,9 @@ function preg_match($pattern, $subject, &$matches = [], int $flags = 0, int $off function preg_replace_callback($pattern, $callback, $subject, int $limit = -1, &$count = null, int $flags = 0) {} /** - * @param string|array $pattern - * @param string|array $replacement - * @param string|array $subject + * @param string|string[] $pattern + * @param string|array $replacement + * @param string|array $subject * @param int $count * @param-out 0|positive-int $count * @return ($subject is array ? list|null : string|null) @@ -242,9 +242,9 @@ function preg_replace_callback($pattern, $callback, $subject, int $limit = -1, & function preg_replace($pattern, $replacement, $subject, int $limit = -1, &$count = null) {} /** - * @param string|array $pattern - * @param string|array $replacement - * @param string|array $subject + * @param string|string[] $pattern + * @param string|array $replacement + * @param string|array $subject * @param int $count * @param-out 0|positive-int $count * @return ($subject is array ? list : string|null) @@ -252,18 +252,18 @@ function preg_replace($pattern, $replacement, $subject, int $limit = -1, &$count function preg_filter($pattern, $replacement, $subject, int $limit = -1, &$count = null) {} /** - * @param array|string $search - * @param array|string $replace - * @param array|string $subject + * @param array|string $search + * @param array|string $replace + * @param array|string $subject * @param-out int $count * @return list|string */ function str_replace($search, $replace, $subject, ?int &$count = null) {} /** - * @param array|string $search - * @param array|string $replace - * @param array|string $subject + * @param array|string $search + * @param array|string $replace + * @param array|string $subject * @param-out int $count * @return list|string */ diff --git a/stubs/ext-ds.stub b/stubs/ext-ds.stub index ba72a0d584..e05628d968 100644 --- a/stubs/ext-ds.stub +++ b/stubs/ext-ds.stub @@ -348,8 +348,8 @@ final class Map implements Collection, ArrayAccess } /** - * @template-covariant TKey - * @template-covariant TValue + * @template TKey + * @template TValue */ final class Pair implements JsonSerializable { diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index a4ee70e41f..df2d5e5ada 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -416,9 +416,6 @@ public function testFunctionThatExistsOn72AndLater(): void public function testBug4715(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $errors = $this->runAnalyse(__DIR__ . '/data/bug-4715.php'); $this->assertNoErrors($errors); } @@ -543,9 +540,9 @@ public function testBug6442(): void { $errors = $this->runAnalyse(__DIR__ . '/data/bug-6442.php'); $this->assertCount(2, $errors); - $this->assertSame('Dumped type: \'Bug6442\\\A\'', $errors[0]->getMessage()); + $this->assertSame('Dumped type: \'Bug6442\\\B\'', $errors[0]->getMessage()); $this->assertSame(9, $errors[0]->getLine()); - $this->assertSame('Dumped type: \'Bug6442\\\B\'', $errors[1]->getMessage()); + $this->assertSame('Dumped type: \'Bug6442\\\A\'', $errors[1]->getMessage()); $this->assertSame(9, $errors[1]->getLine()); } @@ -832,6 +829,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()); @@ -842,7 +843,7 @@ public function testUnresolvableParameter(): void { $errors = $this->runAnalyse(__DIR__ . '/data/unresolvable-parameter.php'); $this->assertCount(3, $errors); - $this->assertSame('Parameter #2 $array of function array_map expects array, array|false given.', $errors[0]->getMessage()); + $this->assertSame('Parameter #2 $array of function array_map expects array, list|false given.', $errors[0]->getMessage()); $this->assertSame(18, $errors[0]->getLine()); $this->assertSame('Method UnresolvableParameter\Collection::pipeInto() has parameter $class with no type specified.', $errors[1]->getMessage()); $this->assertSame(30, $errors[1]->getLine()); @@ -891,7 +892,7 @@ public function testBug7554(): void $errors = $this->runAnalyse(__DIR__ . '/data/bug-7554.php'); $this->assertCount(2, $errors); - $this->assertSame(sprintf('Parameter #1 $%s of function count expects array|Countable, array>|false given.', PHP_VERSION_ID < 80000 ? 'var' : 'value'), $errors[0]->getMessage()); + $this->assertSame(sprintf('Parameter #1 $%s of function count expects array|Countable, list|string>>|false given.', PHP_VERSION_ID < 80000 ? 'var' : 'value'), $errors[0]->getMessage()); $this->assertSame(26, $errors[0]->getLine()); $this->assertSame('Cannot access offset int<1, max> on list}>|false.', $errors[1]->getMessage()); @@ -1074,6 +1075,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()); @@ -1199,7 +1204,7 @@ public function testBug9459(): void { $errors = $this->runAnalyse(__DIR__ . '/data/bug-9459.php'); $this->assertCount(1, $errors); - $this->assertSame('PHPDoc tag @var with type callable(): array is not subtype of native type Closure(): array{}.', $errors[0]->getMessage()); + $this->assertSame('PHPDoc tag @var with type callable(): array is not subtype of native type Closure(): array{}.', $errors[0]->getMessage()); $this->assertSame(10, $errors[0]->getLine()); } @@ -1381,9 +1386,6 @@ public function testBug10979(): void public function testBug11026(): void { - if (PHP_VERSION_ID < 70300) { - $this->markTestSkipped('Test requires PHP 7.3.'); - } $errors = $this->runAnalyse(__DIR__ . '/data/bug-11026.php'); $this->assertNoErrors($errors); } @@ -1417,6 +1419,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); } @@ -1464,6 +1470,16 @@ public function testBug11640(): void $this->assertNoErrors($errors); } + public function testBug11709(): void + { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0.'); + } + + $errors = $this->runAnalyse(__DIR__ . '/data/bug-11709.php'); + $this->assertNoErrors($errors); + } + public function testBug11913(): void { $errors = $this->runAnalyse(__DIR__ . '/data/bug-11913.php'); diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php index f820c64aff..0a27ee2889 100644 --- a/tests/PHPStan/Analyser/AnalyserTest.php +++ b/tests/PHPStan/Analyser/AnalyserTest.php @@ -555,18 +555,6 @@ public function testIgnoreNextLineUnmatched(): void } } - public function testIgnoreNextLineLegacyBehaviour(): void - { - $result = $this->runAnalyser([], false, [__DIR__ . '/data/ignore-next-line-legacy.php'], true, false); - - foreach ([10, 32, 36] as $i => $line) { - $this->assertArrayHasKey($i, $result); - $this->assertInstanceOf(Error::class, $result[$i]); - $this->assertSame('Fail.', $result[$i]->getMessage()); - $this->assertSame($line, $result[$i]->getLine()); - } - } - /** * @dataProvider dataTrueAndFalse */ @@ -653,10 +641,9 @@ private function runAnalyser( bool $reportUnmatchedIgnoredErrors, $filePaths, bool $onlyFiles, - bool $enableIgnoreErrorsWithinPhpDocs = true, ): array { - $analyser = $this->createAnalyser($enableIgnoreErrorsWithinPhpDocs); + $analyser = $this->createAnalyser(); if (is_string($filePaths)) { $filePaths = [$filePaths]; @@ -701,7 +688,7 @@ private function runAnalyser( ); } - private function createAnalyser(bool $enableIgnoreErrorsWithinPhpDocs): Analyser + private function createAnalyser(): Analyser { $ruleRegistry = new DirectRuleRegistry([ new AlwaysFailRule(), @@ -735,27 +722,22 @@ private function createAnalyser(bool $enableIgnoreErrorsWithinPhpDocs): Analyser self::createScopeFactory($reflectionProvider, $typeSpecifier), false, true, + true, [], [], [stdClass::class], true, $this->shouldTreatPhpDocTypesAsCertain(), - self::getContainer()->getParameter('featureToggles')['detectDeadTypeInMultiCatch'], - self::getContainer()->getParameter('featureToggles')['paramOutType'], - 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(), - $enableIgnoreErrorsWithinPhpDocs, ), new DependencyResolver($fileHelper, $reflectionProvider, new ExportedNodeResolver($fileTypeMapper, new ExprPrinter(new Printer())), $fileTypeMapper), new RuleErrorTransformer(), diff --git a/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php b/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php index ff0a0daa9e..ff1be83109 100644 --- a/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php +++ b/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Analyser; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\FunctionCallParametersCheck; use PHPStan\Rules\Methods\CallMethodsRule; use PHPStan\Rules\Methods\MethodCallCheck; @@ -12,7 +11,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -23,10 +21,10 @@ class Bug9307CallMethodsRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, true, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, true, false, 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, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), ); } diff --git a/tests/PHPStan/Analyser/DoNotPolluteScopeWithBlockTest.php b/tests/PHPStan/Analyser/DoNotPolluteScopeWithBlockTest.php new file mode 100644 index 0000000000..cd4ceb5d85 --- /dev/null +++ b/tests/PHPStan/Analyser/DoNotPolluteScopeWithBlockTest.php @@ -0,0 +1,36 @@ +gatherAssertTypes(__DIR__ . '/data/do-not-pollute-scope-with-block.php'); + } + + /** + * @dataProvider dataFileAsserts + * @param mixed ...$args + */ + public function testFileAsserts( + string $assertType, + string $file, + ...$args, + ): void + { + $this->assertFileAsserts($assertType, $file, ...$args); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../../../conf/bleedingEdge.neon', + __DIR__ . '/do-not-pollute-scope-with-block.neon', + ]; + } + +} diff --git a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php index 59ebef356e..7e5fad5dda 100644 --- a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php +++ b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php @@ -17,7 +17,6 @@ public function dataAsserts(): iterable } 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 42b0d24959..a93989ab4b 100644 --- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php @@ -1763,7 +1763,7 @@ public function dataProperties(): array '$this->arrayPropertyOne', ], [ - 'array', + 'array', '$this->arrayPropertyOther', ], [ @@ -3423,7 +3423,7 @@ public function dataTypeFromFunctionPhpDocs(): array '$arrayParameterOne', ], [ - 'array', + 'array', '$arrayParameterOther', ], [ @@ -4264,7 +4264,7 @@ public function dataAnonymousFunction(): array '$str', ], [ - PHP_VERSION_ID < 80000 ? 'list' : 'array', + PHP_VERSION_ID < 80000 ? 'list' : 'array', '$arr', ], [ @@ -4846,7 +4846,7 @@ public function dataArrayFunctions(): array 'array_pop($stringKeys)', ], [ - 'array&hasOffsetValue(\'baz\', stdClass)', + 'non-empty-array&hasOffsetValue(\'baz\', stdClass)', '$stdClassesWithIsset', ], [ @@ -5779,7 +5779,7 @@ public function dataSpecifiedTypesUsingIsFunctions(): array '$null', ], [ - 'array', + 'array', '$array', ], [ @@ -6435,7 +6435,7 @@ public function dataMisleadingTypes(): array '$foo->misleadingIntReturnType()', ], [ - 'mixed', + PHP_VERSION_ID >= 80000 ? 'mixed' : 'MisleadingTypes\mixed', '$foo->misleadingMixedReturnType()', ], ]; @@ -8077,7 +8077,7 @@ public function dataArrayKeysInBranches(): array '$array', ], [ - 'array&hasOffsetValue(\'key\', mixed)', + 'non-empty-array&hasOffsetValue(\'key\', mixed)', '$generalArray', ], [ @@ -8563,11 +8563,11 @@ public function dataIsset(): array '$mixedIsset', ], [ - 'array&hasOffset(\'a\')', + 'non-empty-array&hasOffset(\'a\')', '$mixedArrayKeyExists', ], [ - 'array&hasOffsetValue(\'a\', int)', + 'non-empty-array&hasOffsetValue(\'a\', int)', '$integers', ], [ @@ -8918,9 +8918,6 @@ public function testPhp73Functions( string $expression, ): void { - if (PHP_VERSION_ID < 70300) { - $this->markTestSkipped('Test requires PHP 7.3'); - } $this->assertTypes( __DIR__ . '/data/php73_functions.php', $description, @@ -9050,9 +9047,6 @@ public function testPhp74Functions( string $expression, ): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4'); - } $this->assertTypes( __DIR__ . '/data/php74_functions.php', $description, @@ -9258,7 +9252,7 @@ public function dataInferPrivatePropertyTypeFromConstructor(): array '$this->bool', ], [ - 'array', + 'array', '$this->array', ], ]; @@ -9484,34 +9478,6 @@ public function testArraySpread( ); } - public function dataPhp74FunctionsIn73(): array - { - return [ - [ - 'mixed', - 'password_algos()', - ], - ]; - } - - /** - * @dataProvider dataPhp74FunctionsIn73 - */ - public function testPhp74FunctionsIn73( - string $description, - string $expression, - ): void - { - if (PHP_VERSION_ID >= 70400) { - $this->markTestSkipped('Test does not run on PHP >= 7.4.'); - } - $this->assertTypes( - __DIR__ . '/data/die-73.php', - $description, - $expression, - ); - } - public function dataPhp74FunctionsIn74(): array { return [ @@ -9530,9 +9496,6 @@ public function testPhp74FunctionsIn74( string $expression, ): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->assertTypes( __DIR__ . '/data/die-74.php', $description, diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 1e3afb4e70..1363deb2fe 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -33,7 +33,7 @@ private static function findTestFiles(): iterable yield __DIR__ . '/data/enum-reflection-php81.php'; } - if (PHP_VERSION_ID < 80000 && PHP_VERSION_ID >= 70400) { + if (PHP_VERSION_ID < 80000) { yield __DIR__ . '/data/bug-4902.php'; } @@ -42,8 +42,6 @@ private static function findTestFiles(): iterable yield __DIR__ . '/data/mb-strlen-php82.php'; } elseif (PHP_VERSION_ID >= 80000) { yield __DIR__ . '/data/mb-strlen-php8.php'; - } elseif (PHP_VERSION_ID < 70300) { - yield __DIR__ . '/data/mb-strlen-php72.php'; } else { yield __DIR__ . '/data/mb-strlen-php73.php'; } @@ -88,9 +86,7 @@ private static function findTestFiles(): iterable yield __DIR__ . '/../Rules/Functions/data/varying-acceptor.php'; yield __DIR__ . '/../Rules/Methods/data/bug-4415.php'; - if (PHP_VERSION_ID >= 70400) { - yield __DIR__ . '/../Rules/Methods/data/bug-5372.php'; - } + yield __DIR__ . '/../Rules/Methods/data/bug-5372.php'; yield __DIR__ . '/../Rules/Arrays/data/bug-5372_2.php'; yield __DIR__ . '/../Rules/Methods/data/bug-5562.php'; @@ -104,9 +100,7 @@ private static function findTestFiles(): iterable yield __DIR__ . '/data/new-in-initializers-runtime.php'; } - if (PHP_VERSION_ID >= 70400) { - yield __DIR__ . '/../Rules/Comparison/data/bug-6473.php'; - } + yield __DIR__ . '/../Rules/Comparison/data/bug-6473.php'; yield __DIR__ . '/../Rules/Methods/data/filter-iterator-child-class.php'; @@ -144,9 +138,7 @@ private static function findTestFiles(): iterable yield __DIR__ . '/../Rules/Arrays/data/bug-7469.php'; yield __DIR__ . '/../Rules/Variables/data/bug-3391.php'; - if (PHP_VERSION_ID >= 70400) { - yield __DIR__ . '/../Rules/Functions/data/bug-anonymous-function-method-constant.php'; - } + yield __DIR__ . '/../Rules/Functions/data/bug-anonymous-function-method-constant.php'; if (PHP_VERSION_ID >= 80200) { yield __DIR__ . '/../Rules/Methods/data/true-typehint.php'; @@ -171,12 +163,16 @@ private static function findTestFiles(): iterable yield __DIR__ . '/../Rules/Properties/data/bug-7839.php'; yield __DIR__ . '/../Rules/Classes/data/bug-5333.php'; yield __DIR__ . '/../Rules/Methods/data/bug-8174.php'; - yield __DIR__ . '/../Rules/Comparison/data/bug-8169.php'; + + if (PHP_VERSION_ID >= 80000) { + yield __DIR__ . '/../Rules/Comparison/data/bug-8169.php'; + } yield __DIR__ . '/../Rules/Functions/data/bug-8280.php'; yield __DIR__ . '/../Rules/Comparison/data/bug-8277.php'; yield __DIR__ . '/../Rules/Variables/data/bug-8113.php'; yield __DIR__ . '/../Rules/Functions/data/bug-8389.php'; yield __DIR__ . '/../Rules/Arrays/data/bug-8467a.php'; + if (PHP_VERSION_ID >= 80100) { yield __DIR__ . '/../Rules/Comparison/data/bug-8485.php'; } @@ -208,7 +204,6 @@ private static function findTestFiles(): iterable yield __DIR__ . '/../Rules/Classes/data/mixin-trait-use.php'; yield __DIR__ . '/../Rules/Methods/data/bug-4801.php'; - yield __DIR__ . '/data/template-default.php'; } /** diff --git a/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php b/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php index 025513c4bf..c3476c32fa 100644 --- a/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php +++ b/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php @@ -3,17 +3,12 @@ namespace PHPStan\Analyser; use PHPStan\Testing\TypeInferenceTestCase; -use const PHP_VERSION_ID; class ParameterClosureTypeExtensionArrowFunctionTest extends TypeInferenceTestCase { public function dataFileAsserts(): iterable { - if (PHP_VERSION_ID < 70400) { - return []; - } - yield from $this->gatherAssertTypes(__DIR__ . '/data/parameter-closure-type-extension-arrow-function.php'); } @@ -27,10 +22,6 @@ public function testFileAsserts( ...$args, ): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->assertFileAsserts($assertType, $file, ...$args); } diff --git a/tests/PHPStan/Analyser/ScopePhpVersionTest.php b/tests/PHPStan/Analyser/ScopePhpVersionTest.php new file mode 100644 index 0000000000..fac3b8a066 --- /dev/null +++ b/tests/PHPStan/Analyser/ScopePhpVersionTest.php @@ -0,0 +1,43 @@ +', + __DIR__ . '/data/scope-constants-global.php', + ], + [ + 'int<80000, 80499>', + __DIR__ . '/data/scope-constants-namespace.php', + ], + ]; + } + + /** + * @dataProvider dataTestPhpVersion + */ + public function testPhpVersion(string $expected, string $file): void + { + self::processFile($file, function (Node $node, Scope $scope) use ($expected): void { + if (!($node instanceof Exit_)) { + return; + } + $this->assertSame( + $expected, + $scope->getPhpVersion()->getType()->describe(VerbosityLevel::precise()), + ); + }); + } + +} diff --git a/tests/PHPStan/Analyser/ScopeTest.php b/tests/PHPStan/Analyser/ScopeTest.php index cdad83a96f..4612ef1596 100644 --- a/tests/PHPStan/Analyser/ScopeTest.php +++ b/tests/PHPStan/Analyser/ScopeTest.php @@ -237,8 +237,8 @@ public function testGeneralize(Type $a, Type $b, string $expectedTypeDescription { /** @var ScopeFactory $scopeFactory */ $scopeFactory = self::getContainer()->getByType(ScopeFactory::class); - $scopeA = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $a, $a); - $scopeB = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $b, $b); + $scopeA = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $a, $a, TrinaryLogic::createYes()); + $scopeB = $scopeFactory->create(ScopeContext::create('file.php'))->assignVariable('a', $b, $b, TrinaryLogic::createYes()); $resultScope = $scopeA->generalizeWith($scopeB); $this->assertSame($expectedTypeDescription, $resultScope->getVariableType('a')->describe(VerbosityLevel::precise())); } diff --git a/tests/PHPStan/Analyser/StatementResultTest.php b/tests/PHPStan/Analyser/StatementResultTest.php index 04ca04cb26..da7d60bd3d 100644 --- a/tests/PHPStan/Analyser/StatementResultTest.php +++ b/tests/PHPStan/Analyser/StatementResultTest.php @@ -5,6 +5,7 @@ use PhpParser\Node\Stmt; use PHPStan\Parser\Parser; use PHPStan\Testing\PHPStanTestCase; +use PHPStan\TrinaryLogic; use PHPStan\Type\ArrayType; use PHPStan\Type\IntegerType; use PHPStan\Type\MixedType; @@ -527,16 +528,17 @@ public function testIsAlwaysTerminating( /** @var ScopeFactory $scopeFactory */ $scopeFactory = self::getContainer()->getByType(ScopeFactory::class); $scope = $scopeFactory->create(ScopeContext::create('test.php')) - ->assignVariable('string', new StringType(), new StringType()) - ->assignVariable('x', new IntegerType(), new IntegerType()) - ->assignVariable('cond', new MixedType(), new MixedType()) - ->assignVariable('arr', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType())); + ->assignVariable('string', new StringType(), new StringType(), TrinaryLogic::createYes()) + ->assignVariable('x', new IntegerType(), new IntegerType(), TrinaryLogic::createYes()) + ->assignVariable('cond', new MixedType(), new MixedType(), TrinaryLogic::createYes()) + ->assignVariable('arr', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType()), TrinaryLogic::createYes()); $result = $nodeScopeResolver->processStmtNodes( new Stmt\Namespace_(null, $stmts), $stmts, $scope, static function (): void { }, + StatementContext::createTopLevel(), ); $this->assertSame($expectedIsAlwaysTerminating, $result->isAlwaysTerminating()); } diff --git a/tests/PHPStan/Analyser/TypeSpecifierTest.php b/tests/PHPStan/Analyser/TypeSpecifierTest.php index 999c7169a3..ac9c8aa88f 100644 --- a/tests/PHPStan/Analyser/TypeSpecifierTest.php +++ b/tests/PHPStan/Analyser/TypeSpecifierTest.php @@ -21,6 +21,7 @@ use PHPStan\Node\Expr\AlwaysRememberedExpr; use PHPStan\Node\Printer\Printer; use PHPStan\Testing\PHPStanTestCase; +use PHPStan\TrinaryLogic; use PHPStan\Type\ArrayType; use PHPStan\Type\ClassStringType; use PHPStan\Type\Constant\ConstantBooleanType; @@ -62,20 +63,20 @@ protected function setUp(): void $this->typeSpecifier = self::getContainer()->getService('typeSpecifier'); $this->scope = $this->createScopeFactory($reflectionProvider, $this->typeSpecifier)->create(ScopeContext::create('')); $this->scope = $this->scope->enterClass($reflectionProvider->getClass('DateTime')); - $this->scope = $this->scope->assignVariable('bar', new ObjectType('Bar'), new ObjectType('Bar')); - $this->scope = $this->scope->assignVariable('stringOrNull', new UnionType([new StringType(), new NullType()]), new UnionType([new StringType(), new NullType()])); - $this->scope = $this->scope->assignVariable('string', new StringType(), new StringType()); - $this->scope = $this->scope->assignVariable('fooOrNull', new UnionType([new ObjectType('Foo'), new NullType()]), new UnionType([new ObjectType('Foo'), new NullType()])); - $this->scope = $this->scope->assignVariable('barOrNull', new UnionType([new ObjectType('Bar'), new NullType()]), new UnionType([new ObjectType('Bar'), new NullType()])); - $this->scope = $this->scope->assignVariable('barOrFalse', new UnionType([new ObjectType('Bar'), new ConstantBooleanType(false)]), new UnionType([new ObjectType('Bar'), new ConstantBooleanType(false)])); - $this->scope = $this->scope->assignVariable('stringOrFalse', new UnionType([new StringType(), new ConstantBooleanType(false)]), new UnionType([new StringType(), new ConstantBooleanType(false)])); - $this->scope = $this->scope->assignVariable('array', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType())); - $this->scope = $this->scope->assignVariable('foo', new MixedType(), new MixedType()); - $this->scope = $this->scope->assignVariable('classString', new ClassStringType(), new ClassStringType()); - $this->scope = $this->scope->assignVariable('genericClassString', new GenericClassStringType(new ObjectType('Bar')), new GenericClassStringType(new ObjectType('Bar'))); - $this->scope = $this->scope->assignVariable('object', new ObjectWithoutClassType(), new ObjectWithoutClassType()); - $this->scope = $this->scope->assignVariable('int', new IntegerType(), new IntegerType()); - $this->scope = $this->scope->assignVariable('float', new FloatType(), new FloatType()); + $this->scope = $this->scope->assignVariable('bar', new ObjectType('Bar'), new ObjectType('Bar'), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('stringOrNull', new UnionType([new StringType(), new NullType()]), new UnionType([new StringType(), new NullType()]), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('string', new StringType(), new StringType(), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('fooOrNull', new UnionType([new ObjectType('Foo'), new NullType()]), new UnionType([new ObjectType('Foo'), new NullType()]), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('barOrNull', new UnionType([new ObjectType('Bar'), new NullType()]), new UnionType([new ObjectType('Bar'), new NullType()]), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('barOrFalse', new UnionType([new ObjectType('Bar'), new ConstantBooleanType(false)]), new UnionType([new ObjectType('Bar'), new ConstantBooleanType(false)]), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('stringOrFalse', new UnionType([new StringType(), new ConstantBooleanType(false)]), new UnionType([new StringType(), new ConstantBooleanType(false)]), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('array', new ArrayType(new MixedType(), new MixedType()), new ArrayType(new MixedType(), new MixedType()), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('foo', new MixedType(), new MixedType(), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('classString', new ClassStringType(), new ClassStringType(), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('genericClassString', new GenericClassStringType(new ObjectType('Bar')), new GenericClassStringType(new ObjectType('Bar')), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('object', new ObjectWithoutClassType(), new ObjectWithoutClassType(), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('int', new IntegerType(), new IntegerType(), TrinaryLogic::createYes()); + $this->scope = $this->scope->assignVariable('float', new FloatType(), new FloatType(), TrinaryLogic::createYes()); } /** @@ -1063,7 +1064,7 @@ public function dataCondition(): iterable new Arg(new Variable('array')), ]), [ - '$array' => 'array&hasOffset(\'foo\')', + '$array' => 'non-empty-array&hasOffset(\'foo\')', ], [ '$array' => '~hasOffset(\'foo\')', @@ -1111,7 +1112,7 @@ public function dataCondition(): iterable new Arg(new Variable('array')), ]), [ - '$array' => 'array&hasOffset(\'foo\')', + '$array' => 'non-empty-array&hasOffset(\'foo\')', ], [ '$array' => '~hasOffset(\'foo\')', @@ -1217,8 +1218,8 @@ public function dataCondition(): iterable ), new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')), ), - ['$a' => 'non-empty-array|null'], - ['$a' => 'mixed~non-empty-array & ~null'], + ['$a' => 'non-empty-array|null'], + ['$a' => 'mixed~non-empty-array & ~null'], ], [ new Expr\BinaryOp\BooleanAnd( @@ -1233,7 +1234,7 @@ public function dataCondition(): iterable ), [ '$foo' => 'array', - 'array_filter($foo, \'is_string\', ARRAY_FILTER_USE_KEY)' => 'array', // could be 'array' + 'array_filter($foo, \'is_string\', ARRAY_FILTER_USE_KEY)' => 'array', // could be 'array' ], [], ], @@ -1249,7 +1250,7 @@ public function dataCondition(): iterable ), ), [ - '$foo' => 'non-empty-array', + '$foo' => 'non-empty-array', 'count($foo)' => 'mixed~(0.0|int|false|null)', ], [], @@ -1266,7 +1267,7 @@ public function dataCondition(): iterable ), ), [ - '$foo' => 'non-empty-array', + '$foo' => 'non-empty-array', 'count($foo)' => '2', ], [], diff --git a/tests/PHPStan/Analyser/UnknownMixedTypeOnOlderPhpTest.php b/tests/PHPStan/Analyser/UnknownMixedTypeOnOlderPhpTest.php new file mode 100644 index 0000000000..3c83a57e57 --- /dev/null +++ b/tests/PHPStan/Analyser/UnknownMixedTypeOnOlderPhpTest.php @@ -0,0 +1,42 @@ + + */ +class UnknownMixedTypeOnOlderPhpTest extends RuleTestCase +{ + + protected function getRule(): TRule + { + return self::getContainer()->getByType(ExistingClassesInTypehintsRule::class); + } + + public function testMixedUnknownType(): void + { + $this->analyse([__DIR__ . '/data/unknown-mixed-type.php'], [ + [ + 'Parameter $m of method UnknownMixedType\Foo::doFoo() has invalid type UnknownMixedType\mixed.', + 8, + ], + [ + 'Method UnknownMixedType\Foo::doFoo() has invalid return type UnknownMixedType\mixed.', + 8, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return array_merge(parent::getAdditionalConfigFiles(), [ + __DIR__ . '/unknown-mixed-type.neon', + ]); + } + +} diff --git a/tests/PHPStan/Analyser/data/TestDynamicReturnTypeExtensions.php b/tests/PHPStan/Analyser/data/TestDynamicReturnTypeExtensions.php index 446e478cd0..dd72c4525e 100644 --- a/tests/PHPStan/Analyser/data/TestDynamicReturnTypeExtensions.php +++ b/tests/PHPStan/Analyser/data/TestDynamicReturnTypeExtensions.php @@ -41,16 +41,28 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method { $args = $methodCall->args; if (count($args) === 0) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } $arg = $args[0]->value; if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } if (!($arg->class instanceof \PhpParser\Node\Name)) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } return new ObjectType((string) $arg->class); @@ -75,12 +87,20 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method { $args = $methodCall->args; if (count($args) === 0) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } $argType = $scope->getType($args[0]->value); if (!$argType instanceof ConstantStringType) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } return new ObjectType($argType->getValue()); @@ -105,16 +125,28 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, { $args = $methodCall->args; if (count($args) === 0) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } $arg = $args[0]->value; if (!($arg instanceof \PhpParser\Node\Expr\ClassConstFetch)) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } if (!($arg->class instanceof \PhpParser\Node\Name)) { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } return new ObjectType((string) $arg->class); @@ -215,7 +247,11 @@ public function isMethodSupported(MethodReflection $methodReflection): bool public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type { - return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); + return ParametersAcceptorSelector::selectFromArgs( + $scope, + $methodCall->getArgs(), + $methodReflection->getVariants(), + )->getReturnType(); } } diff --git a/tests/PHPStan/Analyser/data/array-spread.php b/tests/PHPStan/Analyser/data/array-spread.php index 5bd12fdc38..f752a03270 100644 --- a/tests/PHPStan/Analyser/data/array-spread.php +++ b/tests/PHPStan/Analyser/data/array-spread.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 + : mixed) $value + * @phpstan-assert array $value + */ +function isArrayWithStringKeys(mixed $value): void +{ + if (!is_array($value)) { + throw new \Exception('Not an array'); + } + + foreach (array_keys($value) as $key) { + if (!is_string($key)) { + throw new \Exception('Non-string key'); + } + } +} + +function ($m): void { + isArrayWithStringKeys($m); + assertType('array', $m); +}; diff --git a/tests/PHPStan/Analyser/data/bug-4715.php b/tests/PHPStan/Analyser/data/bug-4715.php index d51a97b3e4..508320fb8b 100644 --- a/tests/PHPStan/Analyser/data/bug-4715.php +++ b/tests/PHPStan/Analyser/data/bug-4715.php @@ -30,7 +30,7 @@ class Administration {} class Company { /** - * @var Collection|Administration[] + * @var Collection */ protected Collection $administrations; @@ -40,7 +40,7 @@ public function __construct() } /** - * @return Collection|Administration[] + * @return Collection */ public function getAdministrations() : Collection { diff --git a/tests/PHPStan/Analyser/data/bug-4902.php b/tests/PHPStan/Analyser/data/bug-4902.php index 8e553747ac..fc84a47d33 100644 --- a/tests/PHPStan/Analyser/data/bug-4902.php +++ b/tests/PHPStan/Analyser/data/bug-4902.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 +get(0)); - assertType('bool', $this->get(1)); - assertType('bool', $this->get(2)); - } -} diff --git a/tests/PHPStan/Analyser/data/ignore-next-line-legacy.php b/tests/PHPStan/Analyser/data/ignore-next-line-legacy.php deleted file mode 100644 index fa8f2a50fd..0000000000 --- a/tests/PHPStan/Analyser/data/ignore-next-line-legacy.php +++ /dev/null @@ -1,40 +0,0 @@ -= 7.2 - -namespace MbStrlenPhp72; - -use function PHPStan\Testing\assertType; - -class MbStrlenPhp72 -{ - - /** - * @param non-empty-string $nonEmpty - * @param 'utf-8'|'8bit' $utf8And8bit - * @param 'utf-8'|'foo' $utf8AndInvalidEncoding - * @param '1'|'2'|'5'|'10' $constUnion - * @param 1|2|5|10|123|'1234'|false $constUnionMixed - * @param int|float $intFloat - * @param non-empty-string|int|float $nonEmptyStringIntFloat - * @param ""|false|null $emptyStringFalseNull - * @param ""|bool|null $emptyStringBoolNull - * @param "pass"|"none" $encodingsValidOnlyUntilPhp72 - */ - public function doFoo(int $i, string $s, bool $bool, float $float, $intFloat, $nonEmpty, $nonEmptyStringIntFloat, $emptyStringFalseNull, $emptyStringBoolNull, $constUnion, $constUnionMixed, $utf8And8bit, $utf8AndInvalidEncoding, string $unknownEncoding, $encodingsValidOnlyUntilPhp72) - { - assertType('0', mb_strlen('')); - assertType('5', mb_strlen('hallo')); - assertType('int<0, 1>', mb_strlen($bool)); - assertType('int<1, max>', mb_strlen($i)); - assertType('int<0, max>', mb_strlen($s)); - assertType('int<1, max>', mb_strlen($nonEmpty)); - assertType('int<1, 2>', mb_strlen($constUnion)); - assertType('int<0, 4>', mb_strlen($constUnionMixed)); - assertType('3', mb_strlen(123)); - assertType('1', mb_strlen(true)); - assertType('0', mb_strlen(false)); - assertType('0', mb_strlen(null)); - assertType('1', mb_strlen(1.0)); - assertType('4', mb_strlen(1.23)); - assertType('int<1, max>', mb_strlen($float)); - assertType('int<1, max>', mb_strlen($intFloat)); - assertType('int<1, max>', mb_strlen($nonEmptyStringIntFloat)); - assertType('0', mb_strlen($emptyStringFalseNull)); - assertType('int<0, 1>', mb_strlen($emptyStringBoolNull)); - assertType('8', mb_strlen('паляниця', 'utf-8')); - assertType('11', mb_strlen('alias test🤔', 'utf8')); - assertType('false', mb_strlen('', 'invalid encoding')); - assertType('int<5, 6>', mb_strlen('école', $utf8And8bit)); - assertType('5|false', mb_strlen('école', $utf8AndInvalidEncoding)); - assertType('1|3|5|6|false', mb_strlen('école', $unknownEncoding)); - assertType('2|4|5|6|8|false', mb_strlen('מזגן', $unknownEncoding)); - assertType('6|8|12|13|15|18|24|false', mb_strlen('いい天気ですね〜', $unknownEncoding)); - assertType('3|false', mb_strlen(123, $utf8AndInvalidEncoding)); - assertType('3', mb_strlen('foo', $encodingsValidOnlyUntilPhp72)); - } - -} - diff --git a/tests/PHPStan/Analyser/data/param-out.php b/tests/PHPStan/Analyser/data/param-out.php index 341a4069d4..e34e1c9082 100644 --- a/tests/PHPStan/Analyser/data/param-out.php +++ b/tests/PHPStan/Analyser/data/param-out.php @@ -240,7 +240,7 @@ function foo16() { function fooShuffle() { $array = ["foo" => 123, "bar" => 456]; shuffle($array); - assertType('non-empty-array<0|1, 123|456>&list', $array); + assertType('non-empty-list<123|456>', $array); $emptyArray = []; shuffle($emptyArray); @@ -315,7 +315,7 @@ function testParseStr() { echo $output['arr'][1];//baz */ - \PHPStan\Testing\assertType('array', $output); + \PHPStan\Testing\assertType('array|lowercase-string>', $output); } function fooSimilar() { @@ -392,10 +392,10 @@ function fooHeadersSent() { function fooMbParseStr() { mb_parse_str("foo=bar", $output); - assertType('array', $output); + assertType('array|lowercase-string>', $output); mb_parse_str('email=mail@example.org&city=town&x=1&y[g]=3&f=1.23', $output); - assertType('array', $output); + assertType('array|lowercase-string>', $output); } function fooPreg() diff --git a/tests/PHPStan/Analyser/data/property-native-types.php b/tests/PHPStan/Analyser/data/property-native-types.php index 2892179613..87d990b96f 100644 --- a/tests/PHPStan/Analyser/data/property-native-types.php +++ b/tests/PHPStan/Analyser/data/property-native-types.php @@ -1,4 +1,4 @@ -= 7.4 += 8.0 + +declare(strict_types = 1); namespace Abs; diff --git a/tests/PHPStan/Analyser/nsrt/adapter-reflection-enum-return-types.php b/tests/PHPStan/Analyser/nsrt/adapter-reflection-enum-return-types.php index 4002e1ce16..d21d17e739 100644 --- a/tests/PHPStan/Analyser/nsrt/adapter-reflection-enum-return-types.php +++ b/tests/PHPStan/Analyser/nsrt/adapter-reflection-enum-return-types.php @@ -5,12 +5,13 @@ use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumBackedCase; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnumUnitCase; +use PHPStan\BetterReflection\Reflection\Adapter\ReflectionType; use function PHPStan\Testing\assertType; function (ReflectionEnum $r, string $s): void { assertType('non-empty-string|false', $r->getFileName()); - assertType('int|false', $r->getStartLine()); - assertType('int|false', $r->getEndLine()); + assertType('int', $r->getStartLine()); + assertType('int', $r->getEndLine()); assertType('string|false', $r->getDocComment()); assertType('PHPStan\BetterReflection\Reflection\Adapter\ReflectionClassConstant|false', $r->getReflectionConstant($s)); assertType('PHPStan\BetterReflection\Reflection\Adapter\ReflectionClass|false', $r->getParentClass()); @@ -20,10 +21,10 @@ function (ReflectionEnum $r, string $s): void { function (ReflectionEnumBackedCase $r): void { assertType('string|false', $r->getDocComment()); - assertType('PHPStan\BetterReflection\Reflection\Adapter\ReflectionIntersectionType|PHPStan\BetterReflection\Reflection\Adapter\ReflectionNamedType|PHPStan\BetterReflection\Reflection\Adapter\ReflectionUnionType|null', $r->getType()); + assertType(ReflectionType::class . '|null', $r->getType()); }; function (ReflectionEnumUnitCase $r): void { assertType('string|false', $r->getDocComment()); - assertType('PHPStan\BetterReflection\Reflection\Adapter\ReflectionIntersectionType|PHPStan\BetterReflection\Reflection\Adapter\ReflectionNamedType|PHPStan\BetterReflection\Reflection\Adapter\ReflectionUnionType|null', $r->getType()); + assertType(ReflectionType::class . '|null', $r->getType()); }; diff --git a/tests/PHPStan/Analyser/nsrt/array-chunk.php b/tests/PHPStan/Analyser/nsrt/array-chunk.php index 8e6fa67cf2..cedb50ddb7 100644 --- a/tests/PHPStan/Analyser/nsrt/array-chunk.php +++ b/tests/PHPStan/Analyser/nsrt/array-chunk.php @@ -11,7 +11,7 @@ public function generalArrays(array $arr): void { /** @var mixed[] $arr */ assertType('list>', array_chunk($arr, 2)); - assertType('list', array_chunk($arr, 2, true)); + assertType('list>', array_chunk($arr, 2, true)); /** @var array $arr */ assertType('list>', array_chunk($arr, 2)); @@ -60,8 +60,8 @@ public function chunkUnionTypeLength(array $arr, $positiveRange, $positiveUnion) * @param int<50, max> $bigger50 */ public function lengthIntRanges(array $arr, int $positiveInt, int $bigger50) { - assertType('list>', array_chunk($arr, $positiveInt)); - assertType('list>', array_chunk($arr, $bigger50)); + assertType('list', array_chunk($arr, $positiveInt)); + assertType('list', array_chunk($arr, $bigger50)); } /** @@ -78,11 +78,11 @@ function testLimits(array $arr, int $oneToFour, int $tooBig) { public function offsets(array $arr, array $map): void { if (array_key_exists('foo', $arr)) { - assertType('non-empty-list>', array_chunk($arr, 2)); + assertType('non-empty-list', array_chunk($arr, 2)); assertType('non-empty-list', array_chunk($arr, 2, true)); } if (array_key_exists('foo', $arr) && $arr['foo'] === 'bar') { - assertType('non-empty-list>', array_chunk($arr, 2)); + assertType('non-empty-list', array_chunk($arr, 2)); assertType('non-empty-list', array_chunk($arr, 2, true)); } diff --git a/tests/PHPStan/Analyser/nsrt/array-column-php82.php b/tests/PHPStan/Analyser/nsrt/array-column-php82.php index d53ab61f00..7f0a545edc 100644 --- a/tests/PHPStan/Analyser/nsrt/array-column-php82.php +++ b/tests/PHPStan/Analyser/nsrt/array-column-php82.php @@ -175,7 +175,7 @@ public function testImprecise5(array $array): void assertType('list', array_column($array, 'nodeName')); assertType('array', array_column($array, 'nodeName', 'tagName')); assertType('array', array_column($array, null, 'tagName')); - assertType('list', array_column($array, 'foo')); + assertType('list', array_column($array, 'foo')); assertType('array', array_column($array, 'foo', 'tagName')); assertType('array', array_column($array, 'nodeName', 'foo')); assertType('array', array_column($array, null, 'foo')); @@ -187,7 +187,7 @@ public function testObjects1(array $array): void assertType('non-empty-list', array_column($array, 'nodeName')); assertType('non-empty-array', array_column($array, 'nodeName', 'tagName')); assertType('non-empty-array', array_column($array, null, 'tagName')); - assertType('list', array_column($array, 'foo')); + assertType('list', array_column($array, 'foo')); assertType('array', array_column($array, 'foo', 'tagName')); assertType('non-empty-array', array_column($array, 'nodeName', 'foo')); assertType('non-empty-array', array_column($array, null, 'foo')); @@ -199,7 +199,7 @@ public function testObjects2(array $array): void assertType('array{string}', array_column($array, 'nodeName')); assertType('non-empty-array', array_column($array, 'nodeName', 'tagName')); assertType('non-empty-array', array_column($array, null, 'tagName')); - assertType('list', array_column($array, 'foo')); + assertType('list', array_column($array, 'foo')); assertType('array', array_column($array, 'foo', 'tagName')); assertType('non-empty-array', array_column($array, 'nodeName', 'foo')); assertType('non-empty-array', array_column($array, null, 'foo')); diff --git a/tests/PHPStan/Analyser/nsrt/array-column.php b/tests/PHPStan/Analyser/nsrt/array-column.php index 3e3cedbbff..ee4ad00527 100644 --- a/tests/PHPStan/Analyser/nsrt/array-column.php +++ b/tests/PHPStan/Analyser/nsrt/array-column.php @@ -189,7 +189,7 @@ public function testImprecise5(array $array): void assertType('list', array_column($array, 'nodeName')); assertType('array', array_column($array, 'nodeName', 'tagName')); assertType('array', array_column($array, null, 'tagName')); - assertType('list', array_column($array, 'foo')); + assertType('list', array_column($array, 'foo')); assertType('array', array_column($array, 'foo', 'tagName')); assertType('array', array_column($array, 'nodeName', 'foo')); assertType('array', array_column($array, null, 'foo')); @@ -201,7 +201,7 @@ public function testObjects1(array $array): void assertType('non-empty-list', array_column($array, 'nodeName')); assertType('non-empty-array', array_column($array, 'nodeName', 'tagName')); assertType('non-empty-array', array_column($array, null, 'tagName')); - assertType('list', array_column($array, 'foo')); + assertType('list', array_column($array, 'foo')); assertType('array', array_column($array, 'foo', 'tagName')); assertType('non-empty-array', array_column($array, 'nodeName', 'foo')); assertType('non-empty-array', array_column($array, null, 'foo')); @@ -213,7 +213,7 @@ public function testObjects2(array $array): void assertType('array{string}', array_column($array, 'nodeName')); assertType('non-empty-array', array_column($array, 'nodeName', 'tagName')); assertType('non-empty-array', array_column($array, null, 'tagName')); - assertType('list', array_column($array, 'foo')); + assertType('list', array_column($array, 'foo')); assertType('array', array_column($array, 'foo', 'tagName')); assertType('non-empty-array', array_column($array, 'nodeName', 'foo')); assertType('non-empty-array', array_column($array, null, 'foo')); @@ -227,7 +227,7 @@ final class Foo /** @param array $a */ public function doFoo(array $a): void { - assertType('list', array_column($a, 'nodeName')); + assertType('list', array_column($a, 'nodeName')); assertType('array', array_column($a, 'nodeName', 'tagName')); } diff --git a/tests/PHPStan/Analyser/nsrt/array-fill-keys-php7.php b/tests/PHPStan/Analyser/nsrt/array-fill-keys-php7.php index 7bbc485b5a..c0a4e8dd7a 100644 --- a/tests/PHPStan/Analyser/nsrt/array-fill-keys-php7.php +++ b/tests/PHPStan/Analyser/nsrt/array-fill-keys-php7.php @@ -7,7 +7,7 @@ function mixedAndSubtractedArray($mixed): void { if (is_array($mixed)) { - assertType("array<'b'>", array_fill_keys($mixed, 'b')); + assertType("array", array_fill_keys($mixed, 'b')); } else { assertType("null", array_fill_keys($mixed, 'b')); } diff --git a/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php b/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php index 07c06367dc..4710482534 100644 --- a/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php +++ b/tests/PHPStan/Analyser/nsrt/array-fill-keys-php8.php @@ -7,7 +7,7 @@ function mixedAndSubtractedArray($mixed): void { if (is_array($mixed)) { - assertType("array<'b'>", array_fill_keys($mixed, 'b')); + assertType("array", array_fill_keys($mixed, 'b')); } else { assertType("*NEVER*", array_fill_keys($mixed, 'b')); } diff --git a/tests/PHPStan/Analyser/nsrt/array-filter-arrow-functions.php b/tests/PHPStan/Analyser/nsrt/array-filter-arrow-functions.php index 8b3b17f477..4ad761fc71 100644 --- a/tests/PHPStan/Analyser/nsrt/array-filter-arrow-functions.php +++ b/tests/PHPStan/Analyser/nsrt/array-filter-arrow-functions.php @@ -1,4 +1,4 @@ -= 7.4 +', array_flip($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('null', array_flip($mixed)); } } diff --git a/tests/PHPStan/Analyser/nsrt/array-flip-php8.php b/tests/PHPStan/Analyser/nsrt/array-flip-php8.php index be439d0427..294554e20c 100644 --- a/tests/PHPStan/Analyser/nsrt/array-flip-php8.php +++ b/tests/PHPStan/Analyser/nsrt/array-flip-php8.php @@ -9,7 +9,7 @@ function mixedAndSubtractedArray($mixed) if (is_array($mixed)) { assertType('array<(int|string)>', array_flip($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('*NEVER*', array_flip($mixed)); } } diff --git a/tests/PHPStan/Analyser/nsrt/array-flip.php b/tests/PHPStan/Analyser/nsrt/array-flip.php index b6a6eb6c66..090fcde892 100644 --- a/tests/PHPStan/Analyser/nsrt/array-flip.php +++ b/tests/PHPStan/Analyser/nsrt/array-flip.php @@ -71,25 +71,25 @@ function foo8($mixed) function foo10(array $array) { if (array_key_exists('foo', $array)) { - assertType('array&hasOffset(\'foo\')', $array); + assertType('non-empty-array&hasOffset(\'foo\')', $array); assertType('array', array_flip($array)); } if (array_key_exists('foo', $array) && is_int($array['foo'])) { - assertType("array&hasOffsetValue('foo', int)", $array); + assertType("non-empty-array&hasOffsetValue('foo', int)", $array); assertType('array', array_flip($array)); } if (array_key_exists('foo', $array) && $array['foo'] === 17) { - assertType("array&hasOffsetValue('foo', 17)", $array); - assertType("array&hasOffsetValue(17, 'foo')", array_flip($array)); + assertType("non-empty-array&hasOffsetValue('foo', 17)", $array); + assertType("non-empty-array&hasOffsetValue(17, 'foo')", array_flip($array)); } if ( array_key_exists('foo', $array) && $array['foo'] === 17 && array_key_exists('bar', $array) && $array['bar'] === 17 ) { - assertType("array&hasOffsetValue('bar', 17)&hasOffsetValue('foo', 17)", $array); + assertType("non-empty-array&hasOffsetValue('bar', 17)&hasOffsetValue('foo', 17)", $array); assertType("*NEVER*", array_flip($array)); // this could be array&hasOffsetValue(17, 'bar') according to https://3v4l.org/1TAFk } } diff --git a/tests/PHPStan/Analyser/nsrt/array-intersect-key-php7.php b/tests/PHPStan/Analyser/nsrt/array-intersect-key-php7.php index 79b7af7b18..14dd7b5d0d 100644 --- a/tests/PHPStan/Analyser/nsrt/array-intersect-key-php7.php +++ b/tests/PHPStan/Analyser/nsrt/array-intersect-key-php7.php @@ -16,7 +16,7 @@ public function mixedAndSubtractedArray($mixed, array $otherArrs): void /** @var array $otherArrs */ assertType('array', array_intersect_key($mixed, $otherArrs)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); /** @var array $otherArrs */ assertType('null', array_intersect_key($mixed, $otherArrs)); /** @var array $otherArrs */ diff --git a/tests/PHPStan/Analyser/nsrt/array-intersect-key-php8.php b/tests/PHPStan/Analyser/nsrt/array-intersect-key-php8.php index 4bfd3140e0..9ffde9da83 100644 --- a/tests/PHPStan/Analyser/nsrt/array-intersect-key-php8.php +++ b/tests/PHPStan/Analyser/nsrt/array-intersect-key-php8.php @@ -16,7 +16,7 @@ public function mixedAndSubtractedArray($mixed, array $otherArrs): void /** @var array $otherArrs */ assertType('array', array_intersect_key($mixed, $otherArrs)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); /** @var array $otherArrs */ assertType('*NEVER*', array_intersect_key($mixed, $otherArrs)); /** @var array $otherArrs */ diff --git a/tests/PHPStan/Analyser/nsrt/array-intersect-key.php b/tests/PHPStan/Analyser/nsrt/array-intersect-key.php index bf620b508b..288ba539a2 100644 --- a/tests/PHPStan/Analyser/nsrt/array-intersect-key.php +++ b/tests/PHPStan/Analyser/nsrt/array-intersect-key.php @@ -48,7 +48,7 @@ public function normalArrays(array $arr, array $arr2, array $otherArrs): void assertType('array{}', array_intersect_key($arr, $otherArrs)); if (array_key_exists(17, $arr2)) { - assertType('array<17, string>&hasOffset(17)', array_intersect_key($arr2, [17 => 'bar'])); + assertType('non-empty-array<17, string>&hasOffset(17)', array_intersect_key($arr2, [17 => 'bar'])); /** @var array $otherArrs */ assertType('array', array_intersect_key($arr2, $otherArrs)); /** @var array $otherArrs */ @@ -56,7 +56,7 @@ public function normalArrays(array $arr, array $arr2, array $otherArrs): void } if (array_key_exists(17, $arr2) && $arr2[17] === 'foo') { - assertType("array<17, string>&hasOffsetValue(17, 'foo')", array_intersect_key($arr2, [17 => 'bar'])); + assertType("non-empty-array<17, string>&hasOffsetValue(17, 'foo')", array_intersect_key($arr2, [17 => 'bar'])); /** @var array $otherArrs */ assertType('array', array_intersect_key($arr2, $otherArrs)); /** @var array $otherArrs */ @@ -79,7 +79,7 @@ public function arrayUnpacking(array $arrs, array $arrs2): void /** @param list $arr */ public function list(array $arr, array $otherArrs): void { - assertType('array<0|1, string>&list', array_intersect_key($arr, ['foo', 'bar'])); + assertType('list', array_intersect_key($arr, ['foo', 'bar'])); /** @var array $otherArrs */ assertType('array, string>', array_intersect_key($arr, $otherArrs)); /** @var array $otherArrs */ diff --git a/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php b/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php index aa21248ec6..1b788158d6 100644 --- a/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php +++ b/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php @@ -6,7 +6,7 @@ function foo(array $foo) { if (array_is_list($foo)) { - assertType('list', $foo); + assertType('list', $foo); } else { assertType('array', $foo); } @@ -14,9 +14,9 @@ function foo(array $foo) { function foo2($foo) { if (array_is_list($foo)) { - assertType('list', $foo); + assertType('list', $foo); } else { - assertType('mixed~list', $foo); + assertType('mixed~list', $foo); } } @@ -49,7 +49,7 @@ function foo4(array $foo) { /** @var array $foo */ if (array_is_list($foo)) { - assertType('list', $foo); + assertType('list', $foo); } else { assertType('array', $foo); } diff --git a/tests/PHPStan/Analyser/nsrt/array-key-exists.php b/tests/PHPStan/Analyser/nsrt/array-key-exists.php index a7246dd043..3d0505a9b9 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/array-pop.php b/tests/PHPStan/Analyser/nsrt/array-pop.php index 04494a96df..37a986b0ce 100644 --- a/tests/PHPStan/Analyser/nsrt/array-pop.php +++ b/tests/PHPStan/Analyser/nsrt/array-pop.php @@ -77,7 +77,7 @@ public function foo1($mixed): void if(is_array($mixed)) { assertType('mixed', array_pop($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('mixed', array_pop($mixed)); assertType('*ERROR*', $mixed); } diff --git a/tests/PHPStan/Analyser/nsrt/array-reverse.php b/tests/PHPStan/Analyser/nsrt/array-reverse.php index 28dbd009c4..86a3bb72cf 100644 --- a/tests/PHPStan/Analyser/nsrt/array-reverse.php +++ b/tests/PHPStan/Analyser/nsrt/array-reverse.php @@ -1,4 +1,6 @@ -= 8.0 + +declare(strict_types = 1); namespace ArrayReverse; @@ -12,8 +14,8 @@ class Foo */ public function normalArrays(array $a, array $b): void { - assertType('array', array_reverse($a)); - assertType('array', array_reverse($a, true)); + assertType('array', array_reverse($a)); + assertType('array', array_reverse($a, true)); assertType('array', array_reverse($b)); assertType('array', array_reverse($b, true)); @@ -66,12 +68,12 @@ public function list(array $a, array $b): void public function mixed(mixed $mixed): void { - assertType('array', array_reverse($mixed)); - assertType('array', array_reverse($mixed, true)); + assertType('array', array_reverse($mixed)); + assertType('array', array_reverse($mixed, true)); if (array_key_exists('foo', $mixed)) { assertType('non-empty-array', array_reverse($mixed)); - assertType("array&hasOffset('foo')", array_reverse($mixed, true)); + assertType("non-empty-array&hasOffset('foo')", array_reverse($mixed, true)); } } } diff --git a/tests/PHPStan/Analyser/nsrt/array-search-php7.php b/tests/PHPStan/Analyser/nsrt/array-search-php7.php index 2cd24b7c9d..5816daf659 100644 --- a/tests/PHPStan/Analyser/nsrt/array-search-php7.php +++ b/tests/PHPStan/Analyser/nsrt/array-search-php7.php @@ -16,7 +16,7 @@ public function mixedAndSubtractedArray($mixed, string $string): void assertType('int|string|false', array_search('foo', $mixed)); assertType('int|string|false', array_search($string, $mixed, true)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('null', array_search('foo', $mixed, true)); assertType('null', array_search('foo', $mixed)); assertType('null', array_search($string, $mixed, true)); diff --git a/tests/PHPStan/Analyser/nsrt/array-search-php8.php b/tests/PHPStan/Analyser/nsrt/array-search-php8.php index c3430cc1b5..30b9527e10 100644 --- a/tests/PHPStan/Analyser/nsrt/array-search-php8.php +++ b/tests/PHPStan/Analyser/nsrt/array-search-php8.php @@ -16,7 +16,7 @@ public function mixedAndSubtractedArray($mixed, string $string): void assertType('int|string|false', array_search('foo', $mixed)); assertType('int|string|false', array_search($string, $mixed, true)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('*NEVER*', array_search('foo', $mixed, true)); assertType('*NEVER*', array_search('foo', $mixed)); assertType('*NEVER*', array_search($string, $mixed, true)); diff --git a/tests/PHPStan/Analyser/nsrt/array-shape-list-optional.php b/tests/PHPStan/Analyser/nsrt/array-shape-list-optional.php index f059d14c4d..10049a8317 100644 --- a/tests/PHPStan/Analyser/nsrt/array-shape-list-optional.php +++ b/tests/PHPStan/Analyser/nsrt/array-shape-list-optional.php @@ -9,7 +9,7 @@ class Foo /** * @param list{0: string, 1: int, 2?: string, 3?: string} $valid1 - * @param non-empty-list{0: string, 1: int, 2?: string, 3?: string} $valid2 + * @param non-empty-list{0?: string, 1?: int, 2?: string, 3?: string} $valid2 * @param non-empty-array{0?: string, 1?: int, 2?: string, 3?: string} $valid3 * @param list{0: string, 1: int, 2?: string, 4?: string} $invalid1 * @param list{0: string, 1: int, 2?: string, foo?: string} $invalid2 @@ -22,9 +22,9 @@ public function doFoo( $invalid2 ): void { - assertType('array{0: string, 1: int, 2?: string, 3?: string}&list', $valid1); - assertType('array{0: string, 1: int, 2?: string, 3?: string}&list', $valid2); - assertType('array{0?: string, 1?: int, 2?: string, 3?: string}&non-empty-array', $valid3); + assertType('list{0: string, 1: int, 2?: string, 3?: string}', $valid1); + assertType('non-empty-list{0?: string, 1?: int, 2?: string, 3?: string}', $valid2); + assertType('non-empty-array{0?: string, 1?: int, 2?: string, 3?: string}', $valid3); assertType('*NEVER*', $invalid1); assertType('*NEVER*', $invalid2); } diff --git a/tests/PHPStan/Analyser/nsrt/array-shift.php b/tests/PHPStan/Analyser/nsrt/array-shift.php index eb227de3f6..2d8ef21d7e 100644 --- a/tests/PHPStan/Analyser/nsrt/array-shift.php +++ b/tests/PHPStan/Analyser/nsrt/array-shift.php @@ -77,7 +77,7 @@ public function foo1($mixed): void if(is_array($mixed)) { assertType('mixed', array_shift($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('mixed', array_shift($mixed)); assertType('*ERROR*', $mixed); } diff --git a/tests/PHPStan/Analyser/nsrt/array-slice.php b/tests/PHPStan/Analyser/nsrt/array-slice.php index 87fa61e36f..847f535df1 100644 --- a/tests/PHPStan/Analyser/nsrt/array-slice.php +++ b/tests/PHPStan/Analyser/nsrt/array-slice.php @@ -15,7 +15,7 @@ class Foo public function nonEmpty(array $a, array $b, array $c): void { assertType('array', array_slice($a, 1)); - assertType('list', array_slice($b, 1)); + assertType('list', array_slice($b, 1)); assertType('array', array_slice($c, 1)); } @@ -24,7 +24,7 @@ public function nonEmpty(array $a, array $b, array $c): void */ public function fromMixed($arr): void { - assertType('array', array_slice($arr, 1, 2)); + assertType('array', array_slice($arr, 1, 2)); } public function normalArrays(array $arr): void @@ -94,11 +94,11 @@ public function offsets(array $arr): void { if (array_key_exists(1, $arr)) { assertType('non-empty-array', array_slice($arr, 1, null, false)); - assertType('hasOffset(1)&non-empty-array', array_slice($arr, 1, null, true)); + assertType('non-empty-array&hasOffset(1)', array_slice($arr, 1, null, true)); } if (array_key_exists(1, $arr) && $arr[1] === 'foo') { assertType('non-empty-array', array_slice($arr, 1, null, false)); - assertType("hasOffsetValue(1, 'foo')&non-empty-array", array_slice($arr, 1, null, true)); + assertType("non-empty-array&hasOffsetValue(1, 'foo')", array_slice($arr, 1, null, true)); } } diff --git a/tests/PHPStan/Analyser/nsrt/array_keys-php7.php b/tests/PHPStan/Analyser/nsrt/array_keys-php7.php index 103cb0a003..9f5ca43682 100644 --- a/tests/PHPStan/Analyser/nsrt/array_keys-php7.php +++ b/tests/PHPStan/Analyser/nsrt/array_keys-php7.php @@ -12,7 +12,7 @@ public function sayHello($mixed): void if (is_array($mixed)) { assertType('list<(int|string)>', array_keys($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('null', array_keys($mixed)); } } diff --git a/tests/PHPStan/Analyser/nsrt/array_keys.php b/tests/PHPStan/Analyser/nsrt/array_keys.php index 7ea0a40ff5..6808bf36b3 100644 --- a/tests/PHPStan/Analyser/nsrt/array_keys.php +++ b/tests/PHPStan/Analyser/nsrt/array_keys.php @@ -11,7 +11,7 @@ public function sayHello($mixed): void if(is_array($mixed)) { assertType('list<(int|string)>', array_keys($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('*NEVER*', array_keys($mixed)); } } diff --git a/tests/PHPStan/Analyser/nsrt/array_values-php7.php b/tests/PHPStan/Analyser/nsrt/array_values-php7.php index 10de823980..db378c95aa 100644 --- a/tests/PHPStan/Analyser/nsrt/array_values-php7.php +++ b/tests/PHPStan/Analyser/nsrt/array_values-php7.php @@ -12,7 +12,7 @@ public function foo1($mixed): void if (is_array($mixed)) { assertType('list', array_values($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('null', array_values($mixed)); } } diff --git a/tests/PHPStan/Analyser/nsrt/array_values.php b/tests/PHPStan/Analyser/nsrt/array_values.php index a9fc01c947..18074963a4 100644 --- a/tests/PHPStan/Analyser/nsrt/array_values.php +++ b/tests/PHPStan/Analyser/nsrt/array_values.php @@ -11,7 +11,7 @@ public function foo1($mixed): void if(is_array($mixed)) { assertType('list', array_values($mixed)); } else { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('*NEVER*', array_values($mixed)); } } diff --git a/tests/PHPStan/Analyser/nsrt/arrow-function-types.php b/tests/PHPStan/Analyser/nsrt/arrow-function-types.php index 77cbe12cf8..acb8f74ee4 100644 --- a/tests/PHPStan/Analyser/nsrt/arrow-function-types.php +++ b/tests/PHPStan/Analyser/nsrt/arrow-function-types.php @@ -1,4 +1,4 @@ -= 7.4 += 8.0 namespace AssertConditional; diff --git a/tests/PHPStan/Analyser/nsrt/assert-docblock.php b/tests/PHPStan/Analyser/nsrt/assert-docblock.php index 8923430fd3..a1cbcc9b3e 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; @@ -56,7 +56,7 @@ function validateNotNull($value) : void {} * @param mixed[] $arr */ function takesArray(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); validateStringArray($arr); assertType('array', $arr); @@ -66,22 +66,22 @@ function takesArray(array $arr) : void { * @param mixed[] $arr */ function takesArrayIfTrue(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); if (validateStringArrayIfTrue($arr)) { assertType('array', $arr); } else { - assertType('array', $arr); + assertType('array', $arr); } } /** * @param mixed[] $arr */ function takesArrayIfTrue1(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); if (!validateStringArrayIfTrue($arr)) { - assertType('array', $arr); + assertType('array', $arr); } else { assertType('array', $arr); } @@ -91,12 +91,12 @@ function takesArrayIfTrue1(array $arr) : void { * @param mixed[] $arr */ function takesArrayIfFalse(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); if (!validateStringArrayIfFalse($arr)) { assertType('array', $arr); } else { - assertType('array', $arr); + assertType('array', $arr); } } @@ -104,10 +104,10 @@ function takesArrayIfFalse(array $arr) : void { * @param mixed[] $arr */ function takesArrayIfFalse1(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); if (validateStringArrayIfFalse($arr)) { - assertType('array', $arr); + assertType('array', $arr); } else { assertType('array', $arr); } @@ -117,7 +117,7 @@ function takesArrayIfFalse1(array $arr) : void { * @param mixed[] $arr */ function takesStringOrIntArray(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); if (validateStringOrIntArray($arr)) { assertType('array', $arr); @@ -130,7 +130,7 @@ function takesStringOrIntArray(array $arr) : void { * @param mixed[] $arr */ function takesStringOrNonEmptyIntArray(array $arr) : void { - assertType('array', $arr); + assertType('array', $arr); if (validateStringOrNonEmptyIntArray($arr)) { assertType('array', $arr); diff --git a/tests/PHPStan/Analyser/nsrt/assert-empty.php b/tests/PHPStan/Analyser/nsrt/assert-empty.php index 236e2b43d0..a74e4c1e35 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..913f1e9034 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; @@ -26,5 +26,5 @@ public function assert(mixed $value): void; function intersection($assert, mixed $value): void { $assert->assert($value); - assertType('non-empty-list', $value); + assertType('non-empty-list', $value); } 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/assert-methods.php b/tests/PHPStan/Analyser/nsrt/assert-methods.php index f6609f3f8f..6c278c21ed 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-methods.php +++ b/tests/PHPStan/Analyser/nsrt/assert-methods.php @@ -37,7 +37,7 @@ public function doBar($mixed) public function doBar2(array $objects) { self::doFoo($objects, stdClass::class); - assertType('array', $objects); + assertType('array', $objects); } /** @@ -47,7 +47,7 @@ public function doBar2(array $objects) public function doBar3(array $strings) { self::doFoo($strings, stdClass::class); - assertType('array>', $strings); + assertType('array>', $strings); } /** diff --git a/tests/PHPStan/Analyser/nsrt/block-statement.php b/tests/PHPStan/Analyser/nsrt/block-statement.php new file mode 100644 index 0000000000..fc752007d8 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/block-statement.php @@ -0,0 +1,22 @@ += 8.0 + +declare(strict_types = 1); namespace Bug10037; 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-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-10653.php b/tests/PHPStan/Analyser/nsrt/bug-10653.php new file mode 100644 index 0000000000..fc6642a229 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-10653.php @@ -0,0 +1,13 @@ +mayFail(); + assertType('stdClass|false', $value); + $value = $a->throwOnFailure($value); + assertType(stdClass::class, $value); +}; diff --git a/tests/PHPStan/Analyser/nsrt/bug-10721.php b/tests/PHPStan/Analyser/nsrt/bug-10721.php index cf7ce49272..52d511c163 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-10721.php +++ b/tests/PHPStan/Analyser/nsrt/bug-10721.php @@ -22,9 +22,9 @@ public function retrieve(?int $limit = 20): array assertType("array{'zib', 'zib 2', 'zeit im bild', 'soko', 'landkrimi', 'tatort'}", $list); shuffle($list); - assertType("non-empty-array<0|1|2|3|4|5, 'landkrimi'|'soko'|'tatort'|'zeit im bild'|'zib'|'zib 2'>&list", $list); + assertType("non-empty-list<'landkrimi'|'soko'|'tatort'|'zeit im bild'|'zib'|'zib 2'>", $list); - assertType("non-empty-array<0|1|2|3|4|5, 'landkrimi'|'soko'|'tatort'|'zeit im bild'|'zib'|'zib 2'>&list", array_slice($list, 0, max($limit, 1))); + assertType("non-empty-list<'landkrimi'|'soko'|'tatort'|'zeit im bild'|'zib'|'zib 2'>", array_slice($list, 0, max($limit, 1))); return array_slice($list, 0, max($limit, 1)); } @@ -37,7 +37,7 @@ public function listVariants(): void assertType("array{2: 'zib', 4: 'zib 2'}", $arr); shuffle($arr); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", $arr); + assertType("non-empty-list<'zib'|'zib 2'>", $arr); $list = [ 'zib', @@ -46,37 +46,37 @@ public function listVariants(): void assertType("array{'zib', 'zib 2'}", $list); shuffle($list); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", $list); + assertType("non-empty-list<'zib'|'zib 2'>", $list); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, -1)); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 0)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 1)); // could be non-empty-array - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 2)); + assertType("list<'zib'|'zib 2'>", array_slice($list, -1)); + assertType("non-empty-list<'zib'|'zib 2'>", array_slice($list, 0)); + assertType("list<'zib'|'zib 2'>", array_slice($list, 1)); // could be non-empty-array + assertType("list<'zib'|'zib 2'>", array_slice($list, 2)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, -1, 1)); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 0, 1)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 1, 1)); // could be non-empty-array - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 2, 1)); + assertType("list<'zib'|'zib 2'>", array_slice($list, -1, 1)); + assertType("non-empty-list<'zib'|'zib 2'>", array_slice($list, 0, 1)); + assertType("list<'zib'|'zib 2'>", array_slice($list, 1, 1)); // could be non-empty-array + assertType("list<'zib'|'zib 2'>", array_slice($list, 2, 1)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, -1, 2)); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 0, 2)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 1, 2)); // could be non-empty-array - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 2, 2)); + assertType("list<'zib'|'zib 2'>", array_slice($list, -1, 2)); + assertType("non-empty-list<'zib'|'zib 2'>", array_slice($list, 0, 2)); + assertType("list<'zib'|'zib 2'>", array_slice($list, 1, 2)); // could be non-empty-array + assertType("list<'zib'|'zib 2'>", array_slice($list, 2, 2)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, -1, 3)); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 0, 3)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 1, 3)); // could be non-empty-array - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 2, 3)); + assertType("list<'zib'|'zib 2'>", array_slice($list, -1, 3)); + assertType("non-empty-list<'zib'|'zib 2'>", array_slice($list, 0, 3)); + assertType("list<'zib'|'zib 2'>", array_slice($list, 1, 3)); // could be non-empty-array + assertType("list<'zib'|'zib 2'>", array_slice($list, 2, 3)); assertType("array<0|1, 'zib'|'zib 2'>", array_slice($list, -1, 3, true)); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 0, 3, true)); + assertType("non-empty-list<'zib'|'zib 2'>", array_slice($list, 0, 3, true)); assertType("array<0|1, 'zib'|'zib 2'>", array_slice($list, 1, 3, true)); // could be non-empty-array assertType("array<0|1, 'zib'|'zib 2'>", array_slice($list, 2, 3, true)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, -1, 3, false)); - assertType("non-empty-array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 0, 3, false)); - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 1, 3, false)); // could be non-empty-array - assertType("array<0|1, 'zib'|'zib 2'>&list", array_slice($list, 2, 3, false)); + assertType("list<'zib'|'zib 2'>", array_slice($list, -1, 3, false)); + assertType("non-empty-list<'zib'|'zib 2'>", array_slice($list, 0, 3, false)); + assertType("list<'zib'|'zib 2'>", array_slice($list, 1, 3, false)); // could be non-empty-array + assertType("list<'zib'|'zib 2'>", array_slice($list, 2, 3, false)); } /** diff --git a/tests/PHPStan/Analyser/nsrt/bug-11188.php b/tests/PHPStan/Analyser/nsrt/bug-11188.php index 4c96faacb6..1280620263 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-11188.php +++ b/tests/PHPStan/Analyser/nsrt/bug-11188.php @@ -1,4 +1,4 @@ -= 8.0 namespace Bug11188; diff --git a/tests/PHPStan/Analyser/nsrt/bug-11311-php72.php b/tests/PHPStan/Analyser/nsrt/bug-11311-php72.php deleted file mode 100644 index 957b3557de..0000000000 --- a/tests/PHPStan/Analyser/nsrt/bug-11311-php72.php +++ /dev/null @@ -1,30 +0,0 @@ -\d+)\.(?\d+)(?:\.(?\d+))?/', $s, $matches, PREG_UNMATCHED_AS_NULL)) { - assertType('array{0: string, major: numeric-string, 1: numeric-string, minor: numeric-string, 2: numeric-string, patch?: numeric-string, 3?: numeric-string}', $matches); - } -} - -function doUnmatchedAsNull(string $s): void { - if (preg_match('/(foo)?(bar)?(baz)?/', $s, $matches, PREG_UNMATCHED_AS_NULL)) { - assertType("array{0: string, 1?: ''|'foo', 2?: ''|'bar', 3?: 'baz'}", $matches); - } - assertType("array{}|array{0: string, 1?: ''|'foo', 2?: ''|'bar', 3?: 'baz'}", $matches); -} - -// see https://3v4l.org/VeDob#veol -function unmatchedAsNullWithOptionalGroup(string $s): void { - if (preg_match('/Price: (£|€)?\d+/', $s, $matches, PREG_UNMATCHED_AS_NULL)) { - assertType("array{0: string, 1?: '£'|'€'}", $matches); - } else { - assertType('array{}', $matches); - } - assertType("array{}|array{0: string, 1?: '£'|'€'}", $matches); -} diff --git a/tests/PHPStan/Analyser/nsrt/bug-11311.php b/tests/PHPStan/Analyser/nsrt/bug-11311.php index 0d2eaec66d..a30f261fae 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-11311.php +++ b/tests/PHPStan/Analyser/nsrt/bug-11311.php @@ -1,4 +1,4 @@ -= 7.4 +', $value); } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-1233.php b/tests/PHPStan/Analyser/nsrt/bug-1233.php index 7d70679585..17267e0001 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-1233.php +++ b/tests/PHPStan/Analyser/nsrt/bug-1233.php @@ -10,18 +10,18 @@ public function toArray($value): array { assertType('mixed', $value); if (is_array($value)) { - assertType('array', $value); + assertType('array', $value); return $value; } - assertType('mixed~array', $value); + assertType('mixed~array', $value); if (is_iterable($value)) { assertType('Traversable', $value); return iterator_to_array($value); } - assertType('mixed~array', $value); + assertType('mixed~array', $value); throw new \LogicException(); } diff --git a/tests/PHPStan/Analyser/nsrt/bug-2112.php b/tests/PHPStan/Analyser/nsrt/bug-2112.php index a7d33d1538..65634c415b 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-2112.php +++ b/tests/PHPStan/Analyser/nsrt/bug-2112.php @@ -19,7 +19,7 @@ public function doBar(): void $foos[0] = null; assertType('null', $foos[0]); - assertType('hasOffsetValue(0, null)&non-empty-array', $foos); + assertType('non-empty-array&hasOffsetValue(0, null)', $foos); } /** @return self[] */ diff --git a/tests/PHPStan/Analyser/nsrt/bug-2600-php-version-scope.php b/tests/PHPStan/Analyser/nsrt/bug-2600-php-version-scope.php new file mode 100644 index 0000000000..bf13358857 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-2600-php-version-scope.php @@ -0,0 +1,26 @@ + 7.4 + +namespace Bug2600PhpVersionScope; + +use function PHPStan\Testing\assertType; + +if (PHP_VERSION_ID >= 80000) { + class Foo8 { + /** + * @param mixed $x + */ + public function doBaz(...$x) { + assertType('array', $x); + } + } +} else { + class Foo9 { + /** + * @param mixed $x + */ + public function doBaz(...$x) { + assertType('list', $x); + } + } + +} diff --git a/tests/PHPStan/Analyser/nsrt/bug-2911.php b/tests/PHPStan/Analyser/nsrt/bug-2911.php index 1d75efdcbe..3cfbd308f1 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-2911.php +++ b/tests/PHPStan/Analyser/nsrt/bug-2911.php @@ -134,6 +134,6 @@ private function getResultSettings(array $settings): array function foo(array $array): void { $array['bar'] = 'string'; - assertType("hasOffsetValue('bar', 'string')&non-empty-array", $array); + assertType("non-empty-array&hasOffsetValue('bar', 'string')", $array); } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-3276.php b/tests/PHPStan/Analyser/nsrt/bug-3276.php index ece368c9b1..53faad441b 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-3276.php +++ b/tests/PHPStan/Analyser/nsrt/bug-3276.php @@ -1,4 +1,4 @@ -= 7.4 +', $var); } } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-4099.php b/tests/PHPStan/Analyser/nsrt/bug-4099.php index 0a8d1b4b48..5e5eb30ca2 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4099.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4099.php @@ -22,20 +22,20 @@ function arrayHint(array $arr): void throw new \Exception('no key "key" found.'); } assertType('array{key: array{inner: mixed}}', $arr); - assertNativeType('array&hasOffset(\'key\')', $arr); + assertNativeType('non-empty-array&hasOffset(\'key\')', $arr); assertType('array{inner: mixed}', $arr['key']); assertNativeType('mixed', $arr['key']); if (!array_key_exists('inner', $arr['key'])) { assertType('*NEVER*', $arr); - assertNativeType('array&hasOffset(\'key\')', $arr); + assertNativeType('non-empty-array&hasOffset(\'key\')', $arr); assertType('*NEVER*', $arr['key']); assertNativeType("mixed~hasOffset('inner')", $arr['key']); throw new \Exception('need key.inner'); } assertType('array{key: array{inner: mixed}}', $arr); - assertNativeType('array&hasOffset(\'key\')', $arr); + assertNativeType('non-empty-array&hasOffset(\'key\')', $arr); } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-4117.php b/tests/PHPStan/Analyser/nsrt/bug-4117.php index f1f2f60f40..14732b77b6 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4117.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4117.php @@ -34,7 +34,7 @@ public function broken(int $key) if ($item) { assertType("T of mixed~(0|0.0|''|'0'|array{}|false|null) (class Bug4117Types\GenericList, argument)", $item); } else { - assertType("(array{}&T of mixed~null (class Bug4117Types\GenericList, argument))|(0.0&T of mixed~null (class Bug4117Types\GenericList, argument))|(0&T of mixed~null (class Bug4117Types\GenericList, argument))|(''&T of mixed~null (class Bug4117Types\GenericList, argument))|('0'&T of mixed~null (class Bug4117Types\GenericList, argument))|(T of mixed~null (class Bug4117Types\GenericList, argument)&false)|null", $item); + assertType("(T of mixed~null (class Bug4117Types\GenericList, argument)&false)|(0.0&T of mixed~null (class Bug4117Types\GenericList, argument))|(0&T of mixed~null (class Bug4117Types\GenericList, argument))|(list{}&T of mixed~null (class Bug4117Types\GenericList, argument))|(''&T of mixed~null (class Bug4117Types\GenericList, argument))|('0'&T of mixed~null (class Bug4117Types\GenericList, argument))|null", $item); } assertType('T of mixed~null (class Bug4117Types\GenericList, argument)|null', $item); diff --git a/tests/PHPStan/Analyser/nsrt/bug-4188.php b/tests/PHPStan/Analyser/nsrt/bug-4188.php index 3a7c514215..a34cca26a4 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4188.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4188.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 +', array_keys($meters)); - assertType('non-empty-list', array_values($meters)); + assertType('non-empty-list', array_values($meters)); }; diff --git a/tests/PHPStan/Analyser/nsrt/bug-4434.php b/tests/PHPStan/Analyser/nsrt/bug-4434.php index a1f3bea048..7b48df20fd 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4434.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4434.php @@ -10,14 +10,14 @@ class HelloWorld public function testSendEmailToLog(): void { foreach ([1] as $emailFile) { - assertType('int<5, max>', PHP_MAJOR_VERSION); - assertType('int<5, max>', \PHP_MAJOR_VERSION); + assertType('int<5, 8>', PHP_MAJOR_VERSION); + assertType('int<5, 8>', \PHP_MAJOR_VERSION); if (PHP_MAJOR_VERSION === 7) { assertType('7', PHP_MAJOR_VERSION); assertType('7', \PHP_MAJOR_VERSION); } else { - assertType('int<5, 6>|int<8, max>', PHP_MAJOR_VERSION); - assertType('int<5, 6>|int<8, max>', \PHP_MAJOR_VERSION); + assertType('8|int<5, 6>', PHP_MAJOR_VERSION); + assertType('8|int<5, 6>', \PHP_MAJOR_VERSION); } } } @@ -28,14 +28,14 @@ class HelloWorld2 public function testSendEmailToLog(): void { foreach ([1] as $emailFile) { - assertType('int<5, max>', PHP_MAJOR_VERSION); - assertType('int<5, max>', \PHP_MAJOR_VERSION); + assertType('int<5, 8>', PHP_MAJOR_VERSION); + assertType('int<5, 8>', \PHP_MAJOR_VERSION); if (PHP_MAJOR_VERSION === 100) { - assertType('100', PHP_MAJOR_VERSION); - assertType('100', \PHP_MAJOR_VERSION); + assertType('*NEVER*', PHP_MAJOR_VERSION); + assertType('*NEVER*', \PHP_MAJOR_VERSION); } else { - assertType('int<5, 99>|int<101, max>', PHP_MAJOR_VERSION); - assertType('int<5, 99>|int<101, max>', \PHP_MAJOR_VERSION); + assertType('int<5, 8>', PHP_MAJOR_VERSION); + assertType('int<5, 8>', \PHP_MAJOR_VERSION); } } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-4565.php b/tests/PHPStan/Analyser/nsrt/bug-4565.php index af941f8098..55a1c372a5 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4565.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4565.php @@ -10,9 +10,9 @@ function test(array $variables) { if (!empty($variables['button'])) { assertType('non-empty-array', $attributes); $attributes['type'] = 'button'; - assertType("hasOffsetValue('type', 'button')&non-empty-array", $attributes); + assertType("non-empty-array&hasOffsetValue('type', 'button')", $attributes); unset($attributes['href']); - assertType("array&hasOffsetValue('type', 'button')", $attributes); + assertType("non-empty-array&hasOffsetValue('type', 'button')", $attributes); } assertType('array', $attributes); return $attributes; diff --git a/tests/PHPStan/Analyser/nsrt/bug-4708.php b/tests/PHPStan/Analyser/nsrt/bug-4708.php index d6bae28afc..b6f2302722 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-4708.php +++ b/tests/PHPStan/Analyser/nsrt/bug-4708.php @@ -57,7 +57,7 @@ function GetASCConfig() } else { - assertType("array&hasOffsetValue('bsw', string)", $result); + assertType("non-empty-array&hasOffsetValue('bsw', string)", $result); $result['bsw'] = (int) $result['bsw']; assertType("non-empty-array&hasOffsetValue('bsw', int)", $result); } diff --git a/tests/PHPStan/Analyser/nsrt/bug-5168-php7.php b/tests/PHPStan/Analyser/nsrt/bug-5168-php7.php new file mode 100644 index 0000000000..9e981de789 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-5168-php7.php @@ -0,0 +1,12 @@ += 8.0 + +namespace Bug5168Php8; + +use function PHPStan\Testing\assertType; + +function (float $f): void { + define('LARAVEL_START', microtime(true)); + + $comment = 'Calculated in ' . microtime(true) - $f; + assertType('non-falsy-string', $comment); +}; diff --git a/tests/PHPStan/Analyser/nsrt/bug-6228.php b/tests/PHPStan/Analyser/nsrt/bug-6228.php new file mode 100644 index 0000000000..aee5112add --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-6228.php @@ -0,0 +1,16 @@ +|\DOMNode|\DOMNode[]|string|null $node + */ + public function __construct($node) + { + assertType('array|DOMNode|DOMNodeList|string|null', $node); + } +} 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-6329.php b/tests/PHPStan/Analyser/nsrt/bug-6329.php index c6b49e87e4..b31842e05f 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-6329.php +++ b/tests/PHPStan/Analyser/nsrt/bug-6329.php @@ -106,19 +106,19 @@ function true($a): void function nonEmptyArray1($a): void { if (is_array($a) && [] !== $a || null === $a) { - assertType('non-empty-array|null', $a); + assertType('non-empty-array|null', $a); } if ([] !== $a && is_array($a) || null === $a) { - assertType('non-empty-array|null', $a); + assertType('non-empty-array|null', $a); } if (null === $a || is_array($a) && [] !== $a) { - assertType('non-empty-array|null', $a); + assertType('non-empty-array|null', $a); } if (null === $a || [] !== $a && is_array($a)) { - assertType('non-empty-array|null', $a); + assertType('non-empty-array|null', $a); } } @@ -128,11 +128,11 @@ function nonEmptyArray1($a): void function nonEmptyArray2($a): void { if (is_array($a) && count($a) > 0 || null === $a) { - assertType('non-empty-array|null', $a); + assertType('non-empty-array|null', $a); } if (null === $a || is_array($a) && count($a) > 0) { - assertType('non-empty-array|null', $a); + assertType('non-empty-array|null', $a); } } @@ -155,7 +155,7 @@ function inverse($a, $b, $c): void if (null !== $c && (!is_array($c) || count($c) <= 0)) { } else { - assertType('non-empty-array|null', $c); + assertType('non-empty-array|null', $c); } } diff --git a/tests/PHPStan/Analyser/nsrt/bug-6859.php b/tests/PHPStan/Analyser/nsrt/bug-6859.php index f12e61342f..56cd257c5e 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-6859.php +++ b/tests/PHPStan/Analyser/nsrt/bug-6859.php @@ -1,4 +1,4 @@ -= 7.4 +', array_values($body)); + assertType('non-empty-list', array_values($body)); } } } 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-7144-composer-integration.php b/tests/PHPStan/Analyser/nsrt/bug-7144-composer-integration.php index 057067411c..c60d776d38 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7144-composer-integration.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7144-composer-integration.php @@ -32,14 +32,14 @@ public function test3(array $options): void $curlHandle = curl_init(); foreach (self::$options as $type => $curlOptions) { foreach ($curlOptions as $name => $curlOption) { - \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); + \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); if (isset($options[$type][$name])) { - \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); + \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); if ($type === 'ssl' && $name === 'verify_peer_name') { - \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); + \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); curl_setopt($curlHandle, $curlOption, $options[$type][$name] === true ? 2 : $options[$type][$name]); } else { - \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); + \PHPStan\Testing\assertType('array{http: array{header: array, proxy?: string, request_fulluri: bool}, ssl?: array}', $options); curl_setopt($curlHandle, $curlOption, $options[$type][$name]); } } 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-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-7805.php b/tests/PHPStan/Analyser/nsrt/bug-7805.php index 859b504e50..ec9464ebd3 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7805.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7805.php @@ -14,7 +14,7 @@ function foo(array $params) assertNativeType('array', $params); if (array_key_exists('help', $params)) { assertType('array{help: null}', $params); - assertNativeType("array&hasOffset('help')", $params); + assertNativeType("non-empty-array&hasOffset('help')", $params); unset($params['help']); assertType('array{}', $params); diff --git a/tests/PHPStan/Analyser/nsrt/bug-7915.php b/tests/PHPStan/Analyser/nsrt/bug-7915.php index 1dee1a63d5..a2e63375a7 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-7915.php +++ b/tests/PHPStan/Analyser/nsrt/bug-7915.php @@ -63,7 +63,7 @@ public function setConfigMimicConditionalParamType($name, $value): void function to_utf8($data, bool $isArray = false) { if ($isArray) { - assertType('array', $data); + assertType('array', $data); if (is_array($data)) { // always true foreach ($data as $k => $value) { $data[$k] = to_utf8($value, is_array($value)); 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-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/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-9662.php b/tests/PHPStan/Analyser/nsrt/bug-9662.php index 4da94355c7..d88555a863 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9662.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9662.php @@ -11,74 +11,74 @@ */ function doFoo(string $s, $a, $strings, $mixed) { if (in_array('foo', $a, true)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array('foo', $a, false)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array('foo', $a)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array('0', $a)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array('1', $a)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array(true, $a)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array(false, $a)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array($s, $a, true)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array($s, $a, false)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array($s, $a)) { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } else { - assertType("array", $a); + assertType("array", $a); } - assertType('array', $a); + assertType('array', $a); if (in_array($mixed, $strings, true)) { assertType('non-empty-array', $strings); diff --git a/tests/PHPStan/Analyser/nsrt/bug-9734.php b/tests/PHPStan/Analyser/nsrt/bug-9734.php index ce75fa7197..1628ad6859 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9734.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9734.php @@ -15,9 +15,9 @@ class Foo public function doFoo(array $a): void { if (array_is_list($a)) { - assertType('list', $a); + assertType('list', $a); } else { - assertType('array', $a); // could be non-empty-array + assertType('array', $a); // could be non-empty-array } } @@ -38,9 +38,9 @@ public function doFoo2(): void public function doFoo3(array $a): void { if (array_is_list($a)) { - assertType('non-empty-list', $a); + assertType('non-empty-list', $a); } else { - assertType('non-empty-array', $a); + assertType('non-empty-array', $a); } } 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/bug-9985.php b/tests/PHPStan/Analyser/nsrt/bug-9985.php index edbfebffc5..09a7ad92ea 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9985.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9985.php @@ -20,6 +20,6 @@ function (): void { assertType('array{}|array{a?: true, b: true}|array{a?: true, c?: true}', $warnings); if (!empty($warnings)) { - assertType('array{a?: true, b: true}|(array{a?: true, c?: true}&non-empty-array)', $warnings); + assertType('array{a?: true, b: true}|non-empty-array{a?: true, c?: true}', $warnings); } }; diff --git a/tests/PHPStan/Analyser/nsrt/callable-in-union.php b/tests/PHPStan/Analyser/nsrt/callable-in-union.php index 24db62b428..724ce9cafa 100644 --- a/tests/PHPStan/Analyser/nsrt/callable-in-union.php +++ b/tests/PHPStan/Analyser/nsrt/callable-in-union.php @@ -1,4 +1,4 @@ -= 7.4 += 8.0 namespace ClassImplements; diff --git a/tests/PHPStan/Analyser/nsrt/composer-array-bug.php b/tests/PHPStan/Analyser/nsrt/composer-array-bug.php index fbbcff38a8..354577f098 100644 --- a/tests/PHPStan/Analyser/nsrt/composer-array-bug.php +++ b/tests/PHPStan/Analyser/nsrt/composer-array-bug.php @@ -44,14 +44,14 @@ public function doFoo(): void } } - assertType("array&hasOffsetValue('authors', mixed)", $this->config); + assertType("non-empty-array&hasOffsetValue('authors', mixed)", $this->config); assertType("mixed", $this->config['authors']); if (empty($this->config['authors'])) { unset($this->config['authors']); assertType("array", $this->config); } else { - assertType("array&hasOffsetValue('authors', mixed~(0|0.0|''|'0'|array{}|false|null))", $this->config); + assertType("non-empty-array&hasOffsetValue('authors', mixed~(0|0.0|''|'0'|array{}|false|null))", $this->config); } assertType('array', $this->config); diff --git a/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php b/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php index 55335c6e2e..596e97634a 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; @@ -89,5 +89,5 @@ function invariant(bool $condition, string $message): void function (mixed $value) { invariant(is_array($value), 'must be array'); - assertType('array', $value); + assertType('array', $value); }; diff --git a/tests/PHPStan/Analyser/nsrt/conditional-vars.php b/tests/PHPStan/Analyser/nsrt/conditional-vars.php index 6d86c88014..e76b112f4d 100644 --- a/tests/PHPStan/Analyser/nsrt/conditional-vars.php +++ b/tests/PHPStan/Analyser/nsrt/conditional-vars.php @@ -12,7 +12,7 @@ public function conditionalVarInTernary(array $innerHits): void if (array_key_exists('nearest_premise', $innerHits) || array_key_exists('matching_premises', $innerHits)) { assertType('array', $innerHits); $x = array_key_exists('nearest_premise', $innerHits) - ? assertType("array&hasOffset('nearest_premise')", $innerHits) + ? assertType("non-empty-array&hasOffset('nearest_premise')", $innerHits) : assertType('array', $innerHits); assertType('array', $innerHits); @@ -25,7 +25,7 @@ public function conditionalVarInIf(array $innerHits): void if (array_key_exists('nearest_premise', $innerHits) || array_key_exists('matching_premises', $innerHits)) { assertType('array', $innerHits); if (array_key_exists('nearest_premise', $innerHits)) { - assertType("array&hasOffset('nearest_premise')", $innerHits); + assertType("non-empty-array&hasOffset('nearest_premise')", $innerHits); } else { assertType('array', $innerHits); } diff --git a/tests/PHPStan/Analyser/nsrt/constant-array-optional-set.php b/tests/PHPStan/Analyser/nsrt/constant-array-optional-set.php index 6faaa574c1..fe3512a45b 100644 --- a/tests/PHPStan/Analyser/nsrt/constant-array-optional-set.php +++ b/tests/PHPStan/Analyser/nsrt/constant-array-optional-set.php @@ -60,13 +60,13 @@ class Bar */ public function doFoo($nextAutoIndexes) { - assertType('non-empty-list|int', $nextAutoIndexes); + assertType('int|non-empty-list', $nextAutoIndexes); if (is_int($nextAutoIndexes)) { assertType('int', $nextAutoIndexes); } else { assertType('non-empty-list', $nextAutoIndexes); } - assertType('non-empty-list|int', $nextAutoIndexes); + assertType('int|non-empty-list', $nextAutoIndexes); } /** @@ -75,7 +75,7 @@ public function doFoo($nextAutoIndexes) */ public function doBar($nextAutoIndexes) { - assertType('non-empty-list|int', $nextAutoIndexes); + assertType('int|non-empty-list', $nextAutoIndexes); if (is_int($nextAutoIndexes)) { $nextAutoIndexes = [$nextAutoIndexes]; assertType('array{int}', $nextAutoIndexes); diff --git a/tests/PHPStan/Analyser/nsrt/count-chars-7.4.php b/tests/PHPStan/Analyser/nsrt/count-chars-7.4.php new file mode 100644 index 0000000000..76e0bea581 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/count-chars-7.4.php @@ -0,0 +1,22 @@ +|false', count_chars(self::ABC)); + assertType('array|false', count_chars(self::ABC, 0)); + assertType('array|false', count_chars(self::ABC, 1)); + assertType('array|false', count_chars(self::ABC, 2)); + + assertType('string|false', count_chars(self::ABC, 3)); + assertType('string|false', count_chars(self::ABC, 4)); + + assertType('string|false', count_chars(self::ABC, -1)); + assertType('string|false', count_chars(self::ABC, 5)); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/count-chars-8.0.php b/tests/PHPStan/Analyser/nsrt/count-chars-8.0.php new file mode 100644 index 0000000000..6e0af08f03 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/count-chars-8.0.php @@ -0,0 +1,22 @@ += 8.0 + +namespace CountChars; + +use function PHPStan\Testing\assertType; + +class Y { + const ABC = 'abcdef'; + + function doFoo(): void { + assertType('array', count_chars(self::ABC)); + assertType('array', count_chars(self::ABC, 0)); + assertType('array', count_chars(self::ABC, 1)); + assertType('array', count_chars(self::ABC, 2)); + + assertType('string', count_chars(self::ABC, 3)); + assertType('string', count_chars(self::ABC, 4)); + + assertType('string', count_chars(self::ABC, -1)); + assertType('string', count_chars(self::ABC, 5)); + } +} diff --git a/tests/PHPStan/Analyser/nsrt/count-maybe.php b/tests/PHPStan/Analyser/nsrt/count-maybe.php index 255c936d22..4be30d9f49 100644 --- a/tests/PHPStan/Analyser/nsrt/count-maybe.php +++ b/tests/PHPStan/Analyser/nsrt/count-maybe.php @@ -86,9 +86,9 @@ function doFoo4($maybeCountable, int $mode): void if (count($maybeCountable, $mode) > 0) { assertType('non-empty-list', $maybeCountable); } else { - assertType('list|float', $maybeCountable); + assertType('float|list', $maybeCountable); } - assertType('list|float', $maybeCountable); + assertType('float|list', $maybeCountable); } /** @@ -100,9 +100,9 @@ function doFoo5($maybeCountable, $maybeMode): void if (count($maybeCountable, $maybeMode) > 0) { assertType('non-empty-list', $maybeCountable); } else { - assertType('list|float', $maybeCountable); + assertType('float|list', $maybeCountable); } - assertType('list|float', $maybeCountable); + assertType('float|list', $maybeCountable); } /** @@ -113,9 +113,9 @@ function doFoo6($maybeCountable, float $invalidMode): void if (count($maybeCountable, $invalidMode) > 0) { assertType('non-empty-list', $maybeCountable); } else { - assertType('list|float', $maybeCountable); + assertType('float|list', $maybeCountable); } - assertType('list|float', $maybeCountable); + assertType('float|list', $maybeCountable); } /** @@ -124,11 +124,11 @@ function doFoo6($maybeCountable, float $invalidMode): void function doFoo7($maybeCountable, int $mode): void { if (count($maybeCountable, $mode) > 0) { - assertType('non-empty-list|Countable', $maybeCountable); + assertType('Countable|non-empty-list', $maybeCountable); } else { - assertType('list|Countable|float', $maybeCountable); + assertType('Countable|float|list', $maybeCountable); } - assertType('list|Countable|float', $maybeCountable); + assertType('Countable|float|list', $maybeCountable); } /** @@ -138,11 +138,11 @@ function doFoo7($maybeCountable, int $mode): void function doFoo8($maybeCountable, $maybeMode): void { if (count($maybeCountable, $maybeMode) > 0) { - assertType('non-empty-list|Countable', $maybeCountable); + assertType('Countable|non-empty-list', $maybeCountable); } else { - assertType('list|Countable|float', $maybeCountable); + assertType('Countable|float|list', $maybeCountable); } - assertType('list|Countable|float', $maybeCountable); + assertType('Countable|float|list', $maybeCountable); } /** @@ -151,11 +151,11 @@ function doFoo8($maybeCountable, $maybeMode): void function doFoo9($maybeCountable, float $invalidMode): void { if (count($maybeCountable, $invalidMode) > 0) { - assertType('non-empty-list|Countable', $maybeCountable); + assertType('Countable|non-empty-list', $maybeCountable); } else { - assertType('list|Countable|float', $maybeCountable); + assertType('Countable|float|list', $maybeCountable); } - assertType('list|Countable|float', $maybeCountable); + assertType('Countable|float|list', $maybeCountable); } function doFooBar1(array $countable, int $mode): void diff --git a/tests/PHPStan/Analyser/nsrt/ctype-digit.php b/tests/PHPStan/Analyser/nsrt/ctype-digit.php index 6d013f52e4..ed4704daa7 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-in-array.php b/tests/PHPStan/Analyser/nsrt/enum-in-array.php new file mode 100644 index 0000000000..ca34261bc8 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/enum-in-array.php @@ -0,0 +1,187 @@ += 8.1 + +use function PHPStan\Testing\assertType; + +enum MyEnum: string +{ + + case A = 'a'; + case B = 'b'; + case C = 'c'; + + const SET_AB = [self::A, self::B]; + const SET_C = [self::C]; + const SET_ABC = [self::A, self::B, self::C]; + + public function test1(): void + { + foreach (self::cases() as $enum) { + if (in_array($enum, MyEnum::SET_AB, true)) { + assertType('MyEnum::A|MyEnum::B', $enum); + } elseif (in_array($enum, MyEnum::SET_C, true)) { + assertType('MyEnum::C', $enum); + } else { + assertType('*NEVER*', $enum); + } + } + } + + public function test2(): void + { + foreach (self::cases() as $enum) { + if (in_array($enum, MyEnum::SET_ABC, true)) { + assertType('MyEnum::A|MyEnum::B|MyEnum::C', $enum); + } else { + assertType('*NEVER*', $enum); + } + } + } + + public function test3(): void + { + foreach (self::cases() as $enum) { + if (in_array($enum, MyEnum::SET_C, true)) { + assertType('MyEnum::C', $enum); + } else { + assertType('MyEnum::A|MyEnum::B', $enum); + } + } + } + + public function test4(): void + { + foreach ([MyEnum::C] as $enum) { + if (in_array($enum, MyEnum::SET_C, true)) { + assertType('MyEnum::C', $enum); + } else { + assertType('*NEVER*', $enum); + } + } + } + + public function testNegative1(): void + { + foreach (self::cases() as $enum) { + if (!in_array($enum, MyEnum::SET_AB, true)) { + assertType('MyEnum::C', $enum); + } else { + assertType('MyEnum::A|MyEnum::B', $enum); + } + } + } + + public function testNegative2(): void + { + foreach (self::cases() as $enum) { + if (!in_array($enum, MyEnum::SET_AB, true)) { + assertType('MyEnum::C', $enum); + } elseif (!in_array($enum, MyEnum::SET_AB, true)) { + assertType('*NEVER*', $enum); + } + } + } + + public function testNegative3(): void + { + foreach ([MyEnum::C] as $enum) { + if (!in_array($enum, MyEnum::SET_C, true)) { + assertType('*NEVER*', $enum); + } + } + } + + /** + * @param array $array + */ + public function testNegative4(MyEnum $enum, array $array): void + { + if (!in_array($enum, $array, true)) { + assertType('MyEnum', $enum); + assertType('array', $array); + } else { + assertType('MyEnum', $enum); + assertType('non-empty-array', $array); + } + } + +} + +class InArrayEnum +{ + + /** @param list $list */ + public function testPositive(MyEnum $enum, array $list): void + { + if (in_array($enum, $list, true)) { + return; + } + + assertType(MyEnum::class, $enum); + assertType('list', $list); + } + + /** @param list $list */ + public function testNegative(MyEnum $enum, array $list): void + { + if (!in_array($enum, $list, true)) { + return; + } + + assertType(MyEnum::class, $enum); + assertType('non-empty-list', $list); + } + +} + + +class InArrayOtherFiniteType { + + const SET_AB = ['a', 'b']; + const SET_C = ['c']; + const SET_ABC = ['a', 'b', 'c']; + + public function test1(): void + { + foreach (['a', 'b', 'c'] as $item) { + if (in_array($item, self::SET_AB, true)) { + assertType("'a'|'b'", $item); + } elseif (in_array($item, self::SET_C, true)) { + assertType("'c'", $item); + } else { + assertType('*NEVER*', $item); + } + } + } + + public function test2(): void + { + foreach (['a', 'b', 'c'] as $item) { + if (in_array($item, self::SET_ABC, true)) { + assertType("'a'|'b'|'c'", $item); + } else { + assertType('*NEVER*', $item); + } + } + } + + public function test3(): void + { + foreach (['a', 'b', 'c'] as $item) { + if (in_array($item, self::SET_C, true)) { + assertType("'c'", $item); + } else { + assertType("'a'|'b'", $item); + } + } + } + public function test4(): void + { + foreach (['c'] as $item) { + if (in_array($item, self::SET_C, true)) { + assertType("'c'", $item); + } else { + assertType('*NEVER*', $item); + } + } + } +} 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/falsey-isset-certainty.php b/tests/PHPStan/Analyser/nsrt/falsey-isset-certainty.php index 1fbb9547ac..484d0363e3 100644 --- a/tests/PHPStan/Analyser/nsrt/falsey-isset-certainty.php +++ b/tests/PHPStan/Analyser/nsrt/falsey-isset-certainty.php @@ -1,4 +1,4 @@ -= 8.0 namespace FalseyIssetCertainty; 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/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/fgetcsv-php7.php b/tests/PHPStan/Analyser/nsrt/fgetcsv-php7.php new file mode 100644 index 0000000000..8a38465040 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/fgetcsv-php7.php @@ -0,0 +1,12 @@ +|false|null', fgetcsv($resource)); // nullable when invalid argument is given (https://3v4l.org/4WmR5#v7.4.30) +} diff --git a/tests/PHPStan/Analyser/nsrt/fgetcsv-php8.php b/tests/PHPStan/Analyser/nsrt/fgetcsv-php8.php new file mode 100644 index 0000000000..fccf29931c --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/fgetcsv-php8.php @@ -0,0 +1,12 @@ += 8.0 + +declare(strict_types = 1); + +namespace TestFGetCsvPhp8; + +use function PHPStan\Testing\assertType; + +function test($resource): void +{ + assertType('list|false', fgetcsv($resource)); +} diff --git a/tests/PHPStan/Analyser/nsrt/filesystem-functions.php b/tests/PHPStan/Analyser/nsrt/filesystem-functions.php index 99dbd676f1..fc7614c63a 100644 --- a/tests/PHPStan/Analyser/nsrt/filesystem-functions.php +++ b/tests/PHPStan/Analyser/nsrt/filesystem-functions.php @@ -1,4 +1,4 @@ -= 7.4 += 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..1151d370c1 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; @@ -85,11 +85,11 @@ function mixedInput(mixed $input): void ], false)); // filter flag with add_empty=default - assertType('array', filter_var_array($input, FILTER_VALIDATE_INT)); + assertType('array', filter_var_array($input, FILTER_VALIDATE_INT)); // filter flag with add_empty=true - assertType('array', filter_var_array($input, FILTER_VALIDATE_INT, true)); + assertType('array', filter_var_array($input, FILTER_VALIDATE_INT, true)); // filter flag with add_empty=false - assertType('array', filter_var_array($input, FILTER_VALIDATE_INT, false)); + assertType('array', filter_var_array($input, FILTER_VALIDATE_INT, false)); $filter = [ 'filter' => FILTER_VALIDATE_INT, diff --git a/tests/PHPStan/Analyser/nsrt/filter-var-dynamic-return-type-extension-regression.php b/tests/PHPStan/Analyser/nsrt/filter-var-dynamic-return-type-extension-regression.php index 69fc99f613..172fa40b4f 100644 --- a/tests/PHPStan/Analyser/nsrt/filter-var-dynamic-return-type-extension-regression.php +++ b/tests/PHPStan/Analyser/nsrt/filter-var-dynamic-return-type-extension-regression.php @@ -46,9 +46,9 @@ public function test() } assertType('array{default?: PHPStan\Type\Type, range: PHPStan\Type\Type}', $otherTypes); } - assertType('array{default?: PHPStan\Type\Type, range?: PHPStan\Type\Type}&non-empty-array', $otherTypes); + assertType('non-empty-array{default?: PHPStan\Type\Type, range?: PHPStan\Type\Type}', $otherTypes); if ($exactType !== null) { - assertType('array{default?: PHPStan\Type\Type, range?: PHPStan\Type\Type}&non-empty-array', $otherTypes); + assertType('non-empty-array{default?: PHPStan\Type\Type, range?: PHPStan\Type\Type}', $otherTypes); unset($otherTypes['default']); assertType('array{range?: PHPStan\Type\Type}', $otherTypes); } 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/generics.php b/tests/PHPStan/Analyser/nsrt/generics.php index 80f10030e8..8aa8fae879 100644 --- a/tests/PHPStan/Analyser/nsrt/generics.php +++ b/tests/PHPStan/Analyser/nsrt/generics.php @@ -163,8 +163,8 @@ function testF($arrayOfInt, $callableOrNull) return $a; })); assertType('array', f($arrayOfInt, $callableOrNull)); - assertType('array', f($arrayOfInt, null)); - assertType('array', f($arrayOfInt, '')); + assertType('array', f($arrayOfInt, null)); + assertType('array', f($arrayOfInt, '')); } /** diff --git a/tests/PHPStan/Analyser/nsrt/globals.php b/tests/PHPStan/Analyser/nsrt/globals.php index 7b7b7b8a01..da2ae35787 100644 --- a/tests/PHPStan/Analyser/nsrt/globals.php +++ b/tests/PHPStan/Analyser/nsrt/globals.php @@ -1,11 +1,11 @@ ', $GLOBALS); +\PHPStan\Testing\assertType('array', $_SERVER); +\PHPStan\Testing\assertType('array', $_GET); +\PHPStan\Testing\assertType('array', $_POST); +\PHPStan\Testing\assertType('array', $_FILES); +\PHPStan\Testing\assertType('array', $_COOKIE); +\PHPStan\Testing\assertType('array', $_SESSION); +\PHPStan\Testing\assertType('array', $_REQUEST); +\PHPStan\Testing\assertType('array', $_ENV); diff --git a/tests/PHPStan/Analyser/nsrt/has-offset-type-bug.php b/tests/PHPStan/Analyser/nsrt/has-offset-type-bug.php index 8b470ba316..eacfb06af6 100644 --- a/tests/PHPStan/Analyser/nsrt/has-offset-type-bug.php +++ b/tests/PHPStan/Analyser/nsrt/has-offset-type-bug.php @@ -44,14 +44,14 @@ public function doFoo(array $errorMessages): void */ public function doBar(array $result): void { - assertType('array', $result); + assertType('array', $result); assert($result['totals']['file_errors'] === 3); - assertType("array", $result); + assertType("array", $result); assertType("mixed", $result['totals']); assertType('3', $result['totals']['file_errors']); assertType('mixed', $result['totals']['errors']); assert($result['totals']['errors'] === 0); - assertType("array", $result); + assertType("array", $result); assertType("mixed", $result['totals']); assertType('3', $result['totals']['file_errors']); assertType('0', $result['totals']['errors']); @@ -65,7 +65,7 @@ public function testIsset($range): void { assertType("array{}|array{min?: bool|float|int|string|null, max?: bool|float|int|string|null}", $range); if (isset($range['min']) || isset($range['max'])) { - assertType("array{min?: bool|float|int|string|null, max?: bool|float|int|string|null}&non-empty-array", $range); + assertType("non-empty-array{min?: bool|float|int|string|null, max?: bool|float|int|string|null}", $range); } else { assertType("array{}|array{min?: bool|float|int|string|null, max?: bool|float|int|string|null}", $range); } @@ -144,7 +144,7 @@ public function doBar(array $a, int $i) public function doFoo2(array $a) { if (is_int($a['a'])) { - assertType("array&hasOffsetValue('a', *NEVER*)", $a); + assertType("non-empty-array&hasOffsetValue('a', *NEVER*)", $a); } } 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/Analyser/nsrt/isset-coalesce-empty-type.php b/tests/PHPStan/Analyser/nsrt/isset-coalesce-empty-type.php index 8ffb1ddb89..ad81a1e6ac 100644 --- a/tests/PHPStan/Analyser/nsrt/isset-coalesce-empty-type.php +++ b/tests/PHPStan/Analyser/nsrt/isset-coalesce-empty-type.php @@ -1,4 +1,4 @@ -= 7.4 += 8.0 namespace KeyExists; diff --git a/tests/PHPStan/Analyser/nsrt/list-count.php b/tests/PHPStan/Analyser/nsrt/list-count.php index caf0a17c87..c51ea31efc 100644 --- a/tests/PHPStan/Analyser/nsrt/list-count.php +++ b/tests/PHPStan/Analyser/nsrt/list-count.php @@ -351,25 +351,25 @@ protected function testOptionalKeysInUnionListWithIntRange($row, $twoOrThree, $t if (count($row) >= $twoOrThree) { assertType('array{0: int, 1: string|null, 2?: int|null}', $row); } else { - assertType('(array{0: int, 1?: string|null, 2?: int|null, 3?: float|null}&list)|array{string}', $row); + assertType('array{string}|list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row); } if (count($row) >= $tenOrEleven) { assertType('*NEVER*', $row); } else { - assertType('(array{0: int, 1?: string|null, 2?: int|null, 3?: float|null}&list)|array{string}', $row); + assertType('array{string}|list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row); } if (count($row) >= $twoOrMore) { - assertType('array{0: int, 1: string|null, 2?: int|null, 3?: float|null}&list', $row); + assertType('list{0: int, 1: string|null, 2?: int|null, 3?: float|null}', $row); } else { - assertType('(array{0: int, 1?: string|null, 2?: int|null, 3?: float|null}&list)|array{string}', $row); + assertType('array{string}|list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row); } if (count($row) >= $maxThree) { - assertType('(array{0: int, 1?: string|null, 2?: int|null, 3?: float|null}&list)|array{string}', $row); + assertType('array{string}|list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row); } else { - assertType('array{0: int, 1?: string|null, 2?: int|null, 3?: float|null}&list', $row); + assertType('list{0: int, 1?: string|null, 2?: int|null, 3?: float|null}', $row); } } diff --git a/tests/PHPStan/Analyser/nsrt/list-type.php b/tests/PHPStan/Analyser/nsrt/list-type.php index 40d94efff3..63b9e0037c 100644 --- a/tests/PHPStan/Analyser/nsrt/list-type.php +++ b/tests/PHPStan/Analyser/nsrt/list-type.php @@ -9,19 +9,19 @@ class Foo /** @param list $list */ public function directAssertion($list): void { - assertType('list', $list); + assertType('list', $list); } /** @param list $list */ public function directAssertionParamHint(array $list): void { - assertType('list', $list); + assertType('list', $list); } /** @param list $list */ public function directAssertionNullableParamHint(array $list = null): void { - assertType('list|null', $list); + assertType('list|null', $list); } /** @param list<\DateTime> $list */ @@ -37,7 +37,7 @@ public function withoutGenerics(): void $list[] = '1'; $list[] = true; $list[] = new \stdClass(); - assertType('non-empty-list', $list); + assertType('non-empty-list', $list); } @@ -83,17 +83,17 @@ public function withFullListFunctionality(): void // These won't output errors for now but should when list type will be fully implemented /** @var list $list */ $list = []; - assertType('list', $list); + assertType('list', $list); $list[] = '1'; - assertType('non-empty-list', $list); + assertType('non-empty-list', $list); $list[] = '2'; - assertType('non-empty-list', $list); + assertType('non-empty-list', $list); unset($list[0]);//break list behaviour assertType('array, mixed>', $list); /** @var list $list2 */ $list2 = []; - assertType('list', $list2); + assertType('list', $list2); $list2[2] = '1';//Most likely to create a gap in indexes assertType('non-empty-array, mixed>&hasOffsetValue(2, \'1\')', $list2); } diff --git a/tests/PHPStan/Analyser/nsrt/memcache-get.php b/tests/PHPStan/Analyser/nsrt/memcache-get.php index 735e85b545..533e483682 100644 --- a/tests/PHPStan/Analyser/nsrt/memcache-get.php +++ b/tests/PHPStan/Analyser/nsrt/memcache-get.php @@ -10,5 +10,5 @@ function (): void { $memcache = new Memcache(); assertType('mixed', $memcache->get("key1")); - assertType('array|false', $memcache->get(array("key1", "key2", "key3"))); + assertType('array|false', $memcache->get(array("key1", "key2", "key3"))); }; diff --git a/tests/PHPStan/Analyser/nsrt/mixed-subtract.php b/tests/PHPStan/Analyser/nsrt/mixed-subtract.php index 59fa2afa13..c544802655 100644 --- a/tests/PHPStan/Analyser/nsrt/mixed-subtract.php +++ b/tests/PHPStan/Analyser/nsrt/mixed-subtract.php @@ -21,7 +21,7 @@ function subtract(mixed $m, $moreThenFalsy) { assertType('bool', (bool) $m); } if (!is_array($m)) { - assertType('mixed~array', $m); + assertType('mixed~array', $m); assertType('bool', (bool) $m); } @@ -55,7 +55,7 @@ function subtract(mixed $m, $moreThenFalsy) { } if ($m != 0 && !is_array($m) && $m != null && !is_object($m)) { // subtract more types then falsy - assertType("mixed~(0|0.0|''|'0'|array|object|false|null)", $m); + assertType("mixed~(0|0.0|''|'0'|array|object|false|null)", $m); assertType('true', (bool) $m); } } diff --git a/tests/PHPStan/Analyser/nsrt/mixed-to-number.php b/tests/PHPStan/Analyser/nsrt/mixed-to-number.php index 97cc9d0842..fee2d7bed4 100644 --- a/tests/PHPStan/Analyser/nsrt/mixed-to-number.php +++ b/tests/PHPStan/Analyser/nsrt/mixed-to-number.php @@ -35,7 +35,7 @@ function doFoo($mixed, int $i, float $f, $numericS) { } if (!is_array($mixed)) { - assertType('mixed~array', $mixed); + assertType('mixed~array', $mixed); assertType('(float|int)', $mixed + $mixed); } } 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/narrow-cast.php b/tests/PHPStan/Analyser/nsrt/narrow-cast.php index 1da8858473..5687c0b23a 100644 --- a/tests/PHPStan/Analyser/nsrt/narrow-cast.php +++ b/tests/PHPStan/Analyser/nsrt/narrow-cast.php @@ -14,9 +14,9 @@ function doFoo(string $x, array $arr): void { assertType('string', $x); if ((bool) array_search($x, $arr, true)) { - assertType('non-empty-array', $arr); + assertType('non-empty-array', $arr); } else { - assertType('array', $arr); + assertType('array', $arr); } assertType('string', $x); diff --git a/tests/PHPStan/Analyser/nsrt/native-expressions.php b/tests/PHPStan/Analyser/nsrt/native-expressions.php index 72f5a47e7e..abe041686a 100644 --- a/tests/PHPStan/Analyser/nsrt/native-expressions.php +++ b/tests/PHPStan/Analyser/nsrt/native-expressions.php @@ -34,7 +34,7 @@ public function __construct( /** @var non-empty-array */ private array $array ){ - assertType('non-empty-array', $this->array); + assertType('non-empty-array', $this->array); assertNativeType('array', $this->array); if(count($array) === 0){ throw new \InvalidArgumentException(); diff --git a/tests/PHPStan/Analyser/nsrt/native-types.php b/tests/PHPStan/Analyser/nsrt/native-types.php index 3f09d923cb..6f17a60f5d 100644 --- a/tests/PHPStan/Analyser/nsrt/native-types.php +++ b/tests/PHPStan/Analyser/nsrt/native-types.php @@ -1,4 +1,4 @@ -= 7.4 +', $list); + assertType('non-empty-list', $list); assertType('non-empty-array', $arrayOfStrings); assertType('non-empty-list', $listOfStd); assertType('non-empty-list', $listOfStd2); diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string.php b/tests/PHPStan/Analyser/nsrt/non-empty-string.php index cd831db4d8..59d1af3931 100644 --- a/tests/PHPStan/Analyser/nsrt/non-empty-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string.php @@ -8,6 +8,7 @@ use function strtolower; use function strtoupper; use function ucfirst; +use const ENT_SUBSTITUTE; class Foo { @@ -333,9 +334,17 @@ public function doFoo(string $s, string $nonEmpty, string $nonFalsy, int $i, boo assertType('string', ucwords($s)); assertType('non-empty-string', ucwords($nonEmpty)); assertType('string', htmlspecialchars($s)); + assertType('string', htmlspecialchars($s, ENT_SUBSTITUTE)); + assertType('string', htmlspecialchars($s, 0)); assertType('non-empty-string', htmlspecialchars($nonEmpty)); + assertType('non-empty-string', htmlspecialchars($nonEmpty, ENT_SUBSTITUTE)); + assertType('string', htmlspecialchars($nonEmpty, 0)); assertType('string', htmlentities($s)); + assertType('string', htmlentities($s, ENT_SUBSTITUTE)); + assertType('string', htmlentities($s, 0)); assertType('non-empty-string', htmlentities($nonEmpty)); + assertType('non-empty-string', htmlentities($nonEmpty, ENT_SUBSTITUTE)); + assertType('string', htmlentities($nonEmpty, 0)); assertType('string', urlencode($s)); assertType('non-empty-string', urlencode($nonEmpty)); diff --git a/tests/PHPStan/Analyser/nsrt/non-falsy-string.php b/tests/PHPStan/Analyser/nsrt/non-falsy-string.php index c5fd9fc1d8..744bdaf3b5 100644 --- a/tests/PHPStan/Analyser/nsrt/non-falsy-string.php +++ b/tests/PHPStan/Analyser/nsrt/non-falsy-string.php @@ -3,6 +3,7 @@ namespace NonFalseyString; use function PHPStan\Testing\assertType; +use const ENT_SUBSTITUTE; class Foo { /** @@ -95,7 +96,11 @@ function stringFunctions(string $s, $nonFalsey, $arrayOfNonFalsey, $nonEmptyArra assertType('non-falsy-string', ucfirst($nonFalsey)); assertType('non-falsy-string', ucwords($nonFalsey)); assertType('non-falsy-string', htmlspecialchars($nonFalsey)); + assertType('non-falsy-string', htmlspecialchars($nonFalsey, ENT_SUBSTITUTE)); + assertType('string', htmlspecialchars($nonFalsey, 0)); assertType('non-falsy-string', htmlentities($nonFalsey)); + assertType('non-falsy-string', htmlentities($nonFalsey, ENT_SUBSTITUTE)); + assertType('string', htmlentities($nonFalsey, 0)); assertType('non-falsy-string', urlencode($nonFalsey)); assertType('non-falsy-string', urldecode($nonFalsey)); diff --git a/tests/PHPStan/Analyser/nsrt/nullable-closure-parameter.php b/tests/PHPStan/Analyser/nsrt/nullable-closure-parameter.php index 86eb0c1e87..0758feb78c 100644 --- a/tests/PHPStan/Analyser/nsrt/nullable-closure-parameter.php +++ b/tests/PHPStan/Analyser/nsrt/nullable-closure-parameter.php @@ -1,4 +1,4 @@ -= 7.4 += 8.0 namespace OffsetAccess; diff --git a/tests/PHPStan/Analyser/nsrt/param-closure-this.php b/tests/PHPStan/Analyser/nsrt/param-closure-this.php index 1801bbef2b..96f9fb8f15 100644 --- a/tests/PHPStan/Analyser/nsrt/param-closure-this.php +++ b/tests/PHPStan/Analyser/nsrt/param-closure-this.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 +', PHP_MAJOR_VERSION); +assertType('int<5, 8>', PHP_MAJOR_VERSION); assertType('int<0, max>', PHP_MINOR_VERSION); assertType('int<0, max>', PHP_RELEASE_VERSION); -assertType('int<50207, max>', PHP_VERSION_ID); +assertType('int<50207, 80499>', PHP_VERSION_ID); assertType('string', PHP_EXTRA_VERSION); assertType('0|1', PHP_ZTS); assertType('0|1', PHP_DEBUG); diff --git a/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes-php72.php b/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes-php72.php index 2a3f437a81..f7230851e4 100644 --- a/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes-php72.php +++ b/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes-php72.php @@ -8,7 +8,7 @@ function (string $s): void { preg_replace_callback( $s, function ($matches) { - assertType('array', $matches); + assertType('array', $matches); return ''; }, $s diff --git a/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes.php b/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes.php index 36b6a51f1f..57c486638e 100644 --- a/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes.php +++ b/tests/PHPStan/Analyser/nsrt/preg_replace_callback_shapes.php @@ -1,4 +1,4 @@ -= 7.4 + $bd) { if (empty($bd)) { - assertType('array{product_tax?: mixed, shipping_tax?: array, ecotax_tax?: array, wrapping_tax?: array}', $breakdowns); + assertType('array{product_tax?: mixed, shipping_tax?: array, ecotax_tax?: array, wrapping_tax?: array}', $breakdowns); unset($breakdowns[$type]); - assertType('array{product_tax?: mixed, shipping_tax?: array, ecotax_tax?: array, wrapping_tax?: array}', $breakdowns); + assertType('array{product_tax?: mixed, shipping_tax?: array, ecotax_tax?: array, wrapping_tax?: array}', $breakdowns); } } - assertType('array{product_tax?: mixed, shipping_tax?: array, ecotax_tax?: array, wrapping_tax?: array}', $breakdowns); + assertType('array{product_tax?: mixed, shipping_tax?: array, ecotax_tax?: array, wrapping_tax?: array}', $breakdowns); } public function doFoo(): void diff --git a/tests/PHPStan/Analyser/nsrt/reflection-type.php b/tests/PHPStan/Analyser/nsrt/reflection-type.php index a24a91ced6..d390747fe6 100644 --- a/tests/PHPStan/Analyser/nsrt/reflection-type.php +++ b/tests/PHPStan/Analyser/nsrt/reflection-type.php @@ -1,4 +1,4 @@ -= 7.4 +', $arr); - assertNativeType('list', $arr); + assertNativeType('list', $arr); assertType('list>', array_keys($arr)); assertType('list', array_values($arr)); } @@ -23,7 +23,7 @@ public function normalArrays2(array $arr): void /** @var non-empty-array $arr */ shuffle($arr); assertType('non-empty-list', $arr); - assertNativeType('list', $arr); + assertNativeType('list', $arr); assertType('non-empty-list>', array_keys($arr)); assertType('non-empty-list', array_values($arr)); } @@ -33,10 +33,10 @@ public function normalArrays3(array $arr): void /** @var array $arr */ if (array_key_exists('foo', $arr)) { shuffle($arr); - assertType('non-empty-list', $arr); - assertNativeType('non-empty-list', $arr); + assertType('non-empty-list', $arr); + assertNativeType('non-empty-list', $arr); assertType('non-empty-list>', array_keys($arr)); - assertType('non-empty-list', array_values($arr)); + assertType('non-empty-list', array_values($arr)); } } @@ -45,10 +45,10 @@ public function normalArrays4(array $arr): void /** @var array $arr */ if (array_key_exists('foo', $arr) && $arr['foo'] === 'bar') { shuffle($arr); - assertType('non-empty-list', $arr); - assertNativeType('non-empty-list', $arr); + assertType('non-empty-list', $arr); + assertNativeType('non-empty-list', $arr); assertType('non-empty-list>', array_keys($arr)); - assertType('non-empty-list', array_values($arr)); + assertType('non-empty-list', array_values($arr)); } } @@ -66,8 +66,8 @@ public function constantArrays2(array $arr): void { /** @var array{0?: 1, 1?: 2, 2?: 3} $arr */ shuffle($arr); - assertType('array<0|1|2, 1|2|3>&list', $arr); - assertNativeType('list', $arr); + assertType('list<1|2|3>', $arr); + assertNativeType('list', $arr); assertType('list<0|1|2>', array_keys($arr)); assertType('list<1|2|3>', array_values($arr)); } @@ -76,8 +76,8 @@ public function constantArrays3(array $arr): void { $arr = [1, 2, 3]; shuffle($arr); - assertType('non-empty-array<0|1|2, 1|2|3>&list', $arr); - assertNativeType('non-empty-array<0|1|2, 1|2|3>&list', $arr); + assertType('non-empty-list<1|2|3>', $arr); + assertNativeType('non-empty-list<1|2|3>', $arr); assertType('non-empty-list<0|1|2>', array_keys($arr)); assertType('non-empty-list<1|2|3>', array_values($arr)); } @@ -86,8 +86,8 @@ public function constantArrays4(array $arr): void { $arr = ['a' => 1, 'b' => 2, 'c' => 3]; shuffle($arr); - assertType('non-empty-array<0|1|2, 1|2|3>&list', $arr); - assertNativeType('non-empty-array<0|1|2, 1|2|3>&list', $arr); + assertType('non-empty-list<1|2|3>', $arr); + assertNativeType('non-empty-list<1|2|3>', $arr); assertType('non-empty-list<0|1|2>', array_keys($arr)); assertType('non-empty-list<1|2|3>', array_values($arr)); } @@ -96,8 +96,8 @@ public function constantArrays5(array $arr): void { $arr = [0 => 1, 3 => 2, 42 => 3]; shuffle($arr); - assertType('non-empty-array<0|1|2, 1|2|3>&list', $arr); - assertNativeType('non-empty-array<0|1|2, 1|2|3>&list', $arr); + assertType('non-empty-list<1|2|3>', $arr); + assertNativeType('non-empty-list<1|2|3>', $arr); assertType('non-empty-list<0|1|2>', array_keys($arr)); assertType('non-empty-list<1|2|3>', array_values($arr)); } @@ -106,8 +106,8 @@ public function constantArrays6(array $arr): void { /** @var array{foo?: 1, bar: 2, }|array{baz: 3, foobar?: 4} $arr */ shuffle($arr); - assertType('non-empty-array<0|1, 1|2|3|4>&list', $arr); - assertNativeType('list', $arr); + assertType('non-empty-list<1|2|3|4>', $arr); + assertNativeType('list', $arr); assertType('non-empty-list<0|1>', array_keys($arr)); assertType('non-empty-list<1|2|3|4>', array_values($arr)); } @@ -115,10 +115,10 @@ public function constantArrays6(array $arr): void public function mixed($arr): void { shuffle($arr); - assertType('list', $arr); - assertNativeType('list', $arr); + assertType('list', $arr); + assertNativeType('list', $arr); assertType('list>', array_keys($arr)); - assertType('list', array_values($arr)); + assertType('list', array_values($arr)); } public function subtractedArray($arr): void @@ -134,7 +134,7 @@ public function subtractedArray($arr): void assertType('*ERROR*', $arr); assertNativeType('*ERROR*', $arr); assertType('list', array_keys($arr)); - assertType('list', array_values($arr)); + assertType('list', array_values($arr)); } } diff --git a/tests/PHPStan/Analyser/nsrt/sort.php b/tests/PHPStan/Analyser/nsrt/sort.php index e92b006713..93dfe0d147 100644 --- a/tests/PHPStan/Analyser/nsrt/sort.php +++ b/tests/PHPStan/Analyser/nsrt/sort.php @@ -91,17 +91,17 @@ public function normalArray(array $arr): void $arr1 = $arr; sort($arr1); assertType('list', $arr1); - assertNativeType('list', $arr1); + assertNativeType('list', $arr1); $arr2 = $arr; rsort($arr2); assertType('list', $arr2); - assertNativeType('list', $arr2); + assertNativeType('list', $arr2); $arr3 = $arr; usort($arr3, fn(int $a, int $b) => $a <=> $b); assertType('list', $arr3); - assertNativeType('list', $arr3); + assertNativeType('list', $arr3); } public function mixed($arr): void diff --git a/tests/PHPStan/Analyser/data/template-default.php b/tests/PHPStan/Analyser/nsrt/template-default.php similarity index 99% rename from tests/PHPStan/Analyser/data/template-default.php rename to tests/PHPStan/Analyser/nsrt/template-default.php index 979fbc3636..c73ce4ab38 100644 --- a/tests/PHPStan/Analyser/data/template-default.php +++ b/tests/PHPStan/Analyser/nsrt/template-default.php @@ -1,4 +1,4 @@ -= 8.0 namespace TemplateDefault; diff --git a/tests/PHPStan/Analyser/unknown-mixed-type.neon b/tests/PHPStan/Analyser/unknown-mixed-type.neon new file mode 100644 index 0000000000..a9d8e60640 --- /dev/null +++ b/tests/PHPStan/Analyser/unknown-mixed-type.neon @@ -0,0 +1,2 @@ +parameters: + phpVersion: 70400 diff --git a/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php b/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php index a7cb8997d8..e84ac78e28 100644 --- a/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php +++ b/tests/PHPStan/Command/AnalyseApplicationIntegrationTest.php @@ -16,12 +16,10 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Console\Style\SymfonyStyle; -use function file_exists; use function fopen; use function rewind; use function sprintf; use function stream_get_contents; -use function unlink; use const DIRECTORY_SEPARATOR; class AnalyseApplicationIntegrationTest extends PHPStanTestCase @@ -65,8 +63,6 @@ private function runPath(string $path, int $expectedStatusCode): string new \PHPStan\Command\Symfony\SymfonyStyle(new SymfonyStyle($this->createMock(InputInterface::class), $output)), ); - $memoryLimitFile = self::getContainer()->getParameter('memoryLimitFile'); - $relativePathHelper = new FuzzyRelativePathHelper(new NullRelativePathHelper(), __DIR__, [], DIRECTORY_SEPARATOR); $errorFormatter = new TableErrorFormatter( $relativePathHelper, @@ -90,9 +86,6 @@ private function runPath(string $path, int $expectedStatusCode): string null, $this->createMock(InputInterface::class), ); - if (file_exists($memoryLimitFile)) { - unlink($memoryLimitFile); - } $statusCode = $errorFormatter->formatErrors($analysisResult, $symfonyOutput); rewind($output->getStream()); diff --git a/tests/PHPStan/Command/CommandHelperTest.php b/tests/PHPStan/Command/CommandHelperTest.php index bbb00f122c..ab4b4b793a 100644 --- a/tests/PHPStan/Command/CommandHelperTest.php +++ b/tests/PHPStan/Command/CommandHelperTest.php @@ -124,6 +124,8 @@ public function testBegin( null, $level, false, + false, + false, ); if ($expectException) { $this->fail(); @@ -184,7 +186,6 @@ public function dataParameters(): array 'paths' => [ __DIR__ . DIRECTORY_SEPARATOR . 'relative-paths' . DIRECTORY_SEPARATOR . 'src', ], - 'memoryLimitFile' => __DIR__ . DIRECTORY_SEPARATOR . 'relative-paths' . DIRECTORY_SEPARATOR . '.memory_limit', 'excludePaths' => [ 'analyseAndScan' => [ __DIR__ . DIRECTORY_SEPARATOR . 'relative-paths' . DIRECTORY_SEPARATOR . 'src', @@ -203,6 +204,7 @@ public function dataParameters(): array __DIR__ . DIRECTORY_SEPARATOR . 'relative-paths' . DIRECTORY_SEPARATOR . 'nested' . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'there.php', __DIR__ . DIRECTORY_SEPARATOR . 'relative-paths' . DIRECTORY_SEPARATOR . 'up.php', ], + 'reportUnmatchedIgnoredErrors' => false, 'ignoreErrors' => [ [ 'message' => '#aaa#', @@ -307,6 +309,8 @@ public function testResolveParameters( null, '0', false, + false, + false, ); $parameters = $result->getContainer()->getParameters(); foreach ($expectedParameters as $name => $expectedValue) { diff --git a/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php index ac972f04a9..ace5a21c5b 100644 --- a/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/BaselineNeonErrorFormatterTest.php @@ -448,4 +448,137 @@ public function testEndOfFileNewlines( Assert::assertNotSame("\n", substr($content, -($expectedNewlinesCount + 1), 1)); } + public function dataFormatErrorsWithIdentifiers(): iterable + { + yield [ + [ + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + (new Error( + 'Foo with identifier', + __DIR__ . '/Foo.php', + 5, + ))->withIdentifier('argument.type'), + (new Error( + 'Foo with identifier', + __DIR__ . '/Foo.php', + 6, + ))->withIdentifier('argument.type'), + ], + [ + 'parameters' => [ + 'ignoreErrors' => [ + [ + 'message' => '#^Foo$#', + 'count' => 2, + 'path' => 'Foo.php', + ], + [ + 'message' => '#^Foo with identifier$#', + 'identifier' => 'argument.type', + 'count' => 2, + 'path' => 'Foo.php', + ], + ], + ], + ], + ]; + + yield [ + [ + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + new Error( + 'Foo', + __DIR__ . '/Foo.php', + 5, + ), + (new Error( + 'Foo with same message, different identifier', + __DIR__ . '/Foo.php', + 5, + ))->withIdentifier('argument.type'), + (new Error( + 'Foo with same message, different identifier', + __DIR__ . '/Foo.php', + 6, + ))->withIdentifier('argument.byRef'), + (new Error( + 'Foo with another message', + __DIR__ . '/Foo.php', + 5, + ))->withIdentifier('argument.type'), + ], + [ + 'parameters' => [ + 'ignoreErrors' => [ + [ + 'message' => '#^Foo$#', + 'count' => 2, + 'path' => 'Foo.php', + ], + [ + 'message' => '#^Foo with another message$#', + 'identifier' => 'argument.type', + 'count' => 1, + 'path' => 'Foo.php', + ], + [ + 'message' => '#^Foo with same message, different identifier$#', + 'identifier' => 'argument.byRef', + 'count' => 1, + 'path' => 'Foo.php', + ], + [ + 'message' => '#^Foo with same message, different identifier$#', + 'identifier' => 'argument.type', + 'count' => 1, + 'path' => 'Foo.php', + ], + ], + ], + ], + ]; + } + + /** + * @dataProvider dataFormatErrorsWithIdentifiers + * @param list $errors + * @param mixed[] $expectedOutput + */ + public function testFormatErrorsWithIdentifiers(array $errors, array $expectedOutput): void + { + $formatter = new BaselineNeonErrorFormatter(new SimpleRelativePathHelper(__DIR__)); + $formatter->formatErrors( + new AnalysisResult( + $errors, + [], + [], + [], + [], + false, + null, + true, + 0, + true, + [], + ), + $this->getOutput(), + '', + ); + + $this->assertSame($expectedOutput, Neon::decode($this->getOutputContent())); + } + } diff --git a/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php index b49c717f22..e9590e9402 100644 --- a/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/BaselinePhpErrorFormatterTest.php @@ -80,8 +80,8 @@ public function dataFormatErrors(): iterable 'path' => __DIR__ . '/Foo.php', ]; \$ignoreErrors[] = [ - // identifier: argument.type 'message' => '#^Foo with identifier$#', + 'identifier' => 'argument.type', 'count' => 2, 'path' => __DIR__ . '/Foo.php', ]; @@ -127,15 +127,21 @@ public function dataFormatErrors(): iterable 'path' => __DIR__ . '/Foo.php', ]; \$ignoreErrors[] = [ - // identifier: argument.type 'message' => '#^Foo with another message$#', + 'identifier' => 'argument.type', 'count' => 1, 'path' => __DIR__ . '/Foo.php', ]; \$ignoreErrors[] = [ - // identifiers: argument.byRef, argument.type 'message' => '#^Foo with same message, different identifier$#', - 'count' => 2, + 'identifier' => 'argument.byRef', + 'count' => 1, + 'path' => __DIR__ . '/Foo.php', +]; +\$ignoreErrors[] = [ + 'message' => '#^Foo with same message, different identifier$#', + 'identifier' => 'argument.type', + 'count' => 1, 'path' => __DIR__ . '/Foo.php', ]; diff --git a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php index 85121ad337..40db6547a8 100644 --- a/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php +++ b/tests/PHPStan/Command/ErrorFormatter/TableErrorFormatterTest.php @@ -190,12 +190,13 @@ public function dataFormatterOutputProvider(): iterable 'numGenericErrors' => 0, 'verbose' => false, 'extraEnvVars' => [], - 'expected' => ' ------ ------------ + 'expected' => ' ------ ---------------- Line foo.php - ------ ------------ + ------ ---------------- 5 Foobar\Buz + 🪪 foobar.buz 💡 a tip - ------ ------------ + ------ ---------------- [ERROR] Found 1 error diff --git a/tests/PHPStan/Command/ErrorFormatter/data/unixBaseline.neon b/tests/PHPStan/Command/ErrorFormatter/data/unixBaseline.neon index ca7c8f9c2c..ff39bfc9d7 100644 --- a/tests/PHPStan/Command/ErrorFormatter/data/unixBaseline.neon +++ b/tests/PHPStan/Command/ErrorFormatter/data/unixBaseline.neon @@ -11,7 +11,10 @@ parameters: path: WindowsNewlines.php - - message: "#^PHPDoc tag @param has invalid value \\(\\)\\: Unexpected token \"\\\\n\\\\t \\* \", expected type at offset 113$#" + message: """ + #^PHPDoc tag @param has invalid value \\(\r + \\$object\\)\\: Unexpected token "\\\\r\\\\n\\\\t \\* ", expected type at offset 113 on line 4$# + """ count: 1 path: WindowsNewlines.php diff --git a/tests/PHPStan/Command/ErrorFormatter/data/windowsBaseline.neon b/tests/PHPStan/Command/ErrorFormatter/data/windowsBaseline.neon index 3bfe998b6e..398e241bd7 100644 --- a/tests/PHPStan/Command/ErrorFormatter/data/windowsBaseline.neon +++ b/tests/PHPStan/Command/ErrorFormatter/data/windowsBaseline.neon @@ -11,7 +11,10 @@ parameters: path: UnixNewlines.php - - message: "#^PHPDoc tag @param has invalid value \\(\\)\\: Unexpected token \"\\\\r\\\\n\\\\t \\* \", expected type at offset 110$#" + message: """ + #^PHPDoc tag @param has invalid value \\( + \\$object\\)\\: Unexpected token "\\\\n\\\\t \\* ", expected type at offset 110 on line 4$# + """ count: 1 path: UnixNewlines.php diff --git a/tests/PHPStan/Command/exclude-paths/full.neon b/tests/PHPStan/Command/exclude-paths/full.neon index bb813f036e..275024f3a0 100644 --- a/tests/PHPStan/Command/exclude-paths/full.neon +++ b/tests/PHPStan/Command/exclude-paths/full.neon @@ -3,4 +3,4 @@ parameters: analyse: - test analyseAndScan: - - test2 + - test2 (?) diff --git a/tests/PHPStan/Command/exclude-paths/including-mixed.neon b/tests/PHPStan/Command/exclude-paths/including-mixed.neon index d7b9f3ae38..5cb7be683d 100644 --- a/tests/PHPStan/Command/exclude-paths/including-mixed.neon +++ b/tests/PHPStan/Command/exclude-paths/including-mixed.neon @@ -6,4 +6,4 @@ parameters: analyse: - test analyseAndScan: - - test2 + - test2 (?) diff --git a/tests/PHPStan/Command/exclude-paths/including.neon b/tests/PHPStan/Command/exclude-paths/including.neon index 199397750d..058059038b 100644 --- a/tests/PHPStan/Command/exclude-paths/including.neon +++ b/tests/PHPStan/Command/exclude-paths/including.neon @@ -4,6 +4,6 @@ includes: parameters: excludePaths: analyse: - - test2 + - test2 (?) analyseAndScan: - - test3 + - test3 (?) diff --git a/tests/PHPStan/Command/exclude-paths/straightforward.neon b/tests/PHPStan/Command/exclude-paths/straightforward.neon index 2b5facc315..6a4a1bd0ab 100644 --- a/tests/PHPStan/Command/exclude-paths/straightforward.neon +++ b/tests/PHPStan/Command/exclude-paths/straightforward.neon @@ -1,4 +1,4 @@ parameters: excludePaths: - test - - test2 + - test2 (?) diff --git a/tests/PHPStan/Command/exclude-paths/test/.gitkeep b/tests/PHPStan/Command/exclude-paths/test/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/PHPStan/Command/relative-paths/nested/nested.neon b/tests/PHPStan/Command/relative-paths/nested/nested.neon index 6e097edf21..c004fd54b6 100644 --- a/tests/PHPStan/Command/relative-paths/nested/nested.neon +++ b/tests/PHPStan/Command/relative-paths/nested/nested.neon @@ -3,6 +3,7 @@ parameters: - here.php - test/there.php - ../up.php + reportUnmatchedIgnoredErrors: false ignoreErrors: - message: '#aaa#' diff --git a/tests/PHPStan/Command/relative-paths/root.neon b/tests/PHPStan/Command/relative-paths/root.neon index 834bcfd001..eb1330b4fc 100644 --- a/tests/PHPStan/Command/relative-paths/root.neon +++ b/tests/PHPStan/Command/relative-paths/root.neon @@ -11,7 +11,6 @@ parameters: - %rootDir%/conf paths: - src - memoryLimitFile: .memory_limit excludePaths: - src - src/*/data diff --git a/tests/PHPStan/Composer/AutoloadFilesTest.php b/tests/PHPStan/Composer/AutoloadFilesTest.php index 889d37e1c7..3d735839e3 100644 --- a/tests/PHPStan/Composer/AutoloadFilesTest.php +++ b/tests/PHPStan/Composer/AutoloadFilesTest.php @@ -9,7 +9,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Finder\Finder; use function array_map; -use function array_splice; use function dirname; use function realpath; use function sort; @@ -17,7 +16,6 @@ use function strpos; use function substr; use const DIRECTORY_SEPARATOR; -use const PHP_VERSION_ID; class AutoloadFilesTest extends TestCase { @@ -62,25 +60,17 @@ public function testExpectedFiles(): void 'myclabs/deep-copy/src/DeepCopy/deep_copy.php', // dev dependency of PHPUnit 'react/async/src/functions_include.php', // added to phpstan-dist/bootstrap.php 'react/promise/src/functions_include.php', // added to phpstan-dist/bootstrap.php + 'phpunit/phpunit/src/Framework/Assert/Functions.php', 'symfony/deprecation-contracts/function.php', // afaik polyfills aren't necessary 'symfony/polyfill-ctype/bootstrap.php', // afaik polyfills aren't necessary 'symfony/polyfill-intl-grapheme/bootstrap.php', // afaik polyfills aren't necessary 'symfony/polyfill-intl-normalizer/bootstrap.php', // afaik polyfills aren't necessary 'symfony/polyfill-mbstring/bootstrap.php', // afaik polyfills aren't necessary - 'symfony/polyfill-php73/bootstrap.php', // afaik polyfills aren't necessary - 'symfony/polyfill-php74/bootstrap.php', // afaik polyfills aren't necessary 'symfony/polyfill-php80/bootstrap.php', // afaik polyfills aren't necessary 'symfony/polyfill-php81/bootstrap.php', // afaik polyfills aren't necessary 'symfony/string/Resources/functions.php', // afaik polyfills aren't necessary ]; - $phpunitFunctions = 'phpunit/phpunit/src/Framework/Assert/Functions.php'; - if (PHP_VERSION_ID >= 70300) { - array_splice($expectedFiles, 6, 0, [ - $phpunitFunctions, - ]); - } - $expectedFiles = array_map(static fn (string $path): string => $fileHelper->normalizePath($path), $expectedFiles); sort($expectedFiles); diff --git a/tests/PHPStan/File/FileExcluderTest.php b/tests/PHPStan/File/FileExcluderTest.php index 7477416b6c..3c2d150290 100644 --- a/tests/PHPStan/File/FileExcluderTest.php +++ b/tests/PHPStan/File/FileExcluderTest.php @@ -19,7 +19,7 @@ public function testFilesAreExcludedFromAnalysingOnWindows( { $this->skipIfNotOnWindows(); - $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes, false); + $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes); $this->assertSame($isExcluded, $fileExcluder->isExcludedFromAnalysing($filePath)); } @@ -34,7 +34,7 @@ public function dataExcludeOnWindows(): array ], [ __DIR__ . '/data/excluded-file.php', - [__DIR__], + [__DIR__ . '/*'], true, ], [ @@ -64,7 +64,7 @@ public function dataExcludeOnWindows(): array ], [ __DIR__ . '\data\parse-error.php', - ['tests/PHPStan/File/data'], + ['*/tests/PHPStan/File/data/*'], true, ], [ @@ -99,7 +99,7 @@ public function dataExcludeOnWindows(): array ], [ 'c:\etc\phpstan\dummy-1.php', - ['c:\etc\phpstan\\'], + ['c:\etc\phpstan\\*'], true, ], [ @@ -109,7 +109,7 @@ public function dataExcludeOnWindows(): array ], [ 'c:\etc\phpstan-test\dummy-2.php', - ['c:\etc\phpstan'], + ['c:\etc\phpstan*'], true, ], ]; @@ -127,7 +127,7 @@ public function testFilesAreExcludedFromAnalysingOnUnix( { $this->skipIfNotOnUnix(); - $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes, false); + $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes); $this->assertSame($isExcluded, $fileExcluder->isExcludedFromAnalysing($filePath)); } @@ -142,7 +142,7 @@ public function dataExcludeOnUnix(): array ], [ __DIR__ . '/data/excluded-file.php', - [__DIR__], + [__DIR__ . '/*'], true, ], [ @@ -170,11 +170,6 @@ public function dataExcludeOnUnix(): array [__DIR__ . '/data/[pP]arse-[eE]rror.ph[pP]'], true, ], - [ - __DIR__ . '/data/parse-error.php', - ['tests/PHPStan/File/data'], - true, - ], [ __DIR__ . '/data/parse-error.php', [__DIR__ . '/aaa'], @@ -192,7 +187,7 @@ public function dataExcludeOnUnix(): array ], [ '/etc/phpstan/dummy-1.php', - ['/etc/phpstan/'], + ['/etc/phpstan/*'], true, ], [ @@ -202,7 +197,7 @@ public function dataExcludeOnUnix(): array ], [ '/etc/phpstan-test/dummy-2.php', - ['/etc/phpstan'], + ['/etc/phpstan*'], true, ], ]; @@ -216,16 +211,6 @@ public function dataNoImplicitWildcard(): iterable __DIR__ . '/test', ], false, - true, - ]; - - yield [ - __DIR__ . '/tests/foo.php', - [ - __DIR__ . '/test', - ], - true, - false, ]; yield [ @@ -234,7 +219,6 @@ public function dataNoImplicitWildcard(): iterable __DIR__ . '/test', ], true, - true, ]; yield [ @@ -243,7 +227,6 @@ public function dataNoImplicitWildcard(): iterable __DIR__ . '/FileExcluderTest.php', ], true, - true, ]; yield [ @@ -252,7 +235,6 @@ public function dataNoImplicitWildcard(): iterable __DIR__ . '/test*', ], true, - true, ]; } @@ -263,13 +245,12 @@ public function dataNoImplicitWildcard(): iterable public function testNoImplicitWildcard( string $filePath, array $analyseExcludes, - bool $noImplicitWildcard, bool $isExcluded, ): void { $this->skipIfNotOnUnix(); - $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes, $noImplicitWildcard); + $fileExcluder = new FileExcluder($this->getFileHelper(), $analyseExcludes); $this->assertSame($isExcluded, $fileExcluder->isExcludedFromAnalysing($filePath)); } diff --git a/tests/PHPStan/Generics/GenericsIntegrationTest.php b/tests/PHPStan/Generics/GenericsIntegrationTest.php index 6f25d37cd0..a100809355 100644 --- a/tests/PHPStan/Generics/GenericsIntegrationTest.php +++ b/tests/PHPStan/Generics/GenericsIntegrationTest.php @@ -10,7 +10,7 @@ class GenericsIntegrationTest extends LevelsTestCase { - public function dataTopics(): array + public static function dataTopics(): array { return [ ['functions'], diff --git a/tests/PHPStan/Generics/data/typeProjections.php b/tests/PHPStan/Generics/data/typeProjections.php index 8cfe1f92db..555c1a50ae 100644 --- a/tests/PHPStan/Generics/data/typeProjections.php +++ b/tests/PHPStan/Generics/data/typeProjections.php @@ -1,4 +1,4 @@ -= 7.4 += 80300) { $topics[] = ['constantAccesses83']; diff --git a/tests/PHPStan/Levels/NamedArgumentsIntegrationTest.php b/tests/PHPStan/Levels/NamedArgumentsIntegrationTest.php index 854d9ded9e..d35d7dade7 100644 --- a/tests/PHPStan/Levels/NamedArgumentsIntegrationTest.php +++ b/tests/PHPStan/Levels/NamedArgumentsIntegrationTest.php @@ -10,7 +10,7 @@ class NamedArgumentsIntegrationTest extends LevelsTestCase { - public function dataTopics(): array + public static function dataTopics(): array { return [ ['namedArguments'], diff --git a/tests/PHPStan/Levels/StubValidatorIntegrationTest.php b/tests/PHPStan/Levels/StubValidatorIntegrationTest.php index f4138d043f..59ded11998 100644 --- a/tests/PHPStan/Levels/StubValidatorIntegrationTest.php +++ b/tests/PHPStan/Levels/StubValidatorIntegrationTest.php @@ -10,7 +10,7 @@ class StubValidatorIntegrationTest extends LevelsTestCase { - public function dataTopics(): array + public static function dataTopics(): array { return [ ['stubValidator'], diff --git a/tests/PHPStan/Levels/StubsIntegrationTest.php b/tests/PHPStan/Levels/StubsIntegrationTest.php index dfec2e90f5..089c9b5495 100644 --- a/tests/PHPStan/Levels/StubsIntegrationTest.php +++ b/tests/PHPStan/Levels/StubsIntegrationTest.php @@ -10,7 +10,7 @@ class StubsIntegrationTest extends LevelsTestCase { - public function dataTopics(): array + public static function dataTopics(): array { require_once __DIR__ . '/data/stubs-functions.php'; diff --git a/tests/PHPStan/Levels/data/acceptTypes-10.json b/tests/PHPStan/Levels/data/acceptTypes-10.json new file mode 100644 index 0000000000..8a1b7a3992 --- /dev/null +++ b/tests/PHPStan/Levels/data/acceptTypes-10.json @@ -0,0 +1,17 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 170, + "ignorable": true + }, + { + "message": "Parameter #1 $closure of method Levels\\AcceptTypes\\ClosureAccepts::doBar() expects Closure(Levels\\AcceptTypes\\FooInterface, int): Levels\\AcceptTypes\\FooInterface, Closure(mixed): mixed given.", + "line": 325, + "ignorable": true + }, + { + "message": "Parameter #1 $callable of method Levels\\AcceptTypes\\ClosureAccepts::doBaz() expects callable(Levels\\AcceptTypes\\FooInterface, int): Levels\\AcceptTypes\\FooInterface, Closure(mixed): mixed given.", + "line": 326, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/acceptTypes-5.json b/tests/PHPStan/Levels/data/acceptTypes-5.json index 88d4749a45..76aac5c080 100644 --- a/tests/PHPStan/Levels/data/acceptTypes-5.json +++ b/tests/PHPStan/Levels/data/acceptTypes-5.json @@ -180,7 +180,7 @@ "ignorable": true }, { - "message": "Parameter #1 $nonEmpty of method Levels\\AcceptTypes\\AcceptNonEmpty::doBar() expects non-empty-array, array{} given.", + "message": "Parameter #1 $nonEmpty of method Levels\\AcceptTypes\\AcceptNonEmpty::doBar() expects non-empty-array, array{} given.", "line": 733, "ignorable": true }, @@ -189,4 +189,4 @@ "line": 763, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/acceptTypes-7.json b/tests/PHPStan/Levels/data/acceptTypes-7.json index 9e0afc2f64..ba67e6a9d6 100644 --- a/tests/PHPStan/Levels/data/acceptTypes-7.json +++ b/tests/PHPStan/Levels/data/acceptTypes-7.json @@ -85,7 +85,7 @@ "ignorable": true }, { - "message": "Parameter #1 $array of method Levels\\AcceptTypes\\Baz::requireArray() expects array, array|Levels\\AcceptTypes\\Foo given.", + "message": "Parameter #1 $array of method Levels\\AcceptTypes\\Baz::requireArray() expects array, array|Levels\\AcceptTypes\\Foo given.", "line": 531, "ignorable": true }, @@ -95,12 +95,12 @@ "ignorable": true }, { - "message": "Parameter #1 $array of method Levels\\AcceptTypes\\Baz::requireArray() expects array, array|Levels\\AcceptTypes\\Foo given.", + "message": "Parameter #1 $array of method Levels\\AcceptTypes\\Baz::requireArray() expects array, array|Levels\\AcceptTypes\\Foo given.", "line": 542, "ignorable": true }, { - "message": "Parameter #1 $foo of method Levels\\AcceptTypes\\Baz::requireFoo() expects Levels\\AcceptTypes\\Foo, array|Levels\\AcceptTypes\\Foo given.", + "message": "Parameter #1 $foo of method Levels\\AcceptTypes\\Baz::requireFoo() expects Levels\\AcceptTypes\\Foo, array|Levels\\AcceptTypes\\Foo given.", "line": 543, "ignorable": true }, @@ -160,7 +160,7 @@ "ignorable": true }, { - "message": "Parameter #1 $nonEmpty of method Levels\\AcceptTypes\\AcceptNonEmpty::doBar() expects non-empty-array, array given.", + "message": "Parameter #1 $nonEmpty of method Levels\\AcceptTypes\\AcceptNonEmpty::doBar() expects non-empty-array, array given.", "line": 735, "ignorable": true }, @@ -169,4 +169,4 @@ "line": 756, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/arrayAccess-10.json b/tests/PHPStan/Levels/data/arrayAccess-10.json new file mode 100644 index 0000000000..9dc3ca3eb9 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayAccess-10.json @@ -0,0 +1,7 @@ +[ + { + "message": "Cannot assign offset mixed to SplObjectStorage.", + "line": 43, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayDestructuring-8.json b/tests/PHPStan/Levels/data/arrayDestructuring-8.json index 7842bce806..3b033abd6d 100644 --- a/tests/PHPStan/Levels/data/arrayDestructuring-8.json +++ b/tests/PHPStan/Levels/data/arrayDestructuring-8.json @@ -1,7 +1,7 @@ [ { - "message": "Cannot use array destructuring on array|null.", + "message": "Cannot use array destructuring on array|null.", "line": 15, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/arrayDimFetches-10.json b/tests/PHPStan/Levels/data/arrayDimFetches-10.json new file mode 100644 index 0000000000..900a4ee636 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayDimFetches-10.json @@ -0,0 +1,22 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 14, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 21, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 27, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 28, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayDimFetches-8.json b/tests/PHPStan/Levels/data/arrayDimFetches-8.json index 07568e3768..e7e6efcd13 100644 --- a/tests/PHPStan/Levels/data/arrayDimFetches-8.json +++ b/tests/PHPStan/Levels/data/arrayDimFetches-8.json @@ -1,6 +1,6 @@ [ { - "message": "Offset 0 might not exist on array|null.", + "message": "Offset 0 might not exist on array|null.", "line": 15, "ignorable": true }, @@ -9,4 +9,4 @@ "line": 50, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/callableCalls-10-missing.json b/tests/PHPStan/Levels/data/callableCalls-10-missing.json new file mode 100644 index 0000000000..5c7f12b38d --- /dev/null +++ b/tests/PHPStan/Levels/data/callableCalls-10-missing.json @@ -0,0 +1,12 @@ +[ + { + "message": "Closure invoked with 0 parameters, 1 required.", + "line": 37, + "ignorable": true + }, + { + "message": "Trying to invoke int but it's not a callable.", + "line": 43, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/casts-7.json b/tests/PHPStan/Levels/data/casts-7.json index d9b7a85b78..e2810b0e42 100644 --- a/tests/PHPStan/Levels/data/casts-7.json +++ b/tests/PHPStan/Levels/data/casts-7.json @@ -1,12 +1,12 @@ [ { - "message": "Cannot cast array|(callable(): mixed) to int.", + "message": "Cannot cast array|(callable(): mixed) to int.", "line": 20, "ignorable": true }, { - "message": "Cannot cast array|float|int to string.", + "message": "Cannot cast array|float|int to string.", "line": 21, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/clone-10-missing.json b/tests/PHPStan/Levels/data/clone-10-missing.json new file mode 100644 index 0000000000..40e1203120 --- /dev/null +++ b/tests/PHPStan/Levels/data/clone-10-missing.json @@ -0,0 +1,12 @@ +[ + { + "message": "Cannot clone non-object variable $nullableInt of type int.", + "line": 34, + "ignorable": true + }, + { + "message": "Cannot clone non-object variable $nullableUnion of type int|Levels\\Cloning\\Foo.", + "line": 35, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/coalesce-10.json b/tests/PHPStan/Levels/data/coalesce-10.json new file mode 100644 index 0000000000..e74887cb13 --- /dev/null +++ b/tests/PHPStan/Levels/data/coalesce-10.json @@ -0,0 +1,12 @@ +[ + { + "message": "Cannot access property $bar on mixed.", + "line": 6, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 11, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/constantAccesses-10-missing.json b/tests/PHPStan/Levels/data/constantAccesses-10-missing.json new file mode 100644 index 0000000000..0cc5a3f5d4 --- /dev/null +++ b/tests/PHPStan/Levels/data/constantAccesses-10-missing.json @@ -0,0 +1,17 @@ +[ + { + "message": "Access to undefined constant Levels\\ConstantAccesses\\Foo::BAR_CONSTANT.", + "line": 53, + "ignorable": true + }, + { + "message": "Access to undefined constant Levels\\ConstantAccesses\\Bar|Levels\\ConstantAccesses\\Foo::BAR_CONSTANT.", + "line": 56, + "ignorable": true + }, + { + "message": "Access to undefined constant Levels\\ConstantAccesses\\Bar|Levels\\ConstantAccesses\\Foo::FOO_CONSTANT.", + "line": 55, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/constantAccesses-10.json b/tests/PHPStan/Levels/data/constantAccesses-10.json new file mode 100644 index 0000000000..cf84dbb4c6 --- /dev/null +++ b/tests/PHPStan/Levels/data/constantAccesses-10.json @@ -0,0 +1,62 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 6, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 17, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 18, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 20, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 23, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 49, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 50, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 52, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 53, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 55, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 56, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 58, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/constantAccesses83-10.json b/tests/PHPStan/Levels/data/constantAccesses83-10.json new file mode 100644 index 0000000000..7d5fcb38d3 --- /dev/null +++ b/tests/PHPStan/Levels/data/constantAccesses83-10.json @@ -0,0 +1,27 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 15, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 16, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 18, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 19, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 20, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/echo_-2.json b/tests/PHPStan/Levels/data/echo_-2.json index 1c35f8ef7c..330e326e8e 100644 --- a/tests/PHPStan/Levels/data/echo_-2.json +++ b/tests/PHPStan/Levels/data/echo_-2.json @@ -1,12 +1,12 @@ [ { - "message": "Parameter #1 (array) of echo cannot be converted to string.", + "message": "Parameter #1 (array) of echo cannot be converted to string.", "line": 21, "ignorable": true }, { - "message": "Parameter #2 (array|(callable(): mixed)) of echo cannot be converted to string.", + "message": "Parameter #2 (array|(callable(): mixed)) of echo cannot be converted to string.", "line": 21, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/echo_-7.json b/tests/PHPStan/Levels/data/echo_-7.json index 3f32efd774..275583f027 100644 --- a/tests/PHPStan/Levels/data/echo_-7.json +++ b/tests/PHPStan/Levels/data/echo_-7.json @@ -1,12 +1,12 @@ [ { - "message": "Parameter #3 (array|float|int) of echo cannot be converted to string.", + "message": "Parameter #3 (array|float|int) of echo cannot be converted to string.", "line": 21, "ignorable": true }, { - "message": "Parameter #4 (array|string) of echo cannot be converted to string.", + "message": "Parameter #4 (array|string) of echo cannot be converted to string.", "line": 21, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/encapsedString-2.json b/tests/PHPStan/Levels/data/encapsedString-2.json index 01ea01b977..8035809eb6 100644 --- a/tests/PHPStan/Levels/data/encapsedString-2.json +++ b/tests/PHPStan/Levels/data/encapsedString-2.json @@ -1,11 +1,11 @@ [ { - "message": "Part $array (array) of encapsed string cannot be cast to string.", + "message": "Part $array (array) of encapsed string cannot be cast to string.", "line": 21, "ignorable": true }, { - "message": "Part $arrayOrCallable (array|(callable(): mixed)) of encapsed string cannot be cast to string.", + "message": "Part $arrayOrCallable (array|(callable(): mixed)) of encapsed string cannot be cast to string.", "line": 22, "ignorable": true } diff --git a/tests/PHPStan/Levels/data/encapsedString-7.json b/tests/PHPStan/Levels/data/encapsedString-7.json index 577b87c127..c468ffbc0a 100644 --- a/tests/PHPStan/Levels/data/encapsedString-7.json +++ b/tests/PHPStan/Levels/data/encapsedString-7.json @@ -1,11 +1,11 @@ [ { - "message": "Part $arrayOrFloatOrInt (array|float|int) of encapsed string cannot be cast to string.", + "message": "Part $arrayOrFloatOrInt (array|float|int) of encapsed string cannot be cast to string.", "line": 23, "ignorable": true }, { - "message": "Part $arrayOrString (array|string) of encapsed string cannot be cast to string.", + "message": "Part $arrayOrString (array|string) of encapsed string cannot be cast to string.", "line": 24, "ignorable": true } diff --git a/tests/PHPStan/Levels/data/iterable-7.json b/tests/PHPStan/Levels/data/iterable-7.json index 74440d64d8..5c3c24924d 100644 --- a/tests/PHPStan/Levels/data/iterable-7.json +++ b/tests/PHPStan/Levels/data/iterable-7.json @@ -1,7 +1,7 @@ [ { - "message": "Argument of an invalid type array|false supplied for foreach, only iterables are supported.", + "message": "Argument of an invalid type array|false supplied for foreach, only iterables are supported.", "line": 35, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/iterable-8.json b/tests/PHPStan/Levels/data/iterable-8.json index 17e368b276..0a46f4b75e 100644 --- a/tests/PHPStan/Levels/data/iterable-8.json +++ b/tests/PHPStan/Levels/data/iterable-8.json @@ -1,7 +1,7 @@ [ { - "message": "Argument of an invalid type array|null supplied for foreach, only iterables are supported.", + "message": "Argument of an invalid type array|null supplied for foreach, only iterables are supported.", "line": 26, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/methodCalls-10-missing.json b/tests/PHPStan/Levels/data/methodCalls-10-missing.json new file mode 100644 index 0000000000..47cdcab769 --- /dev/null +++ b/tests/PHPStan/Levels/data/methodCalls-10-missing.json @@ -0,0 +1,52 @@ +[ + { + "message": "Method Levels\\MethodCalls\\Foo::doFoo() invoked with 0 parameters, 1 required.", + "line": 53, + "ignorable": true + }, + { + "message": "Method Levels\\MethodCalls\\Foo::doFoo() invoked with 0 parameters, 1 required.", + "line": 56, + "ignorable": true + }, + { + "message": "Method Levels\\MethodCalls\\Foo::doFoo() invoked with 0 parameters, 1 required.", + "line": 59, + "ignorable": true + }, + { + "message": "Method Levels\\MethodCalls\\Foo::doFoo() invoked with 0 parameters, 1 required.", + "line": 162, + "ignorable": true + }, + { + "message": "Method Levels\\MethodCalls\\Foo::doFoo() invoked with 0 parameters, 1 required.", + "line": 166, + "ignorable": true + }, + { + "message": "Method Levels\\MethodCalls\\Foo::doFoo() invoked with 0 parameters, 1 required.", + "line": 170, + "ignorable": true + }, + { + "message": "Call to an undefined method Levels\\MethodCalls\\Bar|Levels\\MethodCalls\\Foo::doFoo().", + "line": 59, + "ignorable": true + }, + { + "message": "Call to an undefined method Levels\\MethodCalls\\Bar|Levels\\MethodCalls\\Foo::doFoo().", + "line": 60, + "ignorable": true + }, + { + "message": "Call to an undefined method Levels\\MethodCalls\\Bar|Levels\\MethodCalls\\Foo::doFoo().", + "line": 170, + "ignorable": true + }, + { + "message": "Call to an undefined method Levels\\MethodCalls\\Bar|Levels\\MethodCalls\\Foo::doFoo().", + "line": 171, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/missingTypes-6.json b/tests/PHPStan/Levels/data/missingTypes-6.json new file mode 100644 index 0000000000..66b17f1111 --- /dev/null +++ b/tests/PHPStan/Levels/data/missingTypes-6.json @@ -0,0 +1,7 @@ +[ + { + "message": "Class MissingTypesLevels\\Foo extends generic class MissingTypesLevels\\Generic but does not specify its types: T", + "line": 13, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/missingTypes.php b/tests/PHPStan/Levels/data/missingTypes.php new file mode 100644 index 0000000000..ed3d9bd3bf --- /dev/null +++ b/tests/PHPStan/Levels/data/missingTypes.php @@ -0,0 +1,16 @@ + of print cannot be converted to string.", "line": 21, "ignorable": true }, { - "message": "Parameter array|(callable(): mixed) of print cannot be converted to string.", + "message": "Parameter array|(callable(): mixed) of print cannot be converted to string.", "line": 22, "ignorable": true } -] \ No newline at end of file +] diff --git a/tests/PHPStan/Levels/data/print_-7.json b/tests/PHPStan/Levels/data/print_-7.json index 84c94b44c4..532f660fad 100644 --- a/tests/PHPStan/Levels/data/print_-7.json +++ b/tests/PHPStan/Levels/data/print_-7.json @@ -1,11 +1,11 @@ [ { - "message": "Parameter array|float|int of print cannot be converted to string.", + "message": "Parameter array|float|int of print cannot be converted to string.", "line": 23, "ignorable": true }, { - "message": "Parameter array|string of print cannot be converted to string.", + "message": "Parameter array|string of print cannot be converted to string.", "line": 24, "ignorable": true } diff --git a/tests/PHPStan/Levels/data/propertyAccesses-10-missing.json b/tests/PHPStan/Levels/data/propertyAccesses-10-missing.json new file mode 100644 index 0000000000..1a8bc8b4b7 --- /dev/null +++ b/tests/PHPStan/Levels/data/propertyAccesses-10-missing.json @@ -0,0 +1,32 @@ +[ + { + "message": "Access to an undefined property Levels\\PropertyAccesses\\Foo::$bar.", + "line": 61, + "ignorable": true + }, + { + "message": "Access to an undefined property Levels\\PropertyAccesses\\Foo::$bar.", + "line": 166, + "ignorable": true + }, + { + "message": "Access to an undefined property Levels\\PropertyAccesses\\Bar|Levels\\PropertyAccesses\\Foo::$foo.", + "line": 63, + "ignorable": true + }, + { + "message": "Access to an undefined property Levels\\PropertyAccesses\\Bar|Levels\\PropertyAccesses\\Foo::$bar.", + "line": 64, + "ignorable": true + }, + { + "message": "Access to an undefined property Levels\\PropertyAccesses\\Bar|Levels\\PropertyAccesses\\Foo::$foo.", + "line": 169, + "ignorable": true + }, + { + "message": "Access to an undefined property Levels\\PropertyAccesses\\Bar|Levels\\PropertyAccesses\\Foo::$bar.", + "line": 170, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/propertyAccesses-10.json b/tests/PHPStan/Levels/data/propertyAccesses-10.json new file mode 100644 index 0000000000..9581e25ad9 --- /dev/null +++ b/tests/PHPStan/Levels/data/propertyAccesses-10.json @@ -0,0 +1,57 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 14, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 18, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 32, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 36, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 95, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 186, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 187, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 188, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 198, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 199, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 200, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/propertyAccesses-7.json b/tests/PHPStan/Levels/data/propertyAccesses-7.json index aa6291fdfe..b6df87becb 100644 --- a/tests/PHPStan/Levels/data/propertyAccesses-7.json +++ b/tests/PHPStan/Levels/data/propertyAccesses-7.json @@ -38,5 +38,10 @@ "message": "Access to an undefined property Levels\\PropertyAccesses\\Bar|Levels\\PropertyAccesses\\Foo::$bar.", "line": 170, "ignorable": true + }, + { + "message": "Access to an undefined property object::$baz.", + "line": 200, + "ignorable": true } ] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/propertyAccesses-9.json b/tests/PHPStan/Levels/data/propertyAccesses-9.json new file mode 100644 index 0000000000..c7c6ae5a96 --- /dev/null +++ b/tests/PHPStan/Levels/data/propertyAccesses-9.json @@ -0,0 +1,7 @@ +[ + { + "message": "Cannot access property $foo on mixed.", + "line": 197, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/propertyAccesses.php b/tests/PHPStan/Levels/data/propertyAccesses.php index 72c9d4bcda..1c006ab6dc 100644 --- a/tests/PHPStan/Levels/data/propertyAccesses.php +++ b/tests/PHPStan/Levels/data/propertyAccesses.php @@ -174,3 +174,31 @@ public function doBaz() } } + +class ObjectWithIsset +{ + + public function doFoo(): void + { + $test = new \stdClass; + + if (isset($test->foo)) { + echo $test->foo; + echo $test->bar; + echo $test->baz; + } + } + + /** + * @param mixed $test + */ + public function doBar($test): void + { + if (isset($test->foo) && isset($test->bar)) { + echo $test->foo; + echo $test->bar; + echo $test->baz; + } + } + +} diff --git a/tests/PHPStan/Levels/data/stringOffsetAccess-10.json b/tests/PHPStan/Levels/data/stringOffsetAccess-10.json new file mode 100644 index 0000000000..cc773c1e06 --- /dev/null +++ b/tests/PHPStan/Levels/data/stringOffsetAccess-10.json @@ -0,0 +1,32 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 13, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 16, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 23, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 27, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 31, + "ignorable": true + }, + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 35, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/stubValidator-0.json b/tests/PHPStan/Levels/data/stubValidator-0.json index 0517d298af..ce13d6e997 100644 --- a/tests/PHPStan/Levels/data/stubValidator-0.json +++ b/tests/PHPStan/Levels/data/stubValidator-0.json @@ -20,12 +20,12 @@ "ignorable": false }, { - "message": "Method class@anonymous/stubValidator/stubs.php:27::doFoo() has no return type specified.", + "message": "Method ArrayIterator@anonymous/stubValidator/stubs.php:27::doFoo() has no return type specified.", "line": 30, "ignorable": false }, { - "message": "Parameter $foo of method class@anonymous/stubValidator/stubs.php:27::doFoo() has invalid type StubValidator\\Foooooooo.", + "message": "Parameter $foo of method ArrayIterator@anonymous/stubValidator/stubs.php:27::doFoo() has invalid type StubValidator\\Foooooooo.", "line": 30, "ignorable": false } diff --git a/tests/PHPStan/Levels/data/stubs-functions-4.json b/tests/PHPStan/Levels/data/stubs-functions-4.json new file mode 100644 index 0000000000..dd57bdf13f --- /dev/null +++ b/tests/PHPStan/Levels/data/stubs-functions-4.json @@ -0,0 +1,12 @@ +[ + { + "message": "Call to function StubsIntegrationTest\\foo() on a separate line has no effect.", + "line": 11, + "ignorable": true + }, + { + "message": "Call to function StubsIntegrationTest\\foo() on a separate line has no effect.", + "line": 13, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/unreachable-0.json b/tests/PHPStan/Levels/data/unreachable-0.json deleted file mode 100644 index 5091fec153..0000000000 --- a/tests/PHPStan/Levels/data/unreachable-0.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "message": "Return value of function print_r() is always true and the result is printed instead of being returned. Pass in true as parameter #2 $return to return the output instead.", - "line": 38, - "ignorable": true - }, - { - "message": "Return value of function print_r() is always true and the result is printed instead of being returned. Pass in true as parameter #2 $return to return the output instead.", - "line": 89, - "ignorable": true - } -] diff --git a/tests/PHPStan/Levels/data/unreachable-4.json b/tests/PHPStan/Levels/data/unreachable-4.json index 6f937312ae..4e6216b466 100644 --- a/tests/PHPStan/Levels/data/unreachable-4.json +++ b/tests/PHPStan/Levels/data/unreachable-4.json @@ -19,6 +19,11 @@ "line": 38, "ignorable": true }, + { + "message": "Return value of function print_r() is always true and the result is printed instead of being returned. Pass in true as parameter #2 $return to return the output instead.", + "line": 38, + "ignorable": true + }, { "message": "If condition is always true.", "line": 47, @@ -64,6 +69,11 @@ "line": 84, "ignorable": true }, + { + "message": "Return value of function print_r() is always true and the result is printed instead of being returned. Pass in true as parameter #2 $return to return the output instead.", + "line": 89, + "ignorable": true + }, { "message": "Ternary operator condition is always true.", "line": 89, diff --git a/tests/PHPStan/Levels/data/variables-10.json b/tests/PHPStan/Levels/data/variables-10.json new file mode 100644 index 0000000000..fd397067b9 --- /dev/null +++ b/tests/PHPStan/Levels/data/variables-10.json @@ -0,0 +1,7 @@ +[ + { + "message": "Parameter #1 (mixed) of echo cannot be converted to string.", + "line": 7, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Parser/CachedParserTest.php b/tests/PHPStan/Parser/CachedParserTest.php index 13505dbce7..3b97a1b99a 100644 --- a/tests/PHPStan/Parser/CachedParserTest.php +++ b/tests/PHPStan/Parser/CachedParserTest.php @@ -90,15 +90,34 @@ public function testParseTheSameFileWithDifferentMethod(): void $contents = FileReader::read($path); $stmts = $parser->parseString($contents); $this->assertInstanceOf(Namespace_::class, $stmts[0]); - $this->assertNull($stmts[0]->stmts[0]->getAttribute('parent')); + $this->assertInstanceOf(Node\Stmt\Expression::class, $stmts[0]->stmts[0]); + $this->assertInstanceOf(Node\Expr\Assign::class, $stmts[0]->stmts[0]->expr); + $this->assertInstanceOf(Node\Expr\New_::class, $stmts[0]->stmts[0]->expr->expr); + $this->assertNull($stmts[0]->stmts[0]->expr->expr->class->getAttribute(AnonymousClassVisitor::ATTRIBUTE_LINE_INDEX)); $stmts = $parser->parseFile($path); $this->assertInstanceOf(Namespace_::class, $stmts[0]); - $this->assertInstanceOf(Namespace_::class, $stmts[0]->stmts[0]->getAttribute('parent')); + $this->assertInstanceOf(Node\Stmt\Expression::class, $stmts[0]->stmts[0]); + $this->assertInstanceOf(Node\Expr\Assign::class, $stmts[0]->stmts[0]->expr); + $this->assertInstanceOf(Node\Expr\New_::class, $stmts[0]->stmts[0]->expr->expr); + $this->assertSame(1, $stmts[0]->stmts[0]->expr->expr->class->getAttribute(AnonymousClassVisitor::ATTRIBUTE_LINE_INDEX)); + + $this->assertInstanceOf(Node\Stmt\Expression::class, $stmts[0]->stmts[1]); + $this->assertInstanceOf(Node\Expr\Assign::class, $stmts[0]->stmts[1]->expr); + $this->assertInstanceOf(Node\Expr\New_::class, $stmts[0]->stmts[1]->expr->expr); + $this->assertSame(2, $stmts[0]->stmts[1]->expr->expr->class->getAttribute(AnonymousClassVisitor::ATTRIBUTE_LINE_INDEX)); $stmts = $parser->parseString($contents); $this->assertInstanceOf(Namespace_::class, $stmts[0]); - $this->assertInstanceOf(Namespace_::class, $stmts[0]->stmts[0]->getAttribute('parent')); + $this->assertInstanceOf(Node\Stmt\Expression::class, $stmts[0]->stmts[0]); + $this->assertInstanceOf(Node\Expr\Assign::class, $stmts[0]->stmts[0]->expr); + $this->assertInstanceOf(Node\Expr\New_::class, $stmts[0]->stmts[0]->expr->expr); + $this->assertSame(1, $stmts[0]->stmts[0]->expr->expr->class->getAttribute(AnonymousClassVisitor::ATTRIBUTE_LINE_INDEX)); + + $this->assertInstanceOf(Node\Stmt\Expression::class, $stmts[0]->stmts[1]); + $this->assertInstanceOf(Node\Expr\Assign::class, $stmts[0]->stmts[1]->expr); + $this->assertInstanceOf(Node\Expr\New_::class, $stmts[0]->stmts[1]->expr->expr); + $this->assertSame(2, $stmts[0]->stmts[1]->expr->expr->class->getAttribute(AnonymousClassVisitor::ATTRIBUTE_LINE_INDEX)); } } diff --git a/tests/PHPStan/Parser/CleaningParserTest.php b/tests/PHPStan/Parser/CleaningParserTest.php index 692ea7b699..835486fdc2 100644 --- a/tests/PHPStan/Parser/CleaningParserTest.php +++ b/tests/PHPStan/Parser/CleaningParserTest.php @@ -68,6 +68,8 @@ public function testParse( new SimpleParser( new Php7(new Emulative()), new NameResolver(), + new VariadicMethodsVisitor(), + new VariadicFunctionsVisitor(), ), new PhpVersion($phpVersionId), ); diff --git a/tests/PHPStan/Parser/ParserTest.php b/tests/PHPStan/Parser/ParserTest.php new file mode 100644 index 0000000000..94fe9a406b --- /dev/null +++ b/tests/PHPStan/Parser/ParserTest.php @@ -0,0 +1,99 @@ + true, + ], + ]; + + yield [ + __DIR__ . '/data/variadic-methods.php', + VariadicMethodsVisitor::ATTRIBUTE_NAME, + [ + 'VariadicMethod\X' => [ + 'implicit_variadic_fn1' => true, + ], + 'VariadicMethod\Z' => [ + 'implicit_variadic_fnZ' => true, + ], + 'class@anonymous:20:30' => [ + 'implicit_variadic_subZ' => true, + ], + 'class@anonymous:42:52' => [ + 'implicit_variadic_fn' => true, + ], + 'class@anonymous:54:58' => [ + 'implicit_variadic_fn' => true, + ], + 'class@anonymous:61:68' => [ + 'implicit_variadic_fn' => true, + ], + ], + ]; + + yield [ + __DIR__ . '/data/variadic-methods-in-enum.php', + VariadicMethodsVisitor::ATTRIBUTE_NAME, + [ + 'VariadicMethodEnum\X' => [ + 'implicit_variadic_fn1' => true, + ], + ], + ]; + } + + /** + * @dataProvider dataVariadicCallLikes + * @param array|array> $expectedVariadics + * @throws ParserErrorsException + */ + public function testSimpleParserVariadicCallLikes(string $file, string $attributeName, array $expectedVariadics): void + { + /** @var SimpleParser $parser */ + $parser = self::getContainer()->getService('currentPhpVersionSimpleParser'); + $ast = $parser->parseFile($file); + $variadics = $ast[0]->getAttribute($attributeName); + $this->assertIsArray($variadics); + $this->assertCount(count($expectedVariadics), $variadics); + foreach ($expectedVariadics as $key => $expectedVariadic) { + $this->assertArrayHasKey($key, $variadics); + $this->assertSame($expectedVariadic, $variadics[$key]); + } + } + + /** + * @dataProvider dataVariadicCallLikes + * @param array|array> $expectedVariadics + * @throws ParserErrorsException + */ + public function testRichParserVariadicCallLikes(string $file, string $attributeName, array $expectedVariadics): void + { + /** @var RichParser $parser */ + $parser = self::getContainer()->getService('currentPhpVersionRichParser'); + $ast = $parser->parseFile($file); + $variadics = $ast[0]->getAttribute($attributeName); + $this->assertIsArray($variadics); + $this->assertCount(count($expectedVariadics), $variadics); + foreach ($expectedVariadics as $key => $expectedVariadic) { + $this->assertArrayHasKey($key, $variadics); + $this->assertSame($expectedVariadic, $variadics[$key]); + } + } + +} diff --git a/tests/PHPStan/Parser/RichParserTest.php b/tests/PHPStan/Parser/RichParserTest.php index 5fa112a57f..0bc0b3b4c1 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'], ], ]; diff --git a/tests/PHPStan/Parser/data/test.php b/tests/PHPStan/Parser/data/test.php index a6bee51214..b7ee628d37 100644 --- a/tests/PHPStan/Parser/data/test.php +++ b/tests/PHPStan/Parser/data/test.php @@ -2,7 +2,4 @@ namespace CachedParserBug; -class Foo -{ - -} +$a = new class () {}; $b = new class () {}; diff --git a/tests/PHPStan/Parser/data/variadic-functions.php b/tests/PHPStan/Parser/data/variadic-functions.php new file mode 100644 index 0000000000..d1a572e1e0 --- /dev/null +++ b/tests/PHPStan/Parser/data/variadic-functions.php @@ -0,0 +1,31 @@ += 8.1 + +namespace VariadicMethodEnum; + +enum X { + + function non_variadic_fn1($v) { + } + + function variadic_fn1(...$v) { + } + + function implicit_variadic_fn1() { + $args = func_get_args(); + } +} diff --git a/tests/PHPStan/Parser/data/variadic-methods.php b/tests/PHPStan/Parser/data/variadic-methods.php new file mode 100644 index 0000000000..da6135b967 --- /dev/null +++ b/tests/PHPStan/Parser/data/variadic-methods.php @@ -0,0 +1,68 @@ +assertSame( + $expected->describe(), + $phpVersions->producesWarningForFinalPrivateMethods()->describe(), + ); + } + + public function dataProducesWarningForFinalPrivateMethods(): iterable + { + yield [ + TrinaryLogic::createNo(), + new ConstantIntegerType(70400), + ]; + + yield [ + TrinaryLogic::createYes(), + new ConstantIntegerType(80000), + ]; + + yield [ + TrinaryLogic::createYes(), + new ConstantIntegerType(80100), + ]; + + yield [ + TrinaryLogic::createYes(), + IntegerRangeType::fromInterval(80000, null), + ]; + + yield [ + TrinaryLogic::createMaybe(), + IntegerRangeType::fromInterval(null, 80000), + ]; + + yield [ + TrinaryLogic::createNo(), + IntegerRangeType::fromInterval(70200, 70400), + ]; + + yield [ + TrinaryLogic::createMaybe(), + new UnionType([ + IntegerRangeType::fromInterval(70200, 70400), + IntegerRangeType::fromInterval(80200, 80400), + ]), + ]; + } + +} diff --git a/tests/PHPStan/Reflection/Annotations/FinalAnnotationsTest.php b/tests/PHPStan/Reflection/Annotations/FinalAnnotationsTest.php index fb61a5c90e..6df44ad440 100644 --- a/tests/PHPStan/Reflection/Annotations/FinalAnnotationsTest.php +++ b/tests/PHPStan/Reflection/Annotations/FinalAnnotationsTest.php @@ -4,7 +4,6 @@ use FinalAnnotations\FinalFoo; use FinalAnnotations\Foo; -use PhpParser\Node\Name; use PHPStan\Analyser\Scope; use PHPStan\Testing\PHPStanTestCase; @@ -58,14 +57,4 @@ public function testFinalAnnotations(bool $final, string $className, array $fina } } - public function testFinalUserFunctions(): void - { - require_once __DIR__ . '/data/annotations-final.php'; - - $reflectionProvider = $this->createReflectionProvider(); - - $this->assertFalse($reflectionProvider->getFunction(new Name\FullyQualified('FinalAnnotations\foo'), null)->isFinal()->yes()); - $this->assertTrue($reflectionProvider->getFunction(new Name\FullyQualified('FinalAnnotations\finalFoo'), null)->isFinal()->yes()); - } - } diff --git a/tests/PHPStan/Reflection/Annotations/data/annotations-final.php b/tests/PHPStan/Reflection/Annotations/data/annotations-final.php index cb3932500f..f7c7c2da25 100644 --- a/tests/PHPStan/Reflection/Annotations/data/annotations-final.php +++ b/tests/PHPStan/Reflection/Annotations/data/annotations-final.php @@ -2,19 +2,6 @@ namespace FinalAnnotations; -function foo() -{ - -} - -/** - * @final - */ -function finalFoo() -{ - -} - class Foo { diff --git a/tests/PHPStan/Reflection/AnonymousClassReflectionTest.php b/tests/PHPStan/Reflection/AnonymousClassReflectionTest.php index 9310f617f1..b6ee413032 100644 --- a/tests/PHPStan/Reflection/AnonymousClassReflectionTest.php +++ b/tests/PHPStan/Reflection/AnonymousClassReflectionTest.php @@ -101,6 +101,55 @@ public function testReflection(): void ]), 9, ], + [ + implode("\n", [ + 'name: AnonymousClass1d622e3ff3a656e68d55eafbd25eaef1', + 'display name: AnonymousClassReflectionTest\A@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:17:1', + ]), + 17, + ], + [ + implode("\n", [ + 'name: AnonymousClass6e1acc8e948827c8d0439a2225fdbdd0', + 'display name: AnonymousClassReflectionTest\A@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:17:2', + ]), + 17, + ], + [ + implode("\n", [ + 'name: AnonymousClass2a49db3d44479dddd8beaea4ea8131fb', + 'display name: AnonymousClassReflectionTest\A@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:19:1', + ]), + 19, + ], + [ + implode("\n", [ + 'name: AnonymousClass337463cf86ee25e526f445630960b336', + 'display name: AnonymousClassReflectionTest\A@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:19:2', + ]), + 19, + ], + [ + implode("\n", [ + 'name: AnonymousClassda3e79cc45f826d60295f848abab37e7', + 'display name: AnonymousClassReflectionTest\U@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:29', + ]), + 29, + ], + [ + implode("\n", [ + 'name: AnonymousClassc06612bf3776bbe5e50870a8c3151186', + 'display name: AnonymousClassReflectionTest\U@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:31', + ]), + 31, + ], + [ + implode("\n", [ + 'name: AnonymousClassbee6eba8c721d73d649fcc9d361f5902', + 'display name: AnonymousClassReflectionTest\V@anonymous/tests/PHPStan/Reflection/data/anonymous-classes.php:33', + ]), + 33, + ], ]); } diff --git a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php index c9726f3247..8ea1afae71 100644 --- a/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php +++ b/tests/PHPStan/Reflection/BetterReflection/SourceLocator/OptimizedDirectorySourceLocatorTest.php @@ -313,10 +313,6 @@ public function testFunctionDoesNotExist(string $functionName): void public function testBug5525(): void { - if (PHP_VERSION_ID < 70300) { - self::markTestSkipped('This test needs at least PHP 7.3 because of different PCRE engine'); - } - $factory = self::getContainer()->getByType(OptimizedDirectorySourceLocatorFactory::class); $locator = $factory->createByFiles([__DIR__ . '/data/bug-5525.php']); $reflector = new DefaultReflector($locator); diff --git a/tests/PHPStan/Reflection/MixedTypeTest.php b/tests/PHPStan/Reflection/MixedTypeTest.php index 5c5248d38c..6ccc847d84 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/Reflection/ReflectionProviderGoldenTest.php b/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php index d7b8ee4599..870d185d59 100644 --- a/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php +++ b/tests/PHPStan/Reflection/ReflectionProviderGoldenTest.php @@ -341,7 +341,7 @@ private static function generateFunctionMethodBaseDescription($reflection): stri $result .= 'Is deprecated: ' . $reflection->isDeprecated()->describe() . "\n"; } - if (! $reflection->isFinal()->no()) { + if ($reflection instanceof MethodReflection && ! $reflection->isFinal()->no()) { $result .= 'Is final: ' . $reflection->isFinal()->describe() . "\n"; } @@ -364,7 +364,7 @@ private static function generateFunctionMethodBaseDescription($reflection): stri return $result; } - /** @param ParametersAcceptorWithPhpDocs[] $variants */ + /** @param ExtendedParametersAcceptor[] $variants */ private static function generateVariantsDescription(string $name, array $variants, bool $isNamedArguments): string { $variantCount = count($variants); diff --git a/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php b/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php index f912e0d78e..182a6582e9 100644 --- a/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php +++ b/tests/PHPStan/Reflection/SignatureMap/Php8SignatureMapProviderTest.php @@ -12,6 +12,7 @@ use PHPStan\Reflection\PassedByReference; use PHPStan\Reflection\ReflectionProvider\ReflectionProviderProvider; use PHPStan\Testing\PHPStanTestCase; +use PHPStan\Type\Accessory\AccessoryArrayListType; use PHPStan\Type\ArrayType; use PHPStan\Type\BenevolentUnionType; use PHPStan\Type\BooleanType; @@ -23,6 +24,7 @@ use PHPStan\Type\FileTypeMapper; use PHPStan\Type\IntegerRangeType; use PHPStan\Type\IntegerType; +use PHPStan\Type\IntersectionType; use PHPStan\Type\MixedType; use PHPStan\Type\NullType; use PHPStan\Type\ObjectType; @@ -99,14 +101,14 @@ public function dataFunctions(): array new ConstantStringType('errors'), ], [ IntegerRangeType::fromInterval(0, null), - new ArrayType(new IntegerType(), new StringType()), + new IntersectionType([new ArrayType(IntegerRangeType::fromInterval(0, null), new StringType()), new AccessoryArrayListType()]), IntegerRangeType::fromInterval(0, null), - new ArrayType(new IntegerType(), new StringType()), + new IntersectionType([new ArrayType(IntegerRangeType::fromInterval(0, null), new StringType()), new AccessoryArrayListType()]), ]), ]), new UnionType([ new ConstantBooleanType(false), - new ArrayType(new MixedType(true), new MixedType(true)), + new ArrayType(new MixedType(), new MixedType()), ]), false, ], @@ -206,7 +208,7 @@ public function dataMethods(): array 'variadic' => false, ], ], - new UnionType([ + new BenevolentUnionType([ new ObjectType('Closure'), new NullType(), ]), diff --git a/tests/PHPStan/Reflection/UnionTypesTest.php b/tests/PHPStan/Reflection/UnionTypesTest.php index d8977504d2..79fb96b28a 100644 --- a/tests/PHPStan/Reflection/UnionTypesTest.php +++ b/tests/PHPStan/Reflection/UnionTypesTest.php @@ -22,7 +22,7 @@ public function testUnionTypes(): void $this->assertSame('bool|int', $propertyType->describe(VerbosityLevel::precise())); $method = $class->getNativeMethod('doFoo'); - $methodVariant = ParametersAcceptorSelector::selectSingle($method->getVariants()); + $methodVariant = $method->getOnlyVariant(); $methodReturnType = $methodVariant->getReturnType(); $this->assertInstanceOf(UnionType::class, $methodReturnType); $this->assertSame('NativeUnionTypes\\Bar|NativeUnionTypes\\Foo', $methodReturnType->describe(VerbosityLevel::precise())); @@ -32,7 +32,7 @@ public function testUnionTypes(): void $this->assertSame('bool|int', $methodParameterType->describe(VerbosityLevel::precise())); $function = $reflectionProvider->getFunction(new Name('NativeUnionTypes\doFoo'), null); - $functionVariant = ParametersAcceptorSelector::selectSingle($function->getVariants()); + $functionVariant = $function->getOnlyVariant(); $functionReturnType = $functionVariant->getReturnType(); $this->assertInstanceOf(UnionType::class, $functionReturnType); $this->assertSame('NativeUnionTypes\\Bar|NativeUnionTypes\\Foo', $functionReturnType->describe(VerbosityLevel::precise())); diff --git a/tests/PHPStan/Reflection/data/anonymous-classes.php b/tests/PHPStan/Reflection/data/anonymous-classes.php index 9336316ff9..4024445aec 100644 --- a/tests/PHPStan/Reflection/data/anonymous-classes.php +++ b/tests/PHPStan/Reflection/data/anonymous-classes.php @@ -11,3 +11,23 @@ public function __construct(object $object) { } }; + +class A {} + +new class extends A {}; new class extends A {}; + +new class (new class extends A {}) extends A { + public function __construct(object $object) + { + } +}; + +interface U {} + +interface V {} + +new class implements U {}; + +new class implements U, V {}; + +new class implements V, U {}; diff --git a/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php b/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php index a6a68a9b5e..e14d95f33e 100644 --- a/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiClassImplementsRuleTest.php @@ -32,32 +32,32 @@ public function testRuleOutOfPhpStan(): void $this->analyse([__DIR__ . '/data/class-implements-out-of-phpstan.php'], [ [ 'Implementing PHPStan\DependencyInjection\Type\DynamicThrowTypeExtensionProvider is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', - 19, + 20, $tip, ], [ 'Implementing PHPStan\Type\Type is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', - 53, + 54, $tip, ], [ 'Implementing PHPStan\Reflection\ReflectionProvider is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', - 338, + 333, $tip, ], [ 'Implementing PHPStan\Analyser\Scope is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', - 343, + 338, $tip, ], [ 'Implementing PHPStan\Reflection\FunctionReflection is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', - 348, + 343, $tip, ], [ 'Implementing PHPStan\Reflection\ExtendedMethodReflection is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.', - 352, + 347, $tip, ], ]); diff --git a/tests/PHPStan/Rules/Api/ApiInstanceofTypeRuleTest.php b/tests/PHPStan/Rules/Api/ApiInstanceofTypeRuleTest.php index 6be9f18d4b..e12f8aaf14 100644 --- a/tests/PHPStan/Rules/Api/ApiInstanceofTypeRuleTest.php +++ b/tests/PHPStan/Rules/Api/ApiInstanceofTypeRuleTest.php @@ -13,7 +13,7 @@ class ApiInstanceofTypeRuleTest extends RuleTestCase public function getRule(): Rule { - return new ApiInstanceofTypeRule($this->createReflectionProvider(), true, true); + return new ApiInstanceofTypeRule($this->createReflectionProvider()); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleTest.php b/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleTest.php index 2e5388d2b1..c7fe99bc18 100644 --- a/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleTest.php @@ -13,7 +13,7 @@ class NodeConnectingVisitorAttributesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new NodeConnectingVisitorAttributesRule(self::getContainer()); + return new NodeConnectingVisitorAttributesRule(); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleWithVisitorRegisteredTest.php b/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleWithVisitorRegisteredTest.php deleted file mode 100644 index 569d7747eb..0000000000 --- a/tests/PHPStan/Rules/Api/NodeConnectingVisitorAttributesRuleWithVisitorRegisteredTest.php +++ /dev/null @@ -1,32 +0,0 @@ - - */ -class NodeConnectingVisitorAttributesRuleWithVisitorRegisteredTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new NodeConnectingVisitorAttributesRule(self::getContainer()); - } - - public function testRule(): void - { - $this->analyse([__DIR__ . '/data/node-connecting-visitor.php'], []); - } - - public static function getAdditionalConfigFiles(): array - { - return array_merge(parent::getAdditionalConfigFiles(), [ - __DIR__ . '/nodeConnectingVisitorCompatibility.neon', - ]); - } - -} diff --git a/tests/PHPStan/Rules/Api/OldPhpParser4ClassRuleTest.php b/tests/PHPStan/Rules/Api/OldPhpParser4ClassRuleTest.php new file mode 100644 index 0000000000..23892389dd --- /dev/null +++ b/tests/PHPStan/Rules/Api/OldPhpParser4ClassRuleTest.php @@ -0,0 +1,29 @@ + + */ +class OldPhpParser4ClassRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new OldPhpParser4ClassRule(); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/old-php-parser-4-class.php'], [ + [ + 'Class PhpParser\Node\Expr\ArrayItem not found. It has been renamed to PhpParser\Node\ArrayItem in PHP-Parser v5.', + 24, + ], + ]); + } + +} diff --git a/tests/PHPStan/Rules/Api/data/class-implements-out-of-phpstan.php b/tests/PHPStan/Rules/Api/data/class-implements-out-of-phpstan.php index c7b42d7e6e..6ded7325fb 100644 --- a/tests/PHPStan/Rules/Api/data/class-implements-out-of-phpstan.php +++ b/tests/PHPStan/Rules/Api/data/class-implements-out-of-phpstan.php @@ -5,6 +5,7 @@ use PhpParser\Node\Expr\FuncCall; use PHPStan\Analyser\Scope; use PHPStan\DependencyInjection\Type\DynamicThrowTypeExtensionProvider; +use PHPStan\Php\PhpVersion; use PHPStan\Reflection\ClassMemberAccessAnswerer; use PHPStan\Reflection\ExtendedMethodReflection; use PHPStan\Reflection\FunctionReflection; @@ -127,7 +128,7 @@ public function hasConstant(string $constantName): \PHPStan\TrinaryLogic // TODO: Implement hasConstant() method. } - public function getConstant(string $constantName): \PHPStan\Reflection\ConstantReflection + public function getConstant(string $constantName): \PHPStan\Reflection\ClassConstantReflection { // TODO: Implement getConstant() method. } @@ -247,12 +248,12 @@ public function toArrayKey(): \PHPStan\Type\Type // TODO: Implement toArrayKey() method. } - public function isSmallerThan(Type $otherType): \PHPStan\TrinaryLogic + public function isSmallerThan(Type $otherType, PhpVersion $phpVersion): \PHPStan\TrinaryLogic { // TODO: Implement isSmallerThan() method. } - public function isSmallerThanOrEqual(Type $otherType): \PHPStan\TrinaryLogic + public function isSmallerThanOrEqual(Type $otherType, PhpVersion $phpVersion): \PHPStan\TrinaryLogic { // TODO: Implement isSmallerThanOrEqual() method. } @@ -277,22 +278,22 @@ public function isLiteralString(): \PHPStan\TrinaryLogic // TODO: Implement isLiteralString() method. } - public function getSmallerType(): \PHPStan\Type\Type + public function getSmallerType(PhpVersion $phpVersion): \PHPStan\Type\Type { // TODO: Implement getSmallerType() method. } - public function getSmallerOrEqualType(): \PHPStan\Type\Type + public function getSmallerOrEqualType(PhpVersion $phpVersion): \PHPStan\Type\Type { // TODO: Implement getSmallerOrEqualType() method. } - public function getGreaterType(): \PHPStan\Type\Type + public function getGreaterType(PhpVersion $phpVersion): \PHPStan\Type\Type { // TODO: Implement getGreaterType() method. } - public function getGreaterOrEqualType(): \PHPStan\Type\Type + public function getGreaterOrEqualType(PhpVersion $phpVersion): \PHPStan\Type\Type { // TODO: Implement getGreaterOrEqualType() method. } @@ -327,12 +328,6 @@ public function tryRemove(Type $typeToRemove): ?Type // TODO: Implement tryRemove() method. } - public static function __set_state(array $properties): \PHPStan\Type\Type - { - // TODO: Implement __set_state() method. - } - - } abstract class Dolor implements ReflectionProvider diff --git a/tests/PHPStan/Rules/Api/data/old-php-parser-4-class.php b/tests/PHPStan/Rules/Api/data/old-php-parser-4-class.php new file mode 100644 index 0000000000..f9f017054f --- /dev/null +++ b/tests/PHPStan/Rules/Api/data/old-php-parser-4-class.php @@ -0,0 +1,32 @@ +getVariants()); // @api above class + ParametersAcceptorSelector::selectFromArgs($f->getVariants()); // @api above class ScopeContext::create(__DIR__ . '/test.php'); // @api above method } diff --git a/tests/PHPStan/Rules/Api/nodeConnectingVisitorCompatibility.neon b/tests/PHPStan/Rules/Api/nodeConnectingVisitorCompatibility.neon deleted file mode 100644 index efb020baea..0000000000 --- a/tests/PHPStan/Rules/Api/nodeConnectingVisitorCompatibility.neon +++ /dev/null @@ -1,3 +0,0 @@ -conditionalTags: - PhpParser\NodeVisitor\NodeConnectingVisitor: - phpstan.parser.richParserNodeVisitor: true diff --git a/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php b/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php deleted file mode 100644 index ea09ce0cb4..0000000000 --- a/tests/PHPStan/Rules/Arrays/AppendedArrayItemTypeRuleTest.php +++ /dev/null @@ -1,65 +0,0 @@ - - */ -class AppendedArrayItemTypeRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new AppendedArrayItemTypeRule( - new PropertyReflectionFinder(), - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), - ); - } - - public function testAppendedArrayItemType(): void - { - $this->analyse( - [__DIR__ . '/data/appended-array-item.php'], - [ - [ - 'Array (array) does not accept string.', - 18, - ], - [ - 'Array (array) does not accept array{1, 2, 3}.', - 20, - ], - [ - 'Array (array) does not accept array{\'AppendedArrayItem\\\\Foo\', \'classMethod\'}.', - 23, - ], - [ - 'Array (array) does not accept array{\'Foo\', \'Hello world\'}.', - 25, - ], - [ - 'Array (array) does not accept string.', - 27, - ], - [ - 'Array (array) does not accept string.', - 32, - ], - [ - 'Array (array) does not accept Closure(): 1.', - 45, - ], - [ - 'Array (array) does not accept AppendedArrayItem\Baz.', - 79, - ], - ], - ); - } - -} diff --git a/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php b/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php deleted file mode 100644 index d74a1ddd8e..0000000000 --- a/tests/PHPStan/Rules/Arrays/AppendedArrayKeyTypeRuleTest.php +++ /dev/null @@ -1,71 +0,0 @@ - - */ -class AppendedArrayKeyTypeRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new AppendedArrayKeyTypeRule( - new PropertyReflectionFinder(), - true, - ); - } - - public function testRule(): void - { - $this->analyse([__DIR__ . '/data/appended-array-key.php'], [ - [ - 'Array (array) does not accept key int|string.', - 28, - ], - [ - 'Array (array) does not accept key string.', - 30, - ], - [ - 'Array (array) does not accept key int.', - 31, - ], - [ - 'Array (array) does not accept key int|string.', - 33, - ], - [ - 'Array (array) does not accept key 0.', - 38, - ], - [ - 'Array (array) does not accept key 1.', - 46, - ], - [ - 'Array (array<1|2|3, string>) does not accept key int.', - 80, - ], - [ - 'Array (array<1|2|3, string>) does not accept key 4.', - 85, - ], - ]); - } - - public function testBug5372Two(): void - { - $this->analyse([__DIR__ . '/data/bug-5372_2.php'], []); - } - - public function testBug5447(): void - { - $this->analyse([__DIR__ . '/data/bug-5447.php'], []); - } - -} diff --git a/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php b/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php index a536ce6cf5..d37f09084b 100644 --- a/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php @@ -13,15 +13,13 @@ class ArrayDestructuringRuleTest extends RuleTestCase { - private bool $bleedingEdge = false; - protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false); return new ArrayDestructuringRule( $ruleLevelHelper, - new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->bleedingEdge, false, false), + new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, false, false), ); } diff --git a/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php b/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php index b733df51cd..cb14b900fe 100644 --- a/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/ArrayUnpackingRuleTest.php @@ -22,7 +22,7 @@ protected function getRule(): Rule { return new ArrayUnpackingRule( self::getContainer()->getByType(PhpVersion::class), - new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnions, false, false, true, $this->checkBenevolentUnions), + new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnions, false, false, $this->checkBenevolentUnions), ); } diff --git a/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php b/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php deleted file mode 100644 index 51ba629e16..0000000000 --- a/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ -class EmptyArrayItemRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new EmptyArrayItemRule(); - } - - public function testRule(): void - { - $this->analyse([__DIR__ . '/data/empty-array-item.php'], [ - [ - 'Literal array contains empty item.', - 5, - ], - ]); - } - -} diff --git a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php index 70c671135a..df337d9bdf 100644 --- a/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/InvalidKeyInArrayDimFetchRuleTest.php @@ -15,7 +15,7 @@ class InvalidKeyInArrayDimFetchRuleTest extends RuleTestCase protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false); return new InvalidKeyInArrayDimFetchRule($ruleLevelHelper, true); } diff --git a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php index dbb64b29ca..43c6020744 100644 --- a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php @@ -21,7 +21,7 @@ class IterableInForeachRuleTest extends RuleTestCase protected function getRule(): Rule { - return new IterableInForeachRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false)); + return new IterableInForeachRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false)); } public function testCheckWithMaybes(): void @@ -32,7 +32,7 @@ public function testCheckWithMaybes(): void 10, ], [ - 'Argument of an invalid type array|false supplied for foreach, only iterables are supported.', + 'Argument of an invalid type list|false supplied for foreach, only iterables are supported.', 19, ], [ @@ -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 6699adb5f7..e212c65218 100644 --- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php @@ -17,166 +17,23 @@ class NonexistentOffsetInArrayDimFetchRuleTest extends RuleTestCase private bool $checkImplicitMixed = false; - private bool $bleedingEdge = false; - private bool $reportPossiblyNonexistentGeneralArrayOffset = false; private bool $reportPossiblyNonexistentConstantArrayOffset = false; protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false); + $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false); return new NonexistentOffsetInArrayDimFetchRule( $ruleLevelHelper, - new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->bleedingEdge, $this->reportPossiblyNonexistentGeneralArrayOffset, $this->reportPossiblyNonexistentConstantArrayOffset), + new NonexistentOffsetInArrayDimFetchCheck($ruleLevelHelper, true, $this->reportPossiblyNonexistentGeneralArrayOffset, $this->reportPossiblyNonexistentConstantArrayOffset), true, ); } public function testRule(): void { - $this->analyse([__DIR__ . '/data/nonexistent-offset.php'], [ - [ - 'Offset \'b\' does not exist on array{a: stdClass, 0: 2}.', - 17, - ], - [ - 'Offset 1 does not exist on array{a: stdClass, 0: 2}.', - 18, - ], - [ - 'Offset \'a\' does not exist on array{b: 1}.', - 55, - ], - [ - 'Access to offset \'bar\' on an unknown class NonexistentOffset\Bar.', - 101, - 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ], - [ - 'Access to an offset on an unknown class NonexistentOffset\Bar.', - 102, - 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ], - [ - 'Offset 0 does not exist on array.', - 111, - ], - [ - 'Offset \'0\' does not exist on array.', - 112, - ], - [ - 'Offset int does not exist on array.', - 114, - ], - [ - 'Offset \'test\' does not exist on null.', - 126, - ], - [ - 'Cannot access offset 42 on int.', - 142, - ], - [ - 'Cannot access offset 42 on float.', - 143, - ], - [ - 'Cannot access offset 42 on bool.', - 144, - ], - [ - 'Cannot access offset 42 on resource.', - 145, - ], - [ - 'Offset \'c\' does not exist on array{c: false}|array{c: true}|array{e: true}.', - 171, - ], - [ - 'Offset int does not exist on array{}|array{1: 1, 2: 2}|array{3: 3, 4: 4}.', - 190, - ], - [ - 'Offset int does not exist on array{}|array{1: 1, 2: 2}|array{3: 3, 4: 4}.', - 193, - ], - [ - 'Offset \'b\' does not exist on array{a: \'blabla\'}.', - 225, - ], - [ - 'Offset \'b\' does not exist on array{a: \'blabla\'}.', - 228, - ], - [ - 'Cannot access offset \'a\' on Closure(): void.', - 253, - ], - [ - 'Cannot access offset \'a\' on array{a: 1, b: 1}|(Closure(): void).', - 258, - ], - [ - 'Offset null does not exist on array.', - 310, - ], - [ - 'Offset int does not exist on array.', - 312, - ], - [ - 'Offset \'baz\' does not exist on array{bar: 1, baz?: 2}.', - 344, - ], - [ - 'Offset \'foo\' does not exist on ArrayAccess.', - 411, - ], - [ - 'Cannot access offset \'foo\' on stdClass.', - 423, - ], - [ - 'Cannot access offset \'foo\' on true.', - 426, - ], - [ - 'Cannot access offset \'foo\' on false.', - 429, - ], - [ - 'Cannot access offset \'foo\' on resource.', - 433, - ], - [ - 'Cannot access offset \'foo\' on 42.', - 436, - ], - [ - 'Cannot access offset \'foo\' on 4.141.', - 439, - ], - [ - 'Cannot access offset \'foo\' on array|int.', - 443, - ], - [ - 'Offset \'feature_pretty…\' does not exist on array{version: non-falsy-string, commit: string|null, pretty_version: string|null, feature_version: non-falsy-string, feature_pretty_version?: string|null}.', - 504, - ], - [ - "Cannot access offset 'foo' on bool.", - 517, - ], - ]); - } - - public function testRuleBleedingEdge(): void - { - $this->bleedingEdge = true; $this->analyse([__DIR__ . '/data/nonexistent-offset.php'], [ [ 'Offset \'b\' does not exist on array{a: stdClass, 0: 2}.', @@ -305,7 +162,7 @@ public function testRuleBleedingEdge(): void 443, ], [ - 'Offset \'feature_pretty…\' might not exist on array{version: non-falsy-string, commit: string|null, pretty_version: string|null, feature_version: non-falsy-string, feature_pretty_version?: string|null}.', + 'Offset \'feature_pretty_version\' might not exist on array{version: non-falsy-string, commit: string|null, pretty_version: string|null, feature_version: non-falsy-string, feature_pretty_version?: string|null}.', 504, ], [ @@ -327,11 +184,11 @@ public function testStrings(): void 13, ], [ - 'Offset \'foo\' does not exist on array|string.', + 'Offset \'foo\' might not exist on array|string.', 24, ], [ - 'Offset 12.34 does not exist on array|string.', + 'Offset 12.34 might not exist on array|string.', 28, ], ]); @@ -531,7 +388,7 @@ public function testBug7000(): void { $this->analyse([__DIR__ . '/data/bug-7000.php'], [ [ - "Offset 'require'|'require-dev' does not exist on array{require?: array, require-dev?: array}.", + "Offset 'require'|'require-dev' might not exist on array{require?: array, require-dev?: array}.", 16, ], ]); @@ -687,19 +544,14 @@ public function testBug8068(): void public function testBug6243(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-6243.php'], []); } public function testBug8356(): void { - $this->bleedingEdge = true; $this->analyse([__DIR__ . '/data/bug-8356.php'], [ [ - "Offset 'x' might not exist on array|string.", + "Offset 'x' might not exist on array|string.", 7, ], ]); @@ -762,6 +614,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/OffsetAccessAssignOpRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php index 2daf7b7ed4..45750ac2a4 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignOpRuleTest.php @@ -17,7 +17,7 @@ class OffsetAccessAssignOpRuleTest extends RuleTestCase protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnions, false, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnions, false, false, false); return new OffsetAccessAssignOpRule($ruleLevelHelper); } diff --git a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php index 86420630c2..9049635db0 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessAssignmentRuleTest.php @@ -17,7 +17,7 @@ class OffsetAccessAssignmentRuleTest extends RuleTestCase protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnionTypes, false, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnionTypes, false, false, false); return new OffsetAccessAssignmentRule($ruleLevelHelper); } diff --git a/tests/PHPStan/Rules/Arrays/OffsetAccessValueAssignmentRuleTest.php b/tests/PHPStan/Rules/Arrays/OffsetAccessValueAssignmentRuleTest.php index 0129923ae8..38afbe6137 100644 --- a/tests/PHPStan/Rules/Arrays/OffsetAccessValueAssignmentRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/OffsetAccessValueAssignmentRuleTest.php @@ -15,7 +15,7 @@ class OffsetAccessValueAssignmentRuleTest extends RuleTestCase protected function getRule(): Rule { - return new OffsetAccessValueAssignmentRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new OffsetAccessValueAssignmentRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php index 32d4900686..ba43922b08 100644 --- a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php +++ b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php @@ -21,7 +21,7 @@ class UnpackIterableInArrayRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UnpackIterableInArrayRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false)); + return new UnpackIterableInArrayRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false)); } public function testRule(): void @@ -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/Arrays/data/array-unpacking.php b/tests/PHPStan/Rules/Arrays/data/array-unpacking.php index d7d1e64de5..ff2f652cac 100644 --- a/tests/PHPStan/Rules/Arrays/data/array-unpacking.php +++ b/tests/PHPStan/Rules/Arrays/data/array-unpacking.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 7.4 +createReflectionProvider(), true, false, true, false, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), ); } @@ -47,6 +47,10 @@ public function testEchoRule(): void 'Parameter #1 (\'string\'|array{\'string\'}) of echo cannot be converted to string.', 17, ], + [ + 'Parameter #1 (array{}) of echo cannot be converted to string.', + 29, + ], ]); } diff --git a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php index 5734b47928..ee36958b19 100644 --- a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php +++ b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php @@ -22,7 +22,7 @@ class InvalidCastRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new InvalidCastRule($broker, new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false)); + return new InvalidCastRule($broker, new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false)); } public function testRule(): void @@ -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/Cast/InvalidPartOfEncapsedStringRuleTest.php b/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php index 3ba7d5ce61..4503a788e8 100644 --- a/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php +++ b/tests/PHPStan/Rules/Cast/InvalidPartOfEncapsedStringRuleTest.php @@ -19,7 +19,7 @@ protected function getRule(): Rule { return new InvalidPartOfEncapsedStringRule( new ExprPrinter(new Printer()), - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), ); } diff --git a/tests/PHPStan/Rules/Cast/PrintRuleTest.php b/tests/PHPStan/Rules/Cast/PrintRuleTest.php index c7a52e8123..b3a71307ec 100644 --- a/tests/PHPStan/Rules/Cast/PrintRuleTest.php +++ b/tests/PHPStan/Rules/Cast/PrintRuleTest.php @@ -16,7 +16,7 @@ class PrintRuleTest extends RuleTestCase protected function getRule(): Rule { return new PrintRule( - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), ); } diff --git a/tests/PHPStan/Rules/Cast/data/echo.php b/tests/PHPStan/Rules/Cast/data/echo.php index 0235559328..a8f0b53da0 100644 --- a/tests/PHPStan/Rules/Cast/data/echo.php +++ b/tests/PHPStan/Rules/Cast/data/echo.php @@ -23,3 +23,9 @@ function (array $test) /** @var string $test */ echo $test; }; + +function (): void { + { + echo []; + } +}; diff --git a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php index f0deeee108..d4a9dc96d5 100644 --- a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Classes; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -33,16 +32,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), @@ -168,4 +165,28 @@ public function testBug12011(): void ]); } + public function testBug12281(): void + { + if (PHP_VERSION_ID < 80200) { + $this->markTestSkipped('Test requires PHP 8.2.'); + } + + $this->checkExplicitMixed = true; + $this->checkImplicitMixed = true; + $this->analyse([__DIR__ . '/data/bug-12281.php'], [ + [ + 'Attribute class AllowDynamicProperties cannot be used with readonly class.', + 05, + ], + [ + 'Attribute class AllowDynamicProperties cannot be used with enum.', + 12, + ], + [ + 'Attribute class AllowDynamicProperties cannot be used with interface.', + 15, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php index b132e3fe08..64b9783877 100644 --- a/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Classes; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -28,16 +27,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), diff --git a/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php b/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php index 42378de1f2..d8bb82d141 100644 --- a/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php @@ -24,7 +24,7 @@ protected function getRule(): Rule $reflectionProvider = $this->createReflectionProvider(); return new ClassConstantRule( $reflectionProvider, - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), 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/Classes/ForbiddenNameCheckExtensionRuleTest.php b/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php index 9d3ea64034..5286e079fc 100644 --- a/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Classes; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; use PHPStan\Rules\ClassNameCheck; @@ -26,7 +25,7 @@ protected function getRule(): Rule $reflectionProvider = $this->createReflectionProvider(); return new InstantiationRule( $reflectionProvider, - new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), diff --git a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php index fde28cab1a..a7c21443f1 100644 --- a/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ImpossibleInstanceOfRuleTest.php @@ -12,8 +12,6 @@ class ImpossibleInstanceOfRuleTest extends RuleTestCase { - private bool $checkAlwaysTrueInstanceOf; - private bool $treatPhpDocTypesAsCertain; private bool $reportAlwaysTrueInLastCondition = false; @@ -21,7 +19,6 @@ class ImpossibleInstanceOfRuleTest extends RuleTestCase protected function getRule(): Rule { return new ImpossibleInstanceOfRule( - $this->checkAlwaysTrueInstanceOf, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, true, @@ -35,7 +32,6 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testInstanceof(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse( @@ -196,107 +192,8 @@ public function testInstanceof(): void ); } - public function testInstanceofWithoutAlwaysTrue(): void - { - $this->checkAlwaysTrueInstanceOf = false; - $this->treatPhpDocTypesAsCertain = true; - - $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse( - [__DIR__ . '/data/impossible-instanceof.php'], - [ - [ - 'Instanceof between ImpossibleInstanceOf\Dolor and ImpossibleInstanceOf\Lorem will always evaluate to false.', - 71, - ], - [ - 'Instanceof between string and ImpossibleInstanceOf\Foo will always evaluate to false.', - 94, - ], - [ - 'Instanceof between string and \'str\' will always evaluate to false.', - 98, - ], - [ - 'Instanceof between ImpossibleInstanceOf\Test|null and ImpossibleInstanceOf\Lorem will always evaluate to false.', - 119, - ], - [ - 'Instanceof between ImpossibleInstanceOf\Test|null and ImpossibleInstanceOf\Lorem will always evaluate to false.', - 137, - ], - [ - 'Instanceof between ImpossibleInstanceOf\Test|null and ImpossibleInstanceOf\Lorem will always evaluate to false.', - 155, - ], - [ - 'Instanceof between callable and ImpossibleInstanceOf\FinalClassWithoutInvoke will always evaluate to false.', - 204, - ], - [ - 'Instanceof between *NEVER* and ImpossibleInstanceOf\Lorem will always evaluate to false.', - 228, - ], - [ - 'Instanceof between *NEVER* and ImpossibleInstanceOf\Foo will always evaluate to false.', - 234, - ], - [ - 'Instanceof between *NEVER* and ImpossibleInstanceOf\Bar will always evaluate to false.', - 240, - //$tipText, - ], - [ - 'Instanceof between object and Exception will always evaluate to false.', - 303, - ], - [ - 'Instanceof between object and InvalidArgumentException will always evaluate to false.', - 307, - ], - [ - 'Instanceof between ImpossibleInstanceOf\Bar and ImpossibleInstanceOf\BarChild will always evaluate to false.', - 318, - ], - [ - 'Instanceof between ImpossibleInstanceOf\Bar and ImpossibleInstanceOf\BarGrandChild will always evaluate to false.', - 322, - ], - /*[ - 'Instanceof between mixed and int results in an error.', - 353, - ], - [ - 'Instanceof between mixed and ImpossibleInstanceOf\InvalidTypeTest|int results in an error.', - 362, - ],*/ - [ - 'Instanceof between T of Exception and Error will always evaluate to false.', - 404, - $tipText, - ], - [ - 'Instanceof between class-string and DateTimeInterface will always evaluate to false.', - 418, - $tipText, - ], - [ - 'Instanceof between class-string and class-string will always evaluate to false.', - 419, - $tipText, - ], - [ - 'Instanceof between class-string and \'DateTimeInterface\' will always evaluate to false.', - 432, - $tipText, - ], - ], - ); - } - public function testDoNotReportTypesFromPhpDocs(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/impossible-instanceof-not-phpdoc.php'], [ [ @@ -320,7 +217,6 @@ public function testDoNotReportTypesFromPhpDocs(): void public function testReportTypesFromPhpDocs(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/impossible-instanceof-not-phpdoc.php'], [ [ @@ -354,21 +250,18 @@ public function testReportTypesFromPhpDocs(): void public function testBug3096(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-3096.php'], []); } public function testBug6213(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6213.php'], []); } public function testBug5333(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-5333.php'], []); } @@ -379,7 +272,6 @@ public function testBug8042(): void $this->markTestSkipped('This test needs PHP 8.0'); } - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-8042.php'], [ [ @@ -401,14 +293,12 @@ public function testBug7721(): void $this->markTestSkipped('This test needs PHP 8.1'); } - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-7721.php'], []); } public function testUnreachableIfBranches(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../Comparison/data/unreachable-if-branches.php'], [ [ @@ -433,7 +323,6 @@ public function testUnreachableIfBranches(): void public function testIfBranchesDoNotReportPhpDoc(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/../Comparison/data/unreachable-if-branches-not-phpdoc.php'], [ [ @@ -455,7 +344,6 @@ public function testIfBranchesDoNotReportPhpDoc(): void public function testIfBranchesReportPhpDoc(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse([__DIR__ . '/../Comparison/data/unreachable-if-branches-not-phpdoc.php'], [ @@ -493,7 +381,6 @@ public function testIfBranchesReportPhpDoc(): void public function testUnreachableTernaryElse(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../Comparison/data/unreachable-ternary-else-branch.php'], [ [ @@ -509,7 +396,6 @@ public function testUnreachableTernaryElse(): void public function testTernaryElseDoNotReportPhpDoc(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/../Comparison/data/unreachable-ternary-else-branch-not-phpdoc.php'], [ [ @@ -529,7 +415,6 @@ public function testTernaryElseDoNotReportPhpDoc(): void public function testTernaryElseReportPhpDoc(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse([__DIR__ . '/../Comparison/data/unreachable-ternary-else-branch-not-phpdoc.php'], [ @@ -555,7 +440,6 @@ public function testTernaryElseReportPhpDoc(): void public function testBug4689(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-4689.php'], []); } @@ -591,7 +475,6 @@ public function dataReportAlwaysTrueInLastCondition(): iterable */ public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLastCondition, array $expectedErrors): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; $this->analyse([__DIR__ . '/data/impossible-instanceof-report-always-true-last-condition.php'], $expectedErrors); @@ -603,7 +486,6 @@ public function testBug10201(): void $this->markTestSkipped('This test needs PHP 8.1'); } - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-10201.php'], [ [ @@ -615,7 +497,6 @@ public function testBug10201(): void public function testBug3632(): void { - $this->checkAlwaysTrueInstanceOf = true; $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; diff --git a/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php b/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php index 36dc32c352..e4155ce55b 100644 --- a/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php +++ b/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Classes; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; use PHPStan\Rules\ClassNameCheck; @@ -26,7 +25,7 @@ protected function getRule(): Rule $reflectionProvider = $this->createReflectionProvider(); return new InstantiationRule( $reflectionProvider, - new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), @@ -290,6 +289,10 @@ public function testBug4056(): void public function testNamedArguments(): void { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + $this->analyse([__DIR__ . '/data/instantiation-named-arguments.php'], [ [ 'Missing parameter $j (int) in call to InstantiationNamedArguments\Foo constructor.', @@ -442,10 +445,6 @@ public function testBug7594(): void public function testBug3311a(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-3311a.php'], [ [ 'Parameter #1 $bar of class Bug3311a\Foo constructor expects list, array{1: \'baz\'} given.', @@ -503,4 +502,13 @@ public function testBug10248(): void $this->analyse([__DIR__ . '/data/bug-10248.php'], []); } + public function testBug11815(): void + { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + + $this->analyse([__DIR__ . '/data/bug-11815.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php index e8c07ca171..47b81f1ea1 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php @@ -28,7 +28,7 @@ protected function getRule(): Rule ['GlobalTypeAlias' => 'int|string'], $this->createReflectionProvider(), self::getContainer()->getByType(TypeNodeResolver::class), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), @@ -37,7 +37,6 @@ protected function getRule(): Rule new GenericObjectTypeCheck(), true, true, - true, ), ); } diff --git a/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php index fb443854df..76dc96f81c 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php @@ -27,7 +27,7 @@ protected function getRule(): Rule ['GlobalTypeAlias' => 'int|string'], $this->createReflectionProvider(), self::getContainer()->getByType(TypeNodeResolver::class), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), @@ -36,7 +36,6 @@ protected function getRule(): Rule new GenericObjectTypeCheck(), true, true, - true, ), $this->createReflectionProvider(), ); diff --git a/tests/PHPStan/Rules/Classes/LocalTypeTraitUseAliasesRuleTest.php b/tests/PHPStan/Rules/Classes/LocalTypeTraitUseAliasesRuleTest.php index 58ddda39a4..a84377316b 100644 --- a/tests/PHPStan/Rules/Classes/LocalTypeTraitUseAliasesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/LocalTypeTraitUseAliasesRuleTest.php @@ -27,7 +27,7 @@ protected function getRule(): Rule ['GlobalTypeAlias' => 'int|string'], $this->createReflectionProvider(), self::getContainer()->getByType(TypeNodeResolver::class), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), @@ -36,7 +36,6 @@ protected function getRule(): Rule new GenericObjectTypeCheck(), true, true, - true, ), ); } diff --git a/tests/PHPStan/Rules/Classes/MethodTagRuleTest.php b/tests/PHPStan/Rules/Classes/MethodTagRuleTest.php index 7766e03bd8..ae7ff38ec5 100644 --- a/tests/PHPStan/Rules/Classes/MethodTagRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MethodTagRuleTest.php @@ -29,7 +29,7 @@ protected function getRule(): TRule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/Classes/MethodTagTraitRuleTest.php b/tests/PHPStan/Rules/Classes/MethodTagTraitRuleTest.php index 74f70ca72d..fce38f5d98 100644 --- a/tests/PHPStan/Rules/Classes/MethodTagTraitRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MethodTagTraitRuleTest.php @@ -29,7 +29,7 @@ protected function getRule(): TRule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/Classes/MethodTagTraitUseRuleTest.php b/tests/PHPStan/Rules/Classes/MethodTagTraitUseRuleTest.php index 7839c99123..5317938620 100644 --- a/tests/PHPStan/Rules/Classes/MethodTagTraitUseRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MethodTagTraitUseRuleTest.php @@ -30,7 +30,7 @@ protected function getRule(): TRule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/Classes/MixinRuleTest.php b/tests/PHPStan/Rules/Classes/MixinRuleTest.php index b1a1bb39ca..e05283e71b 100644 --- a/tests/PHPStan/Rules/Classes/MixinRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MixinRuleTest.php @@ -30,11 +30,10 @@ protected function getRule(): Rule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, - true, ), ); } diff --git a/tests/PHPStan/Rules/Classes/MixinTraitRuleTest.php b/tests/PHPStan/Rules/Classes/MixinTraitRuleTest.php index a16f6ac23f..9465723963 100644 --- a/tests/PHPStan/Rules/Classes/MixinTraitRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MixinTraitRuleTest.php @@ -29,11 +29,10 @@ protected function getRule(): Rule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, - true, ), $reflectionProvider, ); diff --git a/tests/PHPStan/Rules/Classes/MixinTraitUseRuleTest.php b/tests/PHPStan/Rules/Classes/MixinTraitUseRuleTest.php index 08d3bb1c02..c94636b5e1 100644 --- a/tests/PHPStan/Rules/Classes/MixinTraitUseRuleTest.php +++ b/tests/PHPStan/Rules/Classes/MixinTraitUseRuleTest.php @@ -29,11 +29,10 @@ protected function getRule(): Rule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, - true, ), ); } diff --git a/tests/PHPStan/Rules/Classes/PropertyTagRuleTest.php b/tests/PHPStan/Rules/Classes/PropertyTagRuleTest.php index 7b36d89e90..4ec02315e1 100644 --- a/tests/PHPStan/Rules/Classes/PropertyTagRuleTest.php +++ b/tests/PHPStan/Rules/Classes/PropertyTagRuleTest.php @@ -29,7 +29,7 @@ protected function getRule(): TRule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/Classes/PropertyTagTraitRuleTest.php b/tests/PHPStan/Rules/Classes/PropertyTagTraitRuleTest.php index 3e6ff6c953..1266a5a553 100644 --- a/tests/PHPStan/Rules/Classes/PropertyTagTraitRuleTest.php +++ b/tests/PHPStan/Rules/Classes/PropertyTagTraitRuleTest.php @@ -29,7 +29,7 @@ protected function getRule(): TRule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/Classes/PropertyTagTraitUseRuleTest.php b/tests/PHPStan/Rules/Classes/PropertyTagTraitUseRuleTest.php index 76b4342abe..f45a1b894d 100644 --- a/tests/PHPStan/Rules/Classes/PropertyTagTraitUseRuleTest.php +++ b/tests/PHPStan/Rules/Classes/PropertyTagTraitUseRuleTest.php @@ -29,7 +29,7 @@ protected function getRule(): TRule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/Classes/RequireImplementsRuleTest.php b/tests/PHPStan/Rules/Classes/RequireImplementsRuleTest.php index a2fe9cf7a3..6a147e9398 100644 --- a/tests/PHPStan/Rules/Classes/RequireImplementsRuleTest.php +++ b/tests/PHPStan/Rules/Classes/RequireImplementsRuleTest.php @@ -57,7 +57,7 @@ public function testRule(): void 137, ], [ - 'Trait IncompatibleRequireImplements\ValidPsalmTrait requires using class to implement IncompatibleRequireImplements\RequiredInterface2, but class@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-implements.php:164 does not.', + 'Trait IncompatibleRequireImplements\ValidPsalmTrait requires using class to implement IncompatibleRequireImplements\RequiredInterface2, but IncompatibleRequireImplements\RequiredInterface@anonymous/tests/PHPStan/Rules/PhpDoc/data/incompatible-require-implements.php:164 does not.', 164, ], [ diff --git a/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php b/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php index b6530920df..beb402c267 100644 --- a/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php +++ b/tests/PHPStan/Rules/Classes/UnusedConstructorParametersRuleTest.php @@ -12,15 +12,19 @@ class UnusedConstructorParametersRuleTest extends RuleTestCase { + private bool $reportExactLine = true; + protected function getRule(): Rule { return new UnusedConstructorParametersRule(new UnusedFunctionParametersCheck( $this->createReflectionProvider(), + $this->reportExactLine, )); } - public function testUnusedConstructorParameters(): void + public function testUnusedConstructorParametersNoExactLine(): void { + $this->reportExactLine = false; $this->analyse([__DIR__ . '/data/unused-constructor-parameters.php'], [ [ 'Constructor of class UnusedConstructorParameters\Foo has an unused parameter $unusedParameter.', @@ -33,6 +37,20 @@ public function testUnusedConstructorParameters(): void ]); } + public function testUnusedConstructorParameters(): void + { + $this->analyse([__DIR__ . '/data/unused-constructor-parameters.php'], [ + [ + 'Constructor of class UnusedConstructorParameters\Foo has an unused parameter $unusedParameter.', + 19, + ], + [ + 'Constructor of class UnusedConstructorParameters\Foo has an unused parameter $anotherUnusedParameter.', + 20, + ], + ]); + } + public function testPromotedProperties(): void { $this->analyse([__DIR__ . '/data/unused-constructor-parameters-promoted-properties.php'], []); diff --git a/tests/PHPStan/Rules/Classes/data/bug-11815.php b/tests/PHPStan/Rules/Classes/data/bug-11815.php new file mode 100644 index 0000000000..c08dccb9ea --- /dev/null +++ b/tests/PHPStan/Rules/Classes/data/bug-11815.php @@ -0,0 +1,43 @@ += 8.2 + +declare(strict_types = 1); + +class Dimensions +{ + public function __construct( + public int $width, + public int $height, + ) { + } +} + +class StoreProcessorResult +{ + public function __construct( + public string $path, + public string $mimetype, + public Dimensions $dimensions, + public int $filesize, + public true|null $identical = null, + ) { + } +} + +/** + * @return array{path: string, identical?: true} + */ +function getPath(): array +{ + $data = ['path' => 'some/path']; + if ((bool)rand(0, 1)) { + $data['identical'] = true; + } + return $data; +} + +$data = getPath(); +$data['dimensions'] = new Dimensions(100, 100); +$data['mimetype'] = 'image/png'; +$data['filesize'] = 123456; + +$dto = new StoreProcessorResult(...$data); diff --git a/tests/PHPStan/Rules/Classes/data/bug-12281.php b/tests/PHPStan/Rules/Classes/data/bug-12281.php new file mode 100644 index 0000000000..293d9e5e41 --- /dev/null +++ b/tests/PHPStan/Rules/Classes/data/bug-12281.php @@ -0,0 +1,16 @@ += 8.2 + +namespace Bug12281; + +#[\AllowDynamicProperties] +readonly class BlogData { /* … */ } + +/** @readonly */ +#[\AllowDynamicProperties] +class BlogDataPhpdoc { /* … */ } + +#[\AllowDynamicProperties] +enum BlogDataEnum { /* … */ } + +#[\AllowDynamicProperties] +interface BlogDataInterface { /* … */ } diff --git a/tests/PHPStan/Rules/Classes/data/bug-3311a.php b/tests/PHPStan/Rules/Classes/data/bug-3311a.php index d4f646deb5..bb28ed1eb1 100644 --- a/tests/PHPStan/Rules/Classes/data/bug-3311a.php +++ b/tests/PHPStan/Rules/Classes/data/bug-3311a.php @@ -1,4 +1,4 @@ -= 7.4 +', $foo); - assertNativeType('array', $foo); + assertNativeType('array', $foo); assertType('Bug5333\Route', $res); assertNativeType('Bug5333\Route', $res); diff --git a/tests/PHPStan/Rules/Classes/data/bug-9946.php b/tests/PHPStan/Rules/Classes/data/bug-9946.php index 839ac021a1..e2cb92f5f2 100644 --- a/tests/PHPStan/Rules/Classes/data/bug-9946.php +++ b/tests/PHPStan/Rules/Classes/data/bug-9946.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 +getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - $this->bleedingEdge, $this->reportAlwaysTrueInLastCondition, true, ); @@ -140,90 +135,6 @@ public function testRuleLogicalAnd(): void { $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/boolean-logical-and.php'], [ - [ - 'Left side of && is always true.', - 15, - ], - [ - 'Right side of && is always true.', - 19, - ], - [ - 'Left side of && is always false.', - 24, - ], - [ - 'Right side of && is always false.', - 27, - ], - [ - 'Result of && is always false.', - 30, - ], - [ - 'Right side of && is always true.', - 33, - ], - [ - 'Right side of && is always true.', - 36, - ], - [ - 'Right side of && is always true.', - 39, - ], - [ - 'Result of && is always false.', - 50, - ], - [ - 'Result of && is always true.', - 54, - $tipText, - ], - [ - 'Result of && is always false.', - 60, - ], - [ - 'Result of && is always true.', - 64, - //$tipText, - ], - [ - 'Result of && is always false.', - 66, - //$tipText, - ], - [ - 'Result of && is always false.', - 125, - ], - [ - 'Left side of && is always false.', - 139, - ], - [ - 'Right side of && is always false.', - 141, - ], - [ - 'Left side of && is always true.', - 145, - ], - [ - 'Right side of && is always true.', - 147, - ], - ]); - } - - public function testRuleLogicalAndBleedingEdge(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->bleedingEdge = true; - $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse([__DIR__ . '/data/boolean-logical-and.php'], [ [ 'Left side of and is always true.', diff --git a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php index f8bb760dcf..ce5d1615f4 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanNotConstantConditionRuleTest.php @@ -4,7 +4,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -25,10 +24,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, @@ -127,10 +124,6 @@ public function testTreatPhpDocTypesAsCertainRegression(bool $treatPhpDocTypesAs public function testBug6473(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6473.php'], []); } diff --git a/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php index 38092ce153..ca46233349 100644 --- a/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/BooleanOrConstantConditionRuleTest.php @@ -14,8 +14,6 @@ class BooleanOrConstantConditionRuleTest extends RuleTestCase private bool $treatPhpDocTypesAsCertain; - private bool $bleedingEdge = false; - private bool $reportAlwaysTrueInLastCondition = false; protected function getRule(): Rule @@ -27,13 +25,10 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - $this->bleedingEdge, $this->reportAlwaysTrueInLastCondition, true, ); @@ -132,81 +127,6 @@ public function testRuleLogicalOr(): void { $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/boolean-logical-or.php'], [ - [ - 'Left side of || is always true.', - 15, - ], - [ - 'Right side of || is always true.', - 19, - ], - [ - 'Left side of || is always false.', - 24, - ], - [ - 'Right side of || is always false.', - 27, - ], - [ - 'Right side of || is always true.', - 30, - ], - [ - 'Result of || is always true.', - 33, - ], - [ - 'Right side of || is always false.', - 36, - ], - [ - 'Right side of || is always false.', - 39, - ], - [ - 'Result of || is always true.', - 50, - $tipText, - ], - [ - 'Result of || is always true.', - 54, - $tipText, - ], - [ - 'Result of || is always true.', - 61, - ], - [ - 'Result of || is always true.', - 65, - ], - [ - 'Left side of || is always false.', - 77, - ], - [ - 'Right side of || is always false.', - 79, - ], - [ - 'Left side of || is always true.', - 83, - ], - [ - 'Right side of || is always true.', - 85, - ], - ]); - } - - public function testRuleLogicalOrBleedingEdge(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->bleedingEdge = true; - $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse([__DIR__ . '/data/boolean-logical-or.php'], [ [ 'Left side of or is always true.', diff --git a/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php b/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php index 213b9df52d..e0bbf466ab 100644 --- a/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ConstantLooseComparisonRuleTest.php @@ -12,8 +12,6 @@ class ConstantLooseComparisonRuleTest extends RuleTestCase { - private bool $checkAlwaysTrueStrictComparison; - private bool $treatPhpDocTypesAsCertain = true; private bool $reportAlwaysTrueInLastCondition = false; @@ -21,7 +19,6 @@ class ConstantLooseComparisonRuleTest extends RuleTestCase protected function getRule(): Rule { return new ConstantLooseComparisonRule( - $this->checkAlwaysTrueStrictComparison, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, true, @@ -30,31 +27,6 @@ protected function getRule(): Rule public function testRule(): void { - $this->checkAlwaysTrueStrictComparison = false; - $this->analyse([__DIR__ . '/data/loose-comparison.php'], [ - [ - "Loose comparison using == between 0 and '1' will always evaluate to false.", - 20, - ], - [ - "Loose comparison using == between 0 and '1' will always evaluate to false.", - 27, - ], - [ - "Loose comparison using == between 0 and '1' will always evaluate to false.", - 33, - ], - [ - 'Loose comparison using != between 3 and 3 will always evaluate to false.', - 48, - 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', - ], - ]); - } - - public function testRuleAlwaysTrue(): void - { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/loose-comparison.php'], [ [ "Loose comparison using == between 0 and '0' will always evaluate to true.", @@ -91,7 +63,6 @@ public function testBug8485(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8485.php'], [ [ 'Loose comparison using == between Bug8485\E::c and Bug8485\E::c will always evaluate to true.', @@ -143,7 +114,6 @@ public function dataReportAlwaysTrueInLastCondition(): iterable */ public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLastCondition, array $expectedErrors): void { - $this->checkAlwaysTrueStrictComparison = true; $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; $this->analyse([__DIR__ . '/data/loose-comparison-report-always-true-last-condition.php'], $expectedErrors); } @@ -166,14 +136,12 @@ public function dataTreatPhpDocTypesAsCertain(): iterable */ public function testTreatPhpDocTypesAsCertain(bool $treatPhpDocTypesAsCertain, array $expectedErrors): void { - $this->checkAlwaysTrueStrictComparison = true; $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; $this->analyse([__DIR__ . '/data/loose-comparison-treat-phpdoc-types.php'], $expectedErrors); } public function testBug11694(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-11694.php'], [ [ 'Loose comparison using == between 3 and int<10, 20> will always evaluate to false.', diff --git a/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php index 7d05804a46..38f3237a45 100644 --- a/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/DoWhileLoopConstantConditionRuleTest.php @@ -22,10 +22,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, true, diff --git a/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php index 6c51033309..8a994666be 100644 --- a/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ElseIfConstantConditionRuleTest.php @@ -25,10 +25,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, diff --git a/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php index 479f5db928..1f03a122bd 100644 --- a/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/IfConstantConditionRuleTest.php @@ -23,10 +23,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, true, @@ -169,4 +167,10 @@ public function testBug10561(): void $this->analyse([__DIR__ . '/data/bug-10561.php'], []); } + public function testBug4912(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-4912.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php index 16529f3a74..5480eb394c 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php @@ -17,8 +17,6 @@ class ImpossibleCheckTypeFunctionCallRuleTest extends RuleTestCase { - private bool $checkAlwaysTrueCheckTypeFunctionCall; - private bool $treatPhpDocTypesAsCertain; private bool $reportAlwaysTrueInLastCondition = false; @@ -31,9 +29,7 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [stdClass::class], $this->treatPhpDocTypesAsCertain, - true, ), - $this->checkAlwaysTrueCheckTypeFunctionCall, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, true, @@ -47,7 +43,10 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testImpossibleCheckTypeFunctionCall(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->treatPhpDocTypesAsCertain = true; $this->analyse( [__DIR__ . '/data/check-type-function-call.php'], @@ -268,117 +267,12 @@ public function testImpossibleCheckTypeFunctionCall(): void public function testBug7898(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-7898.php'], []); } - public function testImpossibleCheckTypeFunctionCallWithoutAlwaysTrue(): void - { - $this->checkAlwaysTrueCheckTypeFunctionCall = false; - $this->treatPhpDocTypesAsCertain = true; - $this->analyse( - [__DIR__ . '/data/check-type-function-call.php'], - [ - [ - 'Call to function is_int() with string will always evaluate to false.', - 31, - ], - [ - 'Call to function is_callable() with array will always evaluate to false.', - 44, - 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', - ], - [ - 'Call to function assert() with false will always evaluate to false.', - 48, - ], - [ - 'Call to function is_callable() with \'nonexistentFunction\' will always evaluate to false.', - 87, - ], - [ - 'Call to function is_numeric() with \'blabla\' will always evaluate to false.', - 105, - ], - [ - 'Call to function method_exists() with $this(CheckTypeFunctionCall\FinalClassWithMethodExists) and \'doBar\' will always evaluate to false.', - 194, - ], - [ - 'Call to function in_array() with arguments int, array{\'foo\', \'bar\'} and true will always evaluate to false.', - 236, - ], - [ - 'Call to function in_array() with arguments \'bar\'|\'foo\', array{\'baz\', \'lorem\'} and true will always evaluate to false.', - 245, - ], - [ - 'Call to function in_array() with arguments \'bar\', array{}|array{\'foo\'} and true will always evaluate to false.', - 321, - ], - [ - 'Call to function in_array() with arguments \'baz\', array{0: \'bar\', 1?: \'foo\'} and true will always evaluate to false.', - 337, - ], - [ - 'Call to function in_array() with arguments \'foo\', array{} and true will always evaluate to false.', - 344, - ], - [ - 'Call to function array_key_exists() with \'c\' and array{a: 1, b?: 2} will always evaluate to false.', - 367, - ], - [ - 'Call to function is_string() with mixed will always evaluate to false.', - 561, - ], - [ - 'Call to function is_callable() with mixed will always evaluate to false.', - 572, - ], - [ - 'Call to function method_exists() with \'UndefinedClass\' and string will always evaluate to false.', - 595, - ], - [ - 'Call to function method_exists() with \'UndefinedClass\' and \'test\' will always evaluate to false.', - 598, - ], - [ - 'Call to function method_exists() with $this(CheckTypeFunctionCall\MethodExistsWithTrait) and \'unknown\' will always evaluate to false.', - 631, - ], - [ - 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', - 640, - 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', - ], - [ - 'Call to function method_exists() with \'CheckTypeFunctionCall\\\\MethodExistsWithTrait\' and \'unknown\' will always evaluate to false.', - 649, - ], - [ - 'Call to function assert() with false will always evaluate to false.', - 694, - 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', - ], - [ - 'Call to function is_numeric() with \'blabla\' will always evaluate to false.', - 694, - ], - [ - 'Call to function in_array() with arguments 1, array and true will always evaluate to false.', - 927, - 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', - ], - ], - ); - } - public function testDoNotReportTypesFromPhpDocs(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/check-type-function-call-not-phpdoc.php'], [ [ @@ -390,7 +284,6 @@ public function testDoNotReportTypesFromPhpDocs(): void public function testReportTypesFromPhpDocs(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/check-type-function-call-not-phpdoc.php'], [ [ @@ -417,42 +310,36 @@ public function testReportTypesFromPhpDocs(): void public function testBug2550(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-2550.php'], []); } public function testBug3994(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-3994.php'], []); } public function testBug1613(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-1613.php'], []); } public function testBug2714(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-2714.php'], []); } public function testBug4657(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-4657.php'], []); } public function testBug4999(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-4999.php'], []); } @@ -463,7 +350,6 @@ public function testArrayIsList(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/array-is-list.php'], [ [ @@ -484,14 +370,12 @@ public function testArrayIsList(): void public function testBug3766(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-3766.php'], []); } public function testBug6305(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6305.php'], [ [ @@ -507,21 +391,18 @@ public function testBug6305(): void public function testBug6698(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6698.php'], []); } public function testBug5369(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-5369.php'], []); } public function testBugInArrayDateFormat(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/in-array-date-format.php'], [ [ @@ -548,70 +429,64 @@ public function testBugInArrayDateFormat(): void public function testBug5496(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-5496.php'], []); } public function testBug3892(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-3892.php'], []); } public function testBug3314(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-3314.php'], []); } public function testBug2870(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-2870.php'], []); } public function testBug5354(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-5354.php'], []); } public function testSlevomatCsInArrayBug(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/slevomat-cs-in-array.php'], []); } public function testNonEmptySpecifiedString(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/non-empty-string-impossible-type.php'], []); } public function testBug2755(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-2755.php'], []); } public function testBug7079(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-7079.php'], []); } public function testConditionalTypesInference(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/conditional-types-inference.php'], [ [ @@ -639,63 +514,58 @@ public function testConditionalTypesInference(): void public function testBug6697(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6697.php'], []); } public function testBug6443(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6443.php'], []); } public function testBug7684(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = false; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-7684.php'], []); } public function testBug7224(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-7224.php'], []); } public function testBug4708(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-4708.php'], []); } public function testBug3821(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-3821.php'], []); } public function testBug6599(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-6599.php'], []); } public function testBug7914(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-7914.php'], []); } public function testDocblockAssertEquality(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/docblock-assert-equality.php'], [ [ @@ -707,63 +577,54 @@ public function testDocblockAssertEquality(): void public function testBug8076(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-8076.php'], []); } public function testBug8562(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-8562.php'], []); } public function testBug6938(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-6938.php'], []); } public function testBug8727(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-8727.php'], []); } public function testBug8474(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-8474.php'], []); } public function testBug5695(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-5695.php'], []); } public function testBug8752(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-8752.php'], []); } public function testDiscussion9134(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/discussion-9134.php'], []); } public function testImpossibleMethodExistOnGenericClassString(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; @@ -824,7 +685,6 @@ public function dataReportAlwaysTrueInLastCondition(): iterable */ public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLastCondition, array $expectedErrors): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; $this->analyse([__DIR__ . '/data/impossible-function-report-always-true-last-condition.php'], $expectedErrors); @@ -832,7 +692,6 @@ public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLast public function testObjectShapes(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/property-exists-object-shapes.php'], [ [ @@ -1009,7 +868,6 @@ public function testLooseComparisonAgainstEnums(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $issues = array_map( static function (array $i): array { @@ -1026,7 +884,6 @@ static function (array $i): array { public function testNonStrictInArray(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-9662.php'], []); } @@ -1039,7 +896,6 @@ public function testNonStrictInArrayEnums(): void $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-9662-enums.php'], [ [ @@ -1069,7 +925,6 @@ public function testLooseComparisonAgainstEnumsNoPhpdoc(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = false; $issues = self::getLooseComparisonAgainsEnumsIssues(); $issues = array_values(array_filter($issues, static fn (array $i) => count($i) === 2)); @@ -1080,7 +935,6 @@ public function testBug10502(): void { $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/bug-10502.php'], [ [ @@ -1097,7 +951,6 @@ public function testBug10502(): void public function testAlwaysTruePregMatch(): void { - $this->checkAlwaysTrueCheckTypeFunctionCall = true; $this->treatPhpDocTypesAsCertain = true; $this->analyse([__DIR__ . '/data/always-true-preg-match.php'], []); } diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php index 152cbaa4a4..67245ebaba 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeGenericOverwriteRuleTest.php @@ -19,10 +19,8 @@ public function getRule(): Rule $this->getTypeSpecifier(), [], true, - true, ), true, - true, false, true, ); diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php index 79e7dfb00e..b81646c023 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleEqualsTest.php @@ -19,10 +19,8 @@ public function getRule(): Rule $this->getTypeSpecifier(), [], true, - true, ), true, - true, false, true, ); @@ -42,10 +40,12 @@ public function testRule(): void [ 'Call to method PHPStan\Tests\AssertionClass::assertNotInt() with int will always evaluate to false.', 30, + 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to method PHPStan\Tests\AssertionClass::assertNotInt() with string will always evaluate to true.', 36, + 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to method ImpossibleMethodCall\Foo::isSame() with 1 and 1 will always evaluate to true.', diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php index 5f14946fbb..eceaff15f9 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 @@ -23,9 +24,7 @@ public function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), - true, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, true, @@ -52,10 +51,12 @@ public function testRule(): void [ 'Call to method PHPStan\Tests\AssertionClass::assertNotInt() with int will always evaluate to false.', 30, + 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to method PHPStan\Tests\AssertionClass::assertNotInt() with string will always evaluate to true.', 36, + 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.', ], [ 'Call to method ImpossibleMethodCall\Foo::isSame() with 1 and 1 will always evaluate to true.', @@ -200,19 +201,23 @@ 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'], [ [ '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/ImpossibleCheckTypeStaticMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php index b173c04eea..1cdbc1a7ad 100644 --- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeStaticMethodCallRuleTest.php @@ -23,9 +23,7 @@ public function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), - true, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, true, diff --git a/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php index 7e6c6015ca..c191856047 100644 --- a/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/LogicalXorConstantConditionRuleTest.php @@ -24,10 +24,8 @@ protected function getRule(): TRule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, diff --git a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php index dd583aa13b..af0107c2a6 100644 --- a/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/MatchExpressionRuleTest.php @@ -16,8 +16,6 @@ class MatchExpressionRuleTest extends RuleTestCase private bool $reportAlwaysTrueInLastCondition = false; - private bool $disableUnreachable = false; - protected function getRule(): Rule { return new MatchExpressionRule( @@ -27,13 +25,9 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), - true, - $this->disableUnreachable, $this->reportAlwaysTrueInLastCondition, $this->treatPhpDocTypesAsCertain, ); @@ -61,41 +55,21 @@ public function testRule(): void 28, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 29, - ], [ 'Match arm comparison between 3 and 3 is always true.', 35, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 36, - ], [ 'Match arm comparison between 1 and 1 is always true.', 40, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 41, - ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 42, - ], [ 'Match arm comparison between 1 and 1 is always true.', 46, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 47, - ], [ 'Match expression does not handle remaining value: 3', 50, @@ -170,10 +144,6 @@ public function testEnums(): void 76, 'Remove remaining cases below this one and this error will disappear too.', ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 77, - ], [ 'Match arm comparison between MatchEnums\Foo and MatchEnums\Foo::ONE is always false.', 85, @@ -292,19 +262,11 @@ public function testBug8240(): void 13, 'Remove remaining cases below this one and this error will disappear too.', ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 14, - ], [ 'Match arm comparison between Bug8240\Foo2::BAZ and Bug8240\Foo2::BAZ is always true.', 28, 'Remove remaining cases below this one and this error will disappear too.', ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 29, - ], ]); } @@ -321,41 +283,21 @@ public function testLastArmAlwaysTrue(): void 22, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 23, - ], [ 'Match arm comparison between $this(LastMatchArmAlwaysTrue\Foo)&LastMatchArmAlwaysTrue\Foo::TWO and LastMatchArmAlwaysTrue\Foo::TWO is always true.', 31, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 32, - ], [ 'Match arm comparison between $this(LastMatchArmAlwaysTrue\Foo)&LastMatchArmAlwaysTrue\Foo::TWO and LastMatchArmAlwaysTrue\Foo::TWO is always true.', 40, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 41, - ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 42, - ], [ 'Match arm comparison between $this(LastMatchArmAlwaysTrue\Bar)&LastMatchArmAlwaysTrue\Bar::ONE and LastMatchArmAlwaysTrue\Bar::ONE is always true.', 62, $tipText, ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 63, - ], [ 'Match arm comparison between 1 and 0 is always false.', 70, @@ -369,53 +311,7 @@ public function testLastArmAlwaysTrue(): void public function dataReportAlwaysTrueInLastCondition(): iterable { - yield [false, false, [ - [ - 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', - 23, - 'Remove remaining cases below this one and this error will disappear too.', - ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 24, - ], - [ - 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', - 49, - 'Remove remaining cases below this one and this error will disappear too.', - ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 50, - ], - ]]; - yield [true, false, [ - [ - 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', - 15, - ], - [ - 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', - 23, - ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 24, - ], - [ - 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', - 45, - ], - [ - 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', - 49, - ], - [ - 'Match arm is unreachable because previous comparison is always true.', - 50, - ], - ]]; - yield [false, true, [ + yield [false, [ [ 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', 23, @@ -427,7 +323,7 @@ public function dataReportAlwaysTrueInLastCondition(): iterable 'Remove remaining cases below this one and this error will disappear too.', ], ]]; - yield [true, true, [ + yield [true, [ [ 'Match arm comparison between $this(MatchAlwaysTrueLastArm\Foo)&MatchAlwaysTrueLastArm\Foo::BAR and MatchAlwaysTrueLastArm\Foo::BAR is always true.', 15, @@ -451,14 +347,13 @@ public function dataReportAlwaysTrueInLastCondition(): iterable * @dataProvider dataReportAlwaysTrueInLastCondition * @param list $expectedErrors */ - public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLastCondition, bool $disableUnreachable, array $expectedErrors): void + public function testReportAlwaysTrueInLastCondition(bool $reportAlwaysTrueInLastCondition, array $expectedErrors): void { if (PHP_VERSION_ID < 80100) { $this->markTestSkipped('Test requires PHP 8.1.'); } $this->treatPhpDocTypesAsCertain = true; $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; - $this->disableUnreachable = $disableUnreachable; $this->analyse([__DIR__ . '/data/match-always-true-last-arm.php'], $expectedErrors); } diff --git a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php index 32a755653a..e8efadec21 100644 --- a/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php @@ -14,8 +14,6 @@ class StrictComparisonOfDifferentTypesRuleTest extends RuleTestCase { - private bool $checkAlwaysTrueStrictComparison; - private bool $reportAlwaysTrueInLastCondition = false; private bool $treatPhpDocTypesAsCertain = true; @@ -24,7 +22,6 @@ protected function getRule(): Rule { return new StrictComparisonOfDifferentTypesRule( self::getContainer()->getByType(RicherScopeGetTypeHelper::class), - $this->checkAlwaysTrueStrictComparison, $this->treatPhpDocTypesAsCertain, $this->reportAlwaysTrueInLastCondition, true, @@ -38,7 +35,6 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testStrictComparison(): void { - $this->checkAlwaysTrueStrictComparison = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse( [__DIR__ . '/data/strict-comparison.php'], @@ -298,173 +294,8 @@ public function testStrictComparison(): void ); } - public function testStrictComparisonWithoutAlwaysTrue(): void - { - $this->checkAlwaysTrueStrictComparison = false; - $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse( - [__DIR__ . '/data/strict-comparison.php'], - [ - [ - 'Strict comparison using === between 1 and \'1\' will always evaluate to false.', - 11, - ], - [ - 'Strict comparison using === between 1 and null will always evaluate to false.', - 14, - ], - [ - 'Strict comparison using === between StrictComparison\Bar and 1 will always evaluate to false.', - 15, - ], - [ - 'Strict comparison using === between 1 and array|bool|StrictComparison\Collection will always evaluate to false.', - 19, - $tipText, - ], - [ - 'Strict comparison using === between true and false will always evaluate to false.', - 30, - ], - [ - 'Strict comparison using === between false and true will always evaluate to false.', - 31, - ], - [ - 'Strict comparison using === between 1.0 and 1 will always evaluate to false.', - 46, - ], - [ - 'Strict comparison using === between 1 and 1.0 will always evaluate to false.', - 47, - ], - [ - 'Strict comparison using === between string and null will always evaluate to false.', - 69, - ], - [ - 'Strict comparison using === between 1|2|3 and null will always evaluate to false.', - 98, - ], - [ - 'Strict comparison using === between non-empty-array and null will always evaluate to false.', - 140, - ], - [ - 'Strict comparison using === between non-empty-array and null will always evaluate to false.', - 150, - ], - [ - 'Strict comparison using === between 1 and 2 will always evaluate to false.', - 284, - ], - [ - 'Strict comparison using === between array{X: 1} and array{X: 2} will always evaluate to false.', - 292, - ], - [ - 'Strict comparison using === between array{X: 1, Y: 2} and array{X: 2, Y: 1} will always evaluate to false.', - 300, - ], - [ - 'Strict comparison using === between array{X: 1, Y: 2} and array{Y: 2, X: 1} will always evaluate to false.', - 308, - ], - [ - 'Strict comparison using === between \'/\'|\'\\\\\' and \'//\' will always evaluate to false.', - 320, - ], - [ - 'Strict comparison using === between int<1, max> and \'string\' will always evaluate to false.', - 335, - ], - [ - 'Strict comparison using === between int<0, max> and \'string\' will always evaluate to false.', - 343, - ], - [ - 'Strict comparison using === between int<0, max> and \'string\' will always evaluate to false.', - 360, - ], - [ - 'Strict comparison using === between int<1, max> and \'string\' will always evaluate to false.', - 368, - ], - [ - 'Strict comparison using === between float and \'string\' will always evaluate to false.', - 386, - ], - [ - 'Strict comparison using === between float and \'string\' will always evaluate to false.', - 394, - ], - [ - 'Strict comparison using !== between null and null will always evaluate to false.', - 408, - ], - [ - 'Strict comparison using === between (int|int<2, max>|string) and 1.0 will always evaluate to false.', - 464, - ], - [ - 'Strict comparison using === between (int|int<2, max>|string) and stdClass will always evaluate to false.', - 466, - ], - [ - 'Strict comparison using === between int<0, 1> and 100 will always evaluate to false.', - 622, - $tipText, - ], - [ - 'Strict comparison using === between 100 and \'foo\' will always evaluate to false.', - 624, - ], - [ - 'Strict comparison using === between int<10, max> and \'foo\' will always evaluate to false.', - 635, - ], - [ - 'Strict comparison using === between string|null and 1 will always evaluate to false.', - 685, - ], - [ - 'Strict comparison using === between string|null and 1 will always evaluate to false.', - 695, - ], - [ - 'Strict comparison using === between string|null and 1 will always evaluate to false.', - 705, - ], - [ - 'Strict comparison using === between mixed and \'foo\' will always evaluate to false.', - 808, - 'Type 1|string has already been eliminated from mixed.', - ], - [ - 'Strict comparison using === between NAN and NAN will always evaluate to false.', - 980, - ], - [ - 'Strict comparison using !== between INF and INF will always evaluate to false.', - 982, - ], - [ - 'Strict comparison using === between lowercase-string|false and \'AB\' will always evaluate to false.', - 1014, - $tipText, - ], - [ - 'Strict comparison using === between mixed and null will always evaluate to false.', - 1030, - 'Type null has already been eliminated from mixed.', - ], - ], - ); - } - public function testStrictComparisonPhp71(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/strict-comparison-71.php'], [ [ 'Strict comparison using === between null and null will always evaluate to true.', @@ -475,7 +306,6 @@ public function testStrictComparisonPhp71(): void public function testStrictComparisonPropertyNativeTypesPhp74(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/strict-comparison-property-native-types.php'], [ [ 'Strict comparison using === between string and null will always evaluate to false.', @@ -498,13 +328,11 @@ public function testStrictComparisonPropertyNativeTypesPhp74(): void public function testBug2835(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-2835.php'], []); } public function testBug1860(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-1860.php'], [ [ 'Strict comparison using === between string and null will always evaluate to false.', @@ -519,31 +347,26 @@ public function testBug1860(): void public function testBug3544(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-3544.php'], []); } public function testBug2675(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-2675.php'], []); } public function testBug2220(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-2220.php'], []); } public function testBug1707(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-1707.php'], []); } public function testBug3357(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-3357.php'], []); } @@ -552,7 +375,6 @@ public function testBug4848(): void if (PHP_INT_SIZE !== 8) { $this->markTestSkipped('Test requires 64-bit platform.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-4848.php'], [ [ 'Strict comparison using === between \'18446744073709551615\' and \'9223372036854775807\' will always evaluate to false.', @@ -563,25 +385,21 @@ public function testBug4848(): void public function testBug4793(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-4793.php'], []); } public function testBug5062(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-5062.php'], []); } public function testBug3366(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-3366.php'], []); } public function testBug5362(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-5362.php'], [ [ 'Strict comparison using === between 0 and 1|2 will always evaluate to false.', @@ -592,8 +410,6 @@ public function testBug5362(): void public function testBug6939(): void { - $this->checkAlwaysTrueStrictComparison = true; - if (PHP_VERSION_ID < 80000) { $this->analyse([__DIR__ . '/data/bug-6939.php'], []); return; @@ -609,13 +425,11 @@ public function testBug6939(): void public function testBug7166(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-7166.php'], []); } public function testBug7555(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-7555.php'], [ [ 'Strict comparison using === between 2 and 2 will always evaluate to true.', @@ -627,30 +441,30 @@ public function testBug7555(): void public function testBug7257(): void { - $this->checkAlwaysTrueStrictComparison = false; $this->analyse([__DIR__ . '/data/bug-7257.php'], []); } public function testBug5474(): void { - $this->checkAlwaysTrueStrictComparison = false; $this->analyse([__DIR__ . '/data/bug-5474.php'], [ [ 'Strict comparison using !== between array{test: 1} and array{test: 1} will always evaluate to false.', 25, ], + [ + 'Strict comparison using !== between array{test: 1} and array{test: 5} will always evaluate to true.', + 29, + ], ]); } public function testBug7684(): void { - $this->checkAlwaysTrueStrictComparison = false; $this->analyse([__DIR__ . '/data/bug-7684.php'], []); } public function testBug6181(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-6181.php'], []); } @@ -658,7 +472,6 @@ public function testBug2851b(): void { $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-2851b.php'], [ [ 'Strict comparison using === between 0 and 0 will always evaluate to true.', @@ -670,7 +483,6 @@ public function testBug2851b(): void public function testBug8158(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8158.php'], []); } @@ -680,7 +492,6 @@ public function testBug8485(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8485.php'], [ [ 'Strict comparison using === between Bug8485\E::c and Bug8485\E::c will always evaluate to true.', @@ -718,23 +529,16 @@ public function testBug8485(): void public function testBug8516(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8516.php'], []); } public function testPhpUnitIntegration(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/phpunit-integration.php'], []); } public function testBug8586(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8586.php'], []); } @@ -744,13 +548,11 @@ public function testBug4242(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-4242.php'], []); } public function testBug3633(): void { - $this->checkAlwaysTrueStrictComparison = true; $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; $this->analyse([__DIR__ . '/data/bug-3633.php'], [ [ @@ -821,7 +623,6 @@ public function testBug3633(): void public function testLastConditionAlwaysTrue(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/strict-comparison-last-condition-always-true.php'], [ [ 'Strict comparison using === between \'bar\' and \'bar\' will always evaluate to true.', @@ -833,13 +634,11 @@ public function testLastConditionAlwaysTrue(): void public function testBug3019(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-3019.php'], []); } public function testBug7578(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-7578.php'], []); } @@ -850,14 +649,12 @@ public function testBug6260(): void $this->markTestSkipped('Test requires PHP 8.0.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->treatPhpDocTypesAsCertain = false; $this->analyse([__DIR__ . '/data/bug-6260.php'], []); } public function testBug8736(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8736.php'], []); } @@ -935,20 +732,17 @@ public function testLastMatchArm(bool $reportAlwaysTrueInLastCondition, array $e $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->reportAlwaysTrueInLastCondition = $reportAlwaysTrueInLastCondition; $this->analyse([__DIR__ . '/data/strict-comparison-last-match-arm.php'], $expectedErrors); } public function testBug8776Part1(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8776-1.php'], []); } public function testBug8776Part2(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-8776-2.php'], []); } @@ -969,13 +763,11 @@ public function testBug5978(): void $expectedErrors = []; } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-5978.php'], $expectedErrors); } public function testBug9104(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-9104.php'], [ [ 'Strict comparison using === between int<1, max> and 0 will always evaluate to false.', @@ -991,7 +783,6 @@ public function testEnumTips(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/strict-comparison-enum-tips.php'], [ [ 'Strict comparison using === between StrictComparisonEnumTips\SomeEnum::Two and StrictComparisonEnumTips\SomeEnum::Two will always evaluate to true.', @@ -1007,7 +798,6 @@ public function testBug9142(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-9142.php'], [ [ 'Strict comparison using === between $this(Bug9142\MyEnum) and Bug9142\MyEnum::Three will always evaluate to false.', @@ -1026,7 +816,6 @@ public function testBug4061(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-4061.php'], []); } @@ -1036,7 +825,6 @@ public function testBug9723(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-9723.php'], []); } @@ -1046,25 +834,21 @@ public function testBug9723b(): void $this->markTestSkipped('Test requires PHP 8.1.'); } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-9723b.php'], []); } public function testBug8366(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-8366.php'], []); } public function testBug3300(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/../../Analyser/data/bug-3300.php'], []); } public function testBug11035(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-11035.php'], [ [ "Strict comparison using === between '0' and non-falsy-string will always evaluate to false.", @@ -1076,19 +860,16 @@ public function testBug11035(): void public function testBug9804(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-9804.php'], []); } public function testBug11161(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-11161.php'], []); } public function testBug10697(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-10697.php'], []); } @@ -1136,7 +917,6 @@ public function testLowercaseString(): void ]; } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/lowercase-string.php'], $errors); } @@ -1184,19 +964,21 @@ public function testUppercaseString(): void ]; } - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/uppercase-string.php'], $errors); } public function testBug10493(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/bug-10493.php'], []); } + public function testBug7173(): void + { + $this->analyse([__DIR__ . '/data/bug-7173.php'], []); + } + public function testHashing(): void { - $this->checkAlwaysTrueStrictComparison = true; $this->analyse([__DIR__ . '/data/hashing.php'], [ [ "Strict comparison using === between lowercase-string&non-falsy-string and 'ABC' will always evaluate to false.", diff --git a/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php index fa4a13a729..e1e7474e17 100644 --- a/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/TernaryOperatorConstantConditionRuleTest.php @@ -22,10 +22,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, true, diff --git a/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php b/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php deleted file mode 100644 index f31bbe5023..0000000000 --- a/tests/PHPStan/Rules/Comparison/UnreachableIfBranchesRuleTest.php +++ /dev/null @@ -1,140 +0,0 @@ - - */ -class UnreachableIfBranchesRuleTest extends RuleTestCase -{ - - private bool $treatPhpDocTypesAsCertain; - - protected function getRule(): Rule - { - return new UnreachableIfBranchesRule( - new ConstantConditionRuleHelper( - new ImpossibleCheckTypeHelper( - $this->createReflectionProvider(), - $this->getTypeSpecifier(), - [], - $this->treatPhpDocTypesAsCertain, - true, - ), - $this->treatPhpDocTypesAsCertain, - true, - ), - $this->treatPhpDocTypesAsCertain, - false, - true, - ); - } - - protected function shouldTreatPhpDocTypesAsCertain(): bool - { - return $this->treatPhpDocTypesAsCertain; - } - - public function testRule(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/unreachable-if-branches.php'], [ - [ - 'Else branch is unreachable because previous condition is always true.', - 15, - ], - [ - 'Elseif branch is unreachable because previous condition is always true.', - 25, - ], - [ - 'Else branch is unreachable because previous condition is always true.', - 27, - ], - [ - 'Elseif branch is unreachable because previous condition is always true.', - 39, - ], - [ - 'Else branch is unreachable because previous condition is always true.', - 41, - ], - ]); - } - - public function testDoNotReportPhpDoc(): void - { - $this->treatPhpDocTypesAsCertain = false; - $this->analyse([__DIR__ . '/data/unreachable-if-branches-not-phpdoc.php'], [ - [ - 'Elseif branch is unreachable because previous condition is always true.', - 18, - ], - [ - 'Else branch is unreachable because previous condition is always true.', - 28, - ], - [ - 'Elseif branch is unreachable because previous condition is always true.', - 38, - ], - ]); - } - - public function testReportPhpDoc(): void - { - $this->treatPhpDocTypesAsCertain = true; - $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/unreachable-if-branches-not-phpdoc.php'], [ - [ - 'Elseif branch is unreachable because previous condition is always true.', - 18, - ], - [ - 'Else branch is unreachable because previous condition is always true.', - 28, - ], - [ - 'Elseif branch is unreachable because previous condition is always true.', - 38, - ], - [ - 'Elseif branch is unreachable because previous condition is always true.', - 44, - $tipText, - ], - [ - 'Else branch is unreachable because previous condition is always true.', - 54, - //$tipText, - ], - [ - 'Elseif branch is unreachable because previous condition is always true.', - 64, - //$tipText, - ], - ]); - } - - public function testBug8076(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/bug-8076.php'], []); - } - - public function testBug8562(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/bug-8562.php'], []); - } - - public function testBug7491(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/bug-7491.php'], []); - } - -} diff --git a/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php b/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php deleted file mode 100644 index 00175cc6fc..0000000000 --- a/tests/PHPStan/Rules/Comparison/UnreachableTernaryElseBranchRuleTest.php +++ /dev/null @@ -1,112 +0,0 @@ - - */ -class UnreachableTernaryElseBranchRuleTest extends RuleTestCase -{ - - private bool $treatPhpDocTypesAsCertain; - - protected function getRule(): Rule - { - return new UnreachableTernaryElseBranchRule( - new ConstantConditionRuleHelper( - new ImpossibleCheckTypeHelper( - $this->createReflectionProvider(), - $this->getTypeSpecifier(), - [], - $this->treatPhpDocTypesAsCertain, - true, - ), - $this->treatPhpDocTypesAsCertain, - true, - ), - $this->treatPhpDocTypesAsCertain, - false, - true, - ); - } - - protected function shouldTreatPhpDocTypesAsCertain(): bool - { - return $this->treatPhpDocTypesAsCertain; - } - - public function testRule(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/unreachable-ternary-else-branch.php'], [ - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 6, - ], - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 9, - ], - ]); - } - - public function testDoNotReportPhpDoc(): void - { - $this->treatPhpDocTypesAsCertain = false; - $this->analyse([__DIR__ . '/data/unreachable-ternary-else-branch-not-phpdoc.php'], [ - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 16, - ], - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 17, - ], - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 20, - ], - ]); - } - - public function testReportPhpDoc(): void - { - $this->treatPhpDocTypesAsCertain = true; - $tipText = 'Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'; - $this->analyse([__DIR__ . '/data/unreachable-ternary-else-branch-not-phpdoc.php'], [ - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 16, - ], - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 17, - ], - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 19, - $tipText, - ], - [ - 'Else branch is unreachable because ternary operator condition is always true.', - 20, - ], - ]); - } - - public function testBug3019(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-3019.php'], []); - } - - public function testBug7686(): void - { - $this->treatPhpDocTypesAsCertain = true; - $this->analyse([__DIR__ . '/data/bug-7686.php'], []); - } - -} diff --git a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php index 349eb489ed..4d65f02d2b 100644 --- a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysFalseConditionRuleTest.php @@ -22,10 +22,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, true, diff --git a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php index 2be9972f15..4a377f1855 100644 --- a/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php +++ b/tests/PHPStan/Rules/Comparison/WhileLoopAlwaysTrueConditionRuleTest.php @@ -22,10 +22,8 @@ protected function getRule(): Rule $this->getTypeSpecifier(), [], $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, - true, ), $this->treatPhpDocTypesAsCertain, true, diff --git a/tests/PHPStan/Rules/Comparison/data/TestTypeOverwriteSpecifyingExtensions.php b/tests/PHPStan/Rules/Comparison/data/TestTypeOverwriteSpecifyingExtensions.php index 4e2acbd198..1ba7c4855f 100644 --- a/tests/PHPStan/Rules/Comparison/data/TestTypeOverwriteSpecifyingExtensions.php +++ b/tests/PHPStan/Rules/Comparison/data/TestTypeOverwriteSpecifyingExtensions.php @@ -51,8 +51,8 @@ public function specifyTypes( $node->var, $newType, TypeSpecifierContext::createTruthy(), - true - ); + $scope, + )->setAlwaysOverwriteTypes(); } } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-4708.php b/tests/PHPStan/Rules/Comparison/data/bug-4708.php index 5c60d3dec1..2afa164340 100644 --- a/tests/PHPStan/Rules/Comparison/data/bug-4708.php +++ b/tests/PHPStan/Rules/Comparison/data/bug-4708.php @@ -57,7 +57,7 @@ function GetASCConfig() } else { - assertType('array&hasOffsetValue(\'bsw\', string)', $result); + assertType('non-empty-array&hasOffsetValue(\'bsw\', string)', $result); $result['bsw'] = (int) $result['bsw']; assertType("non-empty-array&hasOffsetValue('bsw', int)", $result); } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-4912.php b/tests/PHPStan/Rules/Comparison/data/bug-4912.php new file mode 100644 index 0000000000..cdbb585f9a --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-4912.php @@ -0,0 +1,27 @@ += 7.4 += 7.4 + 0, + 'item1' => 0, + ]; + + call_user_func(function () use (&$a1) { + $a1['item2'] = 3; + $a1['item1'] = 1; + }); + + if (['item2' => 3, 'item1' => 1] === $a1) { + throw new \Exception(); + } +}; diff --git a/tests/PHPStan/Rules/Comparison/data/bug-7686.php b/tests/PHPStan/Rules/Comparison/data/bug-7686.php deleted file mode 100644 index be05325779..0000000000 --- a/tests/PHPStan/Rules/Comparison/data/bug-7686.php +++ /dev/null @@ -1,25 +0,0 @@ - $input - * @return array<'return'|int, string> - */ - public static function test(array $input): array - { - $output = []; - foreach($input as $match) { - if (array_key_exists($match['name'], $output) == false) { - $output[$match['name']] = ''; - } - if (($match['type'] === '') || (in_array($match['type'], explode('|', $output[$match['name']]), true) === true)) { - continue; - } - $output[$match['name']] = ($output[$match['name']] === '' ? $match['type'] : $output[$match['name']] . '|' . $match['type']); - } - return $output; - } -} 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/Comparison/data/bug-8474.php b/tests/PHPStan/Rules/Comparison/data/bug-8474.php index d6510c8ad6..5412e7a695 100644 --- a/tests/PHPStan/Rules/Comparison/data/bug-8474.php +++ b/tests/PHPStan/Rules/Comparison/data/bug-8474.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 7.4 +getByType(PhpVersion::class), - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), ); } diff --git a/tests/PHPStan/Rules/Constants/MissingClassConstantTypehintRuleTest.php b/tests/PHPStan/Rules/Constants/MissingClassConstantTypehintRuleTest.php index 89b6302e8a..13e745a3d1 100644 --- a/tests/PHPStan/Rules/Constants/MissingClassConstantTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Constants/MissingClassConstantTypehintRuleTest.php @@ -15,7 +15,7 @@ class MissingClassConstantTypehintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingClassConstantTypehintRule(new MissingTypehintCheck(true, true, true, true, [])); + return new MissingClassConstantTypehintRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php deleted file mode 100644 index 7519e3fc48..0000000000 --- a/tests/PHPStan/Rules/DeadCode/BetterNoopRuleTest.php +++ /dev/null @@ -1,161 +0,0 @@ - - */ -class BetterNoopRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new BetterNoopRule(new ExprPrinter(new Printer())); - } - - 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, - ], - [ - 'Unused result of "xor" operator.', - 32, - 'This operator has unexpected precedence, try disambiguating the logic with parentheses ().', - ], - [ - 'Unused result of "and" operator.', - 35, - 'This operator has unexpected precedence, try disambiguating the logic with parentheses ().', - ], - [ - 'Unused result of "or" operator.', - 38, - 'This operator has unexpected precedence, try disambiguating the logic with parentheses ().', - ], - [ - 'Unused result of ternary operator.', - 40, - ], - [ - 'Unused result of ternary operator.', - 41, - ], - [ - 'Unused result of "||" operator.', - 46, - ], - [ - 'Unused result of "&&" operator.', - 49, - ], - ]); - } - - 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, - ], - ]); - } - - public function testRuleImpurePoints(): void - { - $this->analyse([__DIR__ . '/data/noop-impure-points.php'], [ - [ - 'Unused result of "&&" operator.', - 12, - ], - [ - 'Expression "$b()" on a separate line does not do anything.', - 59, - ], - [ - 'Expression "new class…" on a separate line does not do anything.', - 98, - ], - [ - 'Expression "new class…" on a separate line does not do anything.', - 104, - ], - ]); - } - - public function testBug11001(): void - { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - - $this->analyse([__DIR__ . '/data/bug-11001.php'], []); - } - - public function testBug11361(): void - { - $this->analyse([__DIR__ . '/data/bug-11361.php'], []); - } - -} diff --git a/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php index edffaa5b9a..2e082297d1 100644 --- a/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php @@ -15,7 +15,7 @@ class NoopRuleTest extends RuleTestCase protected function getRule(): Rule { - return new NoopRule(new ExprPrinter(new Printer()), false); + return new NoopRule(new ExprPrinter(new Printer())); } public function testRule(): void @@ -77,6 +77,37 @@ public function testRule(): void 'Expression "(string) 1" on a separate line does not do anything.', 30, ], + [ + 'Unused result of "xor" operator.', + 32, + 'This operator has unexpected precedence, try disambiguating the logic with parentheses ().', + ], + [ + 'Unused result of "and" operator.', + 35, + 'This operator has unexpected precedence, try disambiguating the logic with parentheses ().', + ], + [ + 'Unused result of "or" operator.', + 38, + 'This operator has unexpected precedence, try disambiguating the logic with parentheses ().', + ], + [ + 'Unused result of ternary operator.', + 40, + ], + [ + 'Unused result of ternary operator.', + 41, + ], + [ + 'Unused result of "||" operator.', + 46, + ], + [ + 'Unused result of "&&" operator.', + 49, + ], ]); } @@ -90,4 +121,36 @@ public function testNullsafe(): void ]); } + public function testRuleImpurePoints(): void + { + $this->analyse([__DIR__ . '/data/noop-impure-points.php'], [ + [ + 'Unused result of "&&" operator.', + 12, + ], + [ + 'Expression "$b()" on a separate line does not do anything.', + 59, + ], + [ + 'Expression "new class…" on a separate line does not do anything.', + 98, + ], + [ + 'Expression "new class…" on a separate line does not do anything.', + 104, + ], + ]); + } + + public function testBug11001(): void + { + $this->analyse([__DIR__ . '/data/bug-11001.php'], []); + } + + public function testBug11361(): void + { + $this->analyse([__DIR__ . '/data/bug-11361.php'], []); + } + } diff --git a/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php index 24bde42de8..9ef9924063 100644 --- a/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnusedPrivateConstantRuleTest.php @@ -2,7 +2,7 @@ namespace PHPStan\Rules\DeadCode; -use PHPStan\Reflection\ConstantReflection; +use PHPStan\Reflection\ClassConstantReflection; use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtension; use PHPStan\Rules\Constants\DirectAlwaysUsedClassConstantsExtensionProvider; use PHPStan\Rules\Rule; @@ -22,7 +22,7 @@ protected function getRule(): Rule new DirectAlwaysUsedClassConstantsExtensionProvider([ new class() implements AlwaysUsedClassConstantsExtension { - public function isAlwaysUsed(ConstantReflection $constant): bool + public function isAlwaysUsed(ClassConstantReflection $constant): bool { return $constant->getDeclaringClass()->getName() === TestExtension::class && $constant->getName() === 'USED'; diff --git a/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php b/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php index b4d2f4de0b..7650418141 100644 --- a/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php +++ b/tests/PHPStan/Rules/DeadCode/UnusedPrivatePropertyRuleTest.php @@ -241,10 +241,6 @@ public function testBug5337(): void public function testBug5971(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->alwaysWrittenTags = []; $this->alwaysReadTags = []; $this->analyse([__DIR__ . '/data/bug-5971.php'], []); @@ -252,10 +248,6 @@ public function testBug5971(): void public function testBug6107(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->alwaysWrittenTags = []; $this->alwaysReadTags = []; $this->analyse([__DIR__ . '/data/bug-6107.php'], []); diff --git a/tests/PHPStan/Rules/DeadCode/data/bug-11001.php b/tests/PHPStan/Rules/DeadCode/data/bug-11001.php index 5351fc8302..4b39b689c1 100644 --- a/tests/PHPStan/Rules/DeadCode/data/bug-11001.php +++ b/tests/PHPStan/Rules/DeadCode/data/bug-11001.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 +markTestSkipped('Test requires PHP 7.3.'); - } - $this->analyse([__DIR__ . '/data/bug-4814.php'], [ [ 'Dead catch - JsonException is never thrown in the try block.', @@ -415,10 +411,6 @@ public function testBug6262(): void public function testBug6256(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-6256.php'], [ [ 'Dead catch - TypeError is never thrown in the try block.', @@ -449,10 +441,6 @@ public function testBug6256(): void public function testBug6791(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-6791.php'], [ [ 'Dead catch - TypeError is never thrown in the try block.', @@ -471,10 +459,6 @@ public function testBug6791(): void public function testBug6786(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-6786.php'], []); } diff --git a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php b/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php deleted file mode 100644 index debb459f03..0000000000 --- a/tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest.php +++ /dev/null @@ -1,48 +0,0 @@ - - */ -class CatchWithUnthrownExceptionRuleWithDisabledMultiCatchTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new CatchWithUnthrownExceptionRule(new DefaultExceptionTypeResolver( - $this->createReflectionProvider(), - [], - [], - [], - [], - ), true); - } - - public static function getAdditionalConfigFiles(): array - { - return array_merge( - parent::getAdditionalConfigFiles(), - [__DIR__ . '/disable-detect-multi-catch.neon'], - ); - } - - public function testMultiCatchBackwardCompatible(): void - { - $this->analyse([__DIR__ . '/data/unthrown-exception-multi.php'], [ - [ - 'Dead catch - InvalidArgumentException is already caught above.', - 145, - ], - [ - 'Dead catch - InvalidArgumentException is already caught above.', - 156, - ], - ]); - } - -} diff --git a/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php b/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php index 9c8181f4a3..8139960e66 100644 --- a/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/NoncapturingCatchRuleTest.php @@ -5,6 +5,7 @@ use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -12,11 +13,9 @@ class NoncapturingCatchRuleTest extends RuleTestCase { - private PhpVersion $phpVersion; - protected function getRule(): Rule { - return new NoncapturingCatchRule($this->phpVersion); + return new NoncapturingCatchRule(); } public function dataRule(): array @@ -49,7 +48,14 @@ public function dataRule(): array */ public function testRule(int $phpVersion, array $expectedErrors): void { - $this->phpVersion = new PhpVersion($phpVersion); + $testVersion = new PhpVersion($phpVersion); + $runtimeVersion = new PhpVersion(PHP_VERSION_ID); + if ( + $testVersion->getMajorVersionId() !== $runtimeVersion->getMajorVersionId() + || $testVersion->getMinorVersionId() !== $runtimeVersion->getMinorVersionId() + ) { + $this->markTestSkipped('Test requires PHP version ' . $testVersion->getMajorVersionId() . '.' . $testVersion->getMinorVersionId() . '.*'); + } $this->analyse([ __DIR__ . '/data/noncapturing-catch.php', diff --git a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php index 8ef6277fe1..b9ac08e1bd 100644 --- a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php @@ -15,7 +15,7 @@ class ThrowExprTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ThrowExprTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new ThrowExprTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testRule(): void @@ -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, - ],*/ + ], ]); } diff --git a/tests/PHPStan/Rules/Exceptions/TooWideFunctionThrowTypeRuleTest.php b/tests/PHPStan/Rules/Exceptions/TooWideFunctionThrowTypeRuleTest.php index 82871e6145..affb0fc679 100644 --- a/tests/PHPStan/Rules/Exceptions/TooWideFunctionThrowTypeRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/TooWideFunctionThrowTypeRuleTest.php @@ -11,9 +11,11 @@ class TooWideFunctionThrowTypeRuleTest extends RuleTestCase { + private bool $implicitThrows = true; + protected function getRule(): Rule { - return new TooWideFunctionThrowTypeRule(new TooWideThrowTypeCheck()); + return new TooWideFunctionThrowTypeRule(new TooWideThrowTypeCheck($this->implicitThrows)); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Exceptions/TooWideMethodThrowTypeRuleTest.php b/tests/PHPStan/Rules/Exceptions/TooWideMethodThrowTypeRuleTest.php index 98c3737887..1ebd091d9d 100644 --- a/tests/PHPStan/Rules/Exceptions/TooWideMethodThrowTypeRuleTest.php +++ b/tests/PHPStan/Rules/Exceptions/TooWideMethodThrowTypeRuleTest.php @@ -13,9 +13,11 @@ class TooWideMethodThrowTypeRuleTest extends RuleTestCase { + private bool $implicitThrows = true; + protected function getRule(): Rule { - return new TooWideMethodThrowTypeRule(self::getContainer()->getByType(FileTypeMapper::class), new TooWideThrowTypeCheck()); + return new TooWideMethodThrowTypeRule(self::getContainer()->getByType(FileTypeMapper::class), new TooWideThrowTypeCheck($this->implicitThrows)); } public function testRule(): void @@ -55,10 +57,6 @@ public function testBug6233(): void public function testImmediatelyCalledArrowFunction(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/immediately-called-arrow-function.php'], [ [ 'Method ImmediatelyCalledArrowFunction\ImmediatelyCalledCallback::doFoo2() has InvalidArgumentException in PHPDoc @throws tag but it\'s not thrown.', @@ -76,4 +74,31 @@ public function testFirstClassCallable(): void $this->analyse([__DIR__ . '/data/immediately-called-fcc.php'], []); } + public static function dataRuleLookOnlyForExplicitThrowPoints(): iterable + { + yield [ + true, + [], + ]; + yield [ + false, + [ + [ + 'Method TooWideThrowsExplicit\Foo::doFoo() has Exception in PHPDoc @throws tag but it\'s not thrown.', + 11, + ], + ], + ]; + } + + /** + * @dataProvider dataRuleLookOnlyForExplicitThrowPoints + * @param list $errors + */ + public function testRuleLookOnlyForExplicitThrowPoints(bool $implicitThrows, array $errors): void + { + $this->implicitThrows = $implicitThrows; + $this->analyse([__DIR__ . '/data/too-wide-throws-explicit.php'], $errors); + } + } diff --git a/tests/PHPStan/Rules/Exceptions/data/bug-6256.php b/tests/PHPStan/Rules/Exceptions/data/bug-6256.php index c7cb4766ad..ed14c55755 100644 --- a/tests/PHPStan/Rules/Exceptions/data/bug-6256.php +++ b/tests/PHPStan/Rules/Exceptions/data/bug-6256.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 +doBar(); + } + + public function doBar(): void + { + + } + +} diff --git a/tests/PHPStan/Rules/Exceptions/disable-detect-multi-catch.neon b/tests/PHPStan/Rules/Exceptions/disable-detect-multi-catch.neon deleted file mode 100644 index e763557205..0000000000 --- a/tests/PHPStan/Rules/Exceptions/disable-detect-multi-catch.neon +++ /dev/null @@ -1,3 +0,0 @@ -parameters: - featureToggles: - detectDeadTypeInMultiCatch: false diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php index 7f3aab6ac2..1be1cfae69 100644 --- a/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -28,16 +27,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php index bf46cd56a6..a3ba642464 100644 --- a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php @@ -23,7 +23,6 @@ protected function getRule(): Rule true, false, false, - true, false, ))); } @@ -39,9 +38,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, ], ]); } @@ -67,10 +77,6 @@ public function testBugSpaceship(): void public function testBugFunctionMethodConstants(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-anonymous-function-method-constant.php'], []); } diff --git a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php index bcd1c9ee87..a8ffcaf800 100644 --- a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\FunctionCallParametersCheck; use PHPStan\Rules\NullsafeCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; @@ -22,19 +21,17 @@ class CallCallablesRuleTest extends RuleTestCase protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, false); return new CallCallablesRule( new FunctionCallParametersCheck( $ruleLevelHelper, new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), $ruleLevelHelper, true, @@ -159,6 +156,10 @@ public function testRule(): void public function testNamedArguments(): void { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + $this->analyse([__DIR__ . '/data/callables-named-arguments.php'], [ [ 'Missing parameter $j (int) in call to closure.', diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index a89705028b..a6513f03cb 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\FunctionCallParametersCheck; use PHPStan\Rules\NullsafeCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; @@ -28,7 +27,7 @@ protected function getRule(): Rule $broker = $this->createReflectionProvider(); return new CallToFunctionParametersRule( $broker, - new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), ); } @@ -318,9 +317,6 @@ public function testImplodeOnPhp74(): void 8, ], ]; - if (PHP_VERSION_ID < 70400) { - $errors = []; - } if (PHP_VERSION_ID >= 80000) { $errors = [ [ @@ -335,7 +331,6 @@ public function testImplodeOnPhp74(): void public function testImplodeOnLessThanPhp74(): void { - $errors = []; if (PHP_VERSION_ID >= 80000) { $errors = [ [ @@ -343,7 +338,7 @@ public function testImplodeOnLessThanPhp74(): void 8, ], ]; - } elseif (PHP_VERSION_ID >= 70400) { + } else { $errors = [ [ 'Parameter #1 $glue of function implode expects string, array given.', @@ -481,6 +476,10 @@ public function testGenericFunction(): void public function testNamedArguments(): void { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + $errors = [ [ 'Missing parameter $j (int) in call to function FunctionNamedArguments\foo.', @@ -495,12 +494,6 @@ public function testNamedArguments(): void 14, ], ]; - if (PHP_VERSION_ID < 80000) { - $errors[] = [ - 'Missing parameter $arr1 (array) in call to function array_merge.', - 14, - ]; - } require_once __DIR__ . '/data/named-arguments-define.php'; $this->analyse([__DIR__ . '/data/named-arguments.php'], $errors); @@ -660,19 +653,19 @@ public function testPregReplaceCallback(): void { $this->analyse([__DIR__ . '/data/preg_replace_callback.php'], [ [ - 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(string): string given.', + 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(string): string given.', 6, ], [ - 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(string): string given.', + 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(string): string given.', 13, ], [ - 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(array): void given.', + 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(array): void given.', 20, ], [ - 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(): void given.', + 'Parameter #2 $callback of function preg_replace_callback expects callable(array): string, Closure(): void given.', 25, ], ]); @@ -817,10 +810,6 @@ public function testExplode(): void public function testProcOpen(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/proc_open.php'], [ [ "Parameter #1 \$command of function proc_open expects list|string, array{something: 'bogus', in: 'here'} given.", @@ -1325,32 +1314,52 @@ public function testCurlSetOpt(): void 17, ], [ - 'Parameter #3 $value of function curl_setopt expects bool, int given.', + 'Parameter #3 $value of function curl_setopt expects non-empty-string, null given.', + 18, + ], + [ + 'Parameter #3 $value of function curl_setopt expects string, int given.', 19, ], [ - 'Parameter #3 $value of function curl_setopt expects bool, string given.', + 'Parameter #3 $value of function curl_setopt expects string, int given.', 20, ], [ - 'Parameter #3 $value of function curl_setopt expects int, string given.', + 'Parameter #3 $value of function curl_setopt expects bool, int given.', 22, ], + [ + 'Parameter #3 $value of function curl_setopt expects bool, string given.', + 23, + ], + [ + 'Parameter #3 $value of function curl_setopt expects int, string given.', + 25, + ], [ 'Parameter #3 $value of function curl_setopt expects array, string given.', - 24, + 27, ], [ 'Parameter #3 $value of function curl_setopt expects resource, string given.', - 26, + 29, ], [ 'Parameter #3 $value of function curl_setopt expects array|string, int given.', - 28, + 31, + ], + [ + 'Parameter #3 $value of function curl_setopt expects non-empty-string, \'\' given.', + 33, + ], + [ + 'Parameter #3 $value of function curl_setopt expects non-empty-string|null, \'\' given.', + 34, ], [ 'Parameter #3 $value of function curl_setopt expects array, array given.', - 67, + 77, ], ]); } @@ -1531,6 +1540,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'], []); } @@ -1714,6 +1727,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'], []); } @@ -1738,10 +1755,6 @@ public function testDiscussion10454(): void public function testBug10527(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4'); - } - $this->analyse([__DIR__ . '/data/bug-10527.php'], []); } @@ -1771,10 +1784,6 @@ public function testBug4960(): void public function testParamClosureThis(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/function-call-param-closure-this.php'], [ [ 'Parameter #1 $cb of function FunctionCallParamClosureThis\acceptClosure expects bindable closure, static closure given.', @@ -1789,6 +1798,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'], []); } @@ -1806,22 +1819,22 @@ public function testCountArrayShift(): void if (PHP_VERSION_ID < 80000) { $errors = [ [ - 'Parameter #1 $var of function count expects array|Countable, array|false given.', + 'Parameter #1 $var of function count expects array|Countable, array|false given.', 8, ], [ - 'Parameter #1 $var of function count expects array|Countable, array|false given.', + 'Parameter #1 $var of function count expects array|Countable, array|false given.', 16, ], ]; } else { $errors = [ [ - 'Parameter #1 $value of function count expects array|Countable, array|false given.', + 'Parameter #1 $value of function count expects array|Countable, array|false given.', 8, ], [ - 'Parameter #1 $value of function count expects array|Countable, array|false given.', + 'Parameter #1 $value of function count expects array|Countable, array|false given.', 16, ], ]; @@ -1900,6 +1913,17 @@ public function testBug9224(): void $this->analyse([__DIR__ . '/data/bug-9224.php'], []); } + public function testBug7082(): void + { + $this->checkExplicitMixed = true; + $this->analyse([__DIR__ . '/data/bug-7082.php'], [ + [ + 'Parameter #1 $val of function Bug7082\takesStr expects string, mixed given.', + 11, + ], + ]); + } + public function testBug11759(): void { $this->analyse([__DIR__ . '/data/bug-11759.php'], []); diff --git a/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php b/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php index d10eee8e48..ccff7cb19d 100644 --- a/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\FunctionCallParametersCheck; use PHPStan\Rules\NullsafeCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; @@ -21,7 +20,7 @@ class CallUserFuncRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new CallUserFuncRule($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, true, false, true, false), new NullsafeCheck(), new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true)); + return new CallUserFuncRule($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true)); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php index f4a3d5a1bb..41cc608457 100644 --- a/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -28,16 +27,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), diff --git a/tests/PHPStan/Rules/Functions/ClosureReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ClosureReturnTypeRuleTest.php index 020000b38a..6ffeadca25 100644 --- a/tests/PHPStan/Rules/Functions/ClosureReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ClosureReturnTypeRuleTest.php @@ -6,7 +6,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -16,7 +15,7 @@ class ClosureReturnTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ClosureReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false))); + return new ClosureReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false))); } public function testClosureReturnTypeRule(): void @@ -131,10 +130,6 @@ public function testBug7220(): void public function testBugFunctionMethodConstants(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/bug-anonymous-function-method-constant.php'], []); } diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php index 2417944d1a..5b603724ec 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php @@ -34,7 +34,6 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, - true, ), new PhpVersion(PHP_VERSION_ID), ); @@ -243,6 +242,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); } @@ -289,7 +292,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/ExistingClassesInClosureTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php index aa026a0f07..db80402633 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php @@ -34,7 +34,6 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, - true, ), ); } @@ -287,6 +286,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/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index 78415d4616..46e872ec74 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -34,7 +34,6 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, - true, ), ); } @@ -368,6 +367,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); } @@ -421,19 +424,28 @@ 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); } 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.', @@ -444,6 +456,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/Functions/FunctionAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php index 553ab6c462..1961e8e81c 100644 --- a/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -28,16 +27,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), diff --git a/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php b/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php index 2a92e5f5a2..e13fc184fc 100644 --- a/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php +++ b/tests/PHPStan/Rules/Functions/FunctionCallableRuleTest.php @@ -20,7 +20,7 @@ protected function getRule(): Rule return new FunctionCallableRule( $reflectionProvider, - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new PhpVersion(PHP_VERSION_ID), true, true, 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'], []); - } - -} diff --git a/tests/PHPStan/Rules/Functions/ImplodeParameterCastableToStringRuleTest.php b/tests/PHPStan/Rules/Functions/ImplodeParameterCastableToStringRuleTest.php index 25f0facf27..65e4714487 100644 --- a/tests/PHPStan/Rules/Functions/ImplodeParameterCastableToStringRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ImplodeParameterCastableToStringRuleTest.php @@ -17,7 +17,7 @@ class ImplodeParameterCastableToStringRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ImplodeParameterCastableToStringRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, false, false, true, false))); + return new ImplodeParameterCastableToStringRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, true, true, false))); } public function testNamedArguments(): void @@ -64,7 +64,7 @@ public function testImplode(): void { $this->analyse([__DIR__ . '/data/implode.php'], [ [ - 'Parameter #2 $array of function implode expects array, array|string> given.', + 'Parameter #2 $array of function implode expects array, array|string> given.', 9, ], [ @@ -100,4 +100,14 @@ public function testBug8467a(): void $this->analyse([__DIR__ . '/../Arrays/data/bug-8467a.php'], []); } + public function testBug12146(): void + { + $this->analyse([__DIR__ . '/data/bug-12146.php'], [ + [ + 'Parameter #2 $array of function implode expects array, array given.', + 28, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRuleTest.php b/tests/PHPStan/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRuleTest.php index 9ec40a74a9..b6a79b6817 100644 --- a/tests/PHPStan/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/IncompatibleArrowFunctionDefaultParameterTypeRuleTest.php @@ -4,7 +4,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -19,9 +18,6 @@ protected function getRule(): Rule public function testRule(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->analyse([__DIR__ . '/data/incompatible-default-parameter-type-arrow-functions.php'], [ [ 'Default value of the parameter #1 $i (string) of anonymous function is incompatible with type int.', diff --git a/tests/PHPStan/Rules/Functions/IncompatibleClosureFunctionDefaultParameterTypeRuleTest.php b/tests/PHPStan/Rules/Functions/IncompatibleClosureFunctionDefaultParameterTypeRuleTest.php index 8d0506f9fc..88ce97861e 100644 --- a/tests/PHPStan/Rules/Functions/IncompatibleClosureFunctionDefaultParameterTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/IncompatibleClosureFunctionDefaultParameterTypeRuleTest.php @@ -4,7 +4,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -19,9 +18,6 @@ protected function getRule(): Rule public function testRule(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->analyse([__DIR__ . '/data/incompatible-default-parameter-type-closure.php'], [ [ 'Default value of the parameter #1 $i (string) of anonymous function is incompatible with type int.', diff --git a/tests/PHPStan/Rules/Functions/MissingFunctionParameterTypehintRuleTest.php b/tests/PHPStan/Rules/Functions/MissingFunctionParameterTypehintRuleTest.php index a12ee381e9..c88fb550da 100644 --- a/tests/PHPStan/Rules/Functions/MissingFunctionParameterTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Functions/MissingFunctionParameterTypehintRuleTest.php @@ -14,7 +14,7 @@ class MissingFunctionParameterTypehintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingFunctionParameterTypehintRule(new MissingTypehintCheck(true, true, true, true, []), true); + return new MissingFunctionParameterTypehintRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/MissingFunctionReturnTypehintRuleTest.php b/tests/PHPStan/Rules/Functions/MissingFunctionReturnTypehintRuleTest.php index 37cd3ffb81..2b64aba5ba 100644 --- a/tests/PHPStan/Rules/Functions/MissingFunctionReturnTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Functions/MissingFunctionReturnTypehintRuleTest.php @@ -14,7 +14,7 @@ class MissingFunctionReturnTypehintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingFunctionReturnTypehintRule(new MissingTypehintCheck(true, true, true, true, [])); + return new MissingFunctionReturnTypehintRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php index 60d620474c..678738ac50 100644 --- a/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Functions; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -28,16 +27,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), diff --git a/tests/PHPStan/Rules/Functions/ParameterCastableToNumberRuleTest.php b/tests/PHPStan/Rules/Functions/ParameterCastableToNumberRuleTest.php new file mode 100644 index 0000000000..e4708c5f4c --- /dev/null +++ b/tests/PHPStan/Rules/Functions/ParameterCastableToNumberRuleTest.php @@ -0,0 +1,176 @@ + + */ +class ParameterCastableToNumberRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + $broker = $this->createReflectionProvider(); + return new ParameterCastableToNumberRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, true, true, false))); + } + + public function testRule(): void + { + $this->analyse([__DIR__ . '/data/param-castable-to-number-functions.php'], $this->hackPhp74ErrorMessages([ + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array> given.', + 20, + ], + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 21, + ], + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 22, + ], + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 23, + ], + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 24, + ], + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 25, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array> given.', + 27, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 28, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 29, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 30, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 31, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 32, + ], + ])); + } + + public function testNamedArguments(): void + { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0.'); + } + + $this->analyse([__DIR__ . '/data/param-castable-to-number-functions-named-args.php'], [ + [ + 'Parameter $array of function array_sum expects an array of values castable to number, array> given.', + 7, + ], + [ + 'Parameter $array of function array_product expects an array of values castable to number, array> given.', + 8, + ], + ]); + } + + public function testEnum(): void + { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Test requires PHP 8.1.'); + } + + $this->analyse([__DIR__ . '/data/param-castable-to-number-functions-enum.php'], [ + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 12, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 13, + ], + ]); + } + + public function testBug11883(): void + { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Test requires PHP 8.1.'); + } + + $this->analyse([__DIR__ . '/data/bug-11883.php'], [ + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 13, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 14, + ], + ]); + } + + public function testBug12146(): void + { + $this->analyse([__DIR__ . '/data/bug-12146.php'], $this->hackPhp74ErrorMessages([ + [ + 'Parameter #1 $array of function array_sum expects an array of values castable to number, array given.', + 16, + ], + [ + 'Parameter #1 $array of function array_product expects an array of values castable to number, array given.', + 22, + ], + ])); + } + + /** + * @param list $errors + * @return list + */ + private function hackPhp74ErrorMessages(array $errors): array + { + if (PHP_VERSION_ID >= 80000) { + return $errors; + } + + return array_map(static function (array $error): array { + $error[0] = str_replace( + [ + '$array of function array_sum', + '$array of function array_product', + 'array', + ], + [ + '$input of function array_sum', + '$input of function array_product', + 'array', + ], + $error[0], + ); + + return $error; + }, $errors); + } + +} diff --git a/tests/PHPStan/Rules/Functions/ParameterCastableToStringRuleTest.php b/tests/PHPStan/Rules/Functions/ParameterCastableToStringRuleTest.php index 8619497c4f..0ac6304231 100644 --- a/tests/PHPStan/Rules/Functions/ParameterCastableToStringRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ParameterCastableToStringRuleTest.php @@ -19,7 +19,7 @@ class ParameterCastableToStringRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new ParameterCastableToStringRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, false, false, true, false))); + return new ParameterCastableToStringRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, true, true, false))); } public function testRule(): void @@ -154,7 +154,7 @@ public function testBug3946(): void { $this->analyse([__DIR__ . '/data/bug-3946.php'], [ [ - 'Parameter #1 $keys of function array_combine expects an array of values castable to string, array|Bug3946\stdClass|float|int|string> given.', + 'Parameter #1 $keys of function array_combine expects an array of values castable to string, array|string> given.', 8, ], ]); @@ -196,6 +196,20 @@ public function testBug11141(): void ]); } + public function testBug12146(): void + { + $this->analyse([__DIR__ . '/data/bug-12146.php'], $this->hackParameterNames([ + [ + 'Parameter #1 $array of function array_intersect expects an array of values castable to string, array given.', + 34, + ], + [ + 'Parameter #1 $keys of function array_fill_keys expects an array of values castable to string, array given.', + 40, + ], + ])); + } + /** * @param list $errors * @return list diff --git a/tests/PHPStan/Rules/Functions/RandomIntParametersRuleTest.php b/tests/PHPStan/Rules/Functions/RandomIntParametersRuleTest.php index 4b9ab4e23c..40c0526e25 100644 --- a/tests/PHPStan/Rules/Functions/RandomIntParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/RandomIntParametersRuleTest.php @@ -2,6 +2,7 @@ namespace PHPStan\Rules\Functions; +use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use const PHP_INT_SIZE; @@ -14,7 +15,7 @@ class RandomIntParametersRuleTest extends RuleTestCase protected function getRule(): Rule { - return new RandomIntParametersRule($this->createReflectionProvider(), true); + return new RandomIntParametersRule($this->createReflectionProvider(), new PhpVersion(80000), true); } public function testFile(): void diff --git a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php index 28d766512f..de61bd96eb 100644 --- a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php @@ -20,7 +20,7 @@ class ReturnTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), $this->checkNullables, false, true, $this->checkExplicitMixed, false, true, false))); + return new ReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), $this->checkNullables, false, true, $this->checkExplicitMixed, false, false))); } public function testReturnTypeRule(): void @@ -173,7 +173,7 @@ public function testListWithNullablesChecked(): void $this->checkNullables = true; $this->analyse([__DIR__ . '/data/return-list-nullables.php'], [ [ - 'Function ReturnListNullables\doFoo() should return array|null but returns array.', + 'Function ReturnListNullables\doFoo() should return array|null but returns list.', 16, ], ]); @@ -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'], []); @@ -297,6 +301,20 @@ public function testBug8881(): void $this->analyse([__DIR__ . '/data/bug-8881.php'], []); } + public function testBug11126(): void + { + $this->checkExplicitMixed = true; + $this->checkNullables = true; + $this->analyse([__DIR__ . '/data/bug-11126.php'], []); + } + + public function testBug11032(): void + { + $this->checkExplicitMixed = true; + $this->checkNullables = true; + $this->analyse([__DIR__ . '/data/bug-11032.php'], []); + } + public function testBug11549(): void { $this->checkExplicitMixed = true; @@ -304,4 +322,16 @@ public function testBug11549(): void $this->analyse([__DIR__ . '/data/bug-11549.php'], []); } + public function testBug11301(): void + { + $this->checkExplicitMixed = true; + $this->checkNullables = true; + $this->analyse([__DIR__ . '/data/bug-11301.php'], [ + [ + 'Function Bug11301\cString() should return array but returns array.', + 35, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Functions/SortParameterCastableToStringRuleTest.php b/tests/PHPStan/Rules/Functions/SortParameterCastableToStringRuleTest.php index 98076839d1..2fc8264821 100644 --- a/tests/PHPStan/Rules/Functions/SortParameterCastableToStringRuleTest.php +++ b/tests/PHPStan/Rules/Functions/SortParameterCastableToStringRuleTest.php @@ -19,14 +19,14 @@ class SortParameterCastableToStringRuleTest extends RuleTestCase protected function getRule(): Rule { $broker = $this->createReflectionProvider(); - return new SortParameterCastableToStringRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, false, false, true, false))); + return new SortParameterCastableToStringRule($broker, new ParameterCastableToStringCheck(new RuleLevelHelper($broker, true, false, true, true, true, false))); } public function testRule(): void { $this->analyse([__DIR__ . '/data/sort-param-castable-to-string-functions.php'], $this->hackParameterNames([ [ - 'Parameter #1 $array of function array_unique expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function array_unique expects an array of values castable to string, array> given.', 16, ], [ @@ -38,27 +38,27 @@ public function testRule(): void 20, ], [ - 'Parameter #1 $array of function rsort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function rsort expects an array of values castable to string, list> given.', 21, ], [ - 'Parameter #1 $array of function asort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function asort expects an array of values castable to string, list> given.', 22, ], [ - 'Parameter #1 $array of function arsort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function arsort expects an array of values castable to string, array> given.', 23, ], [ - 'Parameter #1 $array of function sort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function sort expects an array of values castable to string, array> given.', 25, ], [ - 'Parameter #1 $array of function rsort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function rsort expects an array of values castable to string, list> given.', 26, ], [ - 'Parameter #1 $array of function asort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function asort expects an array of values castable to string, list> given.', 27, ], [ @@ -70,11 +70,11 @@ public function testRule(): void 32, ], [ - 'Parameter #1 $array of function sort expects an array of values castable to string, array> given.', + 'Parameter #1 $array of function sort expects an array of values castable to string, array> given.', 33, ], [ - 'Parameter #1 $array of function sort expects an array of values castable to string and float, array> given.', + 'Parameter #1 $array of function sort expects an array of values castable to string and float, list> given.', 34, ], ])); @@ -88,7 +88,7 @@ public function testNamedArguments(): void $this->analyse([__DIR__ . '/data/sort-param-castable-to-string-functions-named-args.php'], [ [ - 'Parameter $array of function array_unique expects an array of values castable to string, array> given.', + 'Parameter $array of function array_unique expects an array of values castable to string, array> given.', 7, ], [ @@ -96,15 +96,15 @@ public function testNamedArguments(): void 9, ], [ - 'Parameter $array of function rsort expects an array of values castable to string, array> given.', + 'Parameter $array of function rsort expects an array of values castable to string, list> given.', 10, ], [ - 'Parameter $array of function asort expects an array of values castable to string, array> given.', + 'Parameter $array of function asort expects an array of values castable to string, list> given.', 11, ], [ - 'Parameter $array of function arsort expects an array of values castable to string, array> given.', + 'Parameter $array of function arsort expects an array of values castable to string, array> given.', 12, ], ]); @@ -126,11 +126,11 @@ public function testEnum(): void 14, ], [ - 'Parameter #1 $array of function rsort expects an array of values castable to string, array given.', + 'Parameter #1 $array of function rsort expects an array of values castable to string, list given.', 15, ], [ - 'Parameter #1 $array of function asort expects an array of values castable to string, array given.', + 'Parameter #1 $array of function asort expects an array of values castable to string, list given.', 16, ], [ @@ -145,6 +145,16 @@ public function testBug11167(): void $this->analyse([__DIR__ . '/data/bug-11167.php'], []); } + public function testBug12146(): void + { + $this->analyse([__DIR__ . '/data/bug-12146.php'], $this->hackParameterNames([ + [ + 'Parameter #1 $array of function array_unique expects an array of values castable to string, array given.', + 46, + ], + ])); + } + /** * @param list $errors * @return list diff --git a/tests/PHPStan/Rules/Functions/UnusedClosureUsesRuleTest.php b/tests/PHPStan/Rules/Functions/UnusedClosureUsesRuleTest.php index 0d033268d8..38a555afda 100644 --- a/tests/PHPStan/Rules/Functions/UnusedClosureUsesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/UnusedClosureUsesRuleTest.php @@ -14,7 +14,7 @@ class UnusedClosureUsesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new UnusedClosureUsesRule(new UnusedFunctionParametersCheck($this->createReflectionProvider())); + return new UnusedClosureUsesRule(new UnusedFunctionParametersCheck($this->createReflectionProvider(), true)); } public function testUnusedClosureUses(): void @@ -22,11 +22,11 @@ public function testUnusedClosureUses(): void $this->analyse([__DIR__ . '/data/unused-closure-uses.php'], [ [ 'Anonymous function has an unused use $unused.', - 3, + 6, ], [ 'Anonymous function has an unused use $anotherUnused.', - 3, + 7, ], [ 'Anonymous function has an unused use $usedInClosureUse.', diff --git a/tests/PHPStan/Rules/Functions/data/array_reduce_arrow.php b/tests/PHPStan/Rules/Functions/data/array_reduce_arrow.php index 0606d7a275..d93d7b6ffc 100644 --- a/tests/PHPStan/Rules/Functions/data/array_reduce_arrow.php +++ b/tests/PHPStan/Rules/Functions/data/array_reduce_arrow.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 + 1, 'bar' => 2]; array_walk( diff --git a/tests/PHPStan/Rules/Functions/data/arrow-function-attributes.php b/tests/PHPStan/Rules/Functions/data/arrow-function-attributes.php index fa1ec0f17a..30f1a93884 100644 --- a/tests/PHPStan/Rules/Functions/data/arrow-function-attributes.php +++ b/tests/PHPStan/Rules/Functions/data/arrow-function-attributes.php @@ -1,4 +1,4 @@ -= 7.4 += 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-function-never.php b/tests/PHPStan/Rules/Functions/data/arrow-function-never.php index 227ad163b2..da2cc65566 100644 --- a/tests/PHPStan/Rules/Functions/data/arrow-function-never.php +++ b/tests/PHPStan/Rules/Functions/data/arrow-function-never.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 + 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/Functions/data/bug-11032.php b/tests/PHPStan/Rules/Functions/data/bug-11032.php new file mode 100644 index 0000000000..ea967f31ee --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-11032.php @@ -0,0 +1,42 @@ + + */ + private $promise = null; + + /** + * @return PromiseInterface + */ + public function promise(): PromiseInterface + { + return $this->promise; + } +} + +/** + * @template T + * @param iterable $tasks + * @return PromiseInterface> + */ +function parallel(iterable $tasks): PromiseInterface +{ + /** @var Deferred> $deferred*/ + $deferred = new Deferred(); + + return $deferred->promise(); +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-11126.php b/tests/PHPStan/Rules/Functions/data/bug-11126.php new file mode 100644 index 0000000000..8569f55ac0 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-11126.php @@ -0,0 +1,41 @@ + + */ + public function map(callable $callback): Collection { + return $this; + } +} + +/** + * @param Collection> $in + * @return Collection> + */ +function foo(Collection $in): Collection { + return $in->map(static fn ($v) => $v); +} + +/** + * @param Collection> $in + * @return Collection> + */ +function bar(Collection $in): Collection { + return $in->map(value(...)); +} + +/** + * @param int<0, max> $in + * @return int<0, max> + */ +function value(int $in): int { + return $in; +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-11301.php b/tests/PHPStan/Rules/Functions/data/bug-11301.php new file mode 100644 index 0000000000..5c9f80cc08 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-11301.php @@ -0,0 +1,48 @@ + + */ +function cInt(): array +{ + $a = ['12345']; + $b = ['abc']; + + return array_combine($a, $b); +} + +/** + * @return array + */ +function cInt2(): array +{ + $a = ['12345', 123]; + $b = ['abc', 'def']; + + return array_combine($a, $b); +} + +/** + * @return array + */ +function cString(): array +{ + $a = ['12345']; + $b = ['abc']; + + return array_combine($a, $b); +} + + +/** + * @return array + */ +function cString2(): array +{ + $a = ['12345', 123, 'a']; + $b = ['abc', 'def', 'xy']; + + return array_combine($a, $b); +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-11883.php b/tests/PHPStan/Rules/Functions/data/bug-11883.php new file mode 100644 index 0000000000..a14174777b --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-11883.php @@ -0,0 +1,14 @@ += 8.1 + +namespace Bug11883; + +enum SomeEnum: int +{ + case A = 1; + case B = 2; +} + +$enums1 = [SomeEnum::A, SomeEnum::B]; + +var_dump(array_sum($enums1)); +var_dump(array_product($enums1)); diff --git a/tests/PHPStan/Rules/Functions/data/bug-12146.php b/tests/PHPStan/Rules/Functions/data/bug-12146.php new file mode 100644 index 0000000000..bd0bf858c3 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-12146.php @@ -0,0 +1,49 @@ +|array $validArrayUnion valid + * @param array|array<\stdClass> $invalidArrayUnion invalid, report + * @param ?array<\stdClass> $nullableInvalidArray invalid, but don't report because it's reported by CallToFunctionParametersRule + * @param array<\stdClass>|\SplFixedArray $arrayOrSplArray invalid, but don't report because it's reported by CallToFunctionParametersRule + * @return void + */ +function foo($mixed, $validArrayUnion, $invalidArrayUnion, $nullableInvalidArray, $arrayOrSplArray) { + var_dump(array_sum($mixed)); + var_dump(array_sum($validArrayUnion)); + var_dump(array_sum($invalidArrayUnion)); + var_dump(array_sum($nullableInvalidArray)); + var_dump(array_sum($arrayOrSplArray)); + + var_dump(array_product($mixed)); + var_dump(array_product($validArrayUnion)); + var_dump(array_product($invalidArrayUnion)); + var_dump(array_product($nullableInvalidArray)); + var_dump(array_product($arrayOrSplArray)); + + var_dump(implode(',', $mixed)); + var_dump(implode(',', $validArrayUnion)); + var_dump(implode(',', $invalidArrayUnion)); + var_dump(implode(',', $nullableInvalidArray)); + var_dump(implode(',', $arrayOrSplArray)); + + var_dump(array_intersect($mixed, [5])); + var_dump(array_intersect($validArrayUnion, [5])); + var_dump(array_intersect($invalidArrayUnion, [5])); + var_dump(array_intersect($nullableInvalidArray, [5])); + var_dump(array_intersect($arrayOrSplArray, [5])); + + var_dump(array_fill_keys($mixed, 1)); + var_dump(array_fill_keys($validArrayUnion, 1)); + var_dump(array_fill_keys($invalidArrayUnion, 1)); + var_dump(array_fill_keys($nullableInvalidArray, 1)); + var_dump(array_fill_keys($arrayOrSplArray, 1)); + + var_dump(array_unique($mixed)); + var_dump(array_unique($validArrayUnion)); + var_dump(array_unique($invalidArrayUnion)); + var_dump(array_unique($nullableInvalidArray)); + var_dump(array_unique($arrayOrSplArray)); +} diff --git a/tests/PHPStan/Rules/Functions/data/bug-3261.php b/tests/PHPStan/Rules/Functions/data/bug-3261.php index 5e5c5f874e..b5fc443ff0 100644 --- a/tests/PHPStan/Rules/Functions/data/bug-3261.php +++ b/tests/PHPStan/Rules/Functions/data/bug-3261.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 8.1 + +namespace ParamCastableToNumberFunctionsEnum; + +enum FooEnum +{ + case A; +} + +function invalidUsages() +{ + array_sum([FooEnum::A]); + array_product([FooEnum::A]); +} diff --git a/tests/PHPStan/Rules/Functions/data/param-castable-to-number-functions-named-args.php b/tests/PHPStan/Rules/Functions/data/param-castable-to-number-functions-named-args.php new file mode 100644 index 0000000000..4fdc546062 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/param-castable-to-number-functions-named-args.php @@ -0,0 +1,15 @@ += 8.0 + +namespace ParamCastableToNumberFunctionsNamedArgs; + +function invalidUsages() +{ + var_dump(array_sum(array: [[0]])); + var_dump(array_product(array: [[0]])); +} + +function validUsages() +{ + var_dump(array_sum(array: [1])); + var_dump(array_product(array: [1])); +} diff --git a/tests/PHPStan/Rules/Functions/data/param-castable-to-number-functions.php b/tests/PHPStan/Rules/Functions/data/param-castable-to-number-functions.php new file mode 100644 index 0000000000..9e7c5da4d2 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/param-castable-to-number-functions.php @@ -0,0 +1,45 @@ +7.7'), 5, 5.5, null])); + var_dump(array_product(['5.5', false, true, new \SimpleXMLElement('7.7'), 5, 5.5, null])); +} diff --git a/tests/PHPStan/Rules/Functions/data/uasort_arrow.php b/tests/PHPStan/Rules/Functions/data/uasort_arrow.php index ad064939e7..c23a622d90 100644 --- a/tests/PHPStan/Rules/Functions/data/uasort_arrow.php +++ b/tests/PHPStan/Rules/Functions/data/uasort_arrow.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 +createReflectionProvider(), true, false, true, false, false, true, false), true); + return new YieldFromTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), true); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php b/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php index deec20a074..d658d3aeb4 100644 --- a/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php +++ b/tests/PHPStan/Rules/Generators/YieldTypeRuleTest.php @@ -14,7 +14,7 @@ class YieldTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new YieldTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new YieldTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php b/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php index 05963f5576..dd82f5bada 100644 --- a/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/ClassAncestorsRuleTest.php @@ -18,9 +18,8 @@ protected function getRule(): Rule new GenericAncestorsCheck( $this->createReflectionProvider(), new GenericObjectTypeCheck(), - new VarianceCheck(true, true), + new VarianceCheck(), new UnresolvableTypeHelper(), - true, [], true, ), diff --git a/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php b/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php index 017065a4a8..18181f9bae 100644 --- a/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/EnumAncestorsRuleTest.php @@ -19,9 +19,8 @@ protected function getRule(): Rule new GenericAncestorsCheck( $this->createReflectionProvider(), new GenericObjectTypeCheck(), - new VarianceCheck(true, true), + new VarianceCheck(), new UnresolvableTypeHelper(), - true, [], true, ), diff --git a/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php b/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php index 3a9d430ec0..f82610ea0b 100644 --- a/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/InterfaceAncestorsRuleTest.php @@ -18,9 +18,8 @@ protected function getRule(): Rule new GenericAncestorsCheck( $this->createReflectionProvider(), new GenericObjectTypeCheck(), - new VarianceCheck(true, true), + new VarianceCheck(), new UnresolvableTypeHelper(), - true, [], true, ), diff --git a/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php b/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php index f01b15ba3d..ec893f0947 100644 --- a/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php +++ b/tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php @@ -4,6 +4,7 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -236,6 +237,10 @@ public function testPr2465(): void public function testBug10609(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/data/bug-10609.php'], [ [ 'Template type A is declared as covariant, but occurs in contravariant position in parameter fn of method Bug10609\Collection::tap().', diff --git a/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php b/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php index 97870f3572..0708ec3095 100644 --- a/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php +++ b/tests/PHPStan/Rules/Generics/PropertyVarianceRuleTest.php @@ -16,7 +16,6 @@ protected function getRule(): Rule { return new PropertyVarianceRule( self::getContainer()->getByType(VarianceCheck::class), - true, ); } diff --git a/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php b/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php index 196e663c7b..76dc75145f 100644 --- a/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php +++ b/tests/PHPStan/Rules/Generics/UsedTraitsRuleTest.php @@ -20,9 +20,8 @@ protected function getRule(): Rule new GenericAncestorsCheck( $this->createReflectionProvider(), new GenericObjectTypeCheck(), - new VarianceCheck(true, true), + new VarianceCheck(), new UnresolvableTypeHelper(), - true, [], true, ), 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/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 5c417800f1..0da6911a43 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Methods; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\FunctionCallParametersCheck; use PHPStan\Rules\NullsafeCheck; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; @@ -28,15 +27,13 @@ class CallMethodsRuleTest extends RuleTestCase private bool $checkImplicitMixed = false; - private int $phpVersion = PHP_VERSION_ID; - protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, $this->checkNullables, $this->checkThisOnly, $this->checkUnionTypes, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false); + $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, $this->checkNullables, $this->checkThisOnly, $this->checkUnionTypes, $this->checkExplicitMixed, $this->checkImplicitMixed, false); return new CallMethodsRule( new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), - new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new PhpVersion($this->phpVersion), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), ); } @@ -1601,6 +1598,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; @@ -1818,12 +1819,29 @@ public function testDisallowNamedArguments(): void ]); } + public function testDisallowNamedArgumentsInPhpVersionScope(): void + { + $this->checkThisOnly = false; + $this->checkNullables = true; + $this->checkUnionTypes = true; + + $this->analyse([__DIR__ . '/data/disallow-named-arguments-php-version-scope.php'], [ + [ + 'Named arguments are supported only on PHP 8.0 and later.', + 26, + ], + ]); + } + public function testNamedArguments(): void { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + $this->checkThisOnly = false; $this->checkNullables = true; $this->checkUnionTypes = true; - $this->phpVersion = 80000; $this->analyse([__DIR__ . '/data/named-arguments.php'], [ [ @@ -1903,7 +1921,7 @@ public function testNamedArguments(): void 91, ], [ - 'Parameter ...$args of method NamedArgumentsMethod\Foo::doIpsum() expects string, int given.', + 'Named argument foo for variadic parameter ...$args of method NamedArgumentsMethod\Foo::doIpsum() expects string, int given.', 91, ], [ @@ -1918,6 +1936,14 @@ public function testNamedArguments(): void 'Unpacked argument (...) cannot be followed by a non-unpacked argument.', 94, ], + [ + 'Named argument foo for variadic parameter ...$args of method NamedArgumentsMethod\Foo::doIpsum() expects string, int given.', + 95, + ], + [ + 'Named argument bar for variadic parameter ...$args of method NamedArgumentsMethod\Foo::doIpsum() expects string, int given.', + 95, + ], ]); } @@ -1951,7 +1977,7 @@ public function testOnlyRelevantUnableToResolveTemplateType(): void $this->checkUnionTypes = true; $this->analyse([__DIR__ . '/data/only-relevant-unable-to-resolve-template-type.php'], [ [ - 'Parameter #1 $a of method OnlyRelevantUnableToResolve\Foo::doBaz() expects array, int given.', + 'Parameter #1 $a of method OnlyRelevantUnableToResolve\Foo::doBaz() expects array, int given.', 41, ], [ @@ -2092,7 +2118,11 @@ public function testBug4800(): void $this->checkThisOnly = false; $this->checkNullables = true; $this->checkUnionTypes = true; - $this->phpVersion = 80000; + + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + $this->analyse([__DIR__ . '/data/bug-4800.php'], [ [ 'Missing parameter $bar (string) in call to method Bug4800\HelloWorld2::a().', @@ -2262,11 +2292,11 @@ public function testLiteralString(): void 58, ], [ - 'Parameter #1 $a of method LiteralStringMethod\Foo::requireArrayOfLiteralStrings() expects array, array given.', + 'Parameter #1 $a of method LiteralStringMethod\Foo::requireArrayOfLiteralStrings() expects array, array given.', 60, ], [ - 'Parameter #1 $s of method LiteralStringMethod\Foo::requireLiteralString() expects literal-string, array given.', + 'Parameter #1 $s of method LiteralStringMethod\Foo::requireLiteralString() expects literal-string, array given.', 65, ], [ @@ -2714,6 +2744,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; @@ -3094,6 +3128,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; @@ -3415,6 +3453,35 @@ public function testBug10159(): void $this->analyse([__DIR__ . '/data/bug-10159.php'], []); } + public function testBug1953(): void + { + $this->checkThisOnly = false; + $this->checkNullables = true; + $this->checkUnionTypes = true; + $this->checkExplicitMixed = true; + $this->analyse([__DIR__ . '/data/bug-1953.php'], [ + [ + 'Cannot call method bar() on string.', + 12, + ], + ]); + } + + public function testBug11559c(): void + { + $this->checkThisOnly = false; + $this->checkNullables = true; + $this->checkUnionTypes = true; + $this->checkExplicitMixed = true; + + $this->analyse([__DIR__ . '/data/bug-11559c.php'], [ + [ + 'Method class@anonymous/tests/PHPStan/Rules/Methods/data/bug-11559c.php:6:1::regular_fn() invoked with 3 parameters, 1 required.', + 15, + ], + ]); + } + public function testBug4801(): void { $this->checkThisOnly = false; diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index fbb5e41439..51210125cf 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Methods; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; use PHPStan\Rules\ClassNameCheck; @@ -32,7 +31,7 @@ class CallStaticMethodsRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, $this->checkThisOnly, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false); + $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, $this->checkThisOnly, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false); return new CallStaticMethodsRule( new StaticMethodCallCheck( $reflectionProvider, @@ -47,14 +46,12 @@ protected function getRule(): Rule new FunctionCallParametersCheck( $ruleLevelHelper, new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), ); } @@ -415,6 +412,10 @@ public function testNamedArguments(): void { $this->checkThisOnly = false; + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0'); + } + $this->analyse([__DIR__ . '/data/static-method-named-arguments.php'], [ [ 'Missing parameter $j (int) in call to static method StaticMethodNamedArguments\Foo::doFoo().', @@ -547,15 +548,15 @@ public function testDiscussion7004(): void $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/discussion-7004.php'], [ [ - 'Parameter #1 $data of static method Discussion7004\Foo::fromArray1() expects array, array given.', + 'Parameter #1 $data of static method Discussion7004\Foo::fromArray1() expects array, array given.', 46, ], [ - 'Parameter #1 $data of static method Discussion7004\Foo::fromArray2() expects array{array{newsletterName: string, subscriberCount: int}}, array given.', + 'Parameter #1 $data of static method Discussion7004\Foo::fromArray2() expects array{array{newsletterName: string, subscriberCount: int}}, array given.', 47, ], [ - 'Parameter #1 $data of static method Discussion7004\Foo::fromArray3() expects array{newsletterName: string, subscriberCount: int}, array given.', + 'Parameter #1 $data of static method Discussion7004\Foo::fromArray3() expects array{newsletterName: string, subscriberCount: int}, array given.', 48, ], ]); @@ -758,6 +759,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/CallToConstructorStatementWithoutSideEffectsRuleTest.php b/tests/PHPStan/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRuleTest.php index 29e99526e2..c7c0e8f89a 100644 --- a/tests/PHPStan/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToConstructorStatementWithoutSideEffectsRuleTest.php @@ -13,7 +13,7 @@ class CallToConstructorStatementWithoutSideEffectsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new CallToConstructorStatementWithoutSideEffectsRule($this->createReflectionProvider(), true); + return new CallToConstructorStatementWithoutSideEffectsRule($this->createReflectionProvider()); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/CallToMethodStatementWithoutSideEffectsRuleTest.php b/tests/PHPStan/Rules/Methods/CallToMethodStatementWithoutSideEffectsRuleTest.php index a75873ffd5..f9ca07781c 100644 --- a/tests/PHPStan/Rules/Methods/CallToMethodStatementWithoutSideEffectsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToMethodStatementWithoutSideEffectsRuleTest.php @@ -16,7 +16,7 @@ class CallToMethodStatementWithoutSideEffectsRuleTest extends RuleTestCase protected function getRule(): Rule { - return new CallToMethodStatementWithoutSideEffectsRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new CallToMethodStatementWithoutSideEffectsRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php index 953ca5f982..90564ff6d2 100644 --- a/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallToStaticMethodStatementWithoutSideEffectsRuleTest.php @@ -16,7 +16,7 @@ protected function getRule(): Rule { $broker = $this->createReflectionProvider(); return new CallToStaticMethodStatementWithoutSideEffectsRule( - new RuleLevelHelper($broker, true, false, true, false, false, true, false), + new RuleLevelHelper($broker, true, false, true, false, false, false), $broker, ); } diff --git a/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php b/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php index 4ea2484ef5..28b0091af9 100644 --- a/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ConsistentConstructorRuleTest.php @@ -5,7 +5,6 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; use function sprintf; -use const PHP_VERSION_ID; /** @extends RuleTestCase */ class ConsistentConstructorRuleTest extends RuleTestCase @@ -20,7 +19,7 @@ public function testRule(): void { $this->analyse([__DIR__ . '/data/consistent-constructor.php'], [ [ - sprintf('Parameter #1 $b (int) of method ConsistentConstructor\Bar2::__construct() is not %s with parameter #1 $b (string) of method ConsistentConstructor\Bar::__construct().', PHP_VERSION_ID >= 70400 ? 'contravariant' : 'compatible'), + sprintf('Parameter #1 $b (int) of method ConsistentConstructor\Bar2::__construct() is not %s with parameter #1 $b (string) of method ConsistentConstructor\Bar::__construct().', 'contravariant'), 13, ], [ @@ -40,10 +39,7 @@ public function testRule(): void public function testRuleNoErrors(): void { - $this->analyse( - [__DIR__ . '/data/consistent-constructor-no-errors.php'], - PHP_VERSION_ID < 70400 ? [['Parameter #1 $b (ConsistentConstructorNoErrors\A) of method ConsistentConstructorNoErrors\Baz::__construct() is not compatible with parameter #1 $b (ConsistentConstructorNoErrors\B) of method ConsistentConstructorNoErrors\Foo::__construct().', 49]] : [], - ); + $this->analyse([__DIR__ . '/data/consistent-constructor-no-errors.php'], []); } } diff --git a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php index f95708eda3..4ca35ed5e0 100644 --- a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php @@ -34,7 +34,6 @@ protected function getRule(): Rule new PhpVersion($this->phpVersionId), true, false, - true, ), ); } @@ -362,6 +361,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); } @@ -429,26 +432,75 @@ public function testEnums(): void ]); } - public function dataTrueTypes(): array - { - return [ - [80200, []], - ]; - } - - /** - * @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 = []; + } 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 = [ + [ + 'Parameter $v of method NativeTrueType\Truthy::foo() has invalid type NativeTrueType\true.', + 10, + ], + [ + '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() uses native union types but they're supported only on PHP 8.0 and later.", + 31, + ], + [ + 'Method NativeTrueType\Truthy::trueUnionReturn() has invalid return type NativeTrueType\true.', + 31, + ], + [ + 'Method NativeTrueType\Truthy::trueUnionReturn() has invalid return type NativeTrueType\null.', + 31, + ], + ]; + } $this->analyse([__DIR__ . '/data/true-typehint.php'], $errors); } 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.', @@ -464,6 +516,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/FinalPrivateMethodRuleConfigPhpTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleConfigPhpTest.php new file mode 100644 index 0000000000..dddd414b72 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleConfigPhpTest.php @@ -0,0 +1,34 @@ + */ +class FinalPrivateMethodRuleConfigPhpTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new FinalPrivateMethodRule(); + } + + public function testRulePhpVersions(): void + { + $this->analyse([__DIR__ . '/data/final-private-method-config-phpversion.php'], [ + [ + 'Private method FinalPrivateMethodConfigPhpVersions\PhpVersionViaNEONConfg::foo() cannot be final as it is never overridden by other classes.', + 8, + ], + ]); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/data/final-private-php-version.neon', + ]; + } + +} diff --git a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php index 64a4b89c0f..05be45a380 100644 --- a/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/FinalPrivateMethodRuleTest.php @@ -5,18 +5,15 @@ use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** @extends RuleTestCase */ class FinalPrivateMethodRuleTest extends RuleTestCase { - private int $phpVersionId; - protected function getRule(): Rule { - return new FinalPrivateMethodRule( - new PhpVersion($this->phpVersionId), - ); + return new FinalPrivateMethodRule(); } public function dataRule(): array @@ -44,8 +41,35 @@ public function dataRule(): array */ public function testRule(int $phpVersion, array $errors): void { - $this->phpVersionId = $phpVersion; + $testVersion = new PhpVersion($phpVersion); + $runtimeVersion = new PhpVersion(PHP_VERSION_ID); + + if ( + $testVersion->getMajorVersionId() !== $runtimeVersion->getMajorVersionId() + || $testVersion->getMinorVersionId() !== $runtimeVersion->getMinorVersionId() + ) { + $this->markTestSkipped('Test requires PHP version ' . $testVersion->getMajorVersionId() . '.' . $testVersion->getMinorVersionId() . '.*'); + } + $this->analyse([__DIR__ . '/data/final-private-method.php'], $errors); } + public function testRulePhpVersions(): void + { + $this->analyse([__DIR__ . '/data/final-private-method-phpversions.php'], [ + [ + 'Private method FinalPrivateMethodPhpVersions\FooBarPhp8orHigher::foo() cannot be final as it is never overridden by other classes.', + 9, + ], + [ + 'Private method FinalPrivateMethodPhpVersions\FooBarPhp74OrHigher::foo() cannot be final as it is never overridden by other classes.', + 29, + ], + [ + 'Private method FinalPrivateMethodPhpVersions\FooBarBaz::foo() cannot be final as it is never overridden by other classes.', + 39, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Methods/IllegalConstructorMethodCallRuleTest.php b/tests/PHPStan/Rules/Methods/IllegalConstructorMethodCallRuleTest.php deleted file mode 100644 index 8b0f957e85..0000000000 --- a/tests/PHPStan/Rules/Methods/IllegalConstructorMethodCallRuleTest.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ -class IllegalConstructorMethodCallRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new IllegalConstructorMethodCallRule(); - } - - public function testMethods(): void - { - $this->analyse([__DIR__ . '/data/illegal-constructor-call-rule-test.php'], [ - [ - 'Call to __construct() on an existing object is not allowed.', - 13, - ], - [ - 'Call to __construct() on an existing object is not allowed.', - 18, - ], - [ - 'Call to __construct() on an existing object is not allowed.', - 60, - ], - ]); - } - -} diff --git a/tests/PHPStan/Rules/Methods/IllegalConstructorStaticCallRuleTest.php b/tests/PHPStan/Rules/Methods/IllegalConstructorStaticCallRuleTest.php deleted file mode 100644 index 065a5785bf..0000000000 --- a/tests/PHPStan/Rules/Methods/IllegalConstructorStaticCallRuleTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - */ -class IllegalConstructorStaticCallRuleTest extends RuleTestCase -{ - - protected function getRule(): Rule - { - return new IllegalConstructorStaticCallRule(); - } - - public function testMethods(): void - { - $this->analyse([__DIR__ . '/data/illegal-constructor-call-rule-test.php'], [ - [ - 'Static call to __construct() is only allowed on a parent class in the constructor.', - 31, - ], - [ - 'Static call to __construct() is only allowed on a parent class in the constructor.', - 43, - ], - [ - 'Static call to __construct() is only allowed on a parent class in the constructor.', - 44, - ], - [ - 'Static call to __construct() is only allowed on a parent class in the constructor.', - 49, - ], - [ - 'Static call to __construct() is only allowed on a parent class in the constructor.', - 50, - ], - [ - 'Static call to __construct() is only allowed on a parent class in the constructor.', - 100, - ], - ]); - } - - public function testBug9577(): void - { - if (PHP_VERSION_ID < 80100) { - $this->markTestSkipped('Test requires PHP 8.1.'); - } - - $this->analyse([__DIR__ . '/data/bug-9577.php'], []); - } - -} 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/MethodAttributesRuleTest.php b/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php index 9ce75af6e6..c87aabde90 100644 --- a/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Methods; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -21,8 +20,6 @@ class MethodAttributesRuleTest extends RuleTestCase { - private int $phpVersion; - protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); @@ -30,16 +27,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion($this->phpVersion), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), @@ -52,8 +47,6 @@ protected function getRule(): Rule public function testRule(): void { - $this->phpVersion = 80000; - $this->analyse([__DIR__ . '/data/method-attributes.php'], [ [ 'Attribute class MethodAttributes\Foo does not have the method target.', @@ -64,7 +57,6 @@ public function testRule(): void public function testBug5898(): void { - $this->phpVersion = 70400; $this->analyse([__DIR__ . '/data/bug-5898.php'], []); } diff --git a/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php b/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php index b5bc1f8efb..5058756f1c 100644 --- a/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodCallableRuleTest.php @@ -19,7 +19,7 @@ class MethodCallableRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false); return new MethodCallableRule( new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), diff --git a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php index 93c6a67b9d..5f75cd0554 100644 --- a/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodSignatureRuleTest.php @@ -26,12 +26,10 @@ protected function getRule(): Rule return new OverridingMethodRule( $phpVersion, - new MethodSignatureRule($phpClassReflectionExtension, $this->reportMaybes, $this->reportStatic, true), + new MethodSignatureRule($phpClassReflectionExtension, $this->reportMaybes, $this->reportStatic), true, - new MethodParameterComparisonHelper($phpVersion, true), + new MethodParameterComparisonHelper($phpVersion), $phpClassReflectionExtension, - true, - true, false, ); } @@ -252,9 +250,6 @@ public function testBug4003(): void public function testBug4017(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->reportMaybes = true; $this->reportStatic = true; $this->analyse([__DIR__ . '/data/bug-4017.php'], []); @@ -504,10 +499,6 @@ public function testBug10184(): void public function testBug10208(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->reportMaybes = true; $this->reportStatic = true; @@ -516,10 +507,6 @@ public function testBug10208(): void public function testBug6462(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->reportMaybes = true; $this->reportStatic = true; @@ -528,10 +515,6 @@ public function testBug6462(): void public function testBug4396(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->reportMaybes = true; $this->reportStatic = true; @@ -540,10 +523,6 @@ public function testBug4396(): void public function testBug3580(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->reportMaybes = true; $this->reportStatic = true; diff --git a/tests/PHPStan/Rules/Methods/MissingMethodImplementationRuleTest.php b/tests/PHPStan/Rules/Methods/MissingMethodImplementationRuleTest.php index 82240f467e..babaadaae2 100644 --- a/tests/PHPStan/Rules/Methods/MissingMethodImplementationRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MissingMethodImplementationRuleTest.php @@ -29,7 +29,7 @@ public function testRule(): void 24, ], [ - 'Non-abstract class class@anonymous/tests/PHPStan/Rules/Methods/data/missing-method-impl.php:41 contains abstract method doFoo() from interface MissingMethodImpl\Foo.', + 'Non-abstract class MissingMethodImpl\Foo@anonymous/tests/PHPStan/Rules/Methods/data/missing-method-impl.php:41 contains abstract method doFoo() from interface MissingMethodImpl\Foo.', 41, ], ]); diff --git a/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php b/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php index 89e29bb606..fce941c3ce 100644 --- a/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php @@ -14,7 +14,7 @@ class MissingMethodParameterTypehintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingMethodParameterTypehintRule(new MissingTypehintCheck(true, true, true, true, []), true); + return new MissingMethodParameterTypehintRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/MissingMethodReturnTypehintRuleTest.php b/tests/PHPStan/Rules/Methods/MissingMethodReturnTypehintRuleTest.php index 49fc0b97d1..77ddc7ca0f 100644 --- a/tests/PHPStan/Rules/Methods/MissingMethodReturnTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MissingMethodReturnTypehintRuleTest.php @@ -14,7 +14,7 @@ class MissingMethodReturnTypehintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingMethodReturnTypehintRule(new MissingTypehintCheck(true, true, true, true, [])); + return new MissingMethodReturnTypehintRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/MissingMethodSelfOutTypeRuleTest.php b/tests/PHPStan/Rules/Methods/MissingMethodSelfOutTypeRuleTest.php index 373e46494a..cc74d519e9 100644 --- a/tests/PHPStan/Rules/Methods/MissingMethodSelfOutTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MissingMethodSelfOutTypeRuleTest.php @@ -14,7 +14,7 @@ class MissingMethodSelfOutTypeRuleTest extends RuleTestCase protected function getRule(): TRule { - return new MissingMethodSelfOutTypeRule(new MissingTypehintCheck(true, true, true, true, [])); + return new MissingMethodSelfOutTypeRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php index 826586689a..abbe2927ab 100644 --- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php +++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php @@ -28,12 +28,10 @@ protected function getRule(): Rule return new OverridingMethodRule( $phpVersion, - new MethodSignatureRule($phpClassReflectionExtension, true, true, true), + new MethodSignatureRule($phpClassReflectionExtension, true, true), false, - new MethodParameterComparisonHelper($phpVersion, true), + new MethodParameterComparisonHelper($phpVersion), $phpClassReflectionExtension, - true, - true, $this->checkMissingOverrideMethodAttribute, ); } @@ -238,6 +236,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); } @@ -555,18 +557,12 @@ public function testBug6264(): void public function testBug7717(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->phpVersionId = PHP_VERSION_ID; $this->analyse([__DIR__ . '/data/bug-7717.php'], []); } public function testBug6104(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->phpVersionId = PHP_VERSION_ID; $this->analyse([__DIR__ . '/data/bug-6104.php'], []); } @@ -620,10 +616,6 @@ public function testBug7859(): void public function testBug8081(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->phpVersionId = PHP_VERSION_ID; $this->analyse([__DIR__ . '/data/bug-8081.php'], [ [ @@ -635,10 +627,6 @@ public function testBug8081(): void public function testBug8500(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->phpVersionId = PHP_VERSION_ID; $this->analyse([__DIR__ . '/data/bug-8500.php'], [ [ @@ -650,10 +638,6 @@ public function testBug8500(): void public function testBug9014(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->phpVersionId = PHP_VERSION_ID; $this->analyse([__DIR__ . '/data/bug-9014.php'], [ [ @@ -680,10 +664,6 @@ public function testBug9135(): void public function testBug10101(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->phpVersionId = PHP_VERSION_ID; $this->analyse([__DIR__ . '/data/bug-10101.php'], [ [ @@ -826,4 +806,20 @@ public function testBug10165(): void $this->analyse([__DIR__ . '/data/bug-10165.php'], []); } + public function testBug9524(): void + { + $this->phpVersionId = PHP_VERSION_ID; + $this->analyse([__DIR__ . '/data/bug-9524.php'], []); + } + + public function testSimpleXmlElementChildClass(): void + { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0.'); + } + + $this->phpVersionId = PHP_VERSION_ID; + $this->analyse([__DIR__ . '/data/simple-xml-element-child.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php index 13082d79b0..1fd11fe100 100644 --- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php +++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php @@ -22,7 +22,7 @@ class ReturnTypeRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnionTypes, $this->checkExplicitMixed, false, true, $this->checkBenevolentUnionTypes))); + return new ReturnTypeRule(new FunctionReturnTypeCheck(new RuleLevelHelper($this->createReflectionProvider(), true, false, $this->checkUnionTypes, $this->checkExplicitMixed, false, $this->checkBenevolentUnionTypes))); } public function testReturnTypeRule(): void @@ -237,7 +237,7 @@ public function testReturnTypeRule(): void 759, ], [ - 'Method ReturnTypes\ArrayFillKeysIssue::getIPs2() should return array> but returns array>.', + 'Method ReturnTypes\ArrayFillKeysIssue::getIPs2() should return array> but returns array>.', 817, ], [ @@ -245,7 +245,7 @@ public function testReturnTypeRule(): void 840, ], [ - 'Method ReturnTypes\NestedArrayCheck::doFoo() should return array but returns array>.', + 'Method ReturnTypes\NestedArrayCheck::doFoo() should return array but returns array>.', 860, ], [ @@ -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'], [ [ @@ -834,7 +865,7 @@ public function testBug8146bErrors(): void $this->checkBenevolentUnionTypes = true; $this->analyse([__DIR__ . '/data/bug-8146b-errors.php'], [ [ - "Method Bug8146bError\LocationFixtures::getData() should return array, coordinates: array{lat: float, lng: float}}>> but returns array{Bács-Kiskun: array{Ágasegyháza: array{constituencies: array{'Bács-Kiskun 4.', true, false, Bug8146bError\X, null}, coordinates: array{lat: 46.8386043, lng: 19.4502899}}, Akasztó: array{constituencies: array{'Bács-Kiskun 3.'}, coordinates: array{lat: 46.6898175, lng: 19.205086}}, Apostag: array{constituencies: array{'Bács-Kiskun 3.'}, coordinates: array{lat: 46.8812652, lng: 18.9648478}}, Bácsalmás: array{constituencies: array{'Bács-Kiskun 5.'}, coordinates: array{lat: 46.1250396, lng: 19.3357509}}, Bácsbokod: array{constituencies: array{'Bács-Kiskun 6.'}, coordinates: array{lat: 46.1234737, lng: 19.155708}}, Bácsborsód: array{constituencies: array{'Bács-Kiskun 6.'}, coordinates: array{lat: 46.0989373, lng: 19.1566725}}, Bácsszentgyörgy: array{constituencies: array{'Bács-Kiskun 6.'}, coordinates: array{lat: 45.9746039, lng: 19.0398066}}, Bácsszőlős: array{constituencies: array{'Bács-Kiskun 5.'}, coordinates: array{lat: 46.1352003, lng: 19.4215997}}, ...}, Baranya: non-empty-array|(literal-string&non-falsy-string), float|(literal-string&non-falsy-string)>>>, Békés: array{Almáskamarás: array{constituencies: array{'Békés 4.'}, coordinates: array{lat: 46.4617785, lng: 21.092448}}, Battonya: array{constituencies: array{'Békés 4.'}, coordinates: array{lat: 46.2902462, lng: 21.0199215}}, Békés: array{constituencies: array{'Békés 2.'}, coordinates: array{lat: 46.6704899, lng: 21.0434996}}, Békéscsaba: array{constituencies: array{'Békés 1.'}, coordinates: array{lat: 46.6735939, lng: 21.0877309}}, Békéssámson: array{constituencies: array{'Békés 4.'}, coordinates: array{lat: 46.4208677, lng: 20.6176498}}, Békésszentandrás: array{constituencies: array{'Békés 2.'}, coordinates: array{lat: 46.8715996, lng: 20.48336}}, Bélmegyer: array{constituencies: array{'Békés 3.'}, coordinates: array{lat: 46.8726019, lng: 21.1832832}}, Biharugra: array{constituencies: array{'Békés 3.'}, coordinates: array{lat: 46.9691009, lng: 21.5987651}}, ...}, Borsod-Abaúj-Zemplén: non-empty-array|(literal-string&non-falsy-string), float|(literal-string&non-falsy-string)>>>, Budapest: array{Budapest I. ker.: array{constituencies: array{'Budapest 01.'}, coordinates: array{lat: 47.4968219, lng: 19.037458}}, Budapest II. ker.: array{constituencies: array{'Budapest 03.', 'Budapest 04.'}, coordinates: array{lat: 47.5393329, lng: 18.986934}}, Budapest III. ker.: array{constituencies: array{'Budapest 04.', 'Budapest 10.'}, coordinates: array{lat: 47.5671768, lng: 19.0368517}}, Budapest IV. ker.: array{constituencies: array{'Budapest 11.', 'Budapest 12.'}, coordinates: array{lat: 47.5648915, lng: 19.0913149}}, Budapest V. ker.: array{constituencies: array{'Budapest 01.'}, coordinates: array{lat: 47.5002319, lng: 19.0520181}}, Budapest VI. ker.: array{constituencies: array{'Budapest 05.'}, coordinates: array{lat: 47.509863, lng: 19.0625813}}, Budapest VII. ker.: array{constituencies: array{'Budapest 05.'}, coordinates: array{lat: 47.5027289, lng: 19.073376}}, Budapest VIII. ker.: array{constituencies: array{'Budapest 01.', 'Budapest 06.'}, coordinates: array{lat: 47.4894184, lng: 19.070668}}, ...}, Csongrád-Csanád: array{Algyő: array{constituencies: array{'Csongrád-Csanád 4.'}, coordinates: array{lat: 46.3329625, lng: 20.207889}}, Ambrózfalva: array{constituencies: array{'Csongrád-Csanád 4.'}, coordinates: array{lat: 46.3501417, lng: 20.7313995}}, Apátfalva: array{constituencies: array{'Csongrád-Csanád 4.'}, coordinates: array{lat: 46.173317, lng: 20.5800472}}, Árpádhalom: array{constituencies: array{'Csongrád-Csanád 3.'}, coordinates: array{lat: 46.6158286, lng: 20.547733}}, Ásotthalom: array{constituencies: array{'Csongrád-Csanád 2.'}, coordinates: array{lat: 46.1995983, lng: 19.7833756}}, Baks: array{constituencies: array{'Csongrád-Csanád 3.'}, coordinates: array{lat: 46.5518708, lng: 20.1064166}}, Balástya: array{constituencies: array{'Csongrád-Csanád 3.'}, coordinates: array{lat: 46.4261828, lng: 20.004933}}, Bordány: array{constituencies: array{'Csongrád-Csanád 2.'}, coordinates: array{lat: 46.3194213, lng: 19.9227063}}, ...}, Fejér: array{Aba: array{constituencies: array{'Fejér 5.'}, coordinates: array{lat: 47.0328193, lng: 18.522359}}, Adony: array{constituencies: array{'Fejér 4.'}, coordinates: array{lat: 47.119831, lng: 18.8612469}}, Alap: array{constituencies: array{'Fejér 5.'}, coordinates: array{lat: 46.8075763, lng: 18.684028}}, Alcsútdoboz: array{constituencies: array{'Fejér 3.'}, coordinates: array{lat: 47.4277067, lng: 18.6030325}}, Alsószentiván: array{constituencies: array{'Fejér 5.'}, coordinates: array{lat: 46.7910573, lng: 18.732161}}, Bakonycsernye: array{constituencies: array{'Fejér 2.'}, coordinates: array{lat: 47.321719, lng: 18.0907379}}, Bakonykúti: array{constituencies: array{'Fejér 2.'}, coordinates: array{lat: 47.2458464, lng: 18.195769}}, Balinka: array{constituencies: array{'Fejér 2.'}, coordinates: array{lat: 47.3135736, lng: 18.1907168}}, ...}, Győr-Moson-Sopron: array{Abda: array{constituencies: array{'Győr-Moson-Sopron 5.'}, coordinates: array{lat: 47.6962149, lng: 17.5445786}}, Acsalag: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.676095, lng: 17.1977771}}, Ágfalva: array{constituencies: array{'Győr-Moson-Sopron 4.'}, coordinates: array{lat: 47.688862, lng: 16.5110233}}, Agyagosszergény: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.608545, lng: 16.9409912}}, Árpás: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.5134127, lng: 17.3931579}}, Ásványráró: array{constituencies: array{'Győr-Moson-Sopron 5.'}, coordinates: array{lat: 47.8287695, lng: 17.499195}}, Babót: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.5752269, lng: 17.0758604}}, Bágyogszovát: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.5866036, lng: 17.3617273}}, ...}, ...}.", + "Method Bug8146bError\LocationFixtures::getData() should return array, coordinates: array{lat: float, lng: float}}>> but returns array{Bács-Kiskun: array{Ágasegyháza: array{constituencies: array{'Bács-Kiskun 4.', true, false, Bug8146bError\X, null}, coordinates: array{lat: 46.8386043, lng: 19.4502899}}, Akasztó: array{constituencies: array{'Bács-Kiskun 3.'}, coordinates: array{lat: 46.6898175, lng: 19.205086}}, Apostag: array{constituencies: array{'Bács-Kiskun 3.'}, coordinates: array{lat: 46.8812652, lng: 18.9648478}}, Bácsalmás: array{constituencies: array{'Bács-Kiskun 5.'}, coordinates: array{lat: 46.1250396, lng: 19.3357509}}, Bácsbokod: array{constituencies: array{'Bács-Kiskun 6.'}, coordinates: array{lat: 46.1234737, lng: 19.155708}}, Bácsborsód: array{constituencies: array{'Bács-Kiskun 6.'}, coordinates: array{lat: 46.0989373, lng: 19.1566725}}, Bácsszentgyörgy: array{constituencies: array{'Bács-Kiskun 6.'}, coordinates: array{lat: 45.9746039, lng: 19.0398066}}, Bácsszőlős: array{constituencies: array{'Bács-Kiskun 5.'}, coordinates: array{lat: 46.1352003, lng: 19.4215997}}, ...}, Baranya: non-empty-array|(literal-string&non-falsy-string), float|(literal-string&non-falsy-string)>>>, Békés: array{Almáskamarás: array{constituencies: array{'Békés 4.'}, coordinates: array{lat: 46.4617785, lng: 21.092448}}, Battonya: array{constituencies: array{'Békés 4.'}, coordinates: array{lat: 46.2902462, lng: 21.0199215}}, Békés: array{constituencies: array{'Békés 2.'}, coordinates: array{lat: 46.6704899, lng: 21.0434996}}, Békéscsaba: array{constituencies: array{'Békés 1.'}, coordinates: array{lat: 46.6735939, lng: 21.0877309}}, Békéssámson: array{constituencies: array{'Békés 4.'}, coordinates: array{lat: 46.4208677, lng: 20.6176498}}, Békésszentandrás: array{constituencies: array{'Békés 2.'}, coordinates: array{lat: 46.8715996, lng: 20.48336}}, Bélmegyer: array{constituencies: array{'Békés 3.'}, coordinates: array{lat: 46.8726019, lng: 21.1832832}}, Biharugra: array{constituencies: array{'Békés 3.'}, coordinates: array{lat: 46.9691009, lng: 21.5987651}}, ...}, Borsod-Abaúj-Zemplén: non-empty-array|(literal-string&non-falsy-string), float|(literal-string&non-falsy-string)>>>, Budapest: array{Budapest I. ker.: array{constituencies: array{'Budapest 01.'}, coordinates: array{lat: 47.4968219, lng: 19.037458}}, Budapest II. ker.: array{constituencies: array{'Budapest 03.', 'Budapest 04.'}, coordinates: array{lat: 47.5393329, lng: 18.986934}}, Budapest III. ker.: array{constituencies: array{'Budapest 04.', 'Budapest 10.'}, coordinates: array{lat: 47.5671768, lng: 19.0368517}}, Budapest IV. ker.: array{constituencies: array{'Budapest 11.', 'Budapest 12.'}, coordinates: array{lat: 47.5648915, lng: 19.0913149}}, Budapest V. ker.: array{constituencies: array{'Budapest 01.'}, coordinates: array{lat: 47.5002319, lng: 19.0520181}}, Budapest VI. ker.: array{constituencies: array{'Budapest 05.'}, coordinates: array{lat: 47.509863, lng: 19.0625813}}, Budapest VII. ker.: array{constituencies: array{'Budapest 05.'}, coordinates: array{lat: 47.5027289, lng: 19.073376}}, Budapest VIII. ker.: array{constituencies: array{'Budapest 01.', 'Budapest 06.'}, coordinates: array{lat: 47.4894184, lng: 19.070668}}, ...}, Csongrád-Csanád: array{Algyő: array{constituencies: array{'Csongrád-Csanád 4.'}, coordinates: array{lat: 46.3329625, lng: 20.207889}}, Ambrózfalva: array{constituencies: array{'Csongrád-Csanád 4.'}, coordinates: array{lat: 46.3501417, lng: 20.7313995}}, Apátfalva: array{constituencies: array{'Csongrád-Csanád 4.'}, coordinates: array{lat: 46.173317, lng: 20.5800472}}, Árpádhalom: array{constituencies: array{'Csongrád-Csanád 3.'}, coordinates: array{lat: 46.6158286, lng: 20.547733}}, Ásotthalom: array{constituencies: array{'Csongrád-Csanád 2.'}, coordinates: array{lat: 46.1995983, lng: 19.7833756}}, Baks: array{constituencies: array{'Csongrád-Csanád 3.'}, coordinates: array{lat: 46.5518708, lng: 20.1064166}}, Balástya: array{constituencies: array{'Csongrád-Csanád 3.'}, coordinates: array{lat: 46.4261828, lng: 20.004933}}, Bordány: array{constituencies: array{'Csongrád-Csanád 2.'}, coordinates: array{lat: 46.3194213, lng: 19.9227063}}, ...}, Fejér: array{Aba: array{constituencies: array{'Fejér 5.'}, coordinates: array{lat: 47.0328193, lng: 18.522359}}, Adony: array{constituencies: array{'Fejér 4.'}, coordinates: array{lat: 47.119831, lng: 18.8612469}}, Alap: array{constituencies: array{'Fejér 5.'}, coordinates: array{lat: 46.8075763, lng: 18.684028}}, Alcsútdoboz: array{constituencies: array{'Fejér 3.'}, coordinates: array{lat: 47.4277067, lng: 18.6030325}}, Alsószentiván: array{constituencies: array{'Fejér 5.'}, coordinates: array{lat: 46.7910573, lng: 18.732161}}, Bakonycsernye: array{constituencies: array{'Fejér 2.'}, coordinates: array{lat: 47.321719, lng: 18.0907379}}, Bakonykúti: array{constituencies: array{'Fejér 2.'}, coordinates: array{lat: 47.2458464, lng: 18.195769}}, Balinka: array{constituencies: array{'Fejér 2.'}, coordinates: array{lat: 47.3135736, lng: 18.1907168}}, ...}, Győr-Moson-Sopron: array{Abda: array{constituencies: array{'Győr-Moson-Sopron 5.'}, coordinates: array{lat: 47.6962149, lng: 17.5445786}}, Acsalag: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.676095, lng: 17.1977771}}, Ágfalva: array{constituencies: array{'Győr-Moson-Sopron 4.'}, coordinates: array{lat: 47.688862, lng: 16.5110233}}, Agyagosszergény: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.608545, lng: 16.9409912}}, Árpás: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.5134127, lng: 17.3931579}}, Ásványráró: array{constituencies: array{'Győr-Moson-Sopron 5.'}, coordinates: array{lat: 47.8287695, lng: 17.499195}}, Babót: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.5752269, lng: 17.0758604}}, Bágyogszovát: array{constituencies: array{'Győr-Moson-Sopron 3.'}, coordinates: array{lat: 47.5866036, lng: 17.3617273}}, ...}, ...}.", 12, "Offset 'constituencies' (non-empty-list) does not accept type array{'Bács-Kiskun 4.', true, false, Bug8146bError\X, null}.", ], @@ -870,7 +901,7 @@ public function testMagicSerialization(): void { $this->analyse([__DIR__ . '/data/magic-serialization.php'], [ [ - 'Method MagicSerialization\WrongSignature::__serialize() should return array but returns string.', + 'Method MagicSerialization\WrongSignature::__serialize() should return array but returns string.', 23, ], [ @@ -897,7 +928,7 @@ public function testMagicSignatures(): void 43, ], [ - 'Method MagicSignatures\WrongSignature::__debugInfo() should return array|null but returns string.', + 'Method MagicSignatures\WrongSignature::__debugInfo() should return array|null but returns string.', 47, ], [ @@ -1002,10 +1033,6 @@ public function testWrongListTip(): void public function testArrowFunctionReturningVoidClosure(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/arrow-function-returning-void-closure.php'], []); } @@ -1054,6 +1081,11 @@ public function testBug10715(): void $this->analyse([__DIR__ . '/data/bug-10715.php'], []); } + public function testBug10653(): void + { + $this->analyse([__DIR__ . '/data/bug-10653.php'], []); + } + public function testBug11663(): void { $this->analyse([__DIR__ . '/data/bug-11663.php'], []); diff --git a/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php b/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php index c726ab7fdb..169acc6693 100644 --- a/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php +++ b/tests/PHPStan/Rules/Methods/StaticMethodCallableRuleTest.php @@ -22,7 +22,7 @@ class StaticMethodCallableRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false); + $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false); return new StaticMethodCallableRule( new StaticMethodCallCheck( diff --git a/tests/PHPStan/Rules/Methods/data/arrow-function-bind.php b/tests/PHPStan/Rules/Methods/data/arrow-function-bind.php index 449d409b2c..a71fa7d809 100644 --- a/tests/PHPStan/Rules/Methods/data/arrow-function-bind.php +++ b/tests/PHPStan/Rules/Methods/data/arrow-function-bind.php @@ -1,4 +1,4 @@ -= 7.4 +throwOnFailure($this->mayFail()); + } + + /** + * @template T + * + * @param T $result + * @return (T is false ? never : T) + */ + public function throwOnFailure($result) + { + if ($result === false) { + throw new Exception('Operation failed'); + } + return $result; + } + + /** + * @return stdClass|false + */ + public function mayFail() + { + $this->Counter++; + return $this->Counter % 2 ? new stdClass() : false; + } +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-11559c.php b/tests/PHPStan/Rules/Methods/data/bug-11559c.php new file mode 100644 index 0000000000..54e3ba27b0 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-11559c.php @@ -0,0 +1,16 @@ +implicit_variadic_fn(1, 2, 3); + $c->regular_fn(1, 2, 3); +} diff --git a/tests/PHPStan/Rules/Methods/data/bug-1953.php b/tests/PHPStan/Rules/Methods/data/bug-1953.php new file mode 100644 index 0000000000..c70978996c --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/bug-1953.php @@ -0,0 +1,13 @@ +bar(); +}; diff --git a/tests/PHPStan/Rules/Methods/data/bug-4083.php b/tests/PHPStan/Rules/Methods/data/bug-4083.php index c3a6141896..42bf6d0393 100644 --- a/tests/PHPStan/Rules/Methods/data/bug-4083.php +++ b/tests/PHPStan/Rules/Methods/data/bug-4083.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 8.1 - -namespace Bug9577IllegalConstructorStaticCall; - -trait StringableMessageTrait -{ - public function __construct( - private readonly \Stringable $StringableMessage, - int $code = 0, - ?\Throwable $previous = null, - ) { - parent::__construct((string) $StringableMessage, $code, $previous); - } - - public function getStringableMessage(): \Stringable - { - return $this->StringableMessage; - } -} - -class SpecializedException extends \RuntimeException -{ - use StringableMessageTrait { - StringableMessageTrait::__construct as __traitConstruct; - } - - public function __construct( - private readonly object $aService, - \Stringable $StringableMessage, - int $code = 0, - ?\Throwable $previous = null, - ) { - $this->__traitConstruct($StringableMessage, $code, $previous); - } - - public function getService(): object - { - return $this->aService; - } -} diff --git a/tests/PHPStan/Rules/Methods/data/disallow-named-arguments-php-version-scope.php b/tests/PHPStan/Rules/Methods/data/disallow-named-arguments-php-version-scope.php new file mode 100644 index 0000000000..174fef244d --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/disallow-named-arguments-php-version-scope.php @@ -0,0 +1,35 @@ += 80000) { + class Foo + { + + public function doFoo(): void + { + $this->doBar(i: 1); + } + + public function doBar(int $i): void + { + + } + + } +} else { + class FooBar + { + + public function doFoo(): void + { + $this->doBar(i: 1); + } + + public function doBar(int $i): void + { + + } + + } +} diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method-config-phpversion.php b/tests/PHPStan/Rules/Methods/data/final-private-method-config-phpversion.php new file mode 100644 index 0000000000..6880568c93 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/final-private-method-config-phpversion.php @@ -0,0 +1,11 @@ += 80000) { + class FooBarPhp8orHigher + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID < 80000) { + class FooBarPhp7 + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID > 70400) { + class FooBarPhp74OrHigher + { + + final private function foo(): void + { + } + } +} + +if (PHP_VERSION_ID < 70400 || PHP_VERSION_ID >= 80100) { + class FooBarBaz + { + + final private function foo(): void + { + } + } +} diff --git a/tests/PHPStan/Rules/Methods/data/final-private-method.php b/tests/PHPStan/Rules/Methods/data/final-private-method.php index 35c5410e30..bb06450219 100644 --- a/tests/PHPStan/Rules/Methods/data/final-private-method.php +++ b/tests/PHPStan/Rules/Methods/data/final-private-method.php @@ -1,4 +1,4 @@ -= 7.4 + 1) { - return; - } - $this->__construct($datetime, $timezone); - } - - public function mutate(string $datetime = "now", ?\DateTimeZone $timezone = null): void - { - $this->__construct($datetime, $timezone); - } -} - -class ExtendedDateTimeWithParentCall extends \DateTimeImmutable -{ - public function __construct(string $datetime = "now", ?\DateTimeZone $timezone = null) - { - parent::__construct($datetime, $timezone); - } - - public function mutate(string $datetime = "now", ?\DateTimeZone $timezone = null): void - { - parent::__construct($datetime, $timezone); - } -} - -class ExtendedDateTimeWithSelfCall extends \DateTimeImmutable -{ - public function __construct(string $datetime = "now", ?\DateTimeZone $timezone = null) - { - // Avoid infinite loop - if (count(debug_backtrace()) > 1) { - return; - } - self::__construct($datetime, $timezone); - ExtendedDateTimeWithSelfCall::__construct($datetime, $timezone); - } - - public function mutate(string $datetime = "now", ?\DateTimeZone $timezone = null): void - { - self::__construct($datetime, $timezone); - ExtendedDateTimeWithSelfCall::__construct($datetime, $timezone); - } -} - -class Foo -{ - - public function doFoo() - { - $extendedDateTime = new ExtendedDateTimeWithMethodCall('2022/04/12'); - $extendedDateTime->__construct('2022/04/13'); - } - -} - -abstract class Presenter -{ - - public function __construct() - { - - } - -} - -abstract class BasePresenter extends Presenter -{ - - public function __construct() - { - Presenter::__construct(); - } - -} - -class CatPresenter extends BasePresenter -{ - - public function __construct() - { - Presenter::__construct(); - } - -} - -class DogPresenter extends BasePresenter -{ - - public function __construct() - { - CatPresenter::__construct(); - } - -} 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 @@ +doIpsum(...['a' => 1, 'foo' => 'foo']); $this->doIpsum(...['b' => 1, 'foo' => 'foo']); $this->doIpsum(...[1, 2], 'foo'); + $this->doIpsum(1, 2, foo: 1, bar: 2); } } diff --git a/tests/PHPStan/Rules/Methods/data/returnTypes.php b/tests/PHPStan/Rules/Methods/data/returnTypes.php index 1f94e976ab..b1c453648a 100644 --- a/tests/PHPStan/Rules/Methods/data/returnTypes.php +++ b/tests/PHPStan/Rules/Methods/data/returnTypes.php @@ -375,7 +375,7 @@ public function misleadingIntReturnType(): \ReturnTypes\integer } } - public function misleadingMixedReturnType(): mixed + /*public function misleadingMixedReturnType(): mixed { if (rand(0, 1)) { return 1; @@ -386,7 +386,7 @@ public function misleadingMixedReturnType(): mixed if (rand(0, 1)) { return new mixed(); } - } + }*/ } class FooChild extends Foo diff --git a/tests/PHPStan/Rules/Methods/data/simple-xml-element-child.php b/tests/PHPStan/Rules/Methods/data/simple-xml-element-child.php new file mode 100644 index 0000000000..1251bf5933 --- /dev/null +++ b/tests/PHPStan/Rules/Methods/data/simple-xml-element-child.php @@ -0,0 +1,20 @@ +escapeInput($value), $namespace); + } + + private function escapeInput(?string $value): ?string + { + if ($value === null) { + return null; + } + return htmlspecialchars((string) normalizer_normalize($value), ENT_XML1, 'UTF-8'); + } +} diff --git a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php index f99d9352d9..79eb736c16 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 a656898b2a..135194070b 100644 --- a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php @@ -23,8 +23,7 @@ protected function getRule(): Rule { return new InvalidBinaryOperationRule( new ExprPrinter(new Printer()), - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false), - true, + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), ); } @@ -306,6 +305,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/InvalidComparisonOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php index 3221658bc4..c6879f2dc1 100644 --- a/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php +++ b/tests/PHPStan/Rules/Operators/InvalidComparisonOperationRuleTest.php @@ -16,7 +16,7 @@ class InvalidComparisonOperationRuleTest extends RuleTestCase protected function getRule(): Rule { return new InvalidComparisonOperationRule( - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), ); } @@ -168,4 +168,9 @@ public function testRuleWithNullsafeVariant(): void ]); } + public function testBug11119(): void + { + $this->analyse([__DIR__ . '/data/bug-11119.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php index 5042bb336c..63c757ecc8 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 @@ -19,9 +20,7 @@ class InvalidIncDecOperationRuleTest extends RuleTestCase protected function getRule(): Rule { return new InvalidIncDecOperationRule( - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false), - true, - false, + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), ); } @@ -69,6 +68,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..afd0611e89 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 @@ -19,8 +20,7 @@ class InvalidUnaryOperationRuleTest extends RuleTestCase protected function getRule(): Rule { return new InvalidUnaryOperationRule( - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, true, false), - true, + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), ); } @@ -96,6 +96,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'], [ diff --git a/tests/PHPStan/Rules/Operators/data/bug-11119.php b/tests/PHPStan/Rules/Operators/data/bug-11119.php new file mode 100644 index 0000000000..c0fe6b5feb --- /dev/null +++ b/tests/PHPStan/Rules/Operators/data/bug-11119.php @@ -0,0 +1,17 @@ + ($carry instanceof DateTime && $carry < $time) ? $carry : $time, + null + ); +}; diff --git a/tests/PHPStan/Rules/PhpDoc/FunctionAssertRuleTest.php b/tests/PHPStan/Rules/PhpDoc/FunctionAssertRuleTest.php index ec7035775d..8a69195287 100644 --- a/tests/PHPStan/Rules/PhpDoc/FunctionAssertRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/FunctionAssertRuleTest.php @@ -26,11 +26,10 @@ protected function getRule(): Rule $reflectionProvider, new UnresolvableTypeHelper(), new ClassNameCheck(new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer())), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new GenericObjectTypeCheck(), true, true, - true, )); } @@ -71,7 +70,7 @@ public function testRule(): void 70, ], [ - 'PHPDoc tag @phpstan-assert for $array has no value type specified in iterable type array.', + 'PHPDoc tag @phpstan-assert for $array has no value type specified in iterable type list.', 88, 'See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type', ], diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php index 7995c696f4..c664e1658a 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,17 @@ 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, ); } - 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 +40,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..0047c107ed 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,17 @@ 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, ); } - 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 +92,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', @@ -143,8 +121,27 @@ public function testInvalidTypeInTypeAlias(): void public function testIgnoreWithinPhpDoc(): void { - $this->checkAllInvalidPhpDocs = true; $this->analyse([__DIR__ . '/data/ignore-line-within-phpdoc.php'], []); } + public function testBug6299(): void + { + $this->analyse([__DIR__ . '/data/bug-6299.php'], [ + [ + "PHPDoc tag @phpstan-return has invalid value (array{'numeric': stdClass[], 'branches': array{'names': string[], 'exclude': bool}}}|int): Unexpected token \"}\", expected TOKEN_HORIZONTAL_WS at offset 107 on line 2", + 10, + ], + ]); + } + + public function testBug6692(): void + { + $this->analyse([__DIR__ . '/data/bug-6692.php'], [ + [ + 'PHPDoc tag @return has invalid value ($this): Unexpected token "<", expected TOKEN_HORIZONTAL_WS at offset 21 on line 2', + 11, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php index c2916f9864..7b5f476bc9 100644 --- a/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php @@ -29,7 +29,7 @@ protected function getRule(): Rule new ClassForbiddenNameCheck(self::getContainer()), ), new GenericObjectTypeCheck(), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new UnresolvableTypeHelper(), true, true, diff --git a/tests/PHPStan/Rules/PhpDoc/MethodAssertRuleTest.php b/tests/PHPStan/Rules/PhpDoc/MethodAssertRuleTest.php index 84474ea49a..c038a01891 100644 --- a/tests/PHPStan/Rules/PhpDoc/MethodAssertRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/MethodAssertRuleTest.php @@ -26,11 +26,10 @@ protected function getRule(): Rule $reflectionProvider, new UnresolvableTypeHelper(), new ClassNameCheck(new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer())), - new MissingTypehintCheck(true, true, true, true, []), + new MissingTypehintCheck(true, []), new GenericObjectTypeCheck(), true, true, - true, )); } diff --git a/tests/PHPStan/Rules/PhpDoc/VarTagChangedExpressionTypeRuleTest.php b/tests/PHPStan/Rules/PhpDoc/VarTagChangedExpressionTypeRuleTest.php index f3ea56d12f..c092304ff1 100644 --- a/tests/PHPStan/Rules/PhpDoc/VarTagChangedExpressionTypeRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/VarTagChangedExpressionTypeRuleTest.php @@ -52,19 +52,19 @@ public function testBug10130(): void { $this->analyse([__DIR__ . '/data/bug-10130.php'], [ [ - 'PHPDoc tag @var with type array is not subtype of type array.', + 'PHPDoc tag @var with type array is not subtype of type array.', 14, ], [ - 'PHPDoc tag @var with type array is not subtype of type list.', + 'PHPDoc tag @var with type array is not subtype of type list.', 17, ], [ - 'PHPDoc tag @var with type array is not subtype of type array{id: int}.', + 'PHPDoc tag @var with type array is not subtype of type array{id: int}.', 20, ], [ - 'PHPDoc tag @var with type array is not subtype of type list.', + 'PHPDoc tag @var with type array is not subtype of type list.', 23, ], ]); diff --git a/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php b/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php index 6083de943d..8a1ce3ba51 100644 --- a/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php +++ b/tests/PHPStan/Rules/PhpDoc/WrongVariableNameInVarTagRuleTest.php @@ -13,8 +13,6 @@ class WrongVariableNameInVarTagRuleTest extends RuleTestCase { - private bool $checkTypeAgainstNativeType = false; - private bool $checkTypeAgainstPhpDocType = false; private bool $strictWideningCheck = false; @@ -24,13 +22,20 @@ protected function getRule(): Rule return new WrongVariableNameInVarTagRule( self::getContainer()->getByType(FileTypeMapper::class), new VarTagTypeRuleHelper($this->checkTypeAgainstPhpDocType, $this->strictWideningCheck), - $this->checkTypeAgainstNativeType, ); } public function testRule(): void { $this->analyse([__DIR__ . '/data/wrong-variable-name-var.php'], [ + [ + 'PHPDoc tag @var with type int is not subtype of native type void.', + 11, + ], + [ + 'PHPDoc tag @var with type int is not subtype of native type void.', + 14, + ], [ 'Variable $foo in PHPDoc tag @var does not match assigned variable $test.', 17, @@ -71,6 +76,10 @@ public function testRule(): void 'Variable $foo in PHPDoc tag @var does not exist.', 109, ], + [ + 'PHPDoc tag @var with type int is not subtype of native type void.', + 120, + ], [ 'Multiple PHPDoc @var tags above single variable assignment are not supported.', 126, @@ -253,12 +262,9 @@ public function dataReportWrongType(): iterable ], ]; - yield [false, false, false, []]; - yield [true, false, false, $nativeCheckOnly]; - yield [true, false, true, $nativeCheckOnly]; - yield [false, true, false, []]; - yield [false, true, true, []]; - yield [true, true, false, [ + yield [false, false, $nativeCheckOnly]; + yield [false, true, $nativeCheckOnly]; + yield [true, false, [ [ 'PHPDoc tag @var with type string|null is not subtype of native type string.', 14, @@ -349,7 +355,7 @@ public function dataReportWrongType(): iterable 204, ], ]]; - yield [true, true, true, [ + yield [true, true, [ [ 'PHPDoc tag @var with type string|null is not subtype of native type string.', 14, @@ -460,7 +466,7 @@ public function dataReportWrongType(): iterable 204, ], [ - 'PHPDoc tag @var with type array|null is not subtype of type array{id: int}|null.', + 'PHPDoc tag @var with type array|null is not subtype of type array{id: int}|null.', 235, ], ]]; @@ -469,29 +475,21 @@ public function dataReportWrongType(): iterable /** * @dataProvider dataPermutateCheckTypeAgainst */ - public function testEmptyArrayInitWithWiderPhpDoc(bool $checkTypeAgainstNativeType, bool $checkTypeAgainstPhpDocType): void + public function testEmptyArrayInitWithWiderPhpDoc(bool $checkTypeAgainstPhpDocType): void { - $this->checkTypeAgainstNativeType = $checkTypeAgainstNativeType; $this->checkTypeAgainstPhpDocType = $checkTypeAgainstPhpDocType; - - $errors = !$checkTypeAgainstNativeType - ? [] - : [ - [ - 'PHPDoc tag @var with type int is not subtype of native type array{}.', - 24, - ], - ]; - - $this->analyse([__DIR__ . '/data/var-above-empty-array-widening.php'], $errors); + $this->analyse([__DIR__ . '/data/var-above-empty-array-widening.php'], [ + [ + 'PHPDoc tag @var with type int is not subtype of native type array{}.', + 24, + ], + ]); } public function dataPermutateCheckTypeAgainst(): iterable { - yield [true, true]; - yield [false, true]; - yield [true, false]; - yield [false, false]; + yield [true]; + yield [false]; } /** @@ -499,13 +497,11 @@ public function dataPermutateCheckTypeAgainst(): iterable * @param list $expectedErrors */ public function testReportWrongType( - bool $checkTypeAgainstNativeType, bool $checkTypeAgainstPhpDocType, bool $strictWideningCheck, array $expectedErrors, ): void { - $this->checkTypeAgainstNativeType = $checkTypeAgainstNativeType; $this->checkTypeAgainstPhpDocType = $checkTypeAgainstPhpDocType; $this->strictWideningCheck = $strictWideningCheck; $this->analyse([__DIR__ . '/data/wrong-var-native-type.php'], $expectedErrors); diff --git a/tests/PHPStan/Rules/PhpDoc/data/bug-4227.php b/tests/PHPStan/Rules/PhpDoc/data/bug-4227.php index 440577cae6..41bc50eae0 100644 --- a/tests/PHPStan/Rules/PhpDoc/data/bug-4227.php +++ b/tests/PHPStan/Rules/PhpDoc/data/bug-4227.php @@ -1,4 +1,4 @@ -= 7.4 + [], 'branches' => ['names' => [], 'exclude' => false]]; + } + else { + return 0; + } + } +} diff --git a/tests/PHPStan/Rules/PhpDoc/data/bug-6692.php b/tests/PHPStan/Rules/PhpDoc/data/bug-6692.php new file mode 100644 index 0000000000..41bd197ed9 --- /dev/null +++ b/tests/PHPStan/Rules/PhpDoc/data/bug-6692.php @@ -0,0 +1,27 @@ += 8.0 + +namespace Bug6692; + +/** + * @template T + */ +class Wrapper +{ + /** + * @return $this + */ + public function change(): static + { + return $this; + } +} + +/** + * @template T + * @extends Wrapper + * + * @method self change() + */ +class SubWrapper extends Wrapper +{ +} diff --git a/tests/PHPStan/Rules/PhpDoc/data/bug-7240.php b/tests/PHPStan/Rules/PhpDoc/data/bug-7240.php index da13e6f11b..f5a764e1c9 100644 --- a/tests/PHPStan/Rules/PhpDoc/data/bug-7240.php +++ b/tests/PHPStan/Rules/PhpDoc/data/bug-7240.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 + */ + $arr = ['' => 'empty', 1 => '1']; + } + + public function doFoo2(): void + { + /** @var array */ + $arr = ['' => 'empty', 1 => '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".', diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php index fb222e6595..b6ea917903 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesInAssignRuleTest.php @@ -5,7 +5,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -17,7 +16,7 @@ protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); return new AccessPropertiesInAssignRule( - new AccessPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), true, true), + new AccessPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), true, true), ); } @@ -40,10 +39,6 @@ public function testRule(): void public function testRuleAssignOp(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } - $tipText = 'Learn more: https://phpstan.org/blog/solving-phpstan-access-to-undefined-property'; $this->analyse([__DIR__ . '/data/access-properties-assign-op.php'], [ [ diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php index a07611980b..164aefaafe 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php @@ -23,7 +23,7 @@ class AccessPropertiesRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = $this->createReflectionProvider(); - return new AccessPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, $this->checkThisOnly, $this->checkUnionTypes, false, false, true, false), true, $this->checkDynamicProperties); + return new AccessPropertiesRule($reflectionProvider, new RuleLevelHelper($reflectionProvider, true, $this->checkThisOnly, $this->checkUnionTypes, false, false, false), true, $this->checkDynamicProperties); } public function testAccessProperties(): void @@ -169,6 +169,11 @@ public function testAccessProperties(): void 'Cannot access property $selfOrNull on TestAccessProperties\RevertNonNullabilityForIsset|null.', 407, ], + [ + 'Access to an undefined property object::$baz.', + 438, + $tipText, + ], ], ); } @@ -301,9 +306,6 @@ public function testAccessPropertiesWithoutUnionTypes(): void public function testRuleAssignOp(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } $this->checkThisOnly = false; $this->checkUnionTypes = true; $this->checkDynamicProperties = false; diff --git a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php index e8cd8306de..ea4b27f4f8 100644 --- a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesInAssignRuleTest.php @@ -8,7 +8,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -22,7 +21,7 @@ protected function getRule(): Rule return new AccessStaticPropertiesInAssignRule( new AccessStaticPropertiesRule( $reflectionProvider, - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), @@ -47,9 +46,6 @@ public function testRule(): void public function testRuleAssignOp(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } $this->analyse([__DIR__ . '/data/access-static-properties-assign-op.php'], [ [ 'Access to an undefined static property AccessStaticProperties\AssignOpNonexistentProperty::$flags.', diff --git a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php index 14e4779f22..acbfca290c 100644 --- a/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessStaticPropertiesRuleTest.php @@ -8,7 +8,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -21,7 +20,7 @@ protected function getRule(): Rule $reflectionProvider = $this->createReflectionProvider(); return new AccessStaticPropertiesRule( $reflectionProvider, - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck(self::getContainer()), @@ -31,166 +30,6 @@ protected function getRule(): Rule public function testAccessStaticProperties(): void { - if (PHP_VERSION_ID >= 80200) { - $this->markTestSkipped('Test is not for PHP 8.2.'); - } - $this->analyse([__DIR__ . '/data/access-static-properties.php'], [ - [ - 'Access to an undefined static property FooAccessStaticProperties::$bar.', - 23, - ], - [ - 'Access to an undefined static property BarAccessStaticProperties::$bar.', - 24, - ], - [ - 'Access to an undefined static property FooAccessStaticProperties::$bar.', - 25, - ], - [ - 'Static access to instance property FooAccessStaticProperties::$loremIpsum.', - 26, - ], - [ - 'IpsumAccessStaticProperties::ipsum() accesses parent::$lorem but IpsumAccessStaticProperties does not extend any class.', - 42, - ], - [ - 'Access to protected property $foo of class FooAccessStaticProperties.', - 44, - ], - [ - 'Access to static property $test on an unknown class UnknownStaticProperties.', - 47, - 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$baz.', - 53, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$nonexistent.', - 55, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$emptyBaz.', - 63, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$emptyNonexistent.', - 65, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$anotherNonexistent.', - 71, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$anotherNonexistent.', - 72, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$anotherEmptyNonexistent.', - 75, - ], - [ - 'Access to an undefined static property static(IpsumAccessStaticProperties)::$anotherEmptyNonexistent.', - 78, - ], - [ - 'Accessing self::$staticFooProperty outside of class scope.', - 84, - ], - [ - 'Accessing static::$staticFooProperty outside of class scope.', - 85, - ], - [ - 'Accessing parent::$staticFooProperty outside of class scope.', - 86, - ], - [ - 'Access to protected property $foo of class FooAccessStaticProperties.', - 89, - ], - [ - 'Static access to instance property FooAccessStaticProperties::$loremIpsum.', - 90, - ], - [ - 'Access to an undefined static property FooAccessStaticProperties::$nonexistent.', - 94, - ], - [ - 'Access to static property $test on an unknown class NonexistentClass.', - 97, - 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ], - [ - 'Access to an undefined static property FooAccessStaticProperties&SomeInterface::$nonexistent.', - 108, - ], - [ - 'Cannot access static property $foo on int|string.', - 113, - ], - [ - 'Class FooAccessStaticProperties referenced with incorrect case: FOOAccessStaticPropertieS.', - 119, - ], - [ - 'Access to an undefined static property FooAccessStaticProperties::$unknownProperties.', - 119, - ], - [ - 'Class FooAccessStaticProperties referenced with incorrect case: FOOAccessStaticPropertieS.', - 120, - ], - [ - 'Static access to instance property FooAccessStaticProperties::$loremIpsum.', - 120, - ], - [ - 'Class FooAccessStaticProperties referenced with incorrect case: FOOAccessStaticPropertieS.', - 121, - ], - [ - 'Access to protected property $foo of class FooAccessStaticProperties.', - 121, - ], - [ - 'Class FooAccessStaticProperties referenced with incorrect case: FOOAccessStaticPropertieS.', - 122, - ], - [ - 'Access to an undefined static property ClassOrString|string::$unknownProperty.', - 141, - ], - [ - 'Static access to instance property ClassOrString::$instanceProperty.', - 152, - ], - [ - 'Access to static property $foo on an unknown class TraitWithStaticProperty.', - 209, - 'Learn more at https://phpstan.org/user-guide/discovering-symbols', - ], - [ - 'Static access to instance property AccessWithStatic::$bar.', - 223, - ], - [ - 'Access to an undefined static property static(AccessWithStatic)::$nonexistent.', - 224, - ], - ]); - } - - public function testAccessStaticPropertiesPhp82(): void - { - if (PHP_VERSION_ID < 80200) { - $this->markTestSkipped('Test requires PHP 8.2.'); - } - $this->analyse([__DIR__ . '/data/access-static-properties.php'], [ [ 'Access to an undefined static property FooAccessStaticProperties::$bar.', @@ -416,9 +255,6 @@ public function testAccessStaticPropertiesPhp82(): void public function testRuleAssignOp(): void { - if (PHP_VERSION_ID < 70400) { - self::markTestSkipped('Test requires PHP 7.4.'); - } $this->analyse([__DIR__ . '/data/access-static-properties-assign-op.php'], [ [ 'Access to an undefined static property AccessStaticProperties\AssignOpNonexistentProperty::$flags.', @@ -439,14 +275,12 @@ public function testBug5143(): void public function testBug6809(): void { - $errors = []; - if (PHP_VERSION_ID >= 80200) { - $errors[] = [ + $this->analyse([__DIR__ . '/data/bug-6809.php'], [ + [ 'Access to an undefined static property static(Bug6809\HelloWorld)::$coolClass.', 7, - ]; - } - $this->analyse([__DIR__ . '/data/bug-6809.php'], $errors); + ], + ]); } public function testBug8333(): void diff --git a/tests/PHPStan/Rules/Properties/Bug7074Test.php b/tests/PHPStan/Rules/Properties/Bug7074Test.php index 3748675490..d3398ed7e7 100644 --- a/tests/PHPStan/Rules/Properties/Bug7074Test.php +++ b/tests/PHPStan/Rules/Properties/Bug7074Test.php @@ -15,7 +15,7 @@ class Bug7074Test extends RuleTestCase protected function getRule(): Rule { - return new DefaultValueTypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new DefaultValueTypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/DefaultValueTypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/DefaultValueTypesAssignedToPropertiesRuleTest.php index 5c92162410..eae03f029c 100644 --- a/tests/PHPStan/Rules/Properties/DefaultValueTypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/DefaultValueTypesAssignedToPropertiesRuleTest.php @@ -5,7 +5,6 @@ use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -15,7 +14,7 @@ class DefaultValueTypesAssignedToPropertiesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new DefaultValueTypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new DefaultValueTypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testDefaultValueTypesAssignedToProperties(): void @@ -58,9 +57,6 @@ public function testBug5607(): void public function testBug7933(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->analyse([__DIR__ . '/data/bug-7933.php'], []); } diff --git a/tests/PHPStan/Rules/Properties/MissingPropertyTypehintRuleTest.php b/tests/PHPStan/Rules/Properties/MissingPropertyTypehintRuleTest.php index 324946835a..e17100bc38 100644 --- a/tests/PHPStan/Rules/Properties/MissingPropertyTypehintRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingPropertyTypehintRuleTest.php @@ -14,7 +14,7 @@ class MissingPropertyTypehintRuleTest extends RuleTestCase protected function getRule(): Rule { - return new MissingPropertyTypehintRule(new MissingTypehintCheck(true, true, true, true, [])); + return new MissingPropertyTypehintRule(new MissingTypehintCheck(true, [])); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php index c7a90b03ab..a72e7d23f2 100644 --- a/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingReadOnlyByPhpDocPropertyAssignRuleTest.php @@ -59,10 +59,6 @@ private function isEntityId(PropertyReflection $property, string $propertyName): public function testRule(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->analyse([__DIR__ . '/data/missing-readonly-property-assign-phpdoc.php'], [ [ 'Class MissingReadOnlyPropertyAssignPhpDoc\Foo has an uninitialized @readonly property $unassigned. Assign it in the constructor.', diff --git a/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php b/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php index 02e81f3f55..3b481b8f14 100644 --- a/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php +++ b/tests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php @@ -307,7 +307,7 @@ public function testRedeclaredReadonlyProperties(): void 70, ], [ - 'Readonly property class@anonymous/tests/PHPStan/Rules/Properties/data/redeclare-readonly-property.php:117::$myProp is already assigned.', + 'Readonly property RedeclareReadonlyProperty\A@anonymous/tests/PHPStan/Rules/Properties/data/redeclare-readonly-property.php:117::$myProp is already assigned.', 121, ], [ diff --git a/tests/PHPStan/Rules/Properties/NullsafePropertyFetchRuleTest.php b/tests/PHPStan/Rules/Properties/NullsafePropertyFetchRuleTest.php index 0a0c64ded7..07300834bf 100644 --- a/tests/PHPStan/Rules/Properties/NullsafePropertyFetchRuleTest.php +++ b/tests/PHPStan/Rules/Properties/NullsafePropertyFetchRuleTest.php @@ -66,6 +66,10 @@ public function testBug8517(): void public function testBug9105(): void { + if (PHP_VERSION_ID < 80000) { + self::markTestSkipped('Test requires PHP 8.0.'); + } + $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-9105.php'], []); } diff --git a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php index ecf4597d97..de425931da 100644 --- a/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertiesInInterfaceRuleTest.php @@ -2,8 +2,10 @@ namespace PHPStan\Rules\Properties; +use PHPStan\Php\PhpVersion; use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +use const PHP_VERSION_ID; /** * @extends RuleTestCase @@ -13,21 +15,107 @@ class PropertiesInInterfaceRuleTest extends RuleTestCase protected function getRule(): Rule { - return new PropertiesInInterfaceRule(); + return new PropertiesInInterfaceRule(new PhpVersion(PHP_VERSION_ID)); } - public function testRule(): void + public function testPhp83AndPropertiesInInterface(): void { + if (PHP_VERSION_ID >= 80400) { + $this->markTestSkipped('Test requires PHP 8.3 or earlier.'); + } + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Property hooks cause syntax error on PHP 7.4'); + } + + $this->analyse([__DIR__ . '/data/properties-in-interface.php'], [ + [ + 'Interfaces cannot include properties.', + 7, + ], + [ + 'Interfaces cannot include properties.', + 9, + ], + [ + 'Interfaces cannot include properties.', + 11, + ], + ]); + } + + public function testPhp83AndPropertyHooksInInterface(): void + { + if (PHP_VERSION_ID >= 80400) { + $this->markTestSkipped('Test requires PHP 8.3 or earlier.'); + } + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Property hooks cause syntax error on PHP 7.4'); + } + + $this->analyse([__DIR__ . '/data/property-hooks-in-interface.php'], [ + [ + 'Interfaces cannot include properties.', + 7, + ], + [ + 'Interfaces cannot include properties.', + 9, + ], + ]); + } + + public function testPhp84AndPropertiesInInterface(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + $this->analyse([__DIR__ . '/data/properties-in-interface.php'], [ [ - 'Interfaces may not include properties.', + 'Interfaces can only include hooked properties.', + 9, + ], + [ + 'Interfaces can only include hooked properties.', + 11, + ], + ]); + } + + public function testPhp84AndNonPublicPropertyHooksInInterface(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/property-hooks-visibility-in-interface.php'], [ + [ + 'Interfaces cannot include non-public properties.', 7, ], [ - 'Interfaces may not include properties.', + 'Interfaces cannot include non-public properties.', 9, ], ]); } + public function testPhp84AndPropertyHooksWithBodiesInInterface(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/property-hooks-bodies-in-interface.php'], [ + [ + 'Interfaces cannot include property hooks with bodies.', + 7, + ], + [ + 'Interfaces cannot include property hooks with bodies.', + 13, + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php index b6d394d30b..6f4a6121ec 100644 --- a/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php @@ -2,7 +2,6 @@ namespace PHPStan\Rules\Properties; -use PHPStan\Php\PhpVersion; use PHPStan\Rules\AttributesCheck; use PHPStan\Rules\ClassCaseSensitivityCheck; use PHPStan\Rules\ClassForbiddenNameCheck; @@ -27,16 +26,14 @@ protected function getRule(): Rule new AttributesCheck( $reflectionProvider, new FunctionCallParametersCheck( - new RuleLevelHelper($reflectionProvider, true, false, true, false, false, true, false), + new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false), new NullsafeCheck(), - new PhpVersion(80000), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true, - true, ), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, false), diff --git a/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php new file mode 100644 index 0000000000..0b2ca5ba09 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/PropertyInClassRuleTest.php @@ -0,0 +1,150 @@ + + */ +class PropertyInClassRuleTest extends RuleTestCase +{ + + protected function getRule(): Rule + { + return new PropertyInClassRule(new PhpVersion(PHP_VERSION_ID)); + } + + public function testPhpLessThan84AndHookedPropertiesInClass(): void + { + if (PHP_VERSION_ID >= 80400) { + $this->markTestSkipped('Test requires PHP 8.3 or earlier.'); + } + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Property hooks cause syntax error on PHP 7.4'); + } + + $this->analyse([__DIR__ . '/data/hooked-properties-in-class.php'], [ + [ + 'Property hooks are supported only on PHP 8.4 and later.', + 7, + ], + ]); + } + + public function testPhp84AndHookedPropertiesWithoutBodiesInClass(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/hooked-properties-without-bodies-in-class.php'], [ + [ + 'Non-abstract properties cannot include hooks without bodies.', + 7, + ], + [ + 'Non-abstract properties cannot include hooks without bodies.', + 9, + ], + ]); + } + + public function testPhp84AndNonAbstractHookedPropertiesInClass(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/non-abstract-hooked-properties-in-class.php'], [ + [ + 'Non-abstract properties cannot include hooks without bodies.', + 7, + ], + [ + 'Non-abstract properties cannot include hooks without bodies.', + 9, + ], + ]); + } + + public function testPhp84AndAbstractHookedPropertiesInClass(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/abstract-hooked-properties-in-class.php'], [ + [ + 'Non-abstract classes cannot include abstract properties.', + 7, + ], + [ + 'Non-abstract classes cannot include abstract properties.', + 9, + ], + ]); + } + + public function testPhp84AndNonAbstractHookedPropertiesInAbstractClass(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/non-abstract-hooked-properties-in-abstract-class.php'], [ + [ + 'Non-abstract properties cannot include hooks without bodies.', + 7, + ], + [ + 'Non-abstract properties cannot include hooks without bodies.', + 9, + ], + [ + 'Non-abstract properties cannot include hooks without bodies.', + 25, + ], + ]); + } + + public function testPhp84AndAbstractNonHookedPropertiesInAbstractClass(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/abstract-non-hooked-properties-in-abstract-class.php'], [ + [ + 'Only hooked properties can be declared abstract.', + 7, + ], + [ + 'Only hooked properties can be declared abstract.', + 9, + ], + ]); + } + + public function testPhp84AndAbstractHookedPropertiesWithBodies(): void + { + if (PHP_VERSION_ID < 80400) { + $this->markTestSkipped('Test requires PHP 8.4 or later.'); + } + + $this->analyse([__DIR__ . '/data/abstract-hooked-properties-with-bodies.php'], [ + [ + 'Abstract properties must specify at least one abstract hook.', + 7, + ], + [ + 'Abstract properties must specify at least one abstract hook.', + 12, + ], + ]); + } + +} diff --git a/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php index d5834f4003..f3ba064bac 100644 --- a/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/ReadingWriteOnlyPropertiesRuleTest.php @@ -16,7 +16,7 @@ class ReadingWriteOnlyPropertiesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new ReadingWriteOnlyPropertiesRule(new PropertyDescriptor(), new PropertyReflectionFinder(), new RuleLevelHelper($this->createReflectionProvider(), true, $this->checkThisOnly, true, false, false, true, false), $this->checkThisOnly); + return new ReadingWriteOnlyPropertiesRule(new PropertyDescriptor(), new PropertyReflectionFinder(), new RuleLevelHelper($this->createReflectionProvider(), true, $this->checkThisOnly, true, false, false, false), $this->checkThisOnly); } public function testPropertyMustBeReadableInAssignOp(): void 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 []; - } - -} diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 4c87845d24..dede3e9211 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -17,7 +17,7 @@ class TypesAssignedToPropertiesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new TypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, true, false), new PropertyReflectionFinder()); + return new TypesAssignedToPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, false), new PropertyReflectionFinder()); } public function testTypesAssignedToProperties(): void @@ -353,9 +353,6 @@ public function testBug5804(): void public function testBug6286(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->analyse([__DIR__ . '/data/bug-6286.php'], [ [ 'Property Bug6286\HelloWorld::$details (array{name: string, age: int}) does not accept array{name: string, age: \'Forty-two\'}.', @@ -446,19 +443,12 @@ public function testGenericObjectWithUnspecifiedTemplateTypesLevel8(): void public function testBug5382(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } $this->checkExplicitMixed = false; $this->analyse([__DIR__ . '/data/bug-5382.php'], []); } public function testBug6757(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/bug-6757.php'], []); } @@ -544,10 +534,6 @@ public function testIntegerRangesAndConstants(): void public function testBug3311b(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/bug-3311b.php'], [ [ @@ -566,20 +552,12 @@ public function testBug7789(): void public function testBug9131(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/bug-9131.php'], []); } public function testBug8222(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/bug-8222.php'], []); } @@ -678,20 +656,26 @@ public function testBug11617(): void $this->checkExplicitMixed = true; $this->analyse([__DIR__ . '/data/bug-11617.php'], [ [ - 'Property Bug11617\HelloWorld::$params (array) does not accept array.', + 'Property Bug11617\HelloWorld::$params (array) does not accept array|string>.', 14, ], [ - 'Property Bug11617\HelloWorld::$params (array) does not accept array.', + 'Property Bug11617\HelloWorld::$params (array) does not accept array|string>.', 16, ], [ - 'Property Bug11617\HelloWorld::$params (array) does not accept array.', + 'Property Bug11617\HelloWorld::$params (array) does not accept array|string>.', 21, ], ]); } + public function testBug4174(): void + { + $this->checkExplicitMixed = true; + $this->analyse([__DIR__ . '/data/bug-4174.php'], []); + } + public function testBug12131(): void { $this->checkExplicitMixed = true; diff --git a/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php index d3196aba89..fb64553a3b 100644 --- a/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/WritingToReadOnlyPropertiesRuleTest.php @@ -16,7 +16,7 @@ class WritingToReadOnlyPropertiesRuleTest extends RuleTestCase protected function getRule(): Rule { - return new WritingToReadOnlyPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false), new PropertyDescriptor(), new PropertyReflectionFinder(), $this->checkThisOnly); + return new WritingToReadOnlyPropertiesRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false), new PropertyDescriptor(), new PropertyReflectionFinder(), $this->checkThisOnly); } public function testCheckThisOnlyProperties(): void diff --git a/tests/PHPStan/Rules/Properties/data/abstract-hooked-properties-in-class.php b/tests/PHPStan/Rules/Properties/data/abstract-hooked-properties-in-class.php new file mode 100644 index 0000000000..d035d36810 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/abstract-hooked-properties-in-class.php @@ -0,0 +1,10 @@ + $this->name; + set => $this->name = $value; + } + + public abstract string $lastName { + get => $this->lastName; + set => $this->lastName = $value; + } + + public abstract string $middleName { + get => $this->name; + set; + } + + public abstract string $familyName { + get; + set; + } +} diff --git a/tests/PHPStan/Rules/Properties/data/abstract-non-hooked-properties-in-abstract-class.php b/tests/PHPStan/Rules/Properties/data/abstract-non-hooked-properties-in-abstract-class.php new file mode 100644 index 0000000000..b34e66a886 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/abstract-non-hooked-properties-in-abstract-class.php @@ -0,0 +1,10 @@ += 7.4 +foo) && isset($m->bar)) { + echo $m->foo; + echo $m->bar; + echo $m->baz; + } + } + +} diff --git a/tests/PHPStan/Rules/Properties/data/access-static-properties-assign-op.php b/tests/PHPStan/Rules/Properties/data/access-static-properties-assign-op.php index 0cf096c2e1..9d065b72f3 100644 --- a/tests/PHPStan/Rules/Properties/data/access-static-properties-assign-op.php +++ b/tests/PHPStan/Rules/Properties/data/access-static-properties-assign-op.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 + + */ + public static function getArrayConstAsKey(): array { + return [ + self::NUMBER_TYPE_OFF => 'Off', + self::NUMBER_TYPE_HEAD => 'Head', + self::NUMBER_TYPE_POSITION => 'Position', + ]; + } + + /** + * @return list + */ + public static function getArrayConstAsValue(): array { + return [ + self::NUMBER_TYPE_OFF, + self::NUMBER_TYPE_HEAD, + self::NUMBER_TYPE_POSITION, + ]; + } + + public function checkConstViaArrayKey(): void + { + $numberArray = self::getArrayConstAsKey(); + + // --- + + $newvalue = $this->getIntFromPost('newValue'); + + if ($newvalue && array_key_exists($newvalue, $numberArray)) { + $this->newValue = $newvalue; + } + + if (isset($numberArray[$newvalue])) { + $this->newValue = $newvalue; + } + + // --- + + $newvalue = $this->getIntFromPostWithoutNull('newValue'); + + if ($newvalue && array_key_exists($newvalue, $numberArray)) { + $this->newValue = $newvalue; + } + + if (isset($numberArray[$newvalue])) { + $this->newValue = $newvalue; + } + } + + public function checkConstViaArrayValue(): void + { + $numberArray = self::getArrayConstAsValue(); + + // --- + + $newvalue = $this->getIntFromPost('newValue'); + + if ($newvalue && in_array($newvalue, $numberArray, true)) { + $this->newValue = $newvalue; + } + + // --- + + $newvalue = $this->getIntFromPostWithoutNull('newValue'); + + if ($newvalue && in_array($newvalue, $numberArray, true)) { + $this->newValue = $newvalue; + } + } + + public function getIntFromPost(string $key): ?int { + return isset($_POST[$key]) ? (int)$_POST[$key] : null; + } + + public function getIntFromPostWithoutNull(string $key): int { + return isset($_POST[$key]) ? (int)$_POST[$key] : 0; + } +} diff --git a/tests/PHPStan/Rules/Properties/data/bug-5382.php b/tests/PHPStan/Rules/Properties/data/bug-5382.php index b75b4ab167..7ec41886da 100644 --- a/tests/PHPStan/Rules/Properties/data/bug-5382.php +++ b/tests/PHPStan/Rules/Properties/data/bug-5382.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 + $this->name; + set => $this->name = $value; + } +} diff --git a/tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php b/tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php new file mode 100644 index 0000000000..dc839f0d2c --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/hooked-properties-without-bodies-in-class.php @@ -0,0 +1,10 @@ += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 7.4 += 70300) { - $this->markTestSkipped('This test requires PHP < 7.3.0'); - } - - $this->analyse( - [__DIR__ . '/data/valid-regex-pattern.php'], - [ - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 6, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 7, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 11, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 12, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 16, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 17, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 21, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 22, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 26, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 27, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 29, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 29, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 32, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 33, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 35, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 35, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 38, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 39, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 41, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 41, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok', - 43, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 1 in pattern: ~(~', - 43, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)', - 57, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)', - 58, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 7 in pattern: ~((?:.*)~', - 59, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)nono', - 61, - ], - [ - 'Regex pattern is invalid: Delimiter must not be alphanumeric or backslash in pattern: nok(?:.*)nope', - 62, - ], - [ - 'Regex pattern is invalid: Compilation failed: missing ) at offset 7 in pattern: ~((?:.*)~', - 63, - ], - ], - ); - } - - public function testValidRegexPatternAfter73(): void - { - if (PHP_VERSION_ID < 70300) { - $this->markTestSkipped('This test requires PHP >= 7.3.0'); - } - $messagePart = 'alphanumeric or backslash'; if (PHP_VERSION_ID >= 80200) { $messagePart = 'alphanumeric, backslash, or NUL'; diff --git a/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php b/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php index cad3ca757f..a98c638d24 100644 --- a/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php +++ b/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php @@ -14,11 +14,9 @@ class TooWideMethodReturnTypehintRuleTest extends RuleTestCase private bool $checkProtectedAndPublicMethods = true; - private bool $alwaysCheckFinal = false; - protected function getRule(): Rule { - return new TooWideMethodReturnTypehintRule($this->checkProtectedAndPublicMethods, $this->alwaysCheckFinal); + return new TooWideMethodReturnTypehintRule($this->checkProtectedAndPublicMethods); } public function testPrivate(): void @@ -113,26 +111,6 @@ public function testBug6175(): void public function dataAlwaysCheckFinal(): iterable { yield [ - false, - false, - [ - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\Foo::test() never returns null so it can be removed from the return type.', - 8, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FinalFoo::test() never returns null so it can be removed from the return type.', - 28, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FooFinalMethods::test() never returns null so it can be removed from the return type.', - 48, - ], - ], - ]; - - yield [ - true, false, [ [ @@ -167,42 +145,6 @@ public function dataAlwaysCheckFinal(): iterable ]; yield [ - false, - true, - [ - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\Foo::test() never returns null so it can be removed from the return type.', - 8, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FinalFoo::test() never returns null so it can be removed from the return type.', - 28, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FinalFoo::test2() never returns null so it can be removed from the return type.', - 33, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FinalFoo::test3() never returns null so it can be removed from the return type.', - 38, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FooFinalMethods::test() never returns null so it can be removed from the return type.', - 48, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FooFinalMethods::test2() never returns null so it can be removed from the return type.', - 53, - ], - [ - 'Method MethodTooWideReturnAlwaysCheckFinal\FooFinalMethods::test3() never returns null so it can be removed from the return type.', - 58, - ], - ], - ]; - - yield [ - true, true, [ [ @@ -241,17 +183,15 @@ public function dataAlwaysCheckFinal(): iterable * @dataProvider dataAlwaysCheckFinal * @param list $expectedErrors */ - public function testAlwaysCheckFinal(bool $checkProtectedAndPublicMethods, bool $alwaysCheckFinal, array $expectedErrors): void + public function testAlwaysCheckFinal(bool $checkProtectedAndPublicMethods, array $expectedErrors): void { $this->checkProtectedAndPublicMethods = $checkProtectedAndPublicMethods; - $this->alwaysCheckFinal = $alwaysCheckFinal; $this->analyse([__DIR__ . '/data/method-too-wide-return-always-check-final.php'], $expectedErrors); } public function testBug11980(): void { $this->checkProtectedAndPublicMethods = true; - $this->alwaysCheckFinal = true; $this->analyse([__DIR__ . '/data/bug-11980.php'], [ [ 'Method Bug11980\Demo::process2() never returns void so it can be removed from the return type.', diff --git a/tests/PHPStan/Rules/TooWideTypehints/data/bug-10684.php b/tests/PHPStan/Rules/TooWideTypehints/data/bug-10684.php index 1949d4d8b6..4335dabd72 100644 --- a/tests/PHPStan/Rules/TooWideTypehints/data/bug-10684.php +++ b/tests/PHPStan/Rules/TooWideTypehints/data/bug-10684.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 +getByType(InitializerExprTypeResolver::class)); + return new ConflictingTraitConstantsRule(self::getContainer()->getByType(InitializerExprTypeResolver::class), $this->createReflectionProvider()); } public function testRule(): void diff --git a/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php b/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php new file mode 100644 index 0000000000..fb35b438a0 --- /dev/null +++ b/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php @@ -0,0 +1,102 @@ + + */ +class TraitAttributesRuleTest extends RuleTestCase +{ + + private bool $checkExplicitMixed = false; + + private bool $checkImplicitMixed = false; + + protected function getRule(): Rule + { + $reflectionProvider = $this->createReflectionProvider(); + return new TraitAttributesRule( + new AttributesCheck( + $reflectionProvider, + new FunctionCallParametersCheck( + new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false), + new NullsafeCheck(), + new UnresolvableTypeHelper(), + new PropertyReflectionFinder(), + true, + true, + true, + true, + ), + new ClassNameCheck( + new ClassCaseSensitivityCheck($reflectionProvider, false), + new ClassForbiddenNameCheck(self::getContainer()), + ), + true, + ), + ); + } + + public function testRule(): void + { + if (PHP_VERSION_ID < 80000) { + $this->markTestSkipped('Test requires PHP 8.0.'); + } + + $this->analyse([__DIR__ . '/data/trait-attributes.php'], [ + [ + 'Attribute class TraitAttributes\AbstractAttribute is abstract.', + 8, + ], + [ + 'Attribute class TraitAttributes\MyTargettedAttribute does not have the class target.', + 20, + ], + ]); + } + + public function testBug12011(): void + { + if (PHP_VERSION_ID < 80300) { + $this->markTestSkipped('Test requires PHP 8.3.'); + } + + $this->checkExplicitMixed = true; + $this->checkImplicitMixed = true; + + $this->analyse([__DIR__ . '/data/bug-12011.php'], [ + [ + 'Parameter #1 $name of attribute class Bug12011Trait\Table constructor expects string|null, int given.', + 8, + ], + ]); + } + + public function testBug12281(): void + { + if (PHP_VERSION_ID < 80100) { + $this->markTestSkipped('Test requires PHP 8.1.'); + } + + $this->analyse([__DIR__ . '/data/bug-12281.php'], [ + [ + 'Attribute class AllowDynamicProperties cannot be used with trait.', + 11, + ], + ]); + } + +} diff --git a/tests/PHPStan/Rules/Traits/data/bug-12011.php b/tests/PHPStan/Rules/Traits/data/bug-12011.php new file mode 100644 index 0000000000..32b09d38d3 --- /dev/null +++ b/tests/PHPStan/Rules/Traits/data/bug-12011.php @@ -0,0 +1,26 @@ += 8.3 + +namespace Bug12011Trait; + +use Attribute; + + +#[Table(self::TABLE_NAME)] +trait MyTrait +{ + private const int TABLE_NAME = 1; +} + +class X { + use MyTrait; +} + +#[Attribute(Attribute::TARGET_CLASS)] +final class Table +{ + public function __construct( + public readonly string|null $name = null, + public readonly string|null $schema = null, + ) { + } +} diff --git a/tests/PHPStan/Rules/Traits/data/bug-12281.php b/tests/PHPStan/Rules/Traits/data/bug-12281.php new file mode 100644 index 0000000000..da7d088f1a --- /dev/null +++ b/tests/PHPStan/Rules/Traits/data/bug-12281.php @@ -0,0 +1,19 @@ += 8.2 + +namespace Bug12281Traits; + +#[\AllowDynamicProperties] +enum BlogDataEnum { /* … */ } // reported by ClassAttributesRule + +#[\AllowDynamicProperties] +interface BlogDataInterface { /* … */ } // reported by ClassAttributesRule + +#[\AllowDynamicProperties] +trait BlogDataTrait { /* … */ } + +class Uses +{ + + use BlogDataTrait; + +} diff --git a/tests/PHPStan/Rules/Traits/data/trait-attributes.php b/tests/PHPStan/Rules/Traits/data/trait-attributes.php new file mode 100644 index 0000000000..67906a2dfe --- /dev/null +++ b/tests/PHPStan/Rules/Traits/data/trait-attributes.php @@ -0,0 +1,30 @@ +treatPhpDocTypesAsCertain, - $this->strictUnnecessaryNullsafePropertyFetch, )); } @@ -38,7 +35,6 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testRule(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/empty-rule.php'], [ [ 'Offset \'nonexistent\' on array{2: bool, 3: false, 4: true}|array{bool, false, bool, false, true} in empty() does not exist.', @@ -78,7 +74,6 @@ public function testRule(): void public function testBug970(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-970.php'], [ [ 'Variable $ar in empty() is never defined.', @@ -90,7 +85,6 @@ public function testBug970(): void public function testBug6974(): void { $this->treatPhpDocTypesAsCertain = false; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-6974.php'], [ [ 'Variable $a in empty() always exists and is always falsy.', @@ -102,7 +96,6 @@ public function testBug6974(): void public function testBug6974TreatPhpDocTypesAsCertain(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-6974.php'], [ [ 'Variable $a in empty() always exists and is always falsy.', @@ -122,24 +115,6 @@ public function testBug7109(): void } $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; - - $this->analyse([__DIR__ . '/../Properties/data/bug-7109.php'], [ - [ - 'Expression in empty() is not falsy.', - 59, - ], - ]); - } - - public function testBug7109Strict(): void - { - if (PHP_VERSION_ID < 80000) { - $this->markTestSkipped('Test requires PHP 8.0.'); - } - - $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../Properties/data/bug-7109.php'], [ [ @@ -176,7 +151,6 @@ public function testBug7109Strict(): void public function testBug7318(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../Properties/data/bug-7318.php'], []); } @@ -184,7 +158,6 @@ public function testBug7318(): void public function testBug7424(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-7424.php'], []); } @@ -192,7 +165,6 @@ public function testBug7424(): void public function testBug7724(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-7724.php'], []); } @@ -200,7 +172,6 @@ public function testBug7724(): void public function testBug7199(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-7199.php'], []); } @@ -208,7 +179,6 @@ public function testBug7199(): void public function testBug9126(): void { $this->treatPhpDocTypesAsCertain = false; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-9126.php'], []); } @@ -225,7 +195,6 @@ public function dataBug9403(): iterable public function testBug9403(bool $treatPhpDocTypesAsCertain): void { $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-9403.php'], []); } diff --git a/tests/PHPStan/Rules/Variables/IssetRuleTest.php b/tests/PHPStan/Rules/Variables/IssetRuleTest.php index 2c22dfd35a..a3e1ed68a2 100644 --- a/tests/PHPStan/Rules/Variables/IssetRuleTest.php +++ b/tests/PHPStan/Rules/Variables/IssetRuleTest.php @@ -17,8 +17,6 @@ class IssetRuleTest extends RuleTestCase private bool $treatPhpDocTypesAsCertain; - private bool $strictUnnecessaryNullsafePropertyFetch; - protected function getRule(): Rule { return new IssetRule(new IssetCheck( @@ -26,7 +24,6 @@ protected function getRule(): Rule new PropertyReflectionFinder(), true, $this->treatPhpDocTypesAsCertain, - $this->strictUnnecessaryNullsafePropertyFetch, )); } @@ -38,7 +35,6 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testRule(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/isset.php'], [ [ 'Property IssetRule\FooCoalesce::$string (string) in isset() is not nullable.', @@ -126,7 +122,6 @@ public function testRule(): void public function testRuleWithoutTreatPhpDocTypesAsCertain(): void { $this->treatPhpDocTypesAsCertain = false; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/isset.php'], [ [ 'Property IssetRule\FooCoalesce::$string (string) in isset() is not nullable.', @@ -206,7 +201,6 @@ public function testRuleWithoutTreatPhpDocTypesAsCertain(): void public function testNativePropertyTypes(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/isset-native-property-types.php'], [ /*[ // no way to achieve this with current PHP Reflection API @@ -225,14 +219,12 @@ public function testNativePropertyTypes(): void public function testBug4290(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-4290.php'], []); } public function testBug4671(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-4671.php'], [[ 'Offset numeric-string on array in isset() does not exist.', 13, @@ -242,7 +234,6 @@ public function testBug4671(): void public function testVariableCertaintyInIsset(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/variable-certainty-isset.php'], [ [ 'Variable $alwaysDefinedNotNullable in isset() always exists and is not nullable.', @@ -318,7 +309,6 @@ public function testVariableCertaintyInIsset(): void public function testIssetInGlobalScope(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/isset-global-scope.php'], [ [ 'Variable $alwaysDefinedNotNullable in isset() always exists and is not nullable.', @@ -330,35 +320,21 @@ public function testIssetInGlobalScope(): void public function testNullsafe(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; - $this->analyse([__DIR__ . '/data/isset-nullsafe.php'], []); - } - - public function testBug7109(): void - { - if (PHP_VERSION_ID < 80000) { - $this->markTestSkipped('Test requires PHP 8.0.'); - } - - $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; - - $this->analyse([__DIR__ . '/../Properties/data/bug-7109.php'], [ + $this->analyse([__DIR__ . '/data/isset-nullsafe.php'], [ [ - 'Expression in isset() is not nullable.', - 41, + 'Using nullsafe property access "?->bla" in isset() is unnecessary. Use -> instead.', + 10, ], ]); } - public function testBug7109Strict(): void + public function testBug7109(): void { if (PHP_VERSION_ID < 80000) { $this->markTestSkipped('Test requires PHP 8.0.'); } $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../Properties/data/bug-7109.php'], [ [ @@ -387,7 +363,6 @@ public function testBug7109Strict(): void public function testBug7318(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../Properties/data/bug-7318.php'], [ [ @@ -400,7 +375,6 @@ public function testBug7318(): void public function testBug6163(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-6163.php'], []); } @@ -408,7 +382,6 @@ public function testBug6163(): void public function testBug6997(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-6997.php'], []); } @@ -420,7 +393,6 @@ public function testBug7776(): void } $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-7776.php'], []); } @@ -428,7 +400,6 @@ public function testBug7776(): void public function testBug6008(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-6008.php'], []); } @@ -436,7 +407,6 @@ public function testBug6008(): void public function testBug7292(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-7292.php'], []); } @@ -444,7 +414,6 @@ public function testBug7292(): void public function testObjectShapes(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; // could be checked but current is not $this->analyse([__DIR__ . '/data/isset-object-shapes.php'], []); @@ -453,7 +422,6 @@ public function testObjectShapes(): void public function testBug10151(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-10151.php'], []); } @@ -461,7 +429,6 @@ public function testBug10151(): void public function testBug3985(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../../Analyser/nsrt/bug-3985.php'], [ [ @@ -478,7 +445,6 @@ public function testBug3985(): void public function testBug10064(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-10064.php'], []); } diff --git a/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php b/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php index 4781fa1f18..2b32877d52 100644 --- a/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php +++ b/tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php @@ -17,8 +17,6 @@ class NullCoalesceRuleTest extends RuleTestCase private bool $treatPhpDocTypesAsCertain; - private bool $strictUnnecessaryNullsafePropertyFetch; - protected function getRule(): Rule { return new NullCoalesceRule(new IssetCheck( @@ -26,7 +24,6 @@ protected function getRule(): Rule new PropertyReflectionFinder(), true, $this->treatPhpDocTypesAsCertain, - $this->strictUnnecessaryNullsafePropertyFetch, )); } @@ -38,7 +35,6 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool public function testCoalesceRule(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $errors = [ [ 'Property CoalesceRule\FooCoalesce::$string (string) on left side of ?? is not nullable.', @@ -145,7 +141,6 @@ public function testCoalesceRule(): void public function testCoalesceAssignRule(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/null-coalesce-assign.php'], [ [ 'Property CoalesceAssignRule\FooCoalesce::$string (string) on left side of ??= is not nullable.', @@ -209,14 +204,12 @@ public function testCoalesceAssignRule(): void public function testNullsafe(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/null-coalesce-nullsafe.php'], []); } public function testVariableCertaintyInNullCoalesce(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/variable-certainty-null.php'], [ [ 'Variable $scalar on left side of ?? always exists and is not nullable.', @@ -236,7 +229,6 @@ public function testVariableCertaintyInNullCoalesce(): void public function testVariableCertaintyInNullCoalesceAssign(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/variable-certainty-null-assign.php'], [ [ 'Variable $scalar on left side of ??= always exists and is not nullable.', @@ -256,7 +248,6 @@ public function testVariableCertaintyInNullCoalesceAssign(): void public function testNullCoalesceInGlobalScope(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/null-coalesce-global-scope.php'], [ [ 'Variable $bar on left side of ?? always exists and is not nullable.', @@ -268,7 +259,6 @@ public function testNullCoalesceInGlobalScope(): void public function testBug5933(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/data/bug-5933.php'], []); } @@ -279,24 +269,6 @@ public function testBug7109(): void } $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; - - $this->analyse([__DIR__ . '/../Properties/data/bug-7109.php'], [ - [ - 'Expression on left side of ?? is not nullable.', - 40, - ], - ]); - } - - public function testBug7109Strict(): void - { - if (PHP_VERSION_ID < 80000) { - $this->markTestSkipped('Test requires PHP 8.0.'); - } - - $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../Properties/data/bug-7109.php'], [ [ @@ -324,12 +296,7 @@ public function testBug7109Strict(): void public function testBug7190(): void { - if (PHP_VERSION_ID < 70400) { - $this->markTestSkipped('Test requires PHP 7.4.'); - } - $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = false; $this->analyse([__DIR__ . '/../Properties/data/bug-7190.php'], [ [ @@ -342,7 +309,6 @@ public function testBug7190(): void public function testBug7318(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/../Properties/data/bug-7318.php'], [ [ @@ -355,7 +321,6 @@ public function testBug7318(): void public function testBug7968(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-7968.php'], []); } @@ -363,7 +328,6 @@ public function testBug7968(): void public function testBug8084(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-8084.php'], []); } @@ -371,7 +335,6 @@ public function testBug8084(): void public function testBug10577(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-10577.php'], []); } @@ -379,7 +342,6 @@ public function testBug10577(): void public function testBug10610(): void { $this->treatPhpDocTypesAsCertain = true; - $this->strictUnnecessaryNullsafePropertyFetch = true; $this->analyse([__DIR__ . '/data/bug-10610.php'], []); } diff --git a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php index ed68b380b1..95e94df168 100644 --- a/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ParameterOutAssignedTypeRuleTest.php @@ -15,7 +15,7 @@ class ParameterOutAssignedTypeRuleTest extends RuleTestCase protected function getRule(): TRule { return new ParameterOutAssignedTypeRule( - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, true, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, true, false, false), ); } diff --git a/tests/PHPStan/Rules/Variables/ParameterOutExecutionEndTypeRuleTest.php b/tests/PHPStan/Rules/Variables/ParameterOutExecutionEndTypeRuleTest.php index 26157f4ffb..8f3b40c7b6 100644 --- a/tests/PHPStan/Rules/Variables/ParameterOutExecutionEndTypeRuleTest.php +++ b/tests/PHPStan/Rules/Variables/ParameterOutExecutionEndTypeRuleTest.php @@ -15,7 +15,7 @@ class ParameterOutExecutionEndTypeRuleTest extends RuleTestCase protected function getRule(): Rule { return new ParameterOutExecutionEndTypeRule( - new RuleLevelHelper($this->createReflectionProvider(), true, false, true, true, false, true, false), + new RuleLevelHelper($this->createReflectionProvider(), true, false, true, true, false, false), ); } 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/VariableCloningRuleTest.php b/tests/PHPStan/Rules/Variables/VariableCloningRuleTest.php index 801d2b31f4..f1c3af3cc0 100644 --- a/tests/PHPStan/Rules/Variables/VariableCloningRuleTest.php +++ b/tests/PHPStan/Rules/Variables/VariableCloningRuleTest.php @@ -15,7 +15,7 @@ class VariableCloningRuleTest extends RuleTestCase protected function getRule(): Rule { - return new VariableCloningRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false)); + return new VariableCloningRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, false)); } public function testClone(): void diff --git a/tests/PHPStan/Rules/Variables/data/bug-10151.php b/tests/PHPStan/Rules/Variables/data/bug-10151.php index f93e860eb8..78d5c4219d 100644 --- a/tests/PHPStan/Rules/Variables/data/bug-10151.php +++ b/tests/PHPStan/Rules/Variables/data/bug-10151.php @@ -1,4 +1,4 @@ -= 7.4 +&hasOffsetValue('bar', 'b')&hasOffsetValue('foo', 'a')", $data); + assertType("non-empty-array&hasOffsetValue('bar', 'b')&hasOffsetValue('foo', 'a')", $data); return $data; } } diff --git a/tests/PHPStan/Rules/Variables/data/bug-7292.php b/tests/PHPStan/Rules/Variables/data/bug-7292.php index d4d09b2ed4..9e66bb9793 100644 --- a/tests/PHPStan/Rules/Variables/data/bug-7292.php +++ b/tests/PHPStan/Rules/Variables/data/bug-7292.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 +', $review); + assertType('array>', $review); if ( array_key_exists('review', $review['SurveyInvitation']) && $review['SurveyInvitation']['review'] === null ) { - assertType("array&hasOffsetValue('SurveyInvitation', array&hasOffsetValue('review', null))", $review); + assertType("non-empty-array>&hasOffsetValue('SurveyInvitation', non-empty-array&hasOffsetValue('review', null))", $review); $review['Review'] = [ 'id' => null, 'text' => null, 'answer' => null, ]; - assertType("non-empty-array&hasOffsetValue('Review', array{id: null, text: null, answer: null})&hasOffsetValue('SurveyInvitation', array&hasOffsetValue('review', null))", $review); + assertType("non-empty-array>&hasOffsetValue('Review', array{id: null, text: null, answer: null})&hasOffsetValue('SurveyInvitation', non-empty-array&hasOffsetValue('review', null))", $review); unset($review['SurveyInvitation']['review']); - assertType("non-empty-array&hasOffsetValue('Review', array)&hasOffsetValue('SurveyInvitation', array)", $review); + assertType("non-empty-array>&hasOffsetValue('Review', array)&hasOffsetValue('SurveyInvitation', array)", $review); } - assertType('array', $review); + assertType('array>', $review); if (array_key_exists('User', $review['Review'])) { - assertType("array&hasOffsetValue('Review', array&hasOffset('User'))", $review); + assertType("non-empty-array>&hasOffsetValue('Review', non-empty-array&hasOffset('User'))", $review); $review['User'] = $review['Review']['User']; - assertType("hasOffsetValue('Review', array&hasOffset('User'))&hasOffsetValue('User', mixed)&non-empty-array", $review); + assertType("non-empty-array&hasOffsetValue('Review', non-empty-array&hasOffset('User'))&hasOffsetValue('User', mixed)", $review); unset($review['Review']['User']); - assertType("hasOffsetValue('Review', array)&hasOffsetValue('User', array)&non-empty-array", $review); + assertType("non-empty-array&hasOffsetValue('Review', array)&hasOffsetValue('User', array)", $review); } - assertType("array&hasOffsetValue('Review', array)", $review); + assertType("non-empty-array&hasOffsetValue('Review', array)", $review); }; diff --git a/tests/PHPStan/Rules/Variables/data/defined-variables-arrow-functions.php b/tests/PHPStan/Rules/Variables/data/defined-variables-arrow-functions.php index 10b0fdcb42..3196608c7a 100644 --- a/tests/PHPStan/Rules/Variables/data/defined-variables-arrow-functions.php +++ b/tests/PHPStan/Rules/Variables/data/defined-variables-arrow-functions.php @@ -1,4 +1,4 @@ -= 7.4 += 7.4 += 7.4 += 7.4 += 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; -}; diff --git a/tests/PHPStan/Rules/Variables/data/variable-certainty-null-assign.php b/tests/PHPStan/Rules/Variables/data/variable-certainty-null-assign.php index 8500b14063..d0d2b7c927 100644 --- a/tests/PHPStan/Rules/Variables/data/variable-certainty-null-assign.php +++ b/tests/PHPStan/Rules/Variables/data/variable-certainty-null-assign.php @@ -1,4 +1,4 @@ -= 7.4 + @@ -37,10 +36,6 @@ public function processNode(Node $node, Scope $scope): array public function testRule(): void { - if (PHP_VERSION_ID < 70300) { - self::markTestSkipped('For some reason this test does not work on PHP 7.2 with old PHPUnit'); - } - try { $this->analyse([__DIR__ . '/data/empty-file.php'], []); self::fail('Should throw an exception'); diff --git a/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php b/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php index a70ff82ceb..a941dd86ee 100644 --- a/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php +++ b/tests/PHPStan/Type/Accessory/HasMethodTypeTest.php @@ -70,11 +70,6 @@ public function dataIsSuperTypeOf(): array new HasPropertyType('bar'), TrinaryLogic::createMaybe(), ], - [ - new HasMethodType('foo'), - new HasOffsetType(new MixedType()), - TrinaryLogic::createMaybe(), - ], [ new HasMethodType('foo'), new IterableType(new MixedType(), new MixedType()), diff --git a/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php b/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php index 52b44a6168..4cecca14c1 100644 --- a/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php +++ b/tests/PHPStan/Type/Accessory/HasPropertyTypeTest.php @@ -60,11 +60,6 @@ public function dataIsSuperTypeOf(): array new HasPropertyType('bar'), TrinaryLogic::createMaybe(), ], - [ - new HasPropertyType('foo'), - new HasOffsetType(new MixedType()), - TrinaryLogic::createMaybe(), - ], [ new HasPropertyType('foo'), new IterableType(new MixedType(), new MixedType()), diff --git a/tests/PHPStan/Type/ArrayTypeTest.php b/tests/PHPStan/Type/ArrayTypeTest.php index cd8ddce5bf..e701997c6c 100644 --- a/tests/PHPStan/Type/ArrayTypeTest.php +++ b/tests/PHPStan/Type/ArrayTypeTest.php @@ -71,6 +71,17 @@ public function dataIsSuperTypeOf(): array new IntersectionType([new ArrayType(new IntegerType(), new StringType()), new OversizedArrayType()]), TrinaryLogic::createYes(), ], + [ + new ArrayType(new StringType(), new MixedType()), + new ConstantArrayType([ + new ConstantStringType('a'), + new ConstantStringType('b'), + ], [ + new IntegerType(), + new UnionType([new IntegerType(), new NullType()]), + ]), + TrinaryLogic::createYes(), + ], ]; } @@ -145,7 +156,7 @@ public function testAccepts( TrinaryLogic $expectedResult, ): void { - $actualResult = $acceptingType->accepts($acceptedType, true); + $actualResult = $acceptingType->accepts($acceptedType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/BitwiseFlagHelperTest.php b/tests/PHPStan/Type/BitwiseFlagHelperTest.php index f2136604c3..7703524f47 100644 --- a/tests/PHPStan/Type/BitwiseFlagHelperTest.php +++ b/tests/PHPStan/Type/BitwiseFlagHelperTest.php @@ -127,13 +127,13 @@ public function testExprContainsConst(Expr $expr, string $constName, TrinaryLogi /** @var ScopeFactory $scopeFactory */ $scopeFactory = self::getContainer()->getByType(ScopeFactory::class); $scope = $scopeFactory->create(ScopeContext::create('file.php')) - ->assignVariable('mixedVar', new MixedType(), new MixedType()) - ->assignVariable('stringVar', new StringType(), new StringType()) - ->assignVariable('integerVar', new IntegerType(), new IntegerType()) - ->assignVariable('booleanVar', new BooleanType(), new BooleanType()) - ->assignVariable('floatVar', new FloatType(), new FloatType()) - ->assignVariable('unionIntFloatVar', new UnionType([new IntegerType(), new FloatType()]), new UnionType([new IntegerType(), new FloatType()])) - ->assignVariable('unionStringFloatVar', new UnionType([new StringType(), new FloatType()]), new UnionType([new StringType(), new FloatType()])); + ->assignVariable('mixedVar', new MixedType(), new MixedType(), TrinaryLogic::createYes()) + ->assignVariable('stringVar', new StringType(), new StringType(), TrinaryLogic::createYes()) + ->assignVariable('integerVar', new IntegerType(), new IntegerType(), TrinaryLogic::createYes()) + ->assignVariable('booleanVar', new BooleanType(), new BooleanType(), TrinaryLogic::createYes()) + ->assignVariable('floatVar', new FloatType(), new FloatType(), TrinaryLogic::createYes()) + ->assignVariable('unionIntFloatVar', new UnionType([new IntegerType(), new FloatType()]), new UnionType([new IntegerType(), new FloatType()]), TrinaryLogic::createYes()) + ->assignVariable('unionStringFloatVar', new UnionType([new StringType(), new FloatType()]), new UnionType([new StringType(), new FloatType()]), TrinaryLogic::createYes()); $analyser = new BitwiseFlagHelper($this->createReflectionProvider()); $actual = $analyser->bitwiseOrContainsConstant($expr, $scope, $constName); diff --git a/tests/PHPStan/Type/BooleanTypeTest.php b/tests/PHPStan/Type/BooleanTypeTest.php index 375210eea2..f7552cba51 100644 --- a/tests/PHPStan/Type/BooleanTypeTest.php +++ b/tests/PHPStan/Type/BooleanTypeTest.php @@ -52,7 +52,7 @@ public function dataAccepts(): array */ public function testAccepts(BooleanType $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/CallableTypeTest.php b/tests/PHPStan/Type/CallableTypeTest.php index 87d3bae274..a59308f40c 100644 --- a/tests/PHPStan/Type/CallableTypeTest.php +++ b/tests/PHPStan/Type/CallableTypeTest.php @@ -423,7 +423,7 @@ public function testAccepts( { $this->assertSame( $expectedResult->describe(), - $type->accepts($acceptedType, true)->describe(), + $type->accepts($acceptedType, true)->result->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), ); } diff --git a/tests/PHPStan/Type/ClassStringTypeTest.php b/tests/PHPStan/Type/ClassStringTypeTest.php index 2d827f7271..f4d19a2760 100644 --- a/tests/PHPStan/Type/ClassStringTypeTest.php +++ b/tests/PHPStan/Type/ClassStringTypeTest.php @@ -108,7 +108,7 @@ public function dataAccepts(): iterable */ public function testAccepts(ClassStringType $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php b/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php index 727fd65d01..b047b86a69 100644 --- a/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php +++ b/tests/PHPStan/Type/Constant/ConstantArrayTypeTest.php @@ -18,6 +18,7 @@ use PHPStan\Type\IterableType; use PHPStan\Type\MixedType; use PHPStan\Type\NeverType; +use PHPStan\Type\NullType; use PHPStan\Type\ObjectType; use PHPStan\Type\StringType; use PHPStan\Type\Type; @@ -189,7 +190,7 @@ public function dataAccepts(): iterable ], [ new StringType(), new IntegerType(), - ], 0, [0, 1]), + ], [0], [0, 1]), new ConstantArrayType([ new ConstantStringType('sorton'), new ConstantStringType('limit'), @@ -225,7 +226,7 @@ public function dataAccepts(): iterable ], [ new StringType(), new IntegerType(), - ], 0, [1]), + ], [0], [1]), new ConstantArrayType([ new ConstantStringType('sorton'), new ConstantStringType('limit'), @@ -241,7 +242,7 @@ public function dataAccepts(): iterable new ConstantStringType('limit'), ], [ new IntegerType(), - ], 0, [0]), + ], [0], [0]), new ConstantArrayType([ new ConstantStringType('limit'), ], [ @@ -255,7 +256,7 @@ public function dataAccepts(): iterable new ConstantStringType('limit'), ], [ new IntegerType(), - ], 0), + ], [0]), new ConstantArrayType([ new ConstantStringType('limit'), ], [ @@ -271,7 +272,7 @@ public function dataAccepts(): iterable ], [ new StringType(), new StringType(), - ], 0, [0, 1]), + ], [0], [0, 1]), new ConstantArrayType([ new ConstantStringType('sorton'), new ConstantStringType('limit'), @@ -289,7 +290,7 @@ public function dataAccepts(): iterable ], [ new StringType(), new StringType(), - ], 0, [0, 1]), + ], [0], [0, 1]), new ConstantArrayType([ new ConstantStringType('color'), ], [ @@ -305,7 +306,7 @@ public function dataAccepts(): iterable ], [ new StringType(), new StringType(), - ], 0, [0, 1]), + ], [0], [0, 1]), new ConstantArrayType([ new ConstantStringType('sound'), ], [ @@ -321,14 +322,14 @@ public function dataAccepts(): iterable ], [ new StringType(), new StringType(), - ], 0, [0, 1]), + ], [0], [0, 1]), new ConstantArrayType([ new ConstantStringType('foo'), new ConstantStringType('bar'), ], [ new ConstantStringType('s'), new ConstantStringType('m'), - ], 0, [0, 1]), + ], [0], [0, 1]), TrinaryLogic::createYes(), ]; @@ -339,7 +340,7 @@ public function dataAccepts(): iterable ], [ new StringType(), new IntegerType(), - ], 0, [0, 1]), + ], [0], [0, 1]), new ConstantArrayType([ new ConstantStringType('sorton'), new ConstantStringType('limit'), @@ -413,7 +414,7 @@ public function dataAccepts(): iterable */ public function testAccepts(Type $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), @@ -522,7 +523,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2), + ], [2]), new ConstantArrayType([], []), TrinaryLogic::createNo(), ]; @@ -534,7 +535,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0]), + ], [2], [0]), new ConstantArrayType([], []), TrinaryLogic::createNo(), ]; @@ -546,7 +547,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0, 1]), + ], [2], [0, 1]), new ConstantArrayType([], []), TrinaryLogic::createYes(), ]; @@ -558,12 +559,12 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0, 1]), + ], [2], [0, 1]), new ConstantArrayType([ new ConstantStringType('foo'), ], [ new IntegerType(), - ], 1, [0]), + ], [1], [0]), TrinaryLogic::createYes(), ]; @@ -579,7 +580,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0, 1]), + ], [2], [0, 1]), TrinaryLogic::createMaybe(), ]; @@ -595,7 +596,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0, 1]), + ], [2], [0, 1]), TrinaryLogic::createNo(), ]; @@ -606,7 +607,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0, 1]), + ], [2], [0, 1]), new ConstantArrayType([ new ConstantStringType('foo'), ], [ @@ -623,7 +624,7 @@ public function dataIsSuperTypeOf(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0, 1]), + ], [2], [0, 1]), TrinaryLogic::createMaybe(), ]; @@ -632,7 +633,7 @@ public function dataIsSuperTypeOf(): iterable new ConstantStringType('foo'), ], [ new IntegerType(), - ], 1, [0]), + ], [1], [0]), new ConstantArrayType([ new ConstantStringType('foo'), ], [ @@ -651,9 +652,45 @@ public function dataIsSuperTypeOf(): iterable new ConstantStringType('foo'), ], [ new IntegerType(), - ], 1, [0]), + ], [1], [0]), TrinaryLogic::createMaybe(), ]; + + yield [ + new ConstantArrayType([ + new ConstantStringType('a'), + new ConstantStringType('b'), + ], [ + new IntegerType(), + new UnionType([new IntegerType(), new NullType()]), + ]), + new ArrayType(new StringType(), new MixedType()), + TrinaryLogic::createMaybe(), + ]; + + yield [ + new ConstantArrayType([ + new ConstantStringType('a'), + new ConstantStringType('b'), + ], [ + new IntegerType(), + new UnionType([new IntegerType(), new NullType()]), + ]), + new ArrayType(new StringType(), new StringType()), + TrinaryLogic::createNo(), + ]; + + yield [ + new ConstantArrayType([ + new ConstantIntegerType(1), + new ConstantIntegerType(2), + ], [ + new IntegerType(), + new UnionType([new IntegerType(), new NullType()]), + ]), + new ArrayType(new StringType(), new MixedType()), + TrinaryLogic::createNo(), + ]; } /** @@ -886,14 +923,14 @@ public function dataValuesArray(): iterable ], [ new ConstantStringType('a'), new ConstantStringType('b'), - ], [20], [], false), + ], [20], [], TrinaryLogic::createNo()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), ], [ new ConstantStringType('a'), new ConstantStringType('b'), - ], [2], [], true), + ], [2], [], TrinaryLogic::createYes()), ]; yield 'optional-1' => [ @@ -909,7 +946,7 @@ public function dataValuesArray(): iterable new ConstantStringType('c'), new ConstantStringType('d'), new ConstantStringType('e'), - ], [15], [1, 3], false), + ], [15], [1, 3], TrinaryLogic::createNo()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), @@ -922,7 +959,7 @@ public function dataValuesArray(): iterable new UnionType([new ConstantStringType('c'), new ConstantStringType('d'), new ConstantStringType('e')]), new UnionType([new ConstantStringType('d'), new ConstantStringType('e')]), new ConstantStringType('e'), - ], [3, 4, 5], [3, 4], true), + ], [3, 4, 5], [3, 4], TrinaryLogic::createYes()), ]; yield 'optional-2' => [ @@ -938,7 +975,7 @@ public function dataValuesArray(): iterable new ConstantStringType('c'), new ConstantStringType('d'), new ConstantStringType('e'), - ], [15], [0, 2, 4], false), + ], [15], [0, 2, 4], TrinaryLogic::createNo()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), @@ -951,7 +988,7 @@ public function dataValuesArray(): iterable new UnionType([new ConstantStringType('c'), new ConstantStringType('d'), new ConstantStringType('e')]), new UnionType([new ConstantStringType('d'), new ConstantStringType('e')]), new ConstantStringType('e'), - ], [2, 3, 4, 5], [2, 3, 4], true), + ], [2, 3, 4, 5], [2, 3, 4], TrinaryLogic::createYes()), ]; yield 'optional-at-end-and-list' => [ @@ -963,7 +1000,7 @@ public function dataValuesArray(): iterable new ConstantStringType('a'), new ConstantStringType('b'), new ConstantStringType('c'), - ], [11, 12, 13], [1, 2], true), + ], [11, 12, 13], [1, 2], TrinaryLogic::createYes()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), @@ -972,7 +1009,7 @@ public function dataValuesArray(): iterable new ConstantStringType('a'), new ConstantStringType('b'), new ConstantStringType('c'), - ], [1, 2, 3], [1, 2], true), + ], [1, 2, 3], [1, 2], TrinaryLogic::createYes()), ]; yield 'optional-at-end-but-not-list' => [ @@ -984,7 +1021,7 @@ public function dataValuesArray(): iterable new ConstantStringType('a'), new ConstantStringType('b'), new ConstantStringType('c'), - ], [11, 12, 13], [1, 2], false), + ], [11, 12, 13], [1, 2], TrinaryLogic::createNo()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), @@ -993,7 +1030,7 @@ public function dataValuesArray(): iterable new ConstantStringType('a'), new UnionType([new ConstantStringType('b'), new ConstantStringType('c')]), new ConstantStringType('c'), - ], [1, 2, 3], [1, 2], true), + ], [1, 2, 3], [1, 2], TrinaryLogic::createYes()), ]; } diff --git a/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php b/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php index 1b39e5ff55..c33c33e5a6 100644 --- a/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php +++ b/tests/PHPStan/Type/Constant/ConstantIntegerTypeTest.php @@ -38,7 +38,7 @@ public function dataAccepts(): iterable */ public function testAccepts(ConstantIntegerType $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php b/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php index e700d67a3d..1bf9013c42 100644 --- a/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php +++ b/tests/PHPStan/Type/Enum/EnumCaseObjectTypeTest.php @@ -219,7 +219,7 @@ public function testAccepts( $this->assertSame( $expectedResult->describe(), - $type->accepts($acceptedType, true)->describe(), + $type->accepts($acceptedType, true)->result->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), ); } diff --git a/tests/PHPStan/Type/FileTypeMapperTest.php b/tests/PHPStan/Type/FileTypeMapperTest.php index a5be40c268..c1af0c7740 100644 --- a/tests/PHPStan/Type/FileTypeMapperTest.php +++ b/tests/PHPStan/Type/FileTypeMapperTest.php @@ -3,7 +3,6 @@ namespace PHPStan\Type; use DependentPhpDocs\Foo; -use PHPStan\Broker\Broker; use PHPStan\PhpDoc\Tag\ReturnTag; use PHPStan\ShouldNotHappenException; use PHPStan\Testing\PHPStanTestCase; @@ -161,7 +160,7 @@ public function testFileThrowsPhpDocs(): void public function testFileWithCyclicPhpDocs(): void { - self::getContainer()->getByType(Broker::class); + $this->createReflectionProvider(); /** @var FileTypeMapper $fileTypeMapper */ $fileTypeMapper = self::getContainer()->getByType(FileTypeMapper::class); diff --git a/tests/PHPStan/Type/FloatTypeTest.php b/tests/PHPStan/Type/FloatTypeTest.php index ef878bf6dd..04a9c270ca 100644 --- a/tests/PHPStan/Type/FloatTypeTest.php +++ b/tests/PHPStan/Type/FloatTypeTest.php @@ -66,7 +66,7 @@ public function dataAccepts(): array public function testAccepts(Type $otherType, TrinaryLogic $expectedResult): void { $type = new FloatType(); - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php b/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php index 3efd727f4c..ef6a0faf8d 100644 --- a/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php +++ b/tests/PHPStan/Type/Generic/GenericClassStringTypeTest.php @@ -284,7 +284,7 @@ public function testAccepts( TrinaryLogic $expectedResult, ): void { - $actualResult = $acceptingType->accepts($acceptedType, true); + $actualResult = $acceptingType->accepts($acceptedType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php b/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php index 1012234740..30539fae85 100644 --- a/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php +++ b/tests/PHPStan/Type/Generic/GenericObjectTypeTest.php @@ -340,7 +340,7 @@ public function testAccepts( TrinaryLogic $expectedResult, ): void { - $actualResult = $acceptingType->accepts($acceptedType, true); + $actualResult = $acceptingType->accepts($acceptedType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), @@ -461,7 +461,7 @@ public function testResolveTemplateTypes(Type $received, Type $template, array $ ); } - /** @return array}> */ + /** @return array}> */ public function dataGetReferencedTypeArguments(): array { $templateType = static fn ($name, ?Type $bound = null): Type => TemplateTypeFactory::create( @@ -477,7 +477,6 @@ public function dataGetReferencedTypeArguments(): array new GenericObjectType(D\Invariant::class, [ $templateType('T'), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -485,42 +484,11 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Invariant' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ], null, null, [ - TemplateTypeVariance::createCovariant(), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createContravariant(), - ), - ], - ], - 'param: Invariant' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ], null, null, [ - TemplateTypeVariance::createContravariant(), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createCovariant(), - ), - ], - ], 'param: Out' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Out::class, [ $templateType('T'), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -535,7 +503,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -552,7 +519,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -565,7 +531,6 @@ public function dataGetReferencedTypeArguments(): array new GenericObjectType(D\In::class, [ $templateType('T'), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -580,7 +545,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -597,7 +561,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -612,7 +575,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -627,7 +589,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -635,106 +596,11 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Out>' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\Out::class, [ - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createInvariant(), - ), - ], - ], - 'param: In>' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\In::class, [ - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createInvariant(), - ), - ], - ], - 'param: Invariant>' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\Out::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createCovariant(), - ), - ], - ], - 'param: Invariant>' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\In::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createContravariant(), - ), - ], - ], - 'param: In>>' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\In::class, [ - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\Out::class, [ - $templateType('T'), - ]), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createCovariant(), - ), - ], - ], - 'param: Out>>' => [ - TemplateTypeVariance::createContravariant(), - new GenericObjectType(D\Out::class, [ - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\In::class, [ - $templateType('T'), - ]), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createContravariant(), - ), - ], - ], 'return: Invariant' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Invariant::class, [ $templateType('T'), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -742,42 +608,11 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Invariant' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ], null, null, [ - TemplateTypeVariance::createCovariant(), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createCovariant(), - ), - ], - ], - 'return: Invariant' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ], null, null, [ - TemplateTypeVariance::createContravariant(), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createContravariant(), - ), - ], - ], 'return: Out' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Out::class, [ $templateType('T'), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -792,7 +627,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -809,7 +643,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -822,7 +655,6 @@ public function dataGetReferencedTypeArguments(): array new GenericObjectType(D\In::class, [ $templateType('T'), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -837,7 +669,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -854,7 +685,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -869,7 +699,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -884,101 +713,6 @@ public function dataGetReferencedTypeArguments(): array $templateType('T'), ]), ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createContravariant(), - ), - ], - ], - 'return: Out>' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\Out::class, [ - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createInvariant(), - ), - ], - ], - 'return: In>' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\In::class, [ - new GenericObjectType(D\Invariant::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createInvariant(), - ), - ], - ], - 'return: Invariant>' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\Out::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createCovariant(), - ), - ], - ], - 'return: Invariant>' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\In::class, [ - $templateType('T'), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createContravariant(), - ), - ], - ], - 'return: In>>' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\In::class, [ - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\Out::class, [ - $templateType('T'), - ]), - ]), - ]), - false, - [ - new TemplateTypeReference( - $templateType('T'), - TemplateTypeVariance::createCovariant(), - ), - ], - ], - 'return: Out>>' => [ - TemplateTypeVariance::createCovariant(), - new GenericObjectType(D\Out::class, [ - new GenericObjectType(D\Invariant::class, [ - new GenericObjectType(D\In::class, [ - $templateType('T'), - ]), - ]), - ]), - false, [ new TemplateTypeReference( $templateType('T'), @@ -986,14 +720,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Out> (with invariance composition)' => [ + 'param: Out>' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Out::class, [ new GenericObjectType(D\Invariant::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1001,14 +734,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: In> (with invariance composition)' => [ + 'param: In>' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\In::class, [ new GenericObjectType(D\Invariant::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1016,14 +748,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Invariant> (with invariance composition)' => [ + 'param: Invariant>' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Invariant::class, [ new GenericObjectType(D\Out::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1031,14 +762,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Invariant> (with invariance composition)' => [ + 'param: Invariant>' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Invariant::class, [ new GenericObjectType(D\In::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1046,7 +776,7 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: In>> (with invariance composition)' => [ + 'param: In>>' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\In::class, [ new GenericObjectType(D\Invariant::class, [ @@ -1055,7 +785,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1063,7 +792,7 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Out>> (with invariance composition)' => [ + 'param: Out>>' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Out::class, [ new GenericObjectType(D\Invariant::class, [ @@ -1072,7 +801,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1080,14 +808,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Invariant (with invariance composition)' => [ + 'param: Invariant' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Invariant::class, [ $templateType('T'), ], null, null, [ TemplateTypeVariance::createCovariant(), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1095,14 +822,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'param: Invariant (with invariance composition)' => [ + 'param: Invariant' => [ TemplateTypeVariance::createContravariant(), new GenericObjectType(D\Invariant::class, [ $templateType('T'), ], null, null, [ TemplateTypeVariance::createContravariant(), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1110,14 +836,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Out> (with invariance composition)' => [ + 'return: Out>' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Out::class, [ new GenericObjectType(D\Invariant::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1125,14 +850,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: In> (with invariance composition)' => [ + 'return: In>' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\In::class, [ new GenericObjectType(D\Invariant::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1140,14 +864,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Invariant> (with invariance composition)' => [ + 'return: Invariant>' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Invariant::class, [ new GenericObjectType(D\Out::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1155,14 +878,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Invariant> (with invariance composition)' => [ + 'return: Invariant>' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Invariant::class, [ new GenericObjectType(D\In::class, [ $templateType('T'), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1170,7 +892,7 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: In>> (with invariance composition)' => [ + 'return: In>>' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\In::class, [ new GenericObjectType(D\Invariant::class, [ @@ -1179,7 +901,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1187,7 +908,7 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Out>> (with invariance composition)' => [ + 'return: Out>>' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Out::class, [ new GenericObjectType(D\Invariant::class, [ @@ -1196,7 +917,6 @@ public function dataGetReferencedTypeArguments(): array ]), ]), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1204,14 +924,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Invariant (with invariance composition)' => [ + 'return: Invariant' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Invariant::class, [ $templateType('T'), ], null, null, [ TemplateTypeVariance::createCovariant(), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1219,14 +938,13 @@ public function dataGetReferencedTypeArguments(): array ), ], ], - 'return: Invariant (with invariance composition)' => [ + 'return: Invariant' => [ TemplateTypeVariance::createCovariant(), new GenericObjectType(D\Invariant::class, [ $templateType('T'), ], null, null, [ TemplateTypeVariance::createContravariant(), ]), - true, [ new TemplateTypeReference( $templateType('T'), @@ -1242,10 +960,8 @@ public function dataGetReferencedTypeArguments(): array * * @param array $expectedReferences */ - public function testGetReferencedTypeArguments(TemplateTypeVariance $positionVariance, Type $type, bool $invarianceComposition, array $expectedReferences): void + public function testGetReferencedTypeArguments(TemplateTypeVariance $positionVariance, Type $type, array $expectedReferences): void { - TemplateTypeVariance::setInvarianceCompositionEnabled($invarianceComposition); - $result = []; foreach ($type->getReferencedTemplateTypes($positionVariance) as $r) { $result[] = $r; diff --git a/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php b/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php index 71a57dda6d..c5bd9ac0a6 100644 --- a/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php +++ b/tests/PHPStan/Type/Generic/TemplateTypeVarianceTest.php @@ -87,14 +87,15 @@ public function testIsValidVariance( TrinaryLogic $expectedInversed, ): void { + $templateType = TemplateTypeFactory::create(TemplateTypeScope::createWithFunction('foo'), 'T', null, $variance); $this->assertSame( $expected->describe(), - $variance->isValidVariance($a, $b)->describe(), + $variance->isValidVariance($templateType, $a, $b)->result->describe(), sprintf('%s->isValidVariance(%s, %s)', $variance->describe(), $a->describe(VerbosityLevel::precise()), $b->describe(VerbosityLevel::precise())), ); $this->assertSame( $expectedInversed->describe(), - $variance->isValidVariance($b, $a)->describe(), + $variance->isValidVariance($templateType, $b, $a)->result->describe(), sprintf('%s->isValidVariance(%s, %s)', $variance->describe(), $b->describe(VerbosityLevel::precise()), $a->describe(VerbosityLevel::precise())), ); } diff --git a/tests/PHPStan/Type/IntegerTypeTest.php b/tests/PHPStan/Type/IntegerTypeTest.php index a1c83f7885..79c3ef9560 100644 --- a/tests/PHPStan/Type/IntegerTypeTest.php +++ b/tests/PHPStan/Type/IntegerTypeTest.php @@ -53,7 +53,7 @@ public function dataAccepts(): array */ public function testAccepts(IntegerType $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/IntersectionTypeTest.php b/tests/PHPStan/Type/IntersectionTypeTest.php index 0b5c5c0818..d5259d53e5 100644 --- a/tests/PHPStan/Type/IntersectionTypeTest.php +++ b/tests/PHPStan/Type/IntersectionTypeTest.php @@ -7,9 +7,9 @@ use ObjectTypeEnums\FooEnum; use PHPStan\Testing\PHPStanTestCase; use PHPStan\TrinaryLogic; +use PHPStan\Type\Accessory\AccessoryArrayListType; use PHPStan\Type\Accessory\AccessoryLowercaseStringType; use PHPStan\Type\Accessory\AccessoryUppercaseStringType; -use PHPStan\Type\Accessory\HasOffsetType; use PHPStan\Type\Accessory\HasPropertyType; use PHPStan\Type\Accessory\NonEmptyArrayType; use PHPStan\Type\Accessory\OversizedArrayType; @@ -73,7 +73,7 @@ public function dataAccepts(): Iterator */ public function testAccepts(IntersectionType $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), @@ -155,52 +155,6 @@ public function dataIsSuperTypeOf(): Iterator TrinaryLogic::createNo(), ]; - yield [ - new IntersectionType([ - new ArrayType(new MixedType(), new MixedType()), - new HasOffsetType(new StringType()), - ]), - new ConstantArrayType([ - new ConstantStringType('a'), - new ConstantStringType('b'), - new ConstantStringType('c'), - ], [ - new ConstantIntegerType(1), - new ConstantIntegerType(2), - new ConstantIntegerType(3), - ]), - TrinaryLogic::createMaybe(), - ]; - - yield [ - new IntersectionType([ - new ArrayType(new MixedType(), new MixedType()), - new HasOffsetType(new StringType()), - ]), - new ConstantArrayType([ - new ConstantStringType('a'), - new ConstantStringType('b'), - new ConstantStringType('c'), - new ConstantStringType('d'), - new ConstantStringType('e'), - new ConstantStringType('f'), - new ConstantStringType('g'), - new ConstantStringType('h'), - new ConstantStringType('i'), - ], [ - new ConstantIntegerType(1), - new ConstantIntegerType(2), - new ConstantIntegerType(3), - new ConstantIntegerType(1), - new ConstantIntegerType(2), - new ConstantIntegerType(3), - new ConstantIntegerType(1), - new ConstantIntegerType(2), - new ConstantIntegerType(3), - ]), - TrinaryLogic::createMaybe(), - ]; - yield [ new IntersectionType([ new ObjectType(Traversable::class), @@ -466,6 +420,292 @@ public function dataDescribe(): iterable VerbosityLevel::precise(), 'lowercase-string', ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-list', + ]; + + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new IntegerType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new IntegerType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-list', + ]; + + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-array', + ]; + + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new IntegerType()), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new IntegerType()), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new IntegerType()), + new AccessoryArrayListType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new IntegerType()), + new AccessoryArrayListType(), + ]), + VerbosityLevel::value(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new AccessoryArrayListType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new AccessoryArrayListType(), + ]), + VerbosityLevel::value(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new AccessoryArrayListType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new AccessoryArrayListType(), + ]), + VerbosityLevel::value(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new NonEmptyArrayType(), + ]), + VerbosityLevel::typeOnly(), + 'array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-array', + ]; + + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new NonEmptyArrayType(), + new OversizedArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-array', + ]; + + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new NonEmptyArrayType(), + new OversizedArrayType(), + ]), + VerbosityLevel::precise(), + 'non-empty-array&oversized-array', + ]; + + $constantArrayWithOptionalKeys = new ConstantArrayType([ + new ConstantIntegerType(0), + new ConstantIntegerType(1), + new ConstantIntegerType(2), + new ConstantIntegerType(3), + ], [ + new StringType(), + new StringType(), + new StringType(), + new StringType(), + ], [3], [2, 3], TrinaryLogic::createMaybe()); + + yield [ + new IntersectionType([ + $constantArrayWithOptionalKeys, + new AccessoryArrayListType(), + ]), + VerbosityLevel::typeOnly(), + 'list', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithOptionalKeys, + new AccessoryArrayListType(), + ]), + VerbosityLevel::value(), + 'list{0: string, 1: string, 2?: string, 3?: string}', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithOptionalKeys, + new AccessoryArrayListType(), + ]), + VerbosityLevel::precise(), + 'list{0: string, 1: string, 2?: string, 3?: string}', + ]; + + $constantArrayWithAllOptionalKeys = new ConstantArrayType([ + new ConstantIntegerType(0), + new ConstantIntegerType(1), + new ConstantIntegerType(2), + new ConstantIntegerType(3), + ], [ + new StringType(), + new StringType(), + new StringType(), + new StringType(), + ], [3], [0, 1, 2, 3], TrinaryLogic::createMaybe()); + + yield [ + new IntersectionType([ + $constantArrayWithAllOptionalKeys, + new AccessoryArrayListType(), + ]), + VerbosityLevel::value(), + 'list{0?: string, 1?: string, 2?: string, 3?: string}', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithAllOptionalKeys, + new NonEmptyArrayType(), + new AccessoryArrayListType(), + ]), + VerbosityLevel::value(), + 'non-empty-list{0?: string, 1?: string, 2?: string, 3?: string}', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithAllOptionalKeys, + new NonEmptyArrayType(), + ]), + VerbosityLevel::value(), + 'non-empty-array{0?: string, 1?: string, 2?: string, 3?: string}', + ]; yield [ new IntersectionType([new StringType(), new AccessoryUppercaseStringType()]), VerbosityLevel::typeOnly(), diff --git a/tests/PHPStan/Type/IterableTypeTest.php b/tests/PHPStan/Type/IterableTypeTest.php index 2094ebf589..013c0fd15c 100644 --- a/tests/PHPStan/Type/IterableTypeTest.php +++ b/tests/PHPStan/Type/IterableTypeTest.php @@ -329,7 +329,7 @@ public function dataAccepts(): array */ public function testAccepts(IterableType $iterableType, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $iterableType->accepts($otherType, true); + $actualResult = $iterableType->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/MixedTypeTest.php b/tests/PHPStan/Type/MixedTypeTest.php index 5fe7d0c409..3ffc8f9db7 100644 --- a/tests/PHPStan/Type/MixedTypeTest.php +++ b/tests/PHPStan/Type/MixedTypeTest.php @@ -598,7 +598,7 @@ public function dataSubstractedIsLiteralString(): array public function testSubstractedIsClassString(MixedType $mixedType, Type $typeToSubtract, TrinaryLogic $expectedResult): void { $subtracted = $mixedType->subtract($typeToSubtract); - $actualResult = $subtracted->isClassStringType(); + $actualResult = $subtracted->isClassString(); $this->assertSame( $expectedResult->describe(), diff --git a/tests/PHPStan/Type/ObjectTypeTest.php b/tests/PHPStan/Type/ObjectTypeTest.php index 6d8cfb28ee..f17c18ea97 100644 --- a/tests/PHPStan/Type/ObjectTypeTest.php +++ b/tests/PHPStan/Type/ObjectTypeTest.php @@ -531,7 +531,7 @@ public function testAccepts( { $this->assertSame( $expectedResult->describe(), - $type->accepts($acceptedType, true)->describe(), + $type->accepts($acceptedType, true)->result->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), ); } diff --git a/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php b/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php index e9cb8ada70..3917423ff3 100644 --- a/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php +++ b/tests/PHPStan/Type/SimultaneousTypeTraverserTest.php @@ -22,7 +22,7 @@ public function dataChangeStringIntoNonEmptyString(): iterable new ConstantArrayType( [new ConstantIntegerType(0)], [new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()])], - 1, + [1], ), 'array', ]; @@ -31,7 +31,7 @@ public function dataChangeStringIntoNonEmptyString(): iterable new ConstantArrayType( [new ConstantIntegerType(0)], [new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()])], - 1, + [1], ), 'array', ]; @@ -40,7 +40,7 @@ public function dataChangeStringIntoNonEmptyString(): iterable new ConstantArrayType( [new ConstantIntegerType(0)], [new IntegerType()], - 1, + [1], ), 'array', ]; diff --git a/tests/PHPStan/Type/StringTypeTest.php b/tests/PHPStan/Type/StringTypeTest.php index 8f22550446..813349b91a 100644 --- a/tests/PHPStan/Type/StringTypeTest.php +++ b/tests/PHPStan/Type/StringTypeTest.php @@ -179,7 +179,7 @@ public function dataAccepts(): iterable */ public function testAccepts(StringType $type, Type $otherType, TrinaryLogic $expectedResult): void { - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedResult->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/TemplateTypeTest.php b/tests/PHPStan/Type/TemplateTypeTest.php index 3a17311989..6b184eef8a 100644 --- a/tests/PHPStan/Type/TemplateTypeTest.php +++ b/tests/PHPStan/Type/TemplateTypeTest.php @@ -108,7 +108,7 @@ public function testAccepts( { assert($type instanceof TemplateType); - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedAccept->describe(), $actualResult->describe(), @@ -117,7 +117,7 @@ public function testAccepts( $type = $type->toArgument(); - $actualResult = $type->accepts($otherType, true); + $actualResult = $type->accepts($otherType, true)->result; $this->assertSame( $expectedAcceptArg->describe(), $actualResult->describe(), diff --git a/tests/PHPStan/Type/TypeCombinatorTest.php b/tests/PHPStan/Type/TypeCombinatorTest.php index 0e125a4a81..0ccbf79248 100644 --- a/tests/PHPStan/Type/TypeCombinatorTest.php +++ b/tests/PHPStan/Type/TypeCombinatorTest.php @@ -874,20 +874,6 @@ public function dataUnion(): iterable UnionType::class, "'bar'|'barr'|'baz'|'bazz'|'foo'|'fooo'|'lorem'|'loremm'|'loremmm'", ], - [ - [ - new IntersectionType([ - new ArrayType(new MixedType(), new StringType()), - new HasOffsetType(new StringType()), - ]), - new IntersectionType([ - new ArrayType(new MixedType(), new StringType()), - new HasOffsetType(new StringType()), - ]), - ], - IntersectionType::class, - 'array&hasOffset(string)', - ], [ [ new IntersectionType([ @@ -980,7 +966,7 @@ public function dataUnion(): iterable ]), ], IntersectionType::class, - 'array&hasOffsetValue(\'foo\', mixed)', + 'non-empty-array&hasOffsetValue(\'foo\', mixed)', ], [ [ @@ -1795,7 +1781,7 @@ public function dataUnion(): iterable new ConstantIntegerType(0), ], [ new StringType(), - ], 1, [0]), + ], [1], [0]), ], UnionType::class, 'array{}|array{0?: string}', @@ -1858,22 +1844,6 @@ public function dataUnion(): iterable UnionType::class, 'array{a: int, b: int}|array{b: int, c: int}', ], - [ - [ - TypeCombinator::intersect(new StringType(), new HasOffsetType(new IntegerType())), - TypeCombinator::intersect(new StringType(), new HasOffsetType(new IntegerType())), - ], - IntersectionType::class, - 'string&hasOffset(int)', - ], - [ - [ - TypeCombinator::intersect(new ConstantStringType('abc'), new HasOffsetType(new IntegerType())), - TypeCombinator::intersect(new ConstantStringType('abc'), new HasOffsetType(new IntegerType())), - ], - IntersectionType::class, - '\'abc\'&hasOffset(int)', - ], [ [ StaticTypeFactory::falsey(), @@ -2346,7 +2316,7 @@ public function dataUnion(): iterable TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new HasOffsetValueType(new ConstantStringType('a'), new IntegerType())), ], IntersectionType::class, - 'array&hasOffsetValue(\'a\', int)', + 'non-empty-array&hasOffsetValue(\'a\', int)', ]; yield [ @@ -2367,7 +2337,7 @@ public function dataUnion(): iterable ]), ], IntersectionType::class, - "array&hasOffsetValue('a', mixed)", + "non-empty-array&hasOffsetValue('a', mixed)", ]; yield [ @@ -2394,7 +2364,7 @@ public function dataUnion(): iterable ]), ], IntersectionType::class, - "array&hasOffsetValue(0, array&hasOffsetValue('code', mixed))", + "non-empty-array&hasOffsetValue(0, non-empty-array&hasOffsetValue('code', mixed))", ]; yield [ @@ -2592,7 +2562,7 @@ public function dataUnion(): iterable ]), ], UnionType::class, - 'array{a?: true, b: true}|(array{a?: true, c?: true}&non-empty-array)', + 'array{a?: true, b: true}|non-empty-array{a?: true, c?: true}', ]; yield [ @@ -2679,7 +2649,7 @@ public function dataUnion(): iterable ]), ], IntersectionType::class, - 'array&hasOffsetValue(\'thing\', mixed)', + 'non-empty-array&hasOffsetValue(\'thing\', mixed)', ]; } @@ -3188,7 +3158,7 @@ public function dataIntersect(): iterable new HasOffsetType(new ConstantStringType('a')), ], IntersectionType::class, - 'array&hasOffset(\'a\')', + 'non-empty-array&hasOffset(\'a\')', ], [ [ @@ -3197,25 +3167,7 @@ public function dataIntersect(): iterable new HasOffsetType(new ConstantStringType('a')), ], IntersectionType::class, - 'array&hasOffset(\'a\')', - ], - [ - [ - new ArrayType(new StringType(), new StringType()), - new HasOffsetType(new StringType()), - new HasOffsetType(new StringType()), - ], - IntersectionType::class, - 'array&hasOffset(string)', - ], - [ - [ - new ArrayType(new MixedType(), new MixedType()), - new HasOffsetType(new StringType()), - new HasOffsetType(new StringType()), - ], - IntersectionType::class, - 'array&hasOffset(string)', + 'non-empty-array&hasOffset(\'a\')', ], [ [ @@ -3302,17 +3254,6 @@ public function dataIntersect(): iterable ClosureType::class, 'Closure(): mixed', ], - [ - [ - new UnionType([ - new ArrayType(new MixedType(), new StringType()), - new NullType(), - ]), - new HasOffsetType(new StringType()), - ], - IntersectionType::class, - 'array&hasOffset(string)', - ], [ [ new ArrayType(new MixedType(), new MixedType()), @@ -3375,7 +3316,7 @@ public function dataIntersect(): iterable ]), ], IntersectionType::class, - 'array&hasOffset(\'bar\')&hasOffset(\'foo\')', + 'non-empty-array&hasOffset(\'bar\')&hasOffset(\'foo\')', ], [ [ @@ -3815,20 +3756,12 @@ public function dataIntersect(): iterable ], [ new IntegerType(), new IntegerType(), - ], 2, [0]), + ], [2], [0]), new HasOffsetType(new ConstantStringType('a')), ], ConstantArrayType::class, 'array{a: int, b: int}', ], - [ - [ - new StringType(), - new HasOffsetType(new IntegerType()), - ], - IntersectionType::class, - 'string&hasOffset(int)', - ], [ [ new BenevolentUnionType([new IntegerType(), new StringType()]), @@ -4211,7 +4144,7 @@ public function dataIntersect(): iterable TypeCombinator::intersect(new ArrayType(new MixedType(), new MixedType()), new HasOffsetValueType(new ConstantStringType('a'), new IntegerType())), ], IntersectionType::class, - 'array&hasOffsetValue(\'a\', 1)', + 'non-empty-array&hasOffsetValue(\'a\', 1)', ]; yield [ [ @@ -4371,7 +4304,7 @@ public function dataIntersect(): iterable new NonEmptyArrayType(), ], UnionType::class, - 'array{a?: true, b: true}|(array{a?: true, c?: true}&non-empty-array)', + 'array{a?: true, b: true}|non-empty-array{a?: true, c?: true}', ]; yield [ [ @@ -4407,7 +4340,7 @@ public function dataIntersect(): iterable new NonEmptyArrayType(), ], IntersectionType::class, - 'array{a?: true, c?: true}&non-empty-array', + 'non-empty-array{a?: true, c?: true}', ]; yield [ [ @@ -5014,7 +4947,7 @@ public function dataRemove(): array ], [ new StringType(), new StringType(), - ], 2), + ], [2]), new HasOffsetType(new ConstantIntegerType(1)), NeverType::class, '*NEVER*=implicit', @@ -5026,7 +4959,7 @@ public function dataRemove(): array ], [ new StringType(), new StringType(), - ], 2, [1]), + ], [2], [1]), new HasOffsetType(new ConstantIntegerType(1)), ConstantArrayType::class, 'array{string}', @@ -5038,7 +4971,7 @@ public function dataRemove(): array ], [ new StringType(), new StringType(), - ], 2, [1]), + ], [2], [1]), new HasOffsetType(new ConstantIntegerType(0)), NeverType::class, '*NEVER*=implicit', diff --git a/tests/PHPStan/Type/TypeGetFiniteTypesTest.php b/tests/PHPStan/Type/TypeGetFiniteTypesTest.php index ce605f3d5a..9770a62a72 100644 --- a/tests/PHPStan/Type/TypeGetFiniteTypesTest.php +++ b/tests/PHPStan/Type/TypeGetFiniteTypesTest.php @@ -3,6 +3,7 @@ namespace PHPStan\Type; use PHPStan\Testing\PHPStanTestCase; +use PHPStan\TrinaryLogic; use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantIntegerType; @@ -88,7 +89,7 @@ public function dataGetFiniteTypes(): iterable ], [ new BooleanType(), new BooleanType(), - ], 2), + ], [2]), [ new ConstantArrayType([ new ConstantIntegerType(0), @@ -96,28 +97,28 @@ public function dataGetFiniteTypes(): iterable ], [ new ConstantBooleanType(true), new ConstantBooleanType(true), - ], 2, [], true), + ], [2], [], TrinaryLogic::createYes()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), ], [ new ConstantBooleanType(true), new ConstantBooleanType(false), - ], 2, [], true), + ], [2], [], TrinaryLogic::createYes()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), ], [ new ConstantBooleanType(false), new ConstantBooleanType(true), - ], 2, [], true), + ], [2], [], TrinaryLogic::createYes()), new ConstantArrayType([ new ConstantIntegerType(0), new ConstantIntegerType(1), ], [ new ConstantBooleanType(false), new ConstantBooleanType(false), - ], 2, [], true), + ], [2], [], TrinaryLogic::createYes()), ], ]; } diff --git a/tests/PHPStan/Type/TypeToPhpDocNodeTest.php b/tests/PHPStan/Type/TypeToPhpDocNodeTest.php index ee4e6b55c7..c630063120 100644 --- a/tests/PHPStan/Type/TypeToPhpDocNodeTest.php +++ b/tests/PHPStan/Type/TypeToPhpDocNodeTest.php @@ -4,6 +4,7 @@ use PHPStan\PhpDoc\TypeStringResolver; use PHPStan\Testing\PHPStanTestCase; +use PHPStan\TrinaryLogic; use PHPStan\Type\Accessory\AccessoryArrayListType; use PHPStan\Type\Accessory\AccessoryLiteralStringType; use PHPStan\Type\Accessory\AccessoryLowercaseStringType; @@ -271,7 +272,7 @@ public function dataToPhpDocNode(): iterable yield [ new IntersectionType([new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), new AccessoryArrayListType()]), - 'list', + 'list', ]; yield [ @@ -280,7 +281,7 @@ public function dataToPhpDocNode(): iterable new NonEmptyArrayType(), new AccessoryArrayListType(), ]), - 'non-empty-list', + 'non-empty-list', ]; yield [ @@ -315,6 +316,122 @@ public function dataToPhpDocNode(): iterable ], [2], [1]), "array{0: 'foo', 1?: 'bar'}", ]; + + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new IntegerType()), + new AccessoryArrayListType(), + ]), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), + new AccessoryArrayListType(), + ]), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType(true)), + new AccessoryArrayListType(), + ]), + 'list', + ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType()), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + 'non-empty-list', + ]; + yield [ + new IntersectionType([ + new ArrayType(IntegerRangeType::createAllGreaterThanOrEqualTo(0), new MixedType(true)), + new AccessoryArrayListType(), + new NonEmptyArrayType(), + ]), + 'non-empty-list', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType()), + new NonEmptyArrayType(), + ]), + 'non-empty-array', + ]; + yield [ + new IntersectionType([ + new ArrayType(new MixedType(), new MixedType(true)), + new NonEmptyArrayType(), + ]), + 'non-empty-array', + ]; + $constantArrayWithOptionalKeys = new ConstantArrayType([ + new ConstantIntegerType(0), + new ConstantIntegerType(1), + new ConstantIntegerType(2), + new ConstantIntegerType(3), + ], [ + new StringType(), + new StringType(), + new StringType(), + new StringType(), + ], [3], [2, 3], TrinaryLogic::createMaybe()); + + yield [ + new IntersectionType([ + $constantArrayWithOptionalKeys, + new AccessoryArrayListType(), + ]), + 'list{0: string, 1: string, 2?: string, 3?: string}', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithOptionalKeys, + new AccessoryArrayListType(), + ]), + 'list{0: string, 1: string, 2?: string, 3?: string}', + ]; + + $constantArrayWithAllOptionalKeys = new ConstantArrayType([ + new ConstantIntegerType(0), + new ConstantIntegerType(1), + new ConstantIntegerType(2), + new ConstantIntegerType(3), + ], [ + new StringType(), + new StringType(), + new StringType(), + new StringType(), + ], [3], [0, 1, 2, 3], TrinaryLogic::createMaybe()); + + yield [ + new IntersectionType([ + $constantArrayWithAllOptionalKeys, + new AccessoryArrayListType(), + ]), + 'list{0?: string, 1?: string, 2?: string, 3?: string}', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithAllOptionalKeys, + new NonEmptyArrayType(), + new AccessoryArrayListType(), + ]), + 'non-empty-list{0?: string, 1?: string, 2?: string, 3?: string}', + ]; + + yield [ + new IntersectionType([ + $constantArrayWithAllOptionalKeys, + new NonEmptyArrayType(), + ]), + 'non-empty-array{0?: string, 1?: string, 2?: string, 3?: string}', + ]; } /** diff --git a/tests/PHPStan/Type/UnionTypeTest.php b/tests/PHPStan/Type/UnionTypeTest.php index cd0ee180cc..46b5803374 100644 --- a/tests/PHPStan/Type/UnionTypeTest.php +++ b/tests/PHPStan/Type/UnionTypeTest.php @@ -111,7 +111,7 @@ public function dataSelfCompare(): Iterator yield [new CallableType([$mixedParam, $integerParam], $stringType, false)]; yield [new ClassStringType()]; yield [new ClosureType([$mixedParam, $integerParam], $stringType, false)]; - yield [new ConstantArrayType([$constantStringType, $constantIntegerType], [$mixedType, $stringType], 10, [1])]; + yield [new ConstantArrayType([$constantStringType, $constantIntegerType], [$mixedType, $stringType], [10], [1])]; yield [new ConstantBooleanType(true)]; yield [new ConstantFloatType(3.14)]; yield [$constantIntegerType]; @@ -1305,7 +1305,7 @@ public function testAccepts( { $this->assertSame( $expectedResult->describe(), - $type->accepts($acceptedType, true)->describe(), + $type->accepts($acceptedType, true)->result->describe(), sprintf('%s -> accepts(%s)', $type->describe(VerbosityLevel::precise()), $acceptedType->describe(VerbosityLevel::precise())), ); } @@ -1418,7 +1418,7 @@ public function dataGetConstantArrays(): iterable new ConstantArrayType( [new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], - 2, + [2], [0, 1], ), new NonEmptyArrayType(), @@ -1426,7 +1426,7 @@ public function dataGetConstantArrays(): iterable new ConstantArrayType( [new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ObjectType(Foo::class), new ObjectType(stdClass::class)], - 2, + [2], ), ], [ @@ -1440,7 +1440,7 @@ public function dataGetConstantArrays(): iterable new ConstantArrayType( [new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], - 2, + [2], [0, 1], ), ), @@ -1602,7 +1602,7 @@ public function dataGetArrays(): iterable new ConstantArrayType( [new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], - 2, + [2], [0, 1], ), new NonEmptyArrayType(), @@ -1610,7 +1610,7 @@ public function dataGetArrays(): iterable new ConstantArrayType( [new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ObjectType(Foo::class), new ObjectType(stdClass::class)], - 2, + [2], ), ), [ @@ -1624,13 +1624,13 @@ public function dataGetArrays(): iterable new ConstantArrayType( [new ConstantIntegerType(1), new ConstantIntegerType(2)], [new IntegerType(), new StringType()], - 2, + [2], [0, 1], ), new ConstantArrayType( [new ConstantIntegerType(0), new ConstantIntegerType(1)], [new ObjectType(Foo::class), new ObjectType(stdClass::class)], - 2, + [2], ), ), [ diff --git a/tests/e2e/ResultCacheEndToEndTest.php b/tests/e2e/ResultCacheEndToEndTest.php deleted file mode 100644 index 1117af27b0..0000000000 --- a/tests/e2e/ResultCacheEndToEndTest.php +++ /dev/null @@ -1,208 +0,0 @@ -&1', escapeshellarg(__DIR__ . '/PHP-Parser')), $outputLines, $exitCode); - if ($exitCode === 0) { - return; - } - - $this->fail(implode("\n", $outputLines)); - } - - public function testResultCache(): void - { - $this->runPhpstan(0); - $this->assertResultCache(__DIR__ . '/resultCache_1.php'); - - $this->runPhpstan(0); - $this->assertResultCache(__DIR__ . '/resultCache_1.php'); - - $lexerPath = __DIR__ . '/PHP-Parser/lib/PhpParser/Lexer.php'; - $lexerCode = FileReader::read($lexerPath); - $originalLexerCode = $lexerCode; - - $lexerCode = str_replace('@param string $code', '', $lexerCode); - $lexerCode = str_replace('public function startLexing($code', 'public function startLexing(\\PhpParser\\Node\\Expr\\MethodCall $code', $lexerCode); - file_put_contents($lexerPath, $lexerCode); - - $errorHandlerPath = __DIR__ . '/PHP-Parser/lib/PhpParser/ErrorHandler.php'; - $errorHandlerContents = FileReader::read($errorHandlerPath); - $errorHandlerContents .= "\n\n"; - file_put_contents($errorHandlerPath, $errorHandlerContents); - - $bootstrapPath = __DIR__ . '/PHP-Parser/lib/bootstrap.php'; - $originalBootstrapContents = FileReader::read($bootstrapPath); - file_put_contents($bootstrapPath, "\n\n echo ['foo'];", FILE_APPEND); - - $this->runPhpstanWithErrors(); - $this->runPhpstanWithErrors(); - - file_put_contents($lexerPath, $originalLexerCode); - - unlink($bootstrapPath); - $this->runPhpstan(0); - $this->assertResultCache(__DIR__ . '/resultCache_3.php'); - - file_put_contents($bootstrapPath, $originalBootstrapContents); - $this->runPhpstan(0); - $this->assertResultCache(__DIR__ . '/resultCache_1.php'); - } - - private function runPhpstanWithErrors(): void - { - $result = $this->runPhpstan(1); - $this->assertIsArray($result['totals']); - $this->assertSame(3, $result['totals']['file_errors']); - $this->assertSame(0, $result['totals']['errors']); - - $fileHelper = new FileHelper(__DIR__); - - $this->assertSame('Parameter #1 $code of function token_get_all expects string, PhpParser\Node\Expr\MethodCall given.', $result['files'][$fileHelper->normalizePath(__DIR__ . '/PHP-Parser/lib/PhpParser/Lexer.php')]['messages'][0]['message']); - $this->assertSame('Parameter #1 $code of method PhpParser\Lexer::startLexing() expects PhpParser\Node\Expr\MethodCall, string given.', $result['files'][$fileHelper->normalizePath(__DIR__ . '/PHP-Parser/lib/PhpParser/ParserAbstract.php')]['messages'][0]['message']); - $this->assertSame('Parameter #1 (array{\'foo\'}) of echo cannot be converted to string.', $result['files'][$fileHelper->normalizePath(__DIR__ . '/PHP-Parser/lib/bootstrap.php')]['messages'][0]['message']); - $this->assertResultCache(__DIR__ . '/resultCache_2.php'); - } - - public function testResultCacheDeleteFile(): void - { - $this->runPhpstan(0); - $this->assertResultCache(__DIR__ . '/resultCache_1.php'); - - $serializerPath = __DIR__ . '/PHP-Parser/lib/PhpParser/Serializer.php'; - $serializerCode = FileReader::read($serializerPath); - $originalSerializerCode = $serializerCode; - unlink($serializerPath); - - $fileHelper = new FileHelper(__DIR__); - - $result = $this->runPhpstan(1); - $this->assertIsArray($result['totals']); - $this->assertSame(1, $result['totals']['file_errors'], Json::encode($result)); - $this->assertSame(0, $result['totals']['errors'], Json::encode($result)); - - $message = $result['files'][$fileHelper->normalizePath(__DIR__ . '/PHP-Parser/lib/PhpParser/Serializer/XML.php')]['messages'][0]['message']; - $this->assertSame('Class PhpParser\\Serializer\\XML implements unknown interface PhpParser\\Serializer.', $message); - - file_put_contents($serializerPath, $originalSerializerCode); - $this->runPhpstan(0); - $this->assertResultCache(__DIR__ . '/resultCache_1.php'); - } - - public function testResultCachePath(): void - { - $this->runPhpstan(0, __DIR__ . '/phpstan_resultcachepath.neon'); - - $this->assertFileExists(sys_get_temp_dir() . '/phpstan/myResultCacheFile.php'); - $this->assertResultCache(__DIR__ . '/resultCache_1.php', sys_get_temp_dir() . '/phpstan/myResultCacheFile.php'); - } - - /** - * @return mixed[] - */ - private function runPhpstan(int $expectedExitCode, string $phpstanConfigPath = __DIR__ . '/phpstan.neon'): array - { - exec(sprintf( - '%s %s analyse -c %s -l 5 --no-progress --error-format json lib 2>&1', - escapeshellarg(PHP_BINARY), - escapeshellarg(__DIR__ . '/../../bin/phpstan'), - escapeshellarg($phpstanConfigPath), - ), $outputLines, $exitCode); - $output = implode("\n", $outputLines); - - try { - $json = Json::decode($output, Json::FORCE_ARRAY); - $this->assertIsArray($json); - } catch (JsonException $e) { - $this->fail(sprintf('%s: %s', $e->getMessage(), $output)); - } - - if ($exitCode !== $expectedExitCode) { - $this->fail($output); - } - - return $json; - } - - /** - * @param mixed[] $resultCache - * @return array> - */ - private function transformResultCache(array $resultCache): array - { - $new = []; - $this->assertIsArray($resultCache['dependencies']); - foreach ($resultCache['dependencies'] as $file => $data) { - $this->assertIsString($file); - $this->assertIsArray($data); - $this->assertIsArray($data['dependentFiles']); - - $files = []; - foreach ($data['dependentFiles'] as $filePath) { - $this->assertIsString($filePath); - $files[] = $this->relativizePath($filePath); - } - sort($files); - $new[$this->relativizePath($file)] = $files; - } - - ksort($new); - - return $new; - } - - private function relativizePath(string $path): string - { - $path = str_replace('\\', '/', $path); - $helper = new SimpleRelativePathHelper(str_replace('\\', '/', __DIR__ . '/PHP-Parser')); - return $helper->getRelativePath($path); - } - - private function assertResultCache(string $expectedCachePath, string $actualCachePath = __DIR__ . '/tmp/resultCache.php'): void - { - $resultCache = $this->transformResultCache(require $actualCachePath); - $expectedResultCachePath = require $expectedCachePath; - $this->assertSame($expectedResultCachePath, $resultCache); - } - -} diff --git a/tests/e2e/baseline.neon b/tests/e2e/baseline.neon deleted file mode 100644 index 71c60e0f32..0000000000 --- a/tests/e2e/baseline.neon +++ /dev/null @@ -1,177 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^PHPDoc tag @param references unknown parameter\\: \\$interfaces$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Builder/Class_.php - - - - message: "#^Access to an undefined property PhpParser\\\\Node\\:\\:\\$stmts\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Builder/Interface_.php - - - - message: "#^PHPDoc tag @param references unknown parameter\\: \\$interfaces$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Builder/Interface_.php - - - - message: "#^Access to an undefined property PhpParser\\\\BuilderAbstract\\:\\:\\$flags\\.$#" - count: 2 - path: PHP-Parser/lib/PhpParser/BuilderAbstract.php - - - - message: "#^Method PhpParser\\\\BuilderAbstract\\:\\:normalizeValue\\(\\) should return PhpParser\\\\Node\\\\Expr but returns PhpParser\\\\Node\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/BuilderAbstract.php - - - - message: "#^PHPDoc tag @param has invalid value \\(string\\|Node\\\\Name Name to alias\\)\\: Unexpected token \"Name\", expected variable at offset 88$#" - count: 1 - path: PHP-Parser/lib/PhpParser/BuilderFactory.php - - - - message: "#^Expression \"@\\$undefinedVariable\" on a separate line does not do anything\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Lexer.php - - - - message: "#^Undefined variable\\: \\$undefinedVariable$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Lexer.php - - - - message: "#^Unreachable statement \\- code above always terminates\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Lexer.php - - - - message: "#^Empty array passed to foreach\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Lexer/Emulative.php - - - - message: "#^Method PhpParser\\\\Node\\\\Expr\\\\Closure\\:\\:getStmts\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Node/Expr/Closure.php - - - - message: "#^Unsafe usage of new static\\(\\)\\.$#" - count: 4 - path: PHP-Parser/lib/PhpParser/Node/Name.php - - - - message: "#^Method PhpParser\\\\Node\\\\Stmt\\\\ClassMethod\\:\\:getStmts\\(\\) should return array\\ but returns array\\\\|null\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Node/Stmt/ClassMethod.php - - - - message: "#^Method PhpParser\\\\Node\\\\Stmt\\\\Function_\\:\\:getStmts\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Node/Stmt/Function_.php - - - - message: "#^PHPDoc tag @param for parameter \\$attributes with type array\\|null is not subtype of native type array\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Node/Stmt/TryCatch.php - - - - message: "#^Access to an undefined property PhpParser\\\\Node\\:\\:\\$name\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitor/NameResolver.php - - - - message: "#^Access to an undefined property PhpParser\\\\Node\\:\\:\\$namespacedName\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitor/NameResolver.php - - - - message: "#^Method PhpParser\\\\NodeVisitor\\\\NameResolver\\:\\:beforeTraverse\\(\\) should return array\\\\|null but return statement is missing\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitor/NameResolver.php - - - - message: "#^Method PhpParser\\\\NodeVisitor\\\\NameResolver\\:\\:enterNode\\(\\) should return int\\|PhpParser\\\\Node\\|null but return statement is missing\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitor/NameResolver.php - - - - message: "#^Method PhpParser\\\\NodeVisitorAbstract\\:\\:afterTraverse\\(\\) should return array\\\\|null but return statement is missing\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitorAbstract.php - - - - message: "#^Method PhpParser\\\\NodeVisitorAbstract\\:\\:beforeTraverse\\(\\) should return array\\\\|null but return statement is missing\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitorAbstract.php - - - - message: "#^Method PhpParser\\\\NodeVisitorAbstract\\:\\:enterNode\\(\\) should return int\\|PhpParser\\\\Node\\|null but return statement is missing\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitorAbstract.php - - - - message: "#^Method PhpParser\\\\NodeVisitorAbstract\\:\\:leaveNode\\(\\) should return array\\\\|int\\|PhpParser\\\\Node\\|false\\|null but return statement is missing\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/NodeVisitorAbstract.php - - - - message: "#^Access to an undefined property PhpParser\\\\Node\\\\Expr\\:\\:\\$class\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Parser/Php5.php - - - - message: "#^Access to an undefined property PhpParser\\\\Node\\\\Expr\\:\\:\\$name\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Parser/Php5.php - - - - message: "#^Variable \\$s might not be defined\\.$#" - count: 3 - path: PHP-Parser/lib/PhpParser/Parser/Php5.php - - - - message: "#^Variable \\$s might not be defined\\.$#" - count: 3 - path: PHP-Parser/lib/PhpParser/Parser/Php7.php - - - - message: "#^Comparison operation \"\\<\" between \\(array\\|float\\|int\\<0, max\\>\\) and int results in an error\\.$#" - count: 3 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Comparison operation \"\\>\\=\" between \\(array\\|float\\|int\\) and 0 results in an error\\.$#" - count: 3 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Property PhpParser\\\\ParserAbstract\\:\\:\\$endAttributeStack \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Property PhpParser\\\\ParserAbstract\\:\\:\\$endAttributes \\(array\\) does not accept string\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Unreachable statement \\- code above always terminates\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Variable \\$action might not be defined\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Variable \\$tokenValue might not be defined\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/ParserAbstract.php - - - - message: "#^Argument of an invalid type PhpParser\\\\Node supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: PHP-Parser/lib/PhpParser/Serializer/XML.php - diff --git a/tests/e2e/phpstan.neon b/tests/e2e/phpstan.neon deleted file mode 100644 index b9fe1cd9c1..0000000000 --- a/tests/e2e/phpstan.neon +++ /dev/null @@ -1,7 +0,0 @@ -includes: - - baseline.neon - -parameters: - phpVersion: 80000 - tmpDir: tmp - treatPhpDocTypesAsCertain: false diff --git a/tests/e2e/phpstan_resultcachepath.neon b/tests/e2e/phpstan_resultcachepath.neon deleted file mode 100644 index 3ad1d1a3b1..0000000000 --- a/tests/e2e/phpstan_resultcachepath.neon +++ /dev/null @@ -1,7 +0,0 @@ -includes: - - baseline.neon - -parameters: - phpVersion: 80000 - resultCachePath: %tmpDir%/myResultCacheFile.php - treatPhpDocTypesAsCertain: false diff --git a/tests/e2e/resultCache_1.php b/tests/e2e/resultCache_1.php deleted file mode 100644 index fd17dda8f2..0000000000 --- a/tests/e2e/resultCache_1.php +++ /dev/null @@ -1,2019 +0,0 @@ - - array ( - 0 => 'lib/bootstrap.php', - ), - 'lib/PhpParser/Builder.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Declaration.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderAbstract.php', - 12 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Class_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Declaration.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Trait_.php', - 7 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/FunctionLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Function_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Interface_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Method.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Param.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Property.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Trait_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Use_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/BuilderAbstract.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Declaration.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/BuilderFactory.php' => - array ( - ), - 'lib/PhpParser/Comment.php' => - array ( - 0 => 'lib/PhpParser/Builder/Declaration.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Comment/Doc.php', - 4 => 'lib/PhpParser/Lexer.php', - 5 => 'lib/PhpParser/Node.php', - 6 => 'lib/PhpParser/NodeAbstract.php', - 7 => 'lib/PhpParser/NodeDumper.php', - 8 => 'lib/PhpParser/PrettyPrinterAbstract.php', - 9 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Comment/Doc.php' => - array ( - 0 => 'lib/PhpParser/Builder/Declaration.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Comment.php', - 4 => 'lib/PhpParser/Lexer.php', - 5 => 'lib/PhpParser/Node.php', - 6 => 'lib/PhpParser/NodeAbstract.php', - 7 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Error.php' => - array ( - 0 => 'lib/PhpParser/ErrorHandler.php', - 1 => 'lib/PhpParser/ErrorHandler/Collecting.php', - 2 => 'lib/PhpParser/ErrorHandler/Throwing.php', - 3 => 'lib/PhpParser/Lexer.php', - 4 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 5 => 'lib/PhpParser/Node/Scalar/String_.php', - 6 => 'lib/PhpParser/Node/Stmt/Class_.php', - 7 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 8 => 'lib/PhpParser/Parser/Multiple.php', - 9 => 'lib/PhpParser/Parser/Php5.php', - 10 => 'lib/PhpParser/Parser/Php7.php', - 11 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/ErrorHandler.php' => - array ( - 0 => 'lib/PhpParser/ErrorHandler/Collecting.php', - 1 => 'lib/PhpParser/ErrorHandler/Throwing.php', - 2 => 'lib/PhpParser/Lexer.php', - 3 => 'lib/PhpParser/Lexer/Emulative.php', - 4 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 5 => 'lib/PhpParser/Parser.php', - 6 => 'lib/PhpParser/Parser/Multiple.php', - 7 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/ErrorHandler/Collecting.php' => - array ( - ), - 'lib/PhpParser/ErrorHandler/Throwing.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Multiple.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/Lexer.php' => - array ( - 0 => 'lib/PhpParser/Lexer/Emulative.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Lexer/Emulative.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Node.php' => - array ( - 0 => 'lib/PhpParser/Builder.php', - 1 => 'lib/PhpParser/Builder/Class_.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderAbstract.php', - 12 => 'lib/PhpParser/BuilderFactory.php', - 13 => 'lib/PhpParser/Node/Arg.php', - 14 => 'lib/PhpParser/Node/Const_.php', - 15 => 'lib/PhpParser/Node/Expr.php', - 16 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 17 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 18 => 'lib/PhpParser/Node/Expr/Array_.php', - 19 => 'lib/PhpParser/Node/Expr/Assign.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 23 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 24 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 25 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 26 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 27 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 28 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 29 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 30 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 31 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 32 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 33 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 52 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 53 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 54 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 55 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 56 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 57 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 58 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 59 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 60 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 61 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 62 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 63 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 64 => 'lib/PhpParser/Node/Expr/Cast.php', - 65 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 66 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 67 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 68 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 69 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 70 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 71 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 72 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 73 => 'lib/PhpParser/Node/Expr/Clone_.php', - 74 => 'lib/PhpParser/Node/Expr/Closure.php', - 75 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 76 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 77 => 'lib/PhpParser/Node/Expr/Empty_.php', - 78 => 'lib/PhpParser/Node/Expr/Error.php', - 79 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 80 => 'lib/PhpParser/Node/Expr/Eval_.php', - 81 => 'lib/PhpParser/Node/Expr/Exit_.php', - 82 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 83 => 'lib/PhpParser/Node/Expr/Include_.php', - 84 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 85 => 'lib/PhpParser/Node/Expr/Isset_.php', - 86 => 'lib/PhpParser/Node/Expr/List_.php', - 87 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 88 => 'lib/PhpParser/Node/Expr/New_.php', - 89 => 'lib/PhpParser/Node/Expr/PostDec.php', - 90 => 'lib/PhpParser/Node/Expr/PostInc.php', - 91 => 'lib/PhpParser/Node/Expr/PreDec.php', - 92 => 'lib/PhpParser/Node/Expr/PreInc.php', - 93 => 'lib/PhpParser/Node/Expr/Print_.php', - 94 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 95 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 96 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 97 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 98 => 'lib/PhpParser/Node/Expr/Ternary.php', - 99 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 100 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 101 => 'lib/PhpParser/Node/Expr/Variable.php', - 102 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 103 => 'lib/PhpParser/Node/Expr/Yield_.php', - 104 => 'lib/PhpParser/Node/FunctionLike.php', - 105 => 'lib/PhpParser/Node/Name.php', - 106 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 107 => 'lib/PhpParser/Node/Name/Relative.php', - 108 => 'lib/PhpParser/Node/NullableType.php', - 109 => 'lib/PhpParser/Node/Param.php', - 110 => 'lib/PhpParser/Node/Scalar.php', - 111 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 112 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 113 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 114 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 115 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 116 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 117 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 118 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 119 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 120 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 121 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 122 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 123 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 124 => 'lib/PhpParser/Node/Scalar/String_.php', - 125 => 'lib/PhpParser/Node/Stmt.php', - 126 => 'lib/PhpParser/Node/Stmt/Break_.php', - 127 => 'lib/PhpParser/Node/Stmt/Case_.php', - 128 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 129 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 130 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 131 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 132 => 'lib/PhpParser/Node/Stmt/Class_.php', - 133 => 'lib/PhpParser/Node/Stmt/Const_.php', - 134 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 135 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 136 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 137 => 'lib/PhpParser/Node/Stmt/Do_.php', - 138 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 139 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 140 => 'lib/PhpParser/Node/Stmt/Else_.php', - 141 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 142 => 'lib/PhpParser/Node/Stmt/For_.php', - 143 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 144 => 'lib/PhpParser/Node/Stmt/Function_.php', - 145 => 'lib/PhpParser/Node/Stmt/Global_.php', - 146 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 147 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 148 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 149 => 'lib/PhpParser/Node/Stmt/If_.php', - 150 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 151 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 152 => 'lib/PhpParser/Node/Stmt/Label.php', - 153 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 154 => 'lib/PhpParser/Node/Stmt/Nop.php', - 155 => 'lib/PhpParser/Node/Stmt/Property.php', - 156 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 157 => 'lib/PhpParser/Node/Stmt/Return_.php', - 158 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 159 => 'lib/PhpParser/Node/Stmt/Static_.php', - 160 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 161 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 162 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 163 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 164 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 165 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 166 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 167 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 168 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 169 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 170 => 'lib/PhpParser/Node/Stmt/Use_.php', - 171 => 'lib/PhpParser/Node/Stmt/While_.php', - 172 => 'lib/PhpParser/NodeAbstract.php', - 173 => 'lib/PhpParser/NodeDumper.php', - 174 => 'lib/PhpParser/NodeTraverser.php', - 175 => 'lib/PhpParser/NodeTraverserInterface.php', - 176 => 'lib/PhpParser/NodeVisitor.php', - 177 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 178 => 'lib/PhpParser/NodeVisitorAbstract.php', - 179 => 'lib/PhpParser/Parser.php', - 180 => 'lib/PhpParser/Parser/Multiple.php', - 181 => 'lib/PhpParser/Parser/Php5.php', - 182 => 'lib/PhpParser/Parser/Php7.php', - 183 => 'lib/PhpParser/ParserAbstract.php', - 184 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 185 => 'lib/PhpParser/PrettyPrinterAbstract.php', - 186 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Node/Arg.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 1 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 2 => 'lib/PhpParser/Node/Expr/New_.php', - 3 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Const_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 1 => 'lib/PhpParser/Node/Stmt/Const_.php', - 2 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 3 => 'lib/PhpParser/Parser/Php5.php', - 4 => 'lib/PhpParser/Parser/Php7.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr.php' => - array ( - 0 => 'lib/PhpParser/Builder/Param.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Node/Arg.php', - 4 => 'lib/PhpParser/Node/Const_.php', - 5 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 6 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 7 => 'lib/PhpParser/Node/Expr/Array_.php', - 8 => 'lib/PhpParser/Node/Expr/Assign.php', - 9 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 10 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 11 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 12 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 13 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 14 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 15 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 16 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 17 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 18 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 19 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 22 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 23 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 24 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 25 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 26 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 27 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 28 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 29 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 30 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 31 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 32 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 33 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 51 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 52 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 53 => 'lib/PhpParser/Node/Expr/Cast.php', - 54 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 55 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 56 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 57 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 58 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 59 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 60 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 61 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 62 => 'lib/PhpParser/Node/Expr/Clone_.php', - 63 => 'lib/PhpParser/Node/Expr/Closure.php', - 64 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 65 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 66 => 'lib/PhpParser/Node/Expr/Empty_.php', - 67 => 'lib/PhpParser/Node/Expr/Error.php', - 68 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 69 => 'lib/PhpParser/Node/Expr/Eval_.php', - 70 => 'lib/PhpParser/Node/Expr/Exit_.php', - 71 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 72 => 'lib/PhpParser/Node/Expr/Include_.php', - 73 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 74 => 'lib/PhpParser/Node/Expr/Isset_.php', - 75 => 'lib/PhpParser/Node/Expr/List_.php', - 76 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 77 => 'lib/PhpParser/Node/Expr/New_.php', - 78 => 'lib/PhpParser/Node/Expr/PostDec.php', - 79 => 'lib/PhpParser/Node/Expr/PostInc.php', - 80 => 'lib/PhpParser/Node/Expr/PreDec.php', - 81 => 'lib/PhpParser/Node/Expr/PreInc.php', - 82 => 'lib/PhpParser/Node/Expr/Print_.php', - 83 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 84 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 85 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 86 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 87 => 'lib/PhpParser/Node/Expr/Ternary.php', - 88 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 89 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 90 => 'lib/PhpParser/Node/Expr/Variable.php', - 91 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 92 => 'lib/PhpParser/Node/Expr/Yield_.php', - 93 => 'lib/PhpParser/Node/Param.php', - 94 => 'lib/PhpParser/Node/Scalar.php', - 95 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 96 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 97 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 98 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 99 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 100 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 101 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 102 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 103 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 104 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 105 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 106 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 107 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 108 => 'lib/PhpParser/Node/Scalar/String_.php', - 109 => 'lib/PhpParser/Node/Stmt/Break_.php', - 110 => 'lib/PhpParser/Node/Stmt/Case_.php', - 111 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 112 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 113 => 'lib/PhpParser/Node/Stmt/Do_.php', - 114 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 115 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 116 => 'lib/PhpParser/Node/Stmt/For_.php', - 117 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 118 => 'lib/PhpParser/Node/Stmt/Global_.php', - 119 => 'lib/PhpParser/Node/Stmt/If_.php', - 120 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 121 => 'lib/PhpParser/Node/Stmt/Return_.php', - 122 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 123 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 124 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 125 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 126 => 'lib/PhpParser/Node/Stmt/While_.php', - 127 => 'lib/PhpParser/NodeDumper.php', - 128 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 129 => 'lib/PhpParser/Parser/Php5.php', - 130 => 'lib/PhpParser/Parser/Php7.php', - 131 => 'lib/PhpParser/ParserAbstract.php', - 132 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 133 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Expr/ArrayDimFetch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ArrayItem.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Node/Expr/Array_.php', - 2 => 'lib/PhpParser/Node/Expr/List_.php', - 3 => 'lib/PhpParser/Parser/Php5.php', - 4 => 'lib/PhpParser/Parser/Php7.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Array_.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Assign.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 1 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 2 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 3 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 4 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 5 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 6 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 7 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 8 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 9 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 10 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 11 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 12 => 'lib/PhpParser/Parser/Php5.php', - 13 => 'lib/PhpParser/Parser/Php7.php', - 14 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Concat.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Div.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Minus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Mod.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Mul.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Plus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Pow.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignRef.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 1 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 2 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 3 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 4 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 5 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 6 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 7 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 8 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 9 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 10 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 11 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 12 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 13 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 14 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 15 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 16 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 17 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 18 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 19 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 20 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 21 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 22 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 23 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 24 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 25 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 26 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 27 => 'lib/PhpParser/Parser/Php5.php', - 28 => 'lib/PhpParser/Parser/Php7.php', - 29 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Div.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BitwiseNot.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BooleanNot.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 1 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 2 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 3 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 4 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 5 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 6 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 7 => 'lib/PhpParser/Parser/Php5.php', - 8 => 'lib/PhpParser/Parser/Php7.php', - 9 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Array_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Bool_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Double.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Int_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Object_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/String_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Unset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ClassConstFetch.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Clone_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Closure.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ClosureUse.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/Closure.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ConstFetch.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Empty_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Error.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ErrorSuppress.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Eval_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Exit_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/FuncCall.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Include_.php' => - array ( - 0 => 'lib/PhpParser/NodeDumper.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Instanceof_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Isset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/List_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/MethodCall.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/New_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PostDec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PostInc.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PreDec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PreInc.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Print_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PropertyFetch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ShellExec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/StaticCall.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Ternary.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/UnaryMinus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/UnaryPlus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Variable.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/YieldFrom.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Yield_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/FunctionLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/Builder/Trait_.php', - 3 => 'lib/PhpParser/Node/Expr/Closure.php', - 4 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 5 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 6 => 'lib/PhpParser/Node/Stmt/Function_.php', - 7 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 8 => 'lib/PhpParser/Parser/Php5.php', - 9 => 'lib/PhpParser/Parser/Php7.php', - 10 => 'lib/PhpParser/ParserAbstract.php', - 11 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Name.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Param.php', - 7 => 'lib/PhpParser/Builder/Use_.php', - 8 => 'lib/PhpParser/BuilderAbstract.php', - 9 => 'lib/PhpParser/BuilderFactory.php', - 10 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 11 => 'lib/PhpParser/Node/Expr/Closure.php', - 12 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 13 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 14 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 15 => 'lib/PhpParser/Node/Expr/New_.php', - 16 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 17 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 18 => 'lib/PhpParser/Node/FunctionLike.php', - 19 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 20 => 'lib/PhpParser/Node/Name/Relative.php', - 21 => 'lib/PhpParser/Node/NullableType.php', - 22 => 'lib/PhpParser/Node/Param.php', - 23 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 24 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 25 => 'lib/PhpParser/Node/Stmt/Class_.php', - 26 => 'lib/PhpParser/Node/Stmt/Function_.php', - 27 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 28 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 29 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 30 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 31 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 32 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 33 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 34 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 35 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 36 => 'lib/PhpParser/Parser/Php5.php', - 37 => 'lib/PhpParser/Parser/Php7.php', - 38 => 'lib/PhpParser/ParserAbstract.php', - 39 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 40 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Name/FullyQualified.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Name/Relative.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/NullableType.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/Builder/Function_.php', - 2 => 'lib/PhpParser/Builder/Method.php', - 3 => 'lib/PhpParser/Builder/Param.php', - 4 => 'lib/PhpParser/BuilderAbstract.php', - 5 => 'lib/PhpParser/Node/Expr/Closure.php', - 6 => 'lib/PhpParser/Node/FunctionLike.php', - 7 => 'lib/PhpParser/Node/Param.php', - 8 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 9 => 'lib/PhpParser/Node/Stmt/Function_.php', - 10 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 11 => 'lib/PhpParser/Parser/Php7.php', - 12 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Param.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/Builder/Param.php', - 2 => 'lib/PhpParser/Node/Expr/Closure.php', - 3 => 'lib/PhpParser/Node/FunctionLike.php', - 4 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 5 => 'lib/PhpParser/Node/Stmt/Function_.php', - 6 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 7 => 'lib/PhpParser/Parser/Php5.php', - 8 => 'lib/PhpParser/Parser/Php7.php', - 9 => 'lib/PhpParser/ParserAbstract.php', - 10 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 2 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 3 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 4 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 5 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 6 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 7 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 8 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 9 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 10 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 11 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 12 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 13 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 14 => 'lib/PhpParser/Node/Scalar/String_.php', - 15 => 'lib/PhpParser/Parser/Php5.php', - 16 => 'lib/PhpParser/Parser/Php7.php', - 17 => 'lib/PhpParser/ParserAbstract.php', - 18 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/DNumber.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/Encapsed.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/LNumber.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/ParserAbstract.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst.php' => - array ( - 0 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 1 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 2 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 3 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 4 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 5 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 6 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 7 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 8 => 'lib/PhpParser/Parser/Php5.php', - 9 => 'lib/PhpParser/Parser/Php7.php', - 10 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/File.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Line.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Method.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/String_.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Function_.php', - 2 => 'lib/PhpParser/Builder/Interface_.php', - 3 => 'lib/PhpParser/Builder/Method.php', - 4 => 'lib/PhpParser/Builder/Namespace_.php', - 5 => 'lib/PhpParser/Builder/Property.php', - 6 => 'lib/PhpParser/Builder/Trait_.php', - 7 => 'lib/PhpParser/Builder/Use_.php', - 8 => 'lib/PhpParser/BuilderAbstract.php', - 9 => 'lib/PhpParser/BuilderFactory.php', - 10 => 'lib/PhpParser/Node/Expr/Closure.php', - 11 => 'lib/PhpParser/Node/Expr/New_.php', - 12 => 'lib/PhpParser/Node/FunctionLike.php', - 13 => 'lib/PhpParser/Node/Stmt/Break_.php', - 14 => 'lib/PhpParser/Node/Stmt/Case_.php', - 15 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 16 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 17 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 18 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 19 => 'lib/PhpParser/Node/Stmt/Class_.php', - 20 => 'lib/PhpParser/Node/Stmt/Const_.php', - 21 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 22 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 23 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 24 => 'lib/PhpParser/Node/Stmt/Do_.php', - 25 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 26 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 27 => 'lib/PhpParser/Node/Stmt/Else_.php', - 28 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 29 => 'lib/PhpParser/Node/Stmt/For_.php', - 30 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 31 => 'lib/PhpParser/Node/Stmt/Function_.php', - 32 => 'lib/PhpParser/Node/Stmt/Global_.php', - 33 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 34 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 35 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 36 => 'lib/PhpParser/Node/Stmt/If_.php', - 37 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 38 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 39 => 'lib/PhpParser/Node/Stmt/Label.php', - 40 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 41 => 'lib/PhpParser/Node/Stmt/Nop.php', - 42 => 'lib/PhpParser/Node/Stmt/Property.php', - 43 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 44 => 'lib/PhpParser/Node/Stmt/Return_.php', - 45 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 46 => 'lib/PhpParser/Node/Stmt/Static_.php', - 47 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 48 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 49 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 50 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 51 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 52 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 53 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 54 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 55 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 56 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 57 => 'lib/PhpParser/Node/Stmt/Use_.php', - 58 => 'lib/PhpParser/Node/Stmt/While_.php', - 59 => 'lib/PhpParser/NodeDumper.php', - 60 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 61 => 'lib/PhpParser/Parser/Php5.php', - 62 => 'lib/PhpParser/Parser/Php7.php', - 63 => 'lib/PhpParser/ParserAbstract.php', - 64 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 65 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Break_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Case_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Catch_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassConst.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Interface_.php', - 2 => 'lib/PhpParser/Builder/Method.php', - 3 => 'lib/PhpParser/Builder/Property.php', - 4 => 'lib/PhpParser/Builder/Trait_.php', - 5 => 'lib/PhpParser/BuilderAbstract.php', - 6 => 'lib/PhpParser/Node/Expr/New_.php', - 7 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 8 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 9 => 'lib/PhpParser/Node/Stmt/Class_.php', - 10 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 11 => 'lib/PhpParser/Node/Stmt/Property.php', - 12 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 13 => 'lib/PhpParser/NodeDumper.php', - 14 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 15 => 'lib/PhpParser/Parser/Php5.php', - 16 => 'lib/PhpParser/Parser/Php7.php', - 17 => 'lib/PhpParser/ParserAbstract.php', - 18 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassMethod.php' => - array ( - 0 => 'lib/PhpParser/Builder/Method.php', - 1 => 'lib/PhpParser/Builder/Trait_.php', - 2 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 3 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/ParserAbstract.php', - 7 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Class_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/Builder/Property.php', - 3 => 'lib/PhpParser/BuilderAbstract.php', - 4 => 'lib/PhpParser/Node/Expr/New_.php', - 5 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 6 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 7 => 'lib/PhpParser/Node/Stmt/Property.php', - 8 => 'lib/PhpParser/NodeDumper.php', - 9 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 10 => 'lib/PhpParser/Parser/Php5.php', - 11 => 'lib/PhpParser/Parser/Php7.php', - 12 => 'lib/PhpParser/ParserAbstract.php', - 13 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Const_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Continue_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/DeclareDeclare.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Declare_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Do_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Echo_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ElseIf_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/If_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Else_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/If_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Finally_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/For_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Foreach_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Function_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Global_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Goto_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/GroupUse.php' => - array ( - 0 => 'lib/PhpParser/NodeDumper.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/HaltCompiler.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/If_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/InlineHTML.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 4 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Interface_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Interface_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Label.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Namespace_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 6 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Nop.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 4 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Property.php' => - array ( - 0 => 'lib/PhpParser/Builder/Property.php', - 1 => 'lib/PhpParser/Builder/Trait_.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/PropertyProperty.php' => - array ( - 0 => 'lib/PhpParser/Builder/Property.php', - 1 => 'lib/PhpParser/Node/Stmt/Property.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Return_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/StaticVar.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Static_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Static_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Switch_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Throw_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUse.php' => - array ( - 0 => 'lib/PhpParser/Builder/Trait_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 1 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 2 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 3 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Trait_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Trait_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TryCatch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Unset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/UseUse.php' => - array ( - 0 => 'lib/PhpParser/Builder/Use_.php', - 1 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 2 => 'lib/PhpParser/Node/Stmt/Use_.php', - 3 => 'lib/PhpParser/NodeDumper.php', - 4 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 5 => 'lib/PhpParser/Parser/Php5.php', - 6 => 'lib/PhpParser/Parser/Php7.php', - 7 => 'lib/PhpParser/ParserAbstract.php', - 8 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Use_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Use_.php', - 1 => 'lib/PhpParser/BuilderFactory.php', - 2 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 3 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 4 => 'lib/PhpParser/NodeDumper.php', - 5 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 6 => 'lib/PhpParser/Parser/Php5.php', - 7 => 'lib/PhpParser/Parser/Php7.php', - 8 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/While_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/NodeAbstract.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Param.php', - 7 => 'lib/PhpParser/Builder/Property.php', - 8 => 'lib/PhpParser/Builder/Trait_.php', - 9 => 'lib/PhpParser/Builder/Use_.php', - 10 => 'lib/PhpParser/BuilderAbstract.php', - 11 => 'lib/PhpParser/BuilderFactory.php', - 12 => 'lib/PhpParser/Node/Arg.php', - 13 => 'lib/PhpParser/Node/Const_.php', - 14 => 'lib/PhpParser/Node/Expr.php', - 15 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 16 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 17 => 'lib/PhpParser/Node/Expr/Array_.php', - 18 => 'lib/PhpParser/Node/Expr/Assign.php', - 19 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 23 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 24 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 25 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 26 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 27 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 28 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 29 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 30 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 31 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 32 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 33 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 52 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 53 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 54 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 55 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 56 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 57 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 58 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 59 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 60 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 61 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 62 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 63 => 'lib/PhpParser/Node/Expr/Cast.php', - 64 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 65 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 66 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 67 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 68 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 69 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 70 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 71 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 72 => 'lib/PhpParser/Node/Expr/Clone_.php', - 73 => 'lib/PhpParser/Node/Expr/Closure.php', - 74 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 75 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 76 => 'lib/PhpParser/Node/Expr/Empty_.php', - 77 => 'lib/PhpParser/Node/Expr/Error.php', - 78 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 79 => 'lib/PhpParser/Node/Expr/Eval_.php', - 80 => 'lib/PhpParser/Node/Expr/Exit_.php', - 81 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 82 => 'lib/PhpParser/Node/Expr/Include_.php', - 83 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 84 => 'lib/PhpParser/Node/Expr/Isset_.php', - 85 => 'lib/PhpParser/Node/Expr/List_.php', - 86 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 87 => 'lib/PhpParser/Node/Expr/New_.php', - 88 => 'lib/PhpParser/Node/Expr/PostDec.php', - 89 => 'lib/PhpParser/Node/Expr/PostInc.php', - 90 => 'lib/PhpParser/Node/Expr/PreDec.php', - 91 => 'lib/PhpParser/Node/Expr/PreInc.php', - 92 => 'lib/PhpParser/Node/Expr/Print_.php', - 93 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 94 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 95 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 96 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 97 => 'lib/PhpParser/Node/Expr/Ternary.php', - 98 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 99 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 100 => 'lib/PhpParser/Node/Expr/Variable.php', - 101 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 102 => 'lib/PhpParser/Node/Expr/Yield_.php', - 103 => 'lib/PhpParser/Node/FunctionLike.php', - 104 => 'lib/PhpParser/Node/Name.php', - 105 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 106 => 'lib/PhpParser/Node/Name/Relative.php', - 107 => 'lib/PhpParser/Node/NullableType.php', - 108 => 'lib/PhpParser/Node/Param.php', - 109 => 'lib/PhpParser/Node/Scalar.php', - 110 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 111 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 112 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 113 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 114 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 115 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 116 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 117 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 118 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 119 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 120 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 121 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 122 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 123 => 'lib/PhpParser/Node/Scalar/String_.php', - 124 => 'lib/PhpParser/Node/Stmt.php', - 125 => 'lib/PhpParser/Node/Stmt/Break_.php', - 126 => 'lib/PhpParser/Node/Stmt/Case_.php', - 127 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 128 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 129 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 130 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 131 => 'lib/PhpParser/Node/Stmt/Class_.php', - 132 => 'lib/PhpParser/Node/Stmt/Const_.php', - 133 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 134 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 135 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 136 => 'lib/PhpParser/Node/Stmt/Do_.php', - 137 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 138 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 139 => 'lib/PhpParser/Node/Stmt/Else_.php', - 140 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 141 => 'lib/PhpParser/Node/Stmt/For_.php', - 142 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 143 => 'lib/PhpParser/Node/Stmt/Function_.php', - 144 => 'lib/PhpParser/Node/Stmt/Global_.php', - 145 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 146 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 147 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 148 => 'lib/PhpParser/Node/Stmt/If_.php', - 149 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 150 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 151 => 'lib/PhpParser/Node/Stmt/Label.php', - 152 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 153 => 'lib/PhpParser/Node/Stmt/Nop.php', - 154 => 'lib/PhpParser/Node/Stmt/Property.php', - 155 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 156 => 'lib/PhpParser/Node/Stmt/Return_.php', - 157 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 158 => 'lib/PhpParser/Node/Stmt/Static_.php', - 159 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 160 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 161 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 162 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 163 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 164 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 165 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 166 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 167 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 168 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 169 => 'lib/PhpParser/Node/Stmt/Use_.php', - 170 => 'lib/PhpParser/Node/Stmt/While_.php', - 171 => 'lib/PhpParser/NodeDumper.php', - 172 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 173 => 'lib/PhpParser/Parser/Php5.php', - 174 => 'lib/PhpParser/Parser/Php7.php', - 175 => 'lib/PhpParser/ParserAbstract.php', - 176 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 177 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/NodeDumper.php' => - array ( - ), - 'lib/PhpParser/NodeTraverser.php' => - array ( - ), - 'lib/PhpParser/NodeTraverserInterface.php' => - array ( - 0 => 'lib/PhpParser/NodeTraverser.php', - ), - 'lib/PhpParser/NodeVisitor.php' => - array ( - 0 => 'lib/PhpParser/NodeTraverser.php', - 1 => 'lib/PhpParser/NodeTraverserInterface.php', - 2 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 3 => 'lib/PhpParser/NodeVisitorAbstract.php', - ), - 'lib/PhpParser/NodeVisitor/NameResolver.php' => - array ( - ), - 'lib/PhpParser/NodeVisitorAbstract.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - ), - 'lib/PhpParser/Parser.php' => - array ( - 0 => 'lib/PhpParser/Parser/Multiple.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Multiple.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Php5.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Php7.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Tokens.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/Lexer/Emulative.php', - ), - 'lib/PhpParser/ParserAbstract.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/ParserFactory.php' => - array ( - ), - 'lib/PhpParser/PrettyPrinter/Standard.php' => - array ( - ), - 'lib/PhpParser/PrettyPrinterAbstract.php' => - array ( - 0 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Serializer.php' => - array ( - 0 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Serializer/XML.php' => - array ( - ), - 'lib/PhpParser/Unserializer.php' => - array ( - 0 => 'lib/PhpParser/Unserializer/XML.php', - ), - 'lib/PhpParser/Unserializer/XML.php' => - array ( - ), - 'lib/bootstrap.php' => - array ( - ), -); diff --git a/tests/e2e/resultCache_2.php b/tests/e2e/resultCache_2.php deleted file mode 100644 index fb4e9bb6d8..0000000000 --- a/tests/e2e/resultCache_2.php +++ /dev/null @@ -1,2023 +0,0 @@ - - array ( - 0 => 'lib/bootstrap.php', - ), - 'lib/PhpParser/Builder.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Declaration.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderAbstract.php', - 12 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Class_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Declaration.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Trait_.php', - 7 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/FunctionLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Function_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Interface_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Method.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Param.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Property.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Trait_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Use_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/BuilderAbstract.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Declaration.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/BuilderFactory.php' => - array ( - ), - 'lib/PhpParser/Comment.php' => - array ( - 0 => 'lib/PhpParser/Builder/Declaration.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Comment/Doc.php', - 4 => 'lib/PhpParser/Lexer.php', - 5 => 'lib/PhpParser/Node.php', - 6 => 'lib/PhpParser/NodeAbstract.php', - 7 => 'lib/PhpParser/NodeDumper.php', - 8 => 'lib/PhpParser/PrettyPrinterAbstract.php', - 9 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Comment/Doc.php' => - array ( - 0 => 'lib/PhpParser/Builder/Declaration.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Comment.php', - 4 => 'lib/PhpParser/Lexer.php', - 5 => 'lib/PhpParser/Node.php', - 6 => 'lib/PhpParser/NodeAbstract.php', - 7 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Error.php' => - array ( - 0 => 'lib/PhpParser/ErrorHandler.php', - 1 => 'lib/PhpParser/ErrorHandler/Collecting.php', - 2 => 'lib/PhpParser/ErrorHandler/Throwing.php', - 3 => 'lib/PhpParser/Lexer.php', - 4 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 5 => 'lib/PhpParser/Node/Scalar/String_.php', - 6 => 'lib/PhpParser/Node/Stmt/Class_.php', - 7 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 8 => 'lib/PhpParser/Parser/Multiple.php', - 9 => 'lib/PhpParser/Parser/Php5.php', - 10 => 'lib/PhpParser/Parser/Php7.php', - 11 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/ErrorHandler.php' => - array ( - 0 => 'lib/PhpParser/ErrorHandler/Collecting.php', - 1 => 'lib/PhpParser/ErrorHandler/Throwing.php', - 2 => 'lib/PhpParser/Lexer.php', - 3 => 'lib/PhpParser/Lexer/Emulative.php', - 4 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 5 => 'lib/PhpParser/Parser.php', - 6 => 'lib/PhpParser/Parser/Multiple.php', - 7 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/ErrorHandler/Collecting.php' => - array ( - ), - 'lib/PhpParser/ErrorHandler/Throwing.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Multiple.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/Lexer.php' => - array ( - 0 => 'lib/PhpParser/Lexer/Emulative.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Lexer/Emulative.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Node.php' => - array ( - 0 => 'lib/PhpParser/Builder.php', - 1 => 'lib/PhpParser/Builder/Class_.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderAbstract.php', - 12 => 'lib/PhpParser/BuilderFactory.php', - 13 => 'lib/PhpParser/Lexer.php', - 14 => 'lib/PhpParser/Node/Arg.php', - 15 => 'lib/PhpParser/Node/Const_.php', - 16 => 'lib/PhpParser/Node/Expr.php', - 17 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 18 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 19 => 'lib/PhpParser/Node/Expr/Array_.php', - 20 => 'lib/PhpParser/Node/Expr/Assign.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 23 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 24 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 25 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 26 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 27 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 28 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 29 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 30 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 31 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 32 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 33 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 34 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 52 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 53 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 54 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 55 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 56 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 57 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 58 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 59 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 60 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 61 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 62 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 63 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 64 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 65 => 'lib/PhpParser/Node/Expr/Cast.php', - 66 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 67 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 68 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 69 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 70 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 71 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 72 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 73 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 74 => 'lib/PhpParser/Node/Expr/Clone_.php', - 75 => 'lib/PhpParser/Node/Expr/Closure.php', - 76 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 77 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 78 => 'lib/PhpParser/Node/Expr/Empty_.php', - 79 => 'lib/PhpParser/Node/Expr/Error.php', - 80 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 81 => 'lib/PhpParser/Node/Expr/Eval_.php', - 82 => 'lib/PhpParser/Node/Expr/Exit_.php', - 83 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 84 => 'lib/PhpParser/Node/Expr/Include_.php', - 85 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 86 => 'lib/PhpParser/Node/Expr/Isset_.php', - 87 => 'lib/PhpParser/Node/Expr/List_.php', - 88 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 89 => 'lib/PhpParser/Node/Expr/New_.php', - 90 => 'lib/PhpParser/Node/Expr/PostDec.php', - 91 => 'lib/PhpParser/Node/Expr/PostInc.php', - 92 => 'lib/PhpParser/Node/Expr/PreDec.php', - 93 => 'lib/PhpParser/Node/Expr/PreInc.php', - 94 => 'lib/PhpParser/Node/Expr/Print_.php', - 95 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 96 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 97 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 98 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 99 => 'lib/PhpParser/Node/Expr/Ternary.php', - 100 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 101 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 102 => 'lib/PhpParser/Node/Expr/Variable.php', - 103 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 104 => 'lib/PhpParser/Node/Expr/Yield_.php', - 105 => 'lib/PhpParser/Node/FunctionLike.php', - 106 => 'lib/PhpParser/Node/Name.php', - 107 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 108 => 'lib/PhpParser/Node/Name/Relative.php', - 109 => 'lib/PhpParser/Node/NullableType.php', - 110 => 'lib/PhpParser/Node/Param.php', - 111 => 'lib/PhpParser/Node/Scalar.php', - 112 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 113 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 114 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 115 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 116 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 117 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 118 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 119 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 120 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 121 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 122 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 123 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 124 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 125 => 'lib/PhpParser/Node/Scalar/String_.php', - 126 => 'lib/PhpParser/Node/Stmt.php', - 127 => 'lib/PhpParser/Node/Stmt/Break_.php', - 128 => 'lib/PhpParser/Node/Stmt/Case_.php', - 129 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 130 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 131 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 132 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 133 => 'lib/PhpParser/Node/Stmt/Class_.php', - 134 => 'lib/PhpParser/Node/Stmt/Const_.php', - 135 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 136 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 137 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 138 => 'lib/PhpParser/Node/Stmt/Do_.php', - 139 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 140 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 141 => 'lib/PhpParser/Node/Stmt/Else_.php', - 142 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 143 => 'lib/PhpParser/Node/Stmt/For_.php', - 144 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 145 => 'lib/PhpParser/Node/Stmt/Function_.php', - 146 => 'lib/PhpParser/Node/Stmt/Global_.php', - 147 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 148 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 149 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 150 => 'lib/PhpParser/Node/Stmt/If_.php', - 151 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 152 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 153 => 'lib/PhpParser/Node/Stmt/Label.php', - 154 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 155 => 'lib/PhpParser/Node/Stmt/Nop.php', - 156 => 'lib/PhpParser/Node/Stmt/Property.php', - 157 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 158 => 'lib/PhpParser/Node/Stmt/Return_.php', - 159 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 160 => 'lib/PhpParser/Node/Stmt/Static_.php', - 161 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 162 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 163 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 164 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 165 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 166 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 167 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 168 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 169 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 170 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 171 => 'lib/PhpParser/Node/Stmt/Use_.php', - 172 => 'lib/PhpParser/Node/Stmt/While_.php', - 173 => 'lib/PhpParser/NodeAbstract.php', - 174 => 'lib/PhpParser/NodeDumper.php', - 175 => 'lib/PhpParser/NodeTraverser.php', - 176 => 'lib/PhpParser/NodeTraverserInterface.php', - 177 => 'lib/PhpParser/NodeVisitor.php', - 178 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 179 => 'lib/PhpParser/NodeVisitorAbstract.php', - 180 => 'lib/PhpParser/Parser.php', - 181 => 'lib/PhpParser/Parser/Multiple.php', - 182 => 'lib/PhpParser/Parser/Php5.php', - 183 => 'lib/PhpParser/Parser/Php7.php', - 184 => 'lib/PhpParser/ParserAbstract.php', - 185 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 186 => 'lib/PhpParser/PrettyPrinterAbstract.php', - 187 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Node/Arg.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 1 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 2 => 'lib/PhpParser/Node/Expr/New_.php', - 3 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Const_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 1 => 'lib/PhpParser/Node/Stmt/Const_.php', - 2 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 3 => 'lib/PhpParser/Parser/Php5.php', - 4 => 'lib/PhpParser/Parser/Php7.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr.php' => - array ( - 0 => 'lib/PhpParser/Builder/Param.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Lexer.php', - 4 => 'lib/PhpParser/Node/Arg.php', - 5 => 'lib/PhpParser/Node/Const_.php', - 6 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 7 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 8 => 'lib/PhpParser/Node/Expr/Array_.php', - 9 => 'lib/PhpParser/Node/Expr/Assign.php', - 10 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 11 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 12 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 13 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 14 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 15 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 16 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 17 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 18 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 19 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 23 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 24 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 25 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 26 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 27 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 28 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 29 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 30 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 31 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 32 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 33 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 52 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 53 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 54 => 'lib/PhpParser/Node/Expr/Cast.php', - 55 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 56 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 57 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 58 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 59 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 60 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 61 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 62 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 63 => 'lib/PhpParser/Node/Expr/Clone_.php', - 64 => 'lib/PhpParser/Node/Expr/Closure.php', - 65 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 66 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 67 => 'lib/PhpParser/Node/Expr/Empty_.php', - 68 => 'lib/PhpParser/Node/Expr/Error.php', - 69 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 70 => 'lib/PhpParser/Node/Expr/Eval_.php', - 71 => 'lib/PhpParser/Node/Expr/Exit_.php', - 72 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 73 => 'lib/PhpParser/Node/Expr/Include_.php', - 74 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 75 => 'lib/PhpParser/Node/Expr/Isset_.php', - 76 => 'lib/PhpParser/Node/Expr/List_.php', - 77 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 78 => 'lib/PhpParser/Node/Expr/New_.php', - 79 => 'lib/PhpParser/Node/Expr/PostDec.php', - 80 => 'lib/PhpParser/Node/Expr/PostInc.php', - 81 => 'lib/PhpParser/Node/Expr/PreDec.php', - 82 => 'lib/PhpParser/Node/Expr/PreInc.php', - 83 => 'lib/PhpParser/Node/Expr/Print_.php', - 84 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 85 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 86 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 87 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 88 => 'lib/PhpParser/Node/Expr/Ternary.php', - 89 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 90 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 91 => 'lib/PhpParser/Node/Expr/Variable.php', - 92 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 93 => 'lib/PhpParser/Node/Expr/Yield_.php', - 94 => 'lib/PhpParser/Node/Param.php', - 95 => 'lib/PhpParser/Node/Scalar.php', - 96 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 97 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 98 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 99 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 100 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 101 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 102 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 103 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 104 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 105 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 106 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 107 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 108 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 109 => 'lib/PhpParser/Node/Scalar/String_.php', - 110 => 'lib/PhpParser/Node/Stmt/Break_.php', - 111 => 'lib/PhpParser/Node/Stmt/Case_.php', - 112 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 113 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 114 => 'lib/PhpParser/Node/Stmt/Do_.php', - 115 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 116 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 117 => 'lib/PhpParser/Node/Stmt/For_.php', - 118 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 119 => 'lib/PhpParser/Node/Stmt/Global_.php', - 120 => 'lib/PhpParser/Node/Stmt/If_.php', - 121 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 122 => 'lib/PhpParser/Node/Stmt/Return_.php', - 123 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 124 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 125 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 126 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 127 => 'lib/PhpParser/Node/Stmt/While_.php', - 128 => 'lib/PhpParser/NodeDumper.php', - 129 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 130 => 'lib/PhpParser/Parser/Php5.php', - 131 => 'lib/PhpParser/Parser/Php7.php', - 132 => 'lib/PhpParser/ParserAbstract.php', - 133 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 134 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Expr/ArrayDimFetch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ArrayItem.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Node/Expr/Array_.php', - 2 => 'lib/PhpParser/Node/Expr/List_.php', - 3 => 'lib/PhpParser/Parser/Php5.php', - 4 => 'lib/PhpParser/Parser/Php7.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Array_.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Assign.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 1 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 2 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 3 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 4 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 5 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 6 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 7 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 8 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 9 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 10 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 11 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 12 => 'lib/PhpParser/Parser/Php5.php', - 13 => 'lib/PhpParser/Parser/Php7.php', - 14 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Concat.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Div.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Minus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Mod.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Mul.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Plus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Pow.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignRef.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 1 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 2 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 3 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 4 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 5 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 6 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 7 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 8 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 9 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 10 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 11 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 12 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 13 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 14 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 15 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 16 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 17 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 18 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 19 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 20 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 21 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 22 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 23 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 24 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 25 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 26 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 27 => 'lib/PhpParser/Parser/Php5.php', - 28 => 'lib/PhpParser/Parser/Php7.php', - 29 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Div.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BitwiseNot.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BooleanNot.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 1 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 2 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 3 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 4 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 5 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 6 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 7 => 'lib/PhpParser/Parser/Php5.php', - 8 => 'lib/PhpParser/Parser/Php7.php', - 9 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Array_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Bool_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Double.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Int_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Object_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/String_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Unset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ClassConstFetch.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Clone_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Closure.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ClosureUse.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/Closure.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ConstFetch.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Empty_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Error.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ErrorSuppress.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Eval_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Exit_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/FuncCall.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Include_.php' => - array ( - 0 => 'lib/PhpParser/NodeDumper.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Instanceof_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Isset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/List_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/MethodCall.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/New_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PostDec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PostInc.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PreDec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PreInc.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Print_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PropertyFetch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ShellExec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/StaticCall.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Ternary.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/UnaryMinus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/UnaryPlus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Variable.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/YieldFrom.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Yield_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/FunctionLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/Builder/Trait_.php', - 3 => 'lib/PhpParser/Node/Expr/Closure.php', - 4 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 5 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 6 => 'lib/PhpParser/Node/Stmt/Function_.php', - 7 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 8 => 'lib/PhpParser/Parser/Php5.php', - 9 => 'lib/PhpParser/Parser/Php7.php', - 10 => 'lib/PhpParser/ParserAbstract.php', - 11 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Name.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Param.php', - 7 => 'lib/PhpParser/Builder/Use_.php', - 8 => 'lib/PhpParser/BuilderAbstract.php', - 9 => 'lib/PhpParser/BuilderFactory.php', - 10 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 11 => 'lib/PhpParser/Node/Expr/Closure.php', - 12 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 13 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 14 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 15 => 'lib/PhpParser/Node/Expr/New_.php', - 16 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 17 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 18 => 'lib/PhpParser/Node/FunctionLike.php', - 19 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 20 => 'lib/PhpParser/Node/Name/Relative.php', - 21 => 'lib/PhpParser/Node/NullableType.php', - 22 => 'lib/PhpParser/Node/Param.php', - 23 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 24 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 25 => 'lib/PhpParser/Node/Stmt/Class_.php', - 26 => 'lib/PhpParser/Node/Stmt/Function_.php', - 27 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 28 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 29 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 30 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 31 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 32 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 33 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 34 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 35 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 36 => 'lib/PhpParser/Parser/Php5.php', - 37 => 'lib/PhpParser/Parser/Php7.php', - 38 => 'lib/PhpParser/ParserAbstract.php', - 39 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 40 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Name/FullyQualified.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Name/Relative.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/NullableType.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/Builder/Function_.php', - 2 => 'lib/PhpParser/Builder/Method.php', - 3 => 'lib/PhpParser/Builder/Param.php', - 4 => 'lib/PhpParser/BuilderAbstract.php', - 5 => 'lib/PhpParser/Node/Expr/Closure.php', - 6 => 'lib/PhpParser/Node/FunctionLike.php', - 7 => 'lib/PhpParser/Node/Param.php', - 8 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 9 => 'lib/PhpParser/Node/Stmt/Function_.php', - 10 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 11 => 'lib/PhpParser/Parser/Php7.php', - 12 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Param.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/Builder/Param.php', - 2 => 'lib/PhpParser/Node/Expr/Closure.php', - 3 => 'lib/PhpParser/Node/FunctionLike.php', - 4 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 5 => 'lib/PhpParser/Node/Stmt/Function_.php', - 6 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 7 => 'lib/PhpParser/Parser/Php5.php', - 8 => 'lib/PhpParser/Parser/Php7.php', - 9 => 'lib/PhpParser/ParserAbstract.php', - 10 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 2 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 3 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 4 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 5 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 6 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 7 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 8 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 9 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 10 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 11 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 12 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 13 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 14 => 'lib/PhpParser/Node/Scalar/String_.php', - 15 => 'lib/PhpParser/Parser/Php5.php', - 16 => 'lib/PhpParser/Parser/Php7.php', - 17 => 'lib/PhpParser/ParserAbstract.php', - 18 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/DNumber.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/Encapsed.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/LNumber.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/ParserAbstract.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst.php' => - array ( - 0 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 1 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 2 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 3 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 4 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 5 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 6 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 7 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 8 => 'lib/PhpParser/Parser/Php5.php', - 9 => 'lib/PhpParser/Parser/Php7.php', - 10 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/File.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Line.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Method.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/String_.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Function_.php', - 2 => 'lib/PhpParser/Builder/Interface_.php', - 3 => 'lib/PhpParser/Builder/Method.php', - 4 => 'lib/PhpParser/Builder/Namespace_.php', - 5 => 'lib/PhpParser/Builder/Property.php', - 6 => 'lib/PhpParser/Builder/Trait_.php', - 7 => 'lib/PhpParser/Builder/Use_.php', - 8 => 'lib/PhpParser/BuilderAbstract.php', - 9 => 'lib/PhpParser/BuilderFactory.php', - 10 => 'lib/PhpParser/Node/Expr/Closure.php', - 11 => 'lib/PhpParser/Node/Expr/New_.php', - 12 => 'lib/PhpParser/Node/FunctionLike.php', - 13 => 'lib/PhpParser/Node/Stmt/Break_.php', - 14 => 'lib/PhpParser/Node/Stmt/Case_.php', - 15 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 16 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 17 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 18 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 19 => 'lib/PhpParser/Node/Stmt/Class_.php', - 20 => 'lib/PhpParser/Node/Stmt/Const_.php', - 21 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 22 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 23 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 24 => 'lib/PhpParser/Node/Stmt/Do_.php', - 25 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 26 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 27 => 'lib/PhpParser/Node/Stmt/Else_.php', - 28 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 29 => 'lib/PhpParser/Node/Stmt/For_.php', - 30 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 31 => 'lib/PhpParser/Node/Stmt/Function_.php', - 32 => 'lib/PhpParser/Node/Stmt/Global_.php', - 33 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 34 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 35 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 36 => 'lib/PhpParser/Node/Stmt/If_.php', - 37 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 38 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 39 => 'lib/PhpParser/Node/Stmt/Label.php', - 40 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 41 => 'lib/PhpParser/Node/Stmt/Nop.php', - 42 => 'lib/PhpParser/Node/Stmt/Property.php', - 43 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 44 => 'lib/PhpParser/Node/Stmt/Return_.php', - 45 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 46 => 'lib/PhpParser/Node/Stmt/Static_.php', - 47 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 48 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 49 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 50 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 51 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 52 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 53 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 54 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 55 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 56 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 57 => 'lib/PhpParser/Node/Stmt/Use_.php', - 58 => 'lib/PhpParser/Node/Stmt/While_.php', - 59 => 'lib/PhpParser/NodeDumper.php', - 60 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 61 => 'lib/PhpParser/Parser/Php5.php', - 62 => 'lib/PhpParser/Parser/Php7.php', - 63 => 'lib/PhpParser/ParserAbstract.php', - 64 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 65 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Break_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Case_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Catch_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassConst.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Interface_.php', - 2 => 'lib/PhpParser/Builder/Method.php', - 3 => 'lib/PhpParser/Builder/Property.php', - 4 => 'lib/PhpParser/Builder/Trait_.php', - 5 => 'lib/PhpParser/BuilderAbstract.php', - 6 => 'lib/PhpParser/Node/Expr/New_.php', - 7 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 8 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 9 => 'lib/PhpParser/Node/Stmt/Class_.php', - 10 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 11 => 'lib/PhpParser/Node/Stmt/Property.php', - 12 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 13 => 'lib/PhpParser/NodeDumper.php', - 14 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 15 => 'lib/PhpParser/Parser/Php5.php', - 16 => 'lib/PhpParser/Parser/Php7.php', - 17 => 'lib/PhpParser/ParserAbstract.php', - 18 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassMethod.php' => - array ( - 0 => 'lib/PhpParser/Builder/Method.php', - 1 => 'lib/PhpParser/Builder/Trait_.php', - 2 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 3 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/ParserAbstract.php', - 7 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Class_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/Builder/Property.php', - 3 => 'lib/PhpParser/BuilderAbstract.php', - 4 => 'lib/PhpParser/Node/Expr/New_.php', - 5 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 6 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 7 => 'lib/PhpParser/Node/Stmt/Property.php', - 8 => 'lib/PhpParser/NodeDumper.php', - 9 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 10 => 'lib/PhpParser/Parser/Php5.php', - 11 => 'lib/PhpParser/Parser/Php7.php', - 12 => 'lib/PhpParser/ParserAbstract.php', - 13 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Const_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Continue_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/DeclareDeclare.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Declare_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Do_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Echo_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ElseIf_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/If_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Else_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/If_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Finally_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/For_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Foreach_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Function_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Global_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Goto_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/GroupUse.php' => - array ( - 0 => 'lib/PhpParser/NodeDumper.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/HaltCompiler.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/If_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/InlineHTML.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 4 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Interface_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Interface_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Label.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Namespace_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 6 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Nop.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 4 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Property.php' => - array ( - 0 => 'lib/PhpParser/Builder/Property.php', - 1 => 'lib/PhpParser/Builder/Trait_.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/PropertyProperty.php' => - array ( - 0 => 'lib/PhpParser/Builder/Property.php', - 1 => 'lib/PhpParser/Node/Stmt/Property.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Return_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/StaticVar.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Static_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Static_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Switch_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Throw_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUse.php' => - array ( - 0 => 'lib/PhpParser/Builder/Trait_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 1 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 2 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 3 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Trait_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Trait_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TryCatch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Unset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/UseUse.php' => - array ( - 0 => 'lib/PhpParser/Builder/Use_.php', - 1 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 2 => 'lib/PhpParser/Node/Stmt/Use_.php', - 3 => 'lib/PhpParser/NodeDumper.php', - 4 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 5 => 'lib/PhpParser/Parser/Php5.php', - 6 => 'lib/PhpParser/Parser/Php7.php', - 7 => 'lib/PhpParser/ParserAbstract.php', - 8 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Use_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Use_.php', - 1 => 'lib/PhpParser/BuilderFactory.php', - 2 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 3 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 4 => 'lib/PhpParser/NodeDumper.php', - 5 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 6 => 'lib/PhpParser/Parser/Php5.php', - 7 => 'lib/PhpParser/Parser/Php7.php', - 8 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/While_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/NodeAbstract.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Param.php', - 7 => 'lib/PhpParser/Builder/Property.php', - 8 => 'lib/PhpParser/Builder/Trait_.php', - 9 => 'lib/PhpParser/Builder/Use_.php', - 10 => 'lib/PhpParser/BuilderAbstract.php', - 11 => 'lib/PhpParser/BuilderFactory.php', - 12 => 'lib/PhpParser/Lexer.php', - 13 => 'lib/PhpParser/Node/Arg.php', - 14 => 'lib/PhpParser/Node/Const_.php', - 15 => 'lib/PhpParser/Node/Expr.php', - 16 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 17 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 18 => 'lib/PhpParser/Node/Expr/Array_.php', - 19 => 'lib/PhpParser/Node/Expr/Assign.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 23 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 24 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 25 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 26 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 27 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 28 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 29 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 30 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 31 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 32 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 33 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 52 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 53 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 54 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 55 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 56 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 57 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 58 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 59 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 60 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 61 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 62 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 63 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 64 => 'lib/PhpParser/Node/Expr/Cast.php', - 65 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 66 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 67 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 68 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 69 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 70 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 71 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 72 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 73 => 'lib/PhpParser/Node/Expr/Clone_.php', - 74 => 'lib/PhpParser/Node/Expr/Closure.php', - 75 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 76 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 77 => 'lib/PhpParser/Node/Expr/Empty_.php', - 78 => 'lib/PhpParser/Node/Expr/Error.php', - 79 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 80 => 'lib/PhpParser/Node/Expr/Eval_.php', - 81 => 'lib/PhpParser/Node/Expr/Exit_.php', - 82 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 83 => 'lib/PhpParser/Node/Expr/Include_.php', - 84 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 85 => 'lib/PhpParser/Node/Expr/Isset_.php', - 86 => 'lib/PhpParser/Node/Expr/List_.php', - 87 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 88 => 'lib/PhpParser/Node/Expr/New_.php', - 89 => 'lib/PhpParser/Node/Expr/PostDec.php', - 90 => 'lib/PhpParser/Node/Expr/PostInc.php', - 91 => 'lib/PhpParser/Node/Expr/PreDec.php', - 92 => 'lib/PhpParser/Node/Expr/PreInc.php', - 93 => 'lib/PhpParser/Node/Expr/Print_.php', - 94 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 95 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 96 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 97 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 98 => 'lib/PhpParser/Node/Expr/Ternary.php', - 99 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 100 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 101 => 'lib/PhpParser/Node/Expr/Variable.php', - 102 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 103 => 'lib/PhpParser/Node/Expr/Yield_.php', - 104 => 'lib/PhpParser/Node/FunctionLike.php', - 105 => 'lib/PhpParser/Node/Name.php', - 106 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 107 => 'lib/PhpParser/Node/Name/Relative.php', - 108 => 'lib/PhpParser/Node/NullableType.php', - 109 => 'lib/PhpParser/Node/Param.php', - 110 => 'lib/PhpParser/Node/Scalar.php', - 111 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 112 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 113 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 114 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 115 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 116 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 117 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 118 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 119 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 120 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 121 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 122 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 123 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 124 => 'lib/PhpParser/Node/Scalar/String_.php', - 125 => 'lib/PhpParser/Node/Stmt.php', - 126 => 'lib/PhpParser/Node/Stmt/Break_.php', - 127 => 'lib/PhpParser/Node/Stmt/Case_.php', - 128 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 129 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 130 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 131 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 132 => 'lib/PhpParser/Node/Stmt/Class_.php', - 133 => 'lib/PhpParser/Node/Stmt/Const_.php', - 134 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 135 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 136 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 137 => 'lib/PhpParser/Node/Stmt/Do_.php', - 138 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 139 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 140 => 'lib/PhpParser/Node/Stmt/Else_.php', - 141 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 142 => 'lib/PhpParser/Node/Stmt/For_.php', - 143 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 144 => 'lib/PhpParser/Node/Stmt/Function_.php', - 145 => 'lib/PhpParser/Node/Stmt/Global_.php', - 146 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 147 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 148 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 149 => 'lib/PhpParser/Node/Stmt/If_.php', - 150 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 151 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 152 => 'lib/PhpParser/Node/Stmt/Label.php', - 153 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 154 => 'lib/PhpParser/Node/Stmt/Nop.php', - 155 => 'lib/PhpParser/Node/Stmt/Property.php', - 156 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 157 => 'lib/PhpParser/Node/Stmt/Return_.php', - 158 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 159 => 'lib/PhpParser/Node/Stmt/Static_.php', - 160 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 161 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 162 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 163 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 164 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 165 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 166 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 167 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 168 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 169 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 170 => 'lib/PhpParser/Node/Stmt/Use_.php', - 171 => 'lib/PhpParser/Node/Stmt/While_.php', - 172 => 'lib/PhpParser/NodeDumper.php', - 173 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 174 => 'lib/PhpParser/Parser/Php5.php', - 175 => 'lib/PhpParser/Parser/Php7.php', - 176 => 'lib/PhpParser/ParserAbstract.php', - 177 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 178 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/NodeDumper.php' => - array ( - ), - 'lib/PhpParser/NodeTraverser.php' => - array ( - ), - 'lib/PhpParser/NodeTraverserInterface.php' => - array ( - 0 => 'lib/PhpParser/NodeTraverser.php', - ), - 'lib/PhpParser/NodeVisitor.php' => - array ( - 0 => 'lib/PhpParser/NodeTraverser.php', - 1 => 'lib/PhpParser/NodeTraverserInterface.php', - 2 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 3 => 'lib/PhpParser/NodeVisitorAbstract.php', - ), - 'lib/PhpParser/NodeVisitor/NameResolver.php' => - array ( - ), - 'lib/PhpParser/NodeVisitorAbstract.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - ), - 'lib/PhpParser/Parser.php' => - array ( - 0 => 'lib/PhpParser/Parser/Multiple.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Multiple.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Php5.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Php7.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Tokens.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/Lexer/Emulative.php', - ), - 'lib/PhpParser/ParserAbstract.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/ParserFactory.php' => - array ( - ), - 'lib/PhpParser/PrettyPrinter/Standard.php' => - array ( - ), - 'lib/PhpParser/PrettyPrinterAbstract.php' => - array ( - 0 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Serializer.php' => - array ( - 0 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Serializer/XML.php' => - array ( - ), - 'lib/PhpParser/Unserializer.php' => - array ( - 0 => 'lib/PhpParser/Unserializer/XML.php', - ), - 'lib/PhpParser/Unserializer/XML.php' => - array ( - ), - 'lib/bootstrap.php' => - array ( - ), -); diff --git a/tests/e2e/resultCache_3.php b/tests/e2e/resultCache_3.php deleted file mode 100644 index 993f2b65ee..0000000000 --- a/tests/e2e/resultCache_3.php +++ /dev/null @@ -1,2016 +0,0 @@ - - array ( - 0 => 'lib/bootstrap.php', - ), - 'lib/PhpParser/Builder.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Declaration.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderAbstract.php', - 12 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Class_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Declaration.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Trait_.php', - 7 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/FunctionLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Function_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Interface_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Method.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Param.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Property.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Trait_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/Builder/Use_.php' => - array ( - 0 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/BuilderAbstract.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Declaration.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderFactory.php', - ), - 'lib/PhpParser/BuilderFactory.php' => - array ( - ), - 'lib/PhpParser/Comment.php' => - array ( - 0 => 'lib/PhpParser/Builder/Declaration.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Comment/Doc.php', - 4 => 'lib/PhpParser/Lexer.php', - 5 => 'lib/PhpParser/Node.php', - 6 => 'lib/PhpParser/NodeAbstract.php', - 7 => 'lib/PhpParser/NodeDumper.php', - 8 => 'lib/PhpParser/PrettyPrinterAbstract.php', - 9 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Comment/Doc.php' => - array ( - 0 => 'lib/PhpParser/Builder/Declaration.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Comment.php', - 4 => 'lib/PhpParser/Lexer.php', - 5 => 'lib/PhpParser/Node.php', - 6 => 'lib/PhpParser/NodeAbstract.php', - 7 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Error.php' => - array ( - 0 => 'lib/PhpParser/ErrorHandler.php', - 1 => 'lib/PhpParser/ErrorHandler/Collecting.php', - 2 => 'lib/PhpParser/ErrorHandler/Throwing.php', - 3 => 'lib/PhpParser/Lexer.php', - 4 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 5 => 'lib/PhpParser/Node/Scalar/String_.php', - 6 => 'lib/PhpParser/Node/Stmt/Class_.php', - 7 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 8 => 'lib/PhpParser/Parser/Multiple.php', - 9 => 'lib/PhpParser/Parser/Php5.php', - 10 => 'lib/PhpParser/Parser/Php7.php', - 11 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/ErrorHandler.php' => - array ( - 0 => 'lib/PhpParser/ErrorHandler/Collecting.php', - 1 => 'lib/PhpParser/ErrorHandler/Throwing.php', - 2 => 'lib/PhpParser/Lexer.php', - 3 => 'lib/PhpParser/Lexer/Emulative.php', - 4 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 5 => 'lib/PhpParser/Parser.php', - 6 => 'lib/PhpParser/Parser/Multiple.php', - 7 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/ErrorHandler/Collecting.php' => - array ( - ), - 'lib/PhpParser/ErrorHandler/Throwing.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Multiple.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - ), - 'lib/PhpParser/Lexer.php' => - array ( - 0 => 'lib/PhpParser/Lexer/Emulative.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Lexer/Emulative.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Node.php' => - array ( - 0 => 'lib/PhpParser/Builder.php', - 1 => 'lib/PhpParser/Builder/Class_.php', - 2 => 'lib/PhpParser/Builder/FunctionLike.php', - 3 => 'lib/PhpParser/Builder/Function_.php', - 4 => 'lib/PhpParser/Builder/Interface_.php', - 5 => 'lib/PhpParser/Builder/Method.php', - 6 => 'lib/PhpParser/Builder/Namespace_.php', - 7 => 'lib/PhpParser/Builder/Param.php', - 8 => 'lib/PhpParser/Builder/Property.php', - 9 => 'lib/PhpParser/Builder/Trait_.php', - 10 => 'lib/PhpParser/Builder/Use_.php', - 11 => 'lib/PhpParser/BuilderAbstract.php', - 12 => 'lib/PhpParser/BuilderFactory.php', - 13 => 'lib/PhpParser/Node/Arg.php', - 14 => 'lib/PhpParser/Node/Const_.php', - 15 => 'lib/PhpParser/Node/Expr.php', - 16 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 17 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 18 => 'lib/PhpParser/Node/Expr/Array_.php', - 19 => 'lib/PhpParser/Node/Expr/Assign.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 23 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 24 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 25 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 26 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 27 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 28 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 29 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 30 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 31 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 32 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 33 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 52 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 53 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 54 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 55 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 56 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 57 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 58 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 59 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 60 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 61 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 62 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 63 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 64 => 'lib/PhpParser/Node/Expr/Cast.php', - 65 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 66 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 67 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 68 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 69 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 70 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 71 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 72 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 73 => 'lib/PhpParser/Node/Expr/Clone_.php', - 74 => 'lib/PhpParser/Node/Expr/Closure.php', - 75 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 76 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 77 => 'lib/PhpParser/Node/Expr/Empty_.php', - 78 => 'lib/PhpParser/Node/Expr/Error.php', - 79 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 80 => 'lib/PhpParser/Node/Expr/Eval_.php', - 81 => 'lib/PhpParser/Node/Expr/Exit_.php', - 82 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 83 => 'lib/PhpParser/Node/Expr/Include_.php', - 84 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 85 => 'lib/PhpParser/Node/Expr/Isset_.php', - 86 => 'lib/PhpParser/Node/Expr/List_.php', - 87 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 88 => 'lib/PhpParser/Node/Expr/New_.php', - 89 => 'lib/PhpParser/Node/Expr/PostDec.php', - 90 => 'lib/PhpParser/Node/Expr/PostInc.php', - 91 => 'lib/PhpParser/Node/Expr/PreDec.php', - 92 => 'lib/PhpParser/Node/Expr/PreInc.php', - 93 => 'lib/PhpParser/Node/Expr/Print_.php', - 94 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 95 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 96 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 97 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 98 => 'lib/PhpParser/Node/Expr/Ternary.php', - 99 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 100 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 101 => 'lib/PhpParser/Node/Expr/Variable.php', - 102 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 103 => 'lib/PhpParser/Node/Expr/Yield_.php', - 104 => 'lib/PhpParser/Node/FunctionLike.php', - 105 => 'lib/PhpParser/Node/Name.php', - 106 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 107 => 'lib/PhpParser/Node/Name/Relative.php', - 108 => 'lib/PhpParser/Node/NullableType.php', - 109 => 'lib/PhpParser/Node/Param.php', - 110 => 'lib/PhpParser/Node/Scalar.php', - 111 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 112 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 113 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 114 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 115 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 116 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 117 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 118 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 119 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 120 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 121 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 122 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 123 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 124 => 'lib/PhpParser/Node/Scalar/String_.php', - 125 => 'lib/PhpParser/Node/Stmt.php', - 126 => 'lib/PhpParser/Node/Stmt/Break_.php', - 127 => 'lib/PhpParser/Node/Stmt/Case_.php', - 128 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 129 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 130 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 131 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 132 => 'lib/PhpParser/Node/Stmt/Class_.php', - 133 => 'lib/PhpParser/Node/Stmt/Const_.php', - 134 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 135 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 136 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 137 => 'lib/PhpParser/Node/Stmt/Do_.php', - 138 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 139 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 140 => 'lib/PhpParser/Node/Stmt/Else_.php', - 141 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 142 => 'lib/PhpParser/Node/Stmt/For_.php', - 143 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 144 => 'lib/PhpParser/Node/Stmt/Function_.php', - 145 => 'lib/PhpParser/Node/Stmt/Global_.php', - 146 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 147 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 148 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 149 => 'lib/PhpParser/Node/Stmt/If_.php', - 150 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 151 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 152 => 'lib/PhpParser/Node/Stmt/Label.php', - 153 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 154 => 'lib/PhpParser/Node/Stmt/Nop.php', - 155 => 'lib/PhpParser/Node/Stmt/Property.php', - 156 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 157 => 'lib/PhpParser/Node/Stmt/Return_.php', - 158 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 159 => 'lib/PhpParser/Node/Stmt/Static_.php', - 160 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 161 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 162 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 163 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 164 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 165 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 166 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 167 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 168 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 169 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 170 => 'lib/PhpParser/Node/Stmt/Use_.php', - 171 => 'lib/PhpParser/Node/Stmt/While_.php', - 172 => 'lib/PhpParser/NodeAbstract.php', - 173 => 'lib/PhpParser/NodeDumper.php', - 174 => 'lib/PhpParser/NodeTraverser.php', - 175 => 'lib/PhpParser/NodeTraverserInterface.php', - 176 => 'lib/PhpParser/NodeVisitor.php', - 177 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 178 => 'lib/PhpParser/NodeVisitorAbstract.php', - 179 => 'lib/PhpParser/Parser.php', - 180 => 'lib/PhpParser/Parser/Multiple.php', - 181 => 'lib/PhpParser/Parser/Php5.php', - 182 => 'lib/PhpParser/Parser/Php7.php', - 183 => 'lib/PhpParser/ParserAbstract.php', - 184 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 185 => 'lib/PhpParser/PrettyPrinterAbstract.php', - 186 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Node/Arg.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 1 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 2 => 'lib/PhpParser/Node/Expr/New_.php', - 3 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Const_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 1 => 'lib/PhpParser/Node/Stmt/Const_.php', - 2 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 3 => 'lib/PhpParser/Parser/Php5.php', - 4 => 'lib/PhpParser/Parser/Php7.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr.php' => - array ( - 0 => 'lib/PhpParser/Builder/Param.php', - 1 => 'lib/PhpParser/Builder/Property.php', - 2 => 'lib/PhpParser/BuilderAbstract.php', - 3 => 'lib/PhpParser/Node/Arg.php', - 4 => 'lib/PhpParser/Node/Const_.php', - 5 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 6 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 7 => 'lib/PhpParser/Node/Expr/Array_.php', - 8 => 'lib/PhpParser/Node/Expr/Assign.php', - 9 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 10 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 11 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 12 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 13 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 14 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 15 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 16 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 17 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 18 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 19 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 22 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 23 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 24 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 25 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 26 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 27 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 28 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 29 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 30 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 31 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 32 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 33 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 51 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 52 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 53 => 'lib/PhpParser/Node/Expr/Cast.php', - 54 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 55 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 56 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 57 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 58 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 59 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 60 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 61 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 62 => 'lib/PhpParser/Node/Expr/Clone_.php', - 63 => 'lib/PhpParser/Node/Expr/Closure.php', - 64 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 65 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 66 => 'lib/PhpParser/Node/Expr/Empty_.php', - 67 => 'lib/PhpParser/Node/Expr/Error.php', - 68 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 69 => 'lib/PhpParser/Node/Expr/Eval_.php', - 70 => 'lib/PhpParser/Node/Expr/Exit_.php', - 71 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 72 => 'lib/PhpParser/Node/Expr/Include_.php', - 73 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 74 => 'lib/PhpParser/Node/Expr/Isset_.php', - 75 => 'lib/PhpParser/Node/Expr/List_.php', - 76 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 77 => 'lib/PhpParser/Node/Expr/New_.php', - 78 => 'lib/PhpParser/Node/Expr/PostDec.php', - 79 => 'lib/PhpParser/Node/Expr/PostInc.php', - 80 => 'lib/PhpParser/Node/Expr/PreDec.php', - 81 => 'lib/PhpParser/Node/Expr/PreInc.php', - 82 => 'lib/PhpParser/Node/Expr/Print_.php', - 83 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 84 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 85 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 86 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 87 => 'lib/PhpParser/Node/Expr/Ternary.php', - 88 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 89 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 90 => 'lib/PhpParser/Node/Expr/Variable.php', - 91 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 92 => 'lib/PhpParser/Node/Expr/Yield_.php', - 93 => 'lib/PhpParser/Node/Param.php', - 94 => 'lib/PhpParser/Node/Scalar.php', - 95 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 96 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 97 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 98 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 99 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 100 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 101 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 102 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 103 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 104 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 105 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 106 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 107 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 108 => 'lib/PhpParser/Node/Scalar/String_.php', - 109 => 'lib/PhpParser/Node/Stmt/Break_.php', - 110 => 'lib/PhpParser/Node/Stmt/Case_.php', - 111 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 112 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 113 => 'lib/PhpParser/Node/Stmt/Do_.php', - 114 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 115 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 116 => 'lib/PhpParser/Node/Stmt/For_.php', - 117 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 118 => 'lib/PhpParser/Node/Stmt/Global_.php', - 119 => 'lib/PhpParser/Node/Stmt/If_.php', - 120 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 121 => 'lib/PhpParser/Node/Stmt/Return_.php', - 122 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 123 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 124 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 125 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 126 => 'lib/PhpParser/Node/Stmt/While_.php', - 127 => 'lib/PhpParser/NodeDumper.php', - 128 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 129 => 'lib/PhpParser/Parser/Php5.php', - 130 => 'lib/PhpParser/Parser/Php7.php', - 131 => 'lib/PhpParser/ParserAbstract.php', - 132 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 133 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Expr/ArrayDimFetch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ArrayItem.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Node/Expr/Array_.php', - 2 => 'lib/PhpParser/Node/Expr/List_.php', - 3 => 'lib/PhpParser/Parser/Php5.php', - 4 => 'lib/PhpParser/Parser/Php7.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Array_.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Assign.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 1 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 2 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 3 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 4 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 5 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 6 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 7 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 8 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 9 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 10 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 11 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 12 => 'lib/PhpParser/Parser/Php5.php', - 13 => 'lib/PhpParser/Parser/Php7.php', - 14 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Concat.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Div.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Minus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Mod.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Mul.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Plus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/Pow.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/AssignRef.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 1 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 2 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 3 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 4 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 5 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 6 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 7 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 8 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 9 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 10 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 11 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 12 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 13 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 14 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 15 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 16 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 17 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 18 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 19 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 20 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 21 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 22 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 23 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 24 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 25 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 26 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 27 => 'lib/PhpParser/Parser/Php5.php', - 28 => 'lib/PhpParser/Parser/Php7.php', - 29 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Div.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BitwiseNot.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/BooleanNot.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 1 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 2 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 3 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 4 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 5 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 6 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 7 => 'lib/PhpParser/Parser/Php5.php', - 8 => 'lib/PhpParser/Parser/Php7.php', - 9 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Array_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Bool_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Double.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Int_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Object_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/String_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Cast/Unset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ClassConstFetch.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Clone_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Closure.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ClosureUse.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/Closure.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ConstFetch.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Empty_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Error.php' => - array ( - 0 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ErrorSuppress.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Eval_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Exit_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/FuncCall.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Include_.php' => - array ( - 0 => 'lib/PhpParser/NodeDumper.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Instanceof_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Isset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/List_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/MethodCall.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/New_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PostDec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PostInc.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PreDec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PreInc.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Print_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/PropertyFetch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/ShellExec.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/StaticCall.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Ternary.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/UnaryMinus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/UnaryPlus.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Variable.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/YieldFrom.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Expr/Yield_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/FunctionLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/Builder/Trait_.php', - 3 => 'lib/PhpParser/Node/Expr/Closure.php', - 4 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 5 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 6 => 'lib/PhpParser/Node/Stmt/Function_.php', - 7 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 8 => 'lib/PhpParser/Parser/Php5.php', - 9 => 'lib/PhpParser/Parser/Php7.php', - 10 => 'lib/PhpParser/ParserAbstract.php', - 11 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Name.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Param.php', - 7 => 'lib/PhpParser/Builder/Use_.php', - 8 => 'lib/PhpParser/BuilderAbstract.php', - 9 => 'lib/PhpParser/BuilderFactory.php', - 10 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 11 => 'lib/PhpParser/Node/Expr/Closure.php', - 12 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 13 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 14 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 15 => 'lib/PhpParser/Node/Expr/New_.php', - 16 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 17 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 18 => 'lib/PhpParser/Node/FunctionLike.php', - 19 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 20 => 'lib/PhpParser/Node/Name/Relative.php', - 21 => 'lib/PhpParser/Node/NullableType.php', - 22 => 'lib/PhpParser/Node/Param.php', - 23 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 24 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 25 => 'lib/PhpParser/Node/Stmt/Class_.php', - 26 => 'lib/PhpParser/Node/Stmt/Function_.php', - 27 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 28 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 29 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 30 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 31 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 32 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 33 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 34 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 35 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 36 => 'lib/PhpParser/Parser/Php5.php', - 37 => 'lib/PhpParser/Parser/Php7.php', - 38 => 'lib/PhpParser/ParserAbstract.php', - 39 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 40 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Name/FullyQualified.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Name/Relative.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/NullableType.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/Builder/Function_.php', - 2 => 'lib/PhpParser/Builder/Method.php', - 3 => 'lib/PhpParser/Builder/Param.php', - 4 => 'lib/PhpParser/BuilderAbstract.php', - 5 => 'lib/PhpParser/Node/Expr/Closure.php', - 6 => 'lib/PhpParser/Node/FunctionLike.php', - 7 => 'lib/PhpParser/Node/Param.php', - 8 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 9 => 'lib/PhpParser/Node/Stmt/Function_.php', - 10 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 11 => 'lib/PhpParser/Parser/Php7.php', - 12 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Param.php' => - array ( - 0 => 'lib/PhpParser/Builder/FunctionLike.php', - 1 => 'lib/PhpParser/Builder/Param.php', - 2 => 'lib/PhpParser/Node/Expr/Closure.php', - 3 => 'lib/PhpParser/Node/FunctionLike.php', - 4 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 5 => 'lib/PhpParser/Node/Stmt/Function_.php', - 6 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 7 => 'lib/PhpParser/Parser/Php5.php', - 8 => 'lib/PhpParser/Parser/Php7.php', - 9 => 'lib/PhpParser/ParserAbstract.php', - 10 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 2 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 3 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 4 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 5 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 6 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 7 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 8 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 9 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 10 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 11 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 12 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 13 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 14 => 'lib/PhpParser/Node/Scalar/String_.php', - 15 => 'lib/PhpParser/Parser/Php5.php', - 16 => 'lib/PhpParser/Parser/Php7.php', - 17 => 'lib/PhpParser/ParserAbstract.php', - 18 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/DNumber.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/Encapsed.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/LNumber.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/ParserAbstract.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst.php' => - array ( - 0 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 1 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 2 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 3 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 4 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 5 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 6 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 7 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 8 => 'lib/PhpParser/Parser/Php5.php', - 9 => 'lib/PhpParser/Parser/Php7.php', - 10 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/File.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Line.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Method.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Scalar/String_.php' => - array ( - 0 => 'lib/PhpParser/BuilderAbstract.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Function_.php', - 2 => 'lib/PhpParser/Builder/Interface_.php', - 3 => 'lib/PhpParser/Builder/Method.php', - 4 => 'lib/PhpParser/Builder/Namespace_.php', - 5 => 'lib/PhpParser/Builder/Property.php', - 6 => 'lib/PhpParser/Builder/Trait_.php', - 7 => 'lib/PhpParser/Builder/Use_.php', - 8 => 'lib/PhpParser/BuilderAbstract.php', - 9 => 'lib/PhpParser/BuilderFactory.php', - 10 => 'lib/PhpParser/Node/Expr/Closure.php', - 11 => 'lib/PhpParser/Node/Expr/New_.php', - 12 => 'lib/PhpParser/Node/FunctionLike.php', - 13 => 'lib/PhpParser/Node/Stmt/Break_.php', - 14 => 'lib/PhpParser/Node/Stmt/Case_.php', - 15 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 16 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 17 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 18 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 19 => 'lib/PhpParser/Node/Stmt/Class_.php', - 20 => 'lib/PhpParser/Node/Stmt/Const_.php', - 21 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 22 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 23 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 24 => 'lib/PhpParser/Node/Stmt/Do_.php', - 25 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 26 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 27 => 'lib/PhpParser/Node/Stmt/Else_.php', - 28 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 29 => 'lib/PhpParser/Node/Stmt/For_.php', - 30 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 31 => 'lib/PhpParser/Node/Stmt/Function_.php', - 32 => 'lib/PhpParser/Node/Stmt/Global_.php', - 33 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 34 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 35 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 36 => 'lib/PhpParser/Node/Stmt/If_.php', - 37 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 38 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 39 => 'lib/PhpParser/Node/Stmt/Label.php', - 40 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 41 => 'lib/PhpParser/Node/Stmt/Nop.php', - 42 => 'lib/PhpParser/Node/Stmt/Property.php', - 43 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 44 => 'lib/PhpParser/Node/Stmt/Return_.php', - 45 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 46 => 'lib/PhpParser/Node/Stmt/Static_.php', - 47 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 48 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 49 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 50 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 51 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 52 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 53 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 54 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 55 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 56 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 57 => 'lib/PhpParser/Node/Stmt/Use_.php', - 58 => 'lib/PhpParser/Node/Stmt/While_.php', - 59 => 'lib/PhpParser/NodeDumper.php', - 60 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 61 => 'lib/PhpParser/Parser/Php5.php', - 62 => 'lib/PhpParser/Parser/Php7.php', - 63 => 'lib/PhpParser/ParserAbstract.php', - 64 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 65 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Break_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Case_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Catch_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassConst.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassLike.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Interface_.php', - 2 => 'lib/PhpParser/Builder/Method.php', - 3 => 'lib/PhpParser/Builder/Property.php', - 4 => 'lib/PhpParser/Builder/Trait_.php', - 5 => 'lib/PhpParser/BuilderAbstract.php', - 6 => 'lib/PhpParser/Node/Expr/New_.php', - 7 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 8 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 9 => 'lib/PhpParser/Node/Stmt/Class_.php', - 10 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 11 => 'lib/PhpParser/Node/Stmt/Property.php', - 12 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 13 => 'lib/PhpParser/NodeDumper.php', - 14 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 15 => 'lib/PhpParser/Parser/Php5.php', - 16 => 'lib/PhpParser/Parser/Php7.php', - 17 => 'lib/PhpParser/ParserAbstract.php', - 18 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ClassMethod.php' => - array ( - 0 => 'lib/PhpParser/Builder/Method.php', - 1 => 'lib/PhpParser/Builder/Trait_.php', - 2 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 3 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/ParserAbstract.php', - 7 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Class_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/Method.php', - 2 => 'lib/PhpParser/Builder/Property.php', - 3 => 'lib/PhpParser/BuilderAbstract.php', - 4 => 'lib/PhpParser/Node/Expr/New_.php', - 5 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 6 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 7 => 'lib/PhpParser/Node/Stmt/Property.php', - 8 => 'lib/PhpParser/NodeDumper.php', - 9 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 10 => 'lib/PhpParser/Parser/Php5.php', - 11 => 'lib/PhpParser/Parser/Php7.php', - 12 => 'lib/PhpParser/ParserAbstract.php', - 13 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Const_.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Continue_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/DeclareDeclare.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Declare_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Do_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Echo_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/ElseIf_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/If_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Else_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/If_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Finally_.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/For_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Foreach_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Function_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Function_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Global_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Goto_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/GroupUse.php' => - array ( - 0 => 'lib/PhpParser/NodeDumper.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/HaltCompiler.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/If_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/InlineHTML.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 4 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Interface_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Interface_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Label.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Namespace_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Namespace_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 6 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Nop.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 4 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/Node/Stmt/Property.php' => - array ( - 0 => 'lib/PhpParser/Builder/Property.php', - 1 => 'lib/PhpParser/Builder/Trait_.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/ParserAbstract.php', - 5 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/PropertyProperty.php' => - array ( - 0 => 'lib/PhpParser/Builder/Property.php', - 1 => 'lib/PhpParser/Node/Stmt/Property.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Return_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/StaticVar.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/Static_.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Static_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Switch_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Throw_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUse.php' => - array ( - 0 => 'lib/PhpParser/Builder/Trait_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php' => - array ( - 0 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 1 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 2 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 3 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 4 => 'lib/PhpParser/Parser/Php5.php', - 5 => 'lib/PhpParser/Parser/Php7.php', - 6 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Trait_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Trait_.php', - 1 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 2 => 'lib/PhpParser/Parser/Php5.php', - 3 => 'lib/PhpParser/Parser/Php7.php', - 4 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/TryCatch.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserAbstract.php', - 3 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Unset_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/UseUse.php' => - array ( - 0 => 'lib/PhpParser/Builder/Use_.php', - 1 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 2 => 'lib/PhpParser/Node/Stmt/Use_.php', - 3 => 'lib/PhpParser/NodeDumper.php', - 4 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 5 => 'lib/PhpParser/Parser/Php5.php', - 6 => 'lib/PhpParser/Parser/Php7.php', - 7 => 'lib/PhpParser/ParserAbstract.php', - 8 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/Use_.php' => - array ( - 0 => 'lib/PhpParser/Builder/Use_.php', - 1 => 'lib/PhpParser/BuilderFactory.php', - 2 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 3 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 4 => 'lib/PhpParser/NodeDumper.php', - 5 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 6 => 'lib/PhpParser/Parser/Php5.php', - 7 => 'lib/PhpParser/Parser/Php7.php', - 8 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Node/Stmt/While_.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/NodeAbstract.php' => - array ( - 0 => 'lib/PhpParser/Builder/Class_.php', - 1 => 'lib/PhpParser/Builder/FunctionLike.php', - 2 => 'lib/PhpParser/Builder/Function_.php', - 3 => 'lib/PhpParser/Builder/Interface_.php', - 4 => 'lib/PhpParser/Builder/Method.php', - 5 => 'lib/PhpParser/Builder/Namespace_.php', - 6 => 'lib/PhpParser/Builder/Param.php', - 7 => 'lib/PhpParser/Builder/Property.php', - 8 => 'lib/PhpParser/Builder/Trait_.php', - 9 => 'lib/PhpParser/Builder/Use_.php', - 10 => 'lib/PhpParser/BuilderAbstract.php', - 11 => 'lib/PhpParser/BuilderFactory.php', - 12 => 'lib/PhpParser/Node/Arg.php', - 13 => 'lib/PhpParser/Node/Const_.php', - 14 => 'lib/PhpParser/Node/Expr.php', - 15 => 'lib/PhpParser/Node/Expr/ArrayDimFetch.php', - 16 => 'lib/PhpParser/Node/Expr/ArrayItem.php', - 17 => 'lib/PhpParser/Node/Expr/Array_.php', - 18 => 'lib/PhpParser/Node/Expr/Assign.php', - 19 => 'lib/PhpParser/Node/Expr/AssignOp.php', - 20 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', - 21 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', - 22 => 'lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', - 23 => 'lib/PhpParser/Node/Expr/AssignOp/Concat.php', - 24 => 'lib/PhpParser/Node/Expr/AssignOp/Div.php', - 25 => 'lib/PhpParser/Node/Expr/AssignOp/Minus.php', - 26 => 'lib/PhpParser/Node/Expr/AssignOp/Mod.php', - 27 => 'lib/PhpParser/Node/Expr/AssignOp/Mul.php', - 28 => 'lib/PhpParser/Node/Expr/AssignOp/Plus.php', - 29 => 'lib/PhpParser/Node/Expr/AssignOp/Pow.php', - 30 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', - 31 => 'lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', - 32 => 'lib/PhpParser/Node/Expr/AssignRef.php', - 33 => 'lib/PhpParser/Node/Expr/BinaryOp.php', - 34 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', - 35 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', - 36 => 'lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', - 37 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', - 38 => 'lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', - 39 => 'lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', - 40 => 'lib/PhpParser/Node/Expr/BinaryOp/Concat.php', - 41 => 'lib/PhpParser/Node/Expr/BinaryOp/Div.php', - 42 => 'lib/PhpParser/Node/Expr/BinaryOp/Equal.php', - 43 => 'lib/PhpParser/Node/Expr/BinaryOp/Greater.php', - 44 => 'lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', - 45 => 'lib/PhpParser/Node/Expr/BinaryOp/Identical.php', - 46 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', - 47 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', - 48 => 'lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', - 49 => 'lib/PhpParser/Node/Expr/BinaryOp/Minus.php', - 50 => 'lib/PhpParser/Node/Expr/BinaryOp/Mod.php', - 51 => 'lib/PhpParser/Node/Expr/BinaryOp/Mul.php', - 52 => 'lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', - 53 => 'lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', - 54 => 'lib/PhpParser/Node/Expr/BinaryOp/Plus.php', - 55 => 'lib/PhpParser/Node/Expr/BinaryOp/Pow.php', - 56 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', - 57 => 'lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', - 58 => 'lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', - 59 => 'lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', - 60 => 'lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', - 61 => 'lib/PhpParser/Node/Expr/BitwiseNot.php', - 62 => 'lib/PhpParser/Node/Expr/BooleanNot.php', - 63 => 'lib/PhpParser/Node/Expr/Cast.php', - 64 => 'lib/PhpParser/Node/Expr/Cast/Array_.php', - 65 => 'lib/PhpParser/Node/Expr/Cast/Bool_.php', - 66 => 'lib/PhpParser/Node/Expr/Cast/Double.php', - 67 => 'lib/PhpParser/Node/Expr/Cast/Int_.php', - 68 => 'lib/PhpParser/Node/Expr/Cast/Object_.php', - 69 => 'lib/PhpParser/Node/Expr/Cast/String_.php', - 70 => 'lib/PhpParser/Node/Expr/Cast/Unset_.php', - 71 => 'lib/PhpParser/Node/Expr/ClassConstFetch.php', - 72 => 'lib/PhpParser/Node/Expr/Clone_.php', - 73 => 'lib/PhpParser/Node/Expr/Closure.php', - 74 => 'lib/PhpParser/Node/Expr/ClosureUse.php', - 75 => 'lib/PhpParser/Node/Expr/ConstFetch.php', - 76 => 'lib/PhpParser/Node/Expr/Empty_.php', - 77 => 'lib/PhpParser/Node/Expr/Error.php', - 78 => 'lib/PhpParser/Node/Expr/ErrorSuppress.php', - 79 => 'lib/PhpParser/Node/Expr/Eval_.php', - 80 => 'lib/PhpParser/Node/Expr/Exit_.php', - 81 => 'lib/PhpParser/Node/Expr/FuncCall.php', - 82 => 'lib/PhpParser/Node/Expr/Include_.php', - 83 => 'lib/PhpParser/Node/Expr/Instanceof_.php', - 84 => 'lib/PhpParser/Node/Expr/Isset_.php', - 85 => 'lib/PhpParser/Node/Expr/List_.php', - 86 => 'lib/PhpParser/Node/Expr/MethodCall.php', - 87 => 'lib/PhpParser/Node/Expr/New_.php', - 88 => 'lib/PhpParser/Node/Expr/PostDec.php', - 89 => 'lib/PhpParser/Node/Expr/PostInc.php', - 90 => 'lib/PhpParser/Node/Expr/PreDec.php', - 91 => 'lib/PhpParser/Node/Expr/PreInc.php', - 92 => 'lib/PhpParser/Node/Expr/Print_.php', - 93 => 'lib/PhpParser/Node/Expr/PropertyFetch.php', - 94 => 'lib/PhpParser/Node/Expr/ShellExec.php', - 95 => 'lib/PhpParser/Node/Expr/StaticCall.php', - 96 => 'lib/PhpParser/Node/Expr/StaticPropertyFetch.php', - 97 => 'lib/PhpParser/Node/Expr/Ternary.php', - 98 => 'lib/PhpParser/Node/Expr/UnaryMinus.php', - 99 => 'lib/PhpParser/Node/Expr/UnaryPlus.php', - 100 => 'lib/PhpParser/Node/Expr/Variable.php', - 101 => 'lib/PhpParser/Node/Expr/YieldFrom.php', - 102 => 'lib/PhpParser/Node/Expr/Yield_.php', - 103 => 'lib/PhpParser/Node/FunctionLike.php', - 104 => 'lib/PhpParser/Node/Name.php', - 105 => 'lib/PhpParser/Node/Name/FullyQualified.php', - 106 => 'lib/PhpParser/Node/Name/Relative.php', - 107 => 'lib/PhpParser/Node/NullableType.php', - 108 => 'lib/PhpParser/Node/Param.php', - 109 => 'lib/PhpParser/Node/Scalar.php', - 110 => 'lib/PhpParser/Node/Scalar/DNumber.php', - 111 => 'lib/PhpParser/Node/Scalar/Encapsed.php', - 112 => 'lib/PhpParser/Node/Scalar/EncapsedStringPart.php', - 113 => 'lib/PhpParser/Node/Scalar/LNumber.php', - 114 => 'lib/PhpParser/Node/Scalar/MagicConst.php', - 115 => 'lib/PhpParser/Node/Scalar/MagicConst/Class_.php', - 116 => 'lib/PhpParser/Node/Scalar/MagicConst/Dir.php', - 117 => 'lib/PhpParser/Node/Scalar/MagicConst/File.php', - 118 => 'lib/PhpParser/Node/Scalar/MagicConst/Function_.php', - 119 => 'lib/PhpParser/Node/Scalar/MagicConst/Line.php', - 120 => 'lib/PhpParser/Node/Scalar/MagicConst/Method.php', - 121 => 'lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', - 122 => 'lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', - 123 => 'lib/PhpParser/Node/Scalar/String_.php', - 124 => 'lib/PhpParser/Node/Stmt.php', - 125 => 'lib/PhpParser/Node/Stmt/Break_.php', - 126 => 'lib/PhpParser/Node/Stmt/Case_.php', - 127 => 'lib/PhpParser/Node/Stmt/Catch_.php', - 128 => 'lib/PhpParser/Node/Stmt/ClassConst.php', - 129 => 'lib/PhpParser/Node/Stmt/ClassLike.php', - 130 => 'lib/PhpParser/Node/Stmt/ClassMethod.php', - 131 => 'lib/PhpParser/Node/Stmt/Class_.php', - 132 => 'lib/PhpParser/Node/Stmt/Const_.php', - 133 => 'lib/PhpParser/Node/Stmt/Continue_.php', - 134 => 'lib/PhpParser/Node/Stmt/DeclareDeclare.php', - 135 => 'lib/PhpParser/Node/Stmt/Declare_.php', - 136 => 'lib/PhpParser/Node/Stmt/Do_.php', - 137 => 'lib/PhpParser/Node/Stmt/Echo_.php', - 138 => 'lib/PhpParser/Node/Stmt/ElseIf_.php', - 139 => 'lib/PhpParser/Node/Stmt/Else_.php', - 140 => 'lib/PhpParser/Node/Stmt/Finally_.php', - 141 => 'lib/PhpParser/Node/Stmt/For_.php', - 142 => 'lib/PhpParser/Node/Stmt/Foreach_.php', - 143 => 'lib/PhpParser/Node/Stmt/Function_.php', - 144 => 'lib/PhpParser/Node/Stmt/Global_.php', - 145 => 'lib/PhpParser/Node/Stmt/Goto_.php', - 146 => 'lib/PhpParser/Node/Stmt/GroupUse.php', - 147 => 'lib/PhpParser/Node/Stmt/HaltCompiler.php', - 148 => 'lib/PhpParser/Node/Stmt/If_.php', - 149 => 'lib/PhpParser/Node/Stmt/InlineHTML.php', - 150 => 'lib/PhpParser/Node/Stmt/Interface_.php', - 151 => 'lib/PhpParser/Node/Stmt/Label.php', - 152 => 'lib/PhpParser/Node/Stmt/Namespace_.php', - 153 => 'lib/PhpParser/Node/Stmt/Nop.php', - 154 => 'lib/PhpParser/Node/Stmt/Property.php', - 155 => 'lib/PhpParser/Node/Stmt/PropertyProperty.php', - 156 => 'lib/PhpParser/Node/Stmt/Return_.php', - 157 => 'lib/PhpParser/Node/Stmt/StaticVar.php', - 158 => 'lib/PhpParser/Node/Stmt/Static_.php', - 159 => 'lib/PhpParser/Node/Stmt/Switch_.php', - 160 => 'lib/PhpParser/Node/Stmt/Throw_.php', - 161 => 'lib/PhpParser/Node/Stmt/TraitUse.php', - 162 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', - 163 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', - 164 => 'lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', - 165 => 'lib/PhpParser/Node/Stmt/Trait_.php', - 166 => 'lib/PhpParser/Node/Stmt/TryCatch.php', - 167 => 'lib/PhpParser/Node/Stmt/Unset_.php', - 168 => 'lib/PhpParser/Node/Stmt/UseUse.php', - 169 => 'lib/PhpParser/Node/Stmt/Use_.php', - 170 => 'lib/PhpParser/Node/Stmt/While_.php', - 171 => 'lib/PhpParser/NodeDumper.php', - 172 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 173 => 'lib/PhpParser/Parser/Php5.php', - 174 => 'lib/PhpParser/Parser/Php7.php', - 175 => 'lib/PhpParser/ParserAbstract.php', - 176 => 'lib/PhpParser/PrettyPrinter/Standard.php', - 177 => 'lib/PhpParser/PrettyPrinterAbstract.php', - ), - 'lib/PhpParser/NodeDumper.php' => - array ( - ), - 'lib/PhpParser/NodeTraverser.php' => - array ( - ), - 'lib/PhpParser/NodeTraverserInterface.php' => - array ( - 0 => 'lib/PhpParser/NodeTraverser.php', - ), - 'lib/PhpParser/NodeVisitor.php' => - array ( - 0 => 'lib/PhpParser/NodeTraverser.php', - 1 => 'lib/PhpParser/NodeTraverserInterface.php', - 2 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - 3 => 'lib/PhpParser/NodeVisitorAbstract.php', - ), - 'lib/PhpParser/NodeVisitor/NameResolver.php' => - array ( - ), - 'lib/PhpParser/NodeVisitorAbstract.php' => - array ( - 0 => 'lib/PhpParser/NodeVisitor/NameResolver.php', - ), - 'lib/PhpParser/Parser.php' => - array ( - 0 => 'lib/PhpParser/Parser/Multiple.php', - 1 => 'lib/PhpParser/Parser/Php5.php', - 2 => 'lib/PhpParser/Parser/Php7.php', - 3 => 'lib/PhpParser/ParserAbstract.php', - 4 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Multiple.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Php5.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Php7.php' => - array ( - 0 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/Parser/Tokens.php' => - array ( - 0 => 'lib/PhpParser/Lexer.php', - 1 => 'lib/PhpParser/Lexer/Emulative.php', - ), - 'lib/PhpParser/ParserAbstract.php' => - array ( - 0 => 'lib/PhpParser/Parser/Php5.php', - 1 => 'lib/PhpParser/Parser/Php7.php', - 2 => 'lib/PhpParser/ParserFactory.php', - ), - 'lib/PhpParser/ParserFactory.php' => - array ( - ), - 'lib/PhpParser/PrettyPrinter/Standard.php' => - array ( - ), - 'lib/PhpParser/PrettyPrinterAbstract.php' => - array ( - 0 => 'lib/PhpParser/PrettyPrinter/Standard.php', - ), - 'lib/PhpParser/Serializer.php' => - array ( - 0 => 'lib/PhpParser/Serializer/XML.php', - ), - 'lib/PhpParser/Serializer/XML.php' => - array ( - ), - 'lib/PhpParser/Unserializer.php' => - array ( - 0 => 'lib/PhpParser/Unserializer/XML.php', - ), - 'lib/PhpParser/Unserializer/XML.php' => - array ( - ), -);