diff --git a/.github/workflows/backward-compatibility.yml b/.github/workflows/backward-compatibility.yml
index 0233e1e422..d7651c9202 100644
--- a/.github/workflows/backward-compatibility.yml
+++ b/.github/workflows/backward-compatibility.yml
@@ -6,7 +6,7 @@ on:
   pull_request:
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
     paths:
       - 'src/**'
       - '.github/workflows/backward-compatibility.yml'
diff --git a/.github/workflows/build-issue-bot.yml b/.github/workflows/build-issue-bot.yml
index 278470b466..0e541ca5b1 100644
--- a/.github/workflows/build-issue-bot.yml
+++ b/.github/workflows/build-issue-bot.yml
@@ -9,7 +9,7 @@ on:
       - '.github/workflows/build-issue-bot.yml'
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
     paths:
       - 'issue-bot/**'
       - '.github/workflows/build-issue-bot.yml'
diff --git a/.github/workflows/changelog-generator.yml b/.github/workflows/changelog-generator.yml
index 21971571f3..bda67d4725 100644
--- a/.github/workflows/changelog-generator.yml
+++ b/.github/workflows/changelog-generator.yml
@@ -9,7 +9,7 @@ on:
       - '.github/workflows/changelog-generator.yml'
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
     paths:
       - 'changelog-generator/**'
       - '.github/workflows/changelog-generator.yml'
diff --git a/.github/workflows/checksum-phar.yml b/.github/workflows/checksum-phar.yml
index 47256373d0..994f11ba06 100644
--- a/.github/workflows/checksum-phar.yml
+++ b/.github/workflows/checksum-phar.yml
@@ -12,7 +12,7 @@ on:
       - '.github/workflows/checksum-phar.yml'
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
     paths:
       - 'compiler/**'
       - '.github/workflows/checksum-phar.yml'
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index 53fded3322..239a5e3781 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -11,7 +11,7 @@ on:
       - 'issue-bot/**'
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
     paths-ignore:
       - 'compiler/**'
       - 'apigen/**'
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 03420615cd..bdc15d968a 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -6,7 +6,7 @@ on:
   pull_request:
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
 
 env:
   COMPOSER_ROOT_VERSION: "1.12.x-dev"
@@ -25,8 +25,6 @@ jobs:
       fail-fast: false
       matrix:
         php-version:
-          - "7.2"
-          - "7.3"
           - "7.4"
           - "8.0"
           - "8.1"
diff --git a/.github/workflows/phar.yml b/.github/workflows/phar.yml
index c6c4934b44..f2f75906b3 100644
--- a/.github/workflows/phar.yml
+++ b/.github/workflows/phar.yml
@@ -6,9 +6,12 @@ on:
   pull_request:
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
     tags:
-      - '1.12.*'
+      - '2.0.*'
+
+env:
+  COMPOSER_ROOT_VERSION: "1.12.x-dev"
 
 concurrency:
   group: phar-${{ github.ref }} # will be canceled on subsequent pushes in both branches and pull requests
@@ -76,15 +79,12 @@ jobs:
 
       - name: "Composer dump"
         run: "composer install --no-interaction --no-progress"
-        env:
-          COMPOSER_ROOT_VERSION: "1.12.x-dev"
 
       - name: "Compile PHAR for checksum"
         working-directory: "compiler/build"
         run: "php box.phar compile --no-parallel"
         env:
           PHAR_CHECKSUM: "1"
-          COMPOSER_ROOT_VERSION: "1.12.x-dev"
 
       - name: "Re-sign PHAR"
         run: "php compiler/build/resign.php tmp/phpstan.phar"
@@ -107,25 +107,25 @@ jobs:
   integration-tests:
     if: github.event_name == 'pull_request'
     needs: compiler-tests
-    uses: phpstan/phpstan/.github/workflows/integration-tests.yml@1.12.x
+    uses: phpstan/phpstan/.github/workflows/integration-tests.yml@2.0.x
     with:
-      ref: 1.12.x
+      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:
@@ -152,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..f522ea446e 100644
--- a/.github/workflows/pr-base-on-previous-branch.yml
+++ b/.github/workflows/pr-base-on-previous-branch.yml
@@ -19,6 +19,6 @@ jobs:
       - name: Comment PR
         uses: peter-evans/create-or-update-comment@v4
         with:
-          body: "You've opened the pull request against the latest branch 2.0.x. If your code is relevant on 1.12.x and you want it to be released sooner, please rebase your pull request and change its target to 1.12.x."
+          body: "You've opened the pull request against the latest branch 2.0.x. PHPStan 2.0 is not going to be released for months. If your code is relevant on 1.12.x and you want it to be released sooner, please rebase your pull request and change its target to 1.12.x."
           token: ${{ secrets.PHPSTAN_BOT_TOKEN }}
           issue-number: ${{ github.event.pull_request.number }}
diff --git a/.github/workflows/reflection-golden-test.yml b/.github/workflows/reflection-golden-test.yml
index 6d16f21aaa..2bf67cb14f 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/**'
@@ -65,7 +65,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 d91ab1ff1f..4304d27005 100644
--- a/.github/workflows/spelling.yml
+++ b/.github/workflows/spelling.yml
@@ -6,7 +6,7 @@ on:
   pull_request:
   push:
     branches:
-      - "1.12.x"
+      - "2.0.x"
 
 jobs:
   typos:
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index b19b6c10f7..a0c08f6171 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/**'
@@ -31,8 +31,6 @@ jobs:
       fail-fast: false
       matrix:
         php-version:
-          - "7.2"
-          - "7.3"
           - "7.4"
           - "8.0"
           - "8.1"
@@ -61,18 +59,12 @@ jobs:
         shell: bash
         run: "vendor/bin/simple-downgrade downgrade -c build/downgrade.php ${{ matrix.php-version }}"
 
-      - name: "Paratest patch"
-        if: matrix.php-version == '7.2'
-        run: composer config extra.patches.brianium/paratest --json --merge '["patches/paratest.patch"]'
-        shell: bash
-
-      - name: "Downgrade PHPUnit"
-        if: matrix.php-version == '7.2'
-        run: "composer require --dev phpunit/phpunit:^8.5.31 brianium/paratest:^4.0 composer/semver:^1.2 --update-with-dependencies --ignore-platform-reqs"
-
-      - name: "Update PHPUnit"
-        if: matrix.php-version != '7.2' && matrix.php-version != '7.3'
-        run: "composer update phpunit/phpunit -W"
+      - name: "Upload transformed sources"
+        if: matrix.php-version == '7.4'
+        uses: actions/upload-artifact@v3
+        with:
+          name: transformed-src
+          path: src
 
       - name: "PHPStan"
         run: "make phpstan"
@@ -107,9 +99,6 @@ jobs:
       - name: "Install dependencies"
         run: "composer install --no-interaction --no-progress"
 
-      - name: "Update PHPUnit"
-        run: "composer update phpunit/phpunit -W"
-
       - name: "Cache Result cache"
         uses: actions/cache@v4
         with:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 59d834e9c7..5533bd7e6a 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/**'
@@ -35,7 +35,6 @@ jobs:
       fail-fast: false
       matrix:
         php-version:
-          - "7.3"
           - "7.4"
           - "8.0"
           - "8.1"
@@ -66,10 +65,6 @@ jobs:
         shell: bash
         run: "vendor/bin/simple-downgrade downgrade -c build/downgrade.php ${{ matrix.php-version }}"
 
-      - name: "Update PHPUnit"
-        if: matrix.php-version != '7.3'
-        run: "composer update phpunit/phpunit -W"
-
       - name: "Tests"
         run: "make tests"
 
@@ -162,46 +157,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/build/composer-dependency-analyser.php b/build/composer-dependency-analyser.php
index 723a3ece2e..7502680e13 100644
--- a/build/composer-dependency-analyser.php
+++ b/build/composer-dependency-analyser.php
@@ -33,7 +33,7 @@
 	)
 	->ignoreErrorsOnPackage('phpunit/phpunit', [ErrorType::DEV_DEPENDENCY_IN_PROD]) // prepared test tooling
 	->ignoreErrorsOnPackage('jetbrains/phpstorm-stubs', [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV]) // there is no direct usage, but we need newer version then required by ondrejmirtes/BetterReflection
-	->ignoreErrorsOnPath(__DIR__ . '/../tests', [ErrorType::UNKNOWN_CLASS, ErrorType::UNKNOWN_FUNCTION]) // to be able to test invalid symbols
+	->ignoreErrorsOnPath(__DIR__ . '/../tests', [ErrorType::UNKNOWN_CLASS, ErrorType::UNKNOWN_FUNCTION, ErrorType::SHADOW_DEPENDENCY]) // to be able to test invalid symbols
 	->ignoreUnknownClasses([
 		'JetBrains\PhpStorm\Pure', // not present on composer's classmap
 		'PHPStan\ExtensionInstaller\GeneratedConfig', // generated
diff --git a/compiler/src/Console/PrepareCommand.php b/compiler/src/Console/PrepareCommand.php
index f7f2b6cdf6..6d23dde7a6 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;
@@ -64,7 +65,7 @@ private function fixComposerJson(string $buildDir): void
 
 		unset($json['replace']);
 		$json['name'] = 'phpstan/phpstan';
-		$json['require']['php'] = '^7.2|^8.0';
+		$json['require']['php'] = '^7.4|^8.0';
 
 		// simplify autoload (remove not packed build directory]
 		$json['autoload']['psr-4']['PHPStan\\'] = 'src/';
@@ -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 f6cb9c01db..e4e61cd532 100644
--- a/composer.json
+++ b/composer.json
@@ -22,9 +22,9 @@
 		"nette/php-generator": "3.6.9",
 		"nette/schema": "^1.2.2",
 		"nette/utils": "^3.2.5",
-		"nikic/php-parser": "^4.17.1",
+		"nikic/php-parser": "^5.1.0",
 		"ondram/ci-detector": "^3.4.0",
-		"ondrejmirtes/better-reflection": "6.25.0.17",
+		"ondrejmirtes/better-reflection": "6.42.0.6",
 		"phpstan/php-8-stubs": "0.3.101",
 		"phpstan/phpdoc-parser": "1.30.0",
 		"psr/http-message": "^1.1",
@@ -55,14 +55,13 @@
 	"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",
+		"phpunit/phpunit": "^9.6",
 		"shipmonk/composer-dependency-analyser": "^1.5",
 		"shipmonk/name-collision-detector": "^2.0"
 	},
diff --git a/composer.lock b/composer.lock
index 71beaf624c..0aba247c22 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "f5af1898ab9d95520d1511334b2000c0",
+    "content-hash": "bba4725ca58df1d370b5aa291335076d",
     "packages": [
         {
             "name": "clue/ndjson-react",
@@ -1474,7 +1474,7 @@
             "support": {
                 "source": "https://github.com/JetBrains/phpstorm-stubs/tree/master"
             },
-            "time": "2024-07-24T19:11:43+00:00"
+            "time": "2024-09-01T14:35:14+00:00"
         },
         {
             "name": "nette/bootstrap",
@@ -1963,25 +1963,26 @@
         },
         {
             "name": "nette/utils",
-            "version": "v3.2.7",
+            "version": "v3.2.10",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nette/utils.git",
-                "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99"
+                "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nette/utils/zipball/0af4e3de4df9f1543534beab255ccf459e7a2c99",
-                "reference": "0af4e3de4df9f1543534beab255ccf459e7a2c99",
+                "url": "https://api.github.com/repos/nette/utils/zipball/a4175c62652f2300c8017fb7e640f9ccb11648d2",
+                "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2",
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.2 <8.2"
+                "php": ">=7.2 <8.4"
             },
             "conflict": {
                 "nette/di": "<3.0.6"
             },
             "require-dev": {
+                "jetbrains/phpstorm-attributes": "dev-master",
                 "nette/tester": "~2.0",
                 "phpstan/phpstan": "^1.0",
                 "tracy/tracy": "^2.3"
@@ -2042,31 +2043,33 @@
             ],
             "support": {
                 "issues": "https://github.com/nette/utils/issues",
-                "source": "https://github.com/nette/utils/tree/v3.2.7"
+                "source": "https://github.com/nette/utils/tree/v3.2.10"
             },
-            "time": "2022-01-24T11:29:14+00:00"
+            "time": "2023-07-30T15:38:18+00:00"
         },
         {
             "name": "nikic/php-parser",
-            "version": "v4.19.1",
+            "version": "v5.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b"
+                "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b",
-                "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/683130c2ff8c2739f4822ff7ac5c873ec529abd1",
+                "reference": "683130c2ff8c2739f4822ff7ac5c873ec529abd1",
                 "shasum": ""
             },
             "require": {
+                "ext-ctype": "*",
+                "ext-json": "*",
                 "ext-tokenizer": "*",
-                "php": ">=7.1"
+                "php": ">=7.4"
             },
             "require-dev": {
                 "ircmaxell/php-yacc": "^0.0.7",
-                "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+                "phpunit/phpunit": "^9.0"
             },
             "bin": [
                 "bin/php-parse"
@@ -2074,7 +2077,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.9-dev"
+                    "dev-master": "5.0-dev"
                 }
             },
             "autoload": {
@@ -2098,9 +2101,9 @@
             ],
             "support": {
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
-                "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1"
+                "source": "https://github.com/nikic/PHP-Parser/tree/v5.1.0"
             },
-            "time": "2024-03-17T08:10:35+00:00"
+            "time": "2024-07-01T20:03:41+00:00"
         },
         {
             "name": "ondram/ci-detector",
@@ -2176,23 +2179,23 @@
         },
         {
             "name": "ondrejmirtes/better-reflection",
-            "version": "6.25.0.17",
+            "version": "6.42.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ondrejmirtes/BetterReflection.git",
-                "reference": "2c9cf932ab3306e0fcb90471f3b63fa3190bf7b2"
+                "reference": "955eefa555a862d35c298c69042a176bb39f88e2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/2c9cf932ab3306e0fcb90471f3b63fa3190bf7b2",
-                "reference": "2c9cf932ab3306e0fcb90471f3b63fa3190bf7b2",
+                "url": "https://api.github.com/repos/ondrejmirtes/BetterReflection/zipball/955eefa555a862d35c298c69042a176bb39f88e2",
+                "reference": "955eefa555a862d35c298c69042a176bb39f88e2",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "jetbrains/phpstorm-stubs": "dev-master#217ed9356d07ef89109d3cd7d8c5df10aab4b0d4",
-                "nikic/php-parser": "^4.18.0",
-                "php": "^7.2 || ^8.0"
+                "nikic/php-parser": "^5.1.0",
+                "php": "^7.4 || ^8.0"
             },
             "conflict": {
                 "thecodingmachine/safe": "<1.1.3"
@@ -2201,9 +2204,8 @@
                 "doctrine/coding-standard": "^12.0.0",
                 "phpstan/phpstan": "^1.10.60",
                 "phpstan/phpstan-phpunit": "^1.3.16",
-                "phpunit/phpunit": "^10.5.12",
-                "rector/rector": "0.14.3",
-                "vimeo/psalm": "5.23.0"
+                "phpunit/phpunit": "^11.3.2",
+                "rector/rector": "0.14.3"
             },
             "suggest": {
                 "composer/composer": "Required to use the ComposerSourceLocator"
@@ -2242,9 +2244,9 @@
             ],
             "description": "Better Reflection - an improved code reflection API",
             "support": {
-                "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.25.0.17"
+                "source": "https://github.com/ondrejmirtes/BetterReflection/tree/6.42.0.6"
             },
-            "time": "2024-08-26T20:47:13+00:00"
+            "time": "2024-09-04T11:59:59+00:00"
         },
         {
             "name": "phpstan/php-8-stubs",
@@ -3168,16 +3170,16 @@
         },
         {
             "name": "symfony/console",
-            "version": "v5.4.41",
+            "version": "v5.4.43",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "6473d441a913cb997123b59ff2dbe3d1cf9e11ba"
+                "reference": "e86f8554de667c16dde8aeb89a3990cfde924df9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/6473d441a913cb997123b59ff2dbe3d1cf9e11ba",
-                "reference": "6473d441a913cb997123b59ff2dbe3d1cf9e11ba",
+                "url": "https://api.github.com/repos/symfony/console/zipball/e86f8554de667c16dde8aeb89a3990cfde924df9",
+                "reference": "e86f8554de667c16dde8aeb89a3990cfde924df9",
                 "shasum": ""
             },
             "require": {
@@ -3247,7 +3249,7 @@
                 "terminal"
             ],
             "support": {
-                "source": "https://github.com/symfony/console/tree/v5.4.41"
+                "source": "https://github.com/symfony/console/tree/v5.4.43"
             },
             "funding": [
                 {
@@ -3263,7 +3265,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-06-28T07:48:55+00:00"
+            "time": "2024-08-13T16:31:56+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",
@@ -3334,16 +3336,16 @@
         },
         {
             "name": "symfony/finder",
-            "version": "v5.4.40",
+            "version": "v5.4.43",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "f51cff4687547641c7d8180d74932ab40b2205ce"
+                "reference": "ae25a9145a900764158d439653d5630191155ca0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/f51cff4687547641c7d8180d74932ab40b2205ce",
-                "reference": "f51cff4687547641c7d8180d74932ab40b2205ce",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/ae25a9145a900764158d439653d5630191155ca0",
+                "reference": "ae25a9145a900764158d439653d5630191155ca0",
                 "shasum": ""
             },
             "require": {
@@ -3377,7 +3379,7 @@
             "description": "Finds files and directories via an intuitive fluent interface",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/finder/tree/v5.4.40"
+                "source": "https://github.com/symfony/finder/tree/v5.4.43"
             },
             "funding": [
                 {
@@ -3393,7 +3395,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-05-31T14:33:22+00:00"
+            "time": "2024-08-13T14:03:51+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
@@ -4169,16 +4171,16 @@
         },
         {
             "name": "symfony/string",
-            "version": "v5.4.41",
+            "version": "v5.4.43",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/string.git",
-                "reference": "065a9611e0b1fd2197a867e1fb7f2238191b7096"
+                "reference": "8be1d484951ff5ca995eaf8edcbcb8b9a5888450"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/string/zipball/065a9611e0b1fd2197a867e1fb7f2238191b7096",
-                "reference": "065a9611e0b1fd2197a867e1fb7f2238191b7096",
+                "url": "https://api.github.com/repos/symfony/string/zipball/8be1d484951ff5ca995eaf8edcbcb8b9a5888450",
+                "reference": "8be1d484951ff5ca995eaf8edcbcb8b9a5888450",
                 "shasum": ""
             },
             "require": {
@@ -4235,7 +4237,7 @@
                 "utf8"
             ],
             "support": {
-                "source": "https://github.com/symfony/string/tree/v5.4.41"
+                "source": "https://github.com/symfony/string/tree/v5.4.43"
             },
             "funding": [
                 {
@@ -4251,7 +4253,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-06-28T09:20:55+00:00"
+            "time": "2024-08-01T10:24:28+00:00"
         }
     ],
     "packages-dev": [
@@ -4398,30 +4400,30 @@
         },
         {
             "name": "doctrine/instantiator",
-            "version": "1.4.1",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
+                "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
-                "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
+                "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
                 "shasum": ""
             },
             "require": {
-                "php": "^7.1 || ^8.0"
+                "php": "^8.1"
             },
             "require-dev": {
-                "doctrine/coding-standard": "^9",
+                "doctrine/coding-standard": "^11",
                 "ext-pdo": "*",
                 "ext-phar": "*",
-                "phpbench/phpbench": "^0.16 || ^1",
-                "phpstan/phpstan": "^1.4",
-                "phpstan/phpstan-phpunit": "^1",
-                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
-                "vimeo/psalm": "^4.22"
+                "phpbench/phpbench": "^1.2",
+                "phpstan/phpstan": "^1.9.4",
+                "phpstan/phpstan-phpunit": "^1.3",
+                "phpunit/phpunit": "^9.5.27",
+                "vimeo/psalm": "^5.4"
             },
             "type": "library",
             "autoload": {
@@ -4448,7 +4450,7 @@
             ],
             "support": {
                 "issues": "https://github.com/doctrine/instantiator/issues",
-                "source": "https://github.com/doctrine/instantiator/tree/1.4.1"
+                "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
             },
             "funding": [
                 {
@@ -4464,7 +4466,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-03-03T08:28:38+00:00"
+            "time": "2022-12-30T00:23:10+00:00"
         },
         {
             "name": "jean85/pretty-package-versions",
@@ -4527,16 +4529,16 @@
         },
         {
             "name": "myclabs/deep-copy",
-            "version": "1.11.0",
+            "version": "1.12.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
+                "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
-                "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
+                "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
                 "shasum": ""
             },
             "require": {
@@ -4544,11 +4546,12 @@
             },
             "conflict": {
                 "doctrine/collections": "<1.6.8",
-                "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+                "doctrine/common": "<2.13.3 || >=3 <3.2.2"
             },
             "require-dev": {
                 "doctrine/collections": "^1.6.8",
                 "doctrine/common": "^2.13.3 || ^3.2.2",
+                "phpspec/prophecy": "^1.10",
                 "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
             },
             "type": "library",
@@ -4574,7 +4577,7 @@
             ],
             "support": {
                 "issues": "https://github.com/myclabs/DeepCopy/issues",
-                "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
             },
             "funding": [
                 {
@@ -4582,26 +4585,26 @@
                     "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.x-dev",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ondrejmirtes/simple-downgrader.git",
-                "reference": "832aaae53dcfe358f63180494de8734244773d46"
+                "reference": "dbbf56fab0bc71310ff3766ea204d84f019e99b7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ondrejmirtes/simple-downgrader/zipball/832aaae53dcfe358f63180494de8734244773d46",
-                "reference": "832aaae53dcfe358f63180494de8734244773d46",
+                "url": "https://api.github.com/repos/ondrejmirtes/simple-downgrader/zipball/dbbf56fab0bc71310ff3766ea204d84f019e99b7",
+                "reference": "dbbf56fab0bc71310ff3766ea204d84f019e99b7",
                 "shasum": ""
             },
             "require": {
                 "nette/utils": "^3.2.5",
-                "nikic/php-parser": "^4.18",
-                "php": "^7.2|^8.0",
+                "nikic/php-parser": "^5.0",
+                "php": "^7.4|^8.0",
                 "phpstan/phpdoc-parser": "^1.24.5",
                 "symfony/console": "^5.4",
                 "symfony/finder": "^5.4"
@@ -4629,26 +4632,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.x"
             },
-            "time": "2024-02-12T19:22:32+00:00"
+            "time": "2024-02-12T19:24:54+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",
@@ -4689,9 +4693,15 @@
             "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
             "support": {
                 "issues": "https://github.com/phar-io/manifest/issues",
-                "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+                "source": "https://github.com/phar-io/manifest/tree/2.0.4"
             },
-            "time": "2021-07-20T11:28:43+00:00"
+            "funding": [
+                {
+                    "url": "https://github.com/theseer",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-03T12:33:53+00:00"
         },
         {
             "name": "phar-io/version",
@@ -5016,35 +5026,35 @@
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "9.2.30",
+            "version": "9.2.32",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
+                "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
-                "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
+                "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-libxml": "*",
                 "ext-xmlwriter": "*",
-                "nikic/php-parser": "^4.18 || ^5.0",
+                "nikic/php-parser": "^4.19.1 || ^5.1.0",
                 "php": ">=7.3",
-                "phpunit/php-file-iterator": "^3.0.3",
-                "phpunit/php-text-template": "^2.0.2",
-                "sebastian/code-unit-reverse-lookup": "^2.0.2",
-                "sebastian/complexity": "^2.0",
-                "sebastian/environment": "^5.1.2",
-                "sebastian/lines-of-code": "^1.0.3",
-                "sebastian/version": "^3.0.1",
-                "theseer/tokenizer": "^1.2.0"
+                "phpunit/php-file-iterator": "^3.0.6",
+                "phpunit/php-text-template": "^2.0.4",
+                "sebastian/code-unit-reverse-lookup": "^2.0.3",
+                "sebastian/complexity": "^2.0.3",
+                "sebastian/environment": "^5.1.5",
+                "sebastian/lines-of-code": "^1.0.4",
+                "sebastian/version": "^3.0.2",
+                "theseer/tokenizer": "^1.2.3"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^9.6"
             },
             "suggest": {
                 "ext-pcov": "PHP extension that provides line coverage",
@@ -5053,7 +5063,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.2-dev"
+                    "dev-main": "9.2.x-dev"
                 }
             },
             "autoload": {
@@ -5082,7 +5092,7 @@
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
             },
             "funding": [
                 {
@@ -5090,7 +5100,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T06:47:57+00:00"
+            "time": "2024-08-22T04:23:01+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -5335,50 +5345,50 @@
         },
         {
             "name": "phpunit/phpunit",
-            "version": "9.5.23",
+            "version": "9.6.20",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "888556852e7e9bbeeedb9656afe46118765ade34"
+                "reference": "49d7820565836236411f5dc002d16dd689cde42f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/888556852e7e9bbeeedb9656afe46118765ade34",
-                "reference": "888556852e7e9bbeeedb9656afe46118765ade34",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f",
+                "reference": "49d7820565836236411f5dc002d16dd689cde42f",
                 "shasum": ""
             },
             "require": {
-                "doctrine/instantiator": "^1.3.1",
+                "doctrine/instantiator": "^1.5.0 || ^2",
                 "ext-dom": "*",
                 "ext-json": "*",
                 "ext-libxml": "*",
                 "ext-mbstring": "*",
                 "ext-xml": "*",
                 "ext-xmlwriter": "*",
-                "myclabs/deep-copy": "^1.10.1",
-                "phar-io/manifest": "^2.0.3",
-                "phar-io/version": "^3.0.2",
+                "myclabs/deep-copy": "^1.12.0",
+                "phar-io/manifest": "^2.0.4",
+                "phar-io/version": "^3.2.1",
                 "php": ">=7.3",
-                "phpunit/php-code-coverage": "^9.2.13",
-                "phpunit/php-file-iterator": "^3.0.5",
+                "phpunit/php-code-coverage": "^9.2.31",
+                "phpunit/php-file-iterator": "^3.0.6",
                 "phpunit/php-invoker": "^3.1.1",
-                "phpunit/php-text-template": "^2.0.3",
-                "phpunit/php-timer": "^5.0.2",
-                "sebastian/cli-parser": "^1.0.1",
-                "sebastian/code-unit": "^1.0.6",
-                "sebastian/comparator": "^4.0.5",
-                "sebastian/diff": "^4.0.3",
-                "sebastian/environment": "^5.1.3",
-                "sebastian/exporter": "^4.0.3",
-                "sebastian/global-state": "^5.0.1",
-                "sebastian/object-enumerator": "^4.0.3",
-                "sebastian/resource-operations": "^3.0.3",
-                "sebastian/type": "^3.0",
+                "phpunit/php-text-template": "^2.0.4",
+                "phpunit/php-timer": "^5.0.3",
+                "sebastian/cli-parser": "^1.0.2",
+                "sebastian/code-unit": "^1.0.8",
+                "sebastian/comparator": "^4.0.8",
+                "sebastian/diff": "^4.0.6",
+                "sebastian/environment": "^5.1.5",
+                "sebastian/exporter": "^4.0.6",
+                "sebastian/global-state": "^5.0.7",
+                "sebastian/object-enumerator": "^4.0.4",
+                "sebastian/resource-operations": "^3.0.4",
+                "sebastian/type": "^3.2.1",
                 "sebastian/version": "^3.0.2"
             },
             "suggest": {
-                "ext-soap": "*",
-                "ext-xdebug": "*"
+                "ext-soap": "To be able to generate mocks based on WSDL files",
+                "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
             },
             "bin": [
                 "phpunit"
@@ -5386,7 +5396,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.5-dev"
+                    "dev-master": "9.6-dev"
                 }
             },
             "autoload": {
@@ -5417,7 +5427,8 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.23"
+                "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20"
             },
             "funding": [
                 {
@@ -5427,22 +5438,26 @@
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+                    "type": "tidelift"
                 }
             ],
-            "time": "2022-08-22T14:01:36+00:00"
+            "time": "2024-07-10T11:45:39+00:00"
         },
         {
             "name": "sebastian/cli-parser",
-            "version": "1.0.1",
+            "version": "1.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/cli-parser.git",
-                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
-                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
+                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
                 "shasum": ""
             },
             "require": {
@@ -5477,7 +5492,7 @@
             "homepage": "https://github.com/sebastianbergmann/cli-parser",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
-                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
             },
             "funding": [
                 {
@@ -5485,7 +5500,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T06:08:49+00:00"
+            "time": "2024-03-02T06:27:43+00:00"
         },
         {
             "name": "sebastian/code-unit",
@@ -5600,16 +5615,16 @@
         },
         {
             "name": "sebastian/comparator",
-            "version": "4.0.6",
+            "version": "4.0.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "55f4261989e546dc112258c7a75935a81a7ce382"
+                "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382",
-                "reference": "55f4261989e546dc112258c7a75935a81a7ce382",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
+                "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
                 "shasum": ""
             },
             "require": {
@@ -5662,7 +5677,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
-                "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6"
+                "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
             },
             "funding": [
                 {
@@ -5670,7 +5685,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T15:49:45+00:00"
+            "time": "2022-09-14T12:41:17+00:00"
         },
         {
             "name": "sebastian/complexity",
@@ -5731,16 +5746,16 @@
         },
         {
             "name": "sebastian/diff",
-            "version": "4.0.4",
+            "version": "4.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
-                "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
+                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
                 "shasum": ""
             },
             "require": {
@@ -5785,7 +5800,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/diff/issues",
-                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
             },
             "funding": [
                 {
@@ -5793,7 +5808,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:10:38+00:00"
+            "time": "2024-03-02T06:30:58+00:00"
         },
         {
             "name": "sebastian/environment",
@@ -5860,16 +5875,16 @@
         },
         {
             "name": "sebastian/exporter",
-            "version": "4.0.4",
+            "version": "4.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9"
+                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9",
-                "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
+                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
                 "shasum": ""
             },
             "require": {
@@ -5925,7 +5940,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
-                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
+                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
             },
             "funding": [
                 {
@@ -5933,20 +5948,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-11-11T14:18:36+00:00"
+            "time": "2024-03-02T06:33:00+00:00"
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.5",
+            "version": "5.0.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
+                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
-                "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
                 "shasum": ""
             },
             "require": {
@@ -5989,7 +6004,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
+                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
             },
             "funding": [
                 {
@@ -5997,7 +6012,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-02-14T08:28:10+00:00"
+            "time": "2024-03-02T06:35:11+00:00"
         },
         {
             "name": "sebastian/lines-of-code",
@@ -6170,16 +6185,16 @@
         },
         {
             "name": "sebastian/recursion-context",
-            "version": "4.0.4",
+            "version": "4.0.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172"
+                "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172",
-                "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
+                "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
                 "shasum": ""
             },
             "require": {
@@ -6218,10 +6233,10 @@
                 }
             ],
             "description": "Provides functionality to recursively process PHP variables",
-            "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+            "homepage": "https://github.com/sebastianbergmann/recursion-context",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
-                "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4"
+                "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
             },
             "funding": [
                 {
@@ -6229,20 +6244,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:17:30+00:00"
+            "time": "2023-02-03T06:07:39+00:00"
         },
         {
             "name": "sebastian/resource-operations",
-            "version": "3.0.3",
+            "version": "3.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/resource-operations.git",
-                "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
+                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
-                "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
+                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
                 "shasum": ""
             },
             "require": {
@@ -6254,7 +6269,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
@@ -6275,8 +6290,7 @@
             "description": "Provides a list of PHP built-in functions that operate on resources",
             "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
             "support": {
-                "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
-                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
+                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
             },
             "funding": [
                 {
@@ -6284,20 +6298,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T06:45:17+00:00"
+            "time": "2024-03-14T16:00:52+00:00"
         },
         {
             "name": "sebastian/type",
-            "version": "3.0.0",
+            "version": "3.2.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/type.git",
-                "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad"
+                "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
-                "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
+                "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
                 "shasum": ""
             },
             "require": {
@@ -6309,7 +6323,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "3.2-dev"
                 }
             },
             "autoload": {
@@ -6332,7 +6346,7 @@
             "homepage": "https://github.com/sebastianbergmann/type",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/type/issues",
-                "source": "https://github.com/sebastianbergmann/type/tree/3.0.0"
+                "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
             },
             "funding": [
                 {
@@ -6340,7 +6354,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-03-15T09:54:48+00:00"
+            "time": "2023-02-03T06:13:03+00:00"
         },
         {
             "name": "sebastian/version",
@@ -6521,16 +6535,16 @@
         },
         {
             "name": "theseer/tokenizer",
-            "version": "1.2.1",
+            "version": "1.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/theseer/tokenizer.git",
-                "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
+                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
-                "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
+                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
                 "shasum": ""
             },
             "require": {
@@ -6559,7 +6573,7 @@
             "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
             "support": {
                 "issues": "https://github.com/theseer/tokenizer/issues",
-                "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
+                "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
             },
             "funding": [
                 {
@@ -6567,7 +6581,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..12694539ae 100644
--- a/conf/bleedingEdge.neon
+++ b/conf/bleedingEdge.neon
@@ -39,7 +39,6 @@ parameters:
 		newRuleLevelHelper: true
 		instanceofType: true
 		paramOutVariance: true
-		allInvalidPhpDocs: true
 		strictStaticMethodTemplateTypeVariance: true
 		propertyVariance: true
 		genericPrototypeMessage: true
diff --git a/conf/config.level2.neon b/conf/config.level2.neon
index 1399394032..d7a7cc943b 100644
--- a/conf/config.level2.neon
+++ b/conf/config.level2.neon
@@ -146,7 +146,6 @@ services:
 	-
 		class: PHPStan\Rules\PhpDoc\InvalidPhpDocTagValueRule
 		arguments:
-			checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs%
 			invalidPhpDocTagLine: %featureToggles.invalidPhpDocTagLine%
 		tags:
 			- phpstan.rules.rule
@@ -159,8 +158,6 @@ services:
 			- phpstan.rules.rule
 	-
 		class: PHPStan\Rules\PhpDoc\InvalidPHPStanDocTagRule
-		arguments:
-			checkAllInvalidPhpDocs: %featureToggles.allInvalidPhpDocs%
 		tags:
 			- phpstan.rules.rule
 	-
diff --git a/conf/config.level3.neon b/conf/config.level3.neon
index 5540500714..f205db23b6 100644
--- a/conf/config.level3.neon
+++ b/conf/config.level3.neon
@@ -30,7 +30,6 @@ rules:
 	- PHPStan\Rules\Properties\ReadOnlyPropertyAssignRule
 	- PHPStan\Rules\Properties\ReadOnlyPropertyAssignRefRule
 	- PHPStan\Rules\Properties\TypesAssignedToPropertiesRule
-	- PHPStan\Rules\Variables\ThrowTypeRule
 	- PHPStan\Rules\Variables\VariableCloningRule
 
 parameters:
diff --git a/conf/config.level4.neon b/conf/config.level4.neon
index 8f3ecc86bc..421cafcd9e 100644
--- a/conf/config.level4.neon
+++ b/conf/config.level4.neon
@@ -96,13 +96,6 @@ services:
 		tags:
 			- phpstan.rules.rule
 
-	-
-		class: PHPStan\Rules\DeadCode\NoopRule
-		arguments:
-			better: %featureToggles.betterNoop%
-		tags:
-			- phpstan.rules.rule
-
 	-
 		class: PHPStan\Rules\DeadCode\CallToConstructorStatementWithoutImpurePointsRule
 
diff --git a/conf/config.level5.neon b/conf/config.level5.neon
index 184cee83b8..470689b7c2 100644
--- a/conf/config.level5.neon
+++ b/conf/config.level5.neon
@@ -42,12 +42,6 @@ services:
 
 	-
 		class: PHPStan\Rules\Functions\CallUserFuncRule
-	-
-		class: PHPStan\Rules\Functions\ImplodeFunctionRule
-		arguments:
-			disabled: %featureToggles.checkParameterCastableToStringFunctions%
-		tags:
-			- phpstan.rules.rule
 	-
 		class: PHPStan\Rules\Functions\ParameterCastableToStringRule
 	-
diff --git a/conf/config.neon b/conf/config.neon
index 255be78dc2..ae411edcca 100644
--- a/conf/config.neon
+++ b/conf/config.neon
@@ -74,7 +74,7 @@ parameters:
 		newRuleLevelHelper: false
 		instanceofType: false
 		paramOutVariance: false
-		allInvalidPhpDocs: false
+
 		strictStaticMethodTemplateTypeVariance: false
 		propertyVariance: false
 		genericPrototypeMessage: false
@@ -372,6 +372,11 @@ services:
 		tags:
 			- phpstan.parser.richParserNodeVisitor
 
+	-
+		class: PHPStan\Parser\StandaloneThrowExprVisitor
+		tags:
+			- phpstan.parser.richParserNodeVisitor
+
 	-
 		class: PHPStan\Parser\TryCatchTypeVisitor
 		tags:
@@ -2010,7 +2015,6 @@ services:
 		class: PHPStan\Parser\RichParser
 		arguments:
 			parser: @currentPhpVersionPhpParser
-			lexer: @currentPhpVersionLexer
 			enableIgnoreErrorsWithinPhpDocs: %featureToggles.enableIgnoreErrorsWithinPhpDocs%
 		autowired: no
 
@@ -2045,7 +2049,11 @@ services:
 		autowired: false
 
 	currentPhpVersionPhpParser:
-		class: PhpParser\Parser\Php7
+		factory: @currentPhpVersionPhpParserFactory::create()
+		autowired: false
+
+	currentPhpVersionPhpParserFactory:
+		class: PHPStan\Parser\PhpParserFactory
 		arguments:
 			lexer: @currentPhpVersionLexer
 		autowired: false
@@ -2161,7 +2169,7 @@ services:
 		autowired: false
 
 	php8PhpParser:
-		class: PhpParser\Parser\Php7
+		class: PhpParser\Parser\Php8
 		arguments:
 			lexer: @php8Lexer
 		autowired: false
diff --git a/conf/config.stubValidator.neon b/conf/config.stubValidator.neon
index 1645698a92..ae22e5ccdc 100644
--- a/conf/config.stubValidator.neon
+++ b/conf/config.stubValidator.neon
@@ -13,7 +13,7 @@ services:
 		arguments:
 			php8Parser: @php8PhpParser
 
-	nodeScopeResolverClassReflector:
+	nodeScopeResolverReflector:
 		factory: @stubReflector
 
 	stubBetterReflectionProvider:
@@ -38,3 +38,11 @@ services:
 		factory: @stubBetterReflectionProvider
 		autowired:
 			- PHPStan\Reflection\ReflectionProvider
+
+	currentPhpVersionLexer:
+		factory: @php8Lexer
+		autowired: false
+
+	currentPhpVersionPhpParser:
+		factory: @php8PhpParser
+		autowired: false
diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon
index 05d6d79f0c..8b986b0442 100644
--- a/conf/parametersSchema.neon
+++ b/conf/parametersSchema.neon
@@ -69,7 +69,6 @@ parametersSchema:
 		newRuleLevelHelper: bool()
 		instanceofType: bool()
 		paramOutVariance: bool()
-		allInvalidPhpDocs: bool()
 		strictStaticMethodTemplateTypeVariance: bool()
 		propertyVariance: bool()
 		genericPrototypeMessage: bool()
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 77ff81fd1a..7bbba41b08 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -1801,35 +1801,19 @@ parameters:
 
 		-
 			message: """
-				#^Instantiation of deprecated class PHPStan\\\\Rules\\\\DeadCode\\\\NoopRule\\:
-				Replaced by PHPStan\\\\Rules\\\\DeadCode\\\\BetterNoopRule$#
+				#^Instantiation of deprecated class PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRule\\:
+				Since PHP\\-Parser 5\\.0 this is a parse error\\.$#
 			"""
 			count: 1
-			path: tests/PHPStan/Rules/DeadCode/NoopRuleTest.php
+			path: tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.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$#
+				#^Return type of method PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRuleTest\\:\\:getRule\\(\\) has typehint with deprecated class PHPStan\\\\Rules\\\\Arrays\\\\EmptyArrayItemRule\\:
+				Since PHP\\-Parser 5\\.0 this is a parse error\\.$#
 			"""
 			count: 1
-			path: tests/PHPStan/Rules/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
+			path: tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php
 
 		-
 			message: "#^PHPDoc tag @var assumes the expression with type PHPStan\\\\Type\\\\Generic\\\\TemplateType is always PHPStan\\\\Type\\\\Generic\\\\TemplateMixedType but it's error\\-prone and dangerous\\.$#"
diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php
index cb4dd6b858..b6a38997a8 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;
@@ -1125,20 +1123,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;
 				}
 
@@ -1149,7 +1147,7 @@ private function resolveType(string $exprString, Expr $node): Type
 			}
 
 			return $resultType ?? new ConstantStringType('');
-		} elseif ($node instanceof DNumber) {
+		} elseif ($node instanceof Node\Scalar\Float_) {
 			return $this->initializerExprTypeResolver->getType($node, InitializerExprContext::fromScope($this));
 		} elseif ($node instanceof Expr\CallLike && $node->isFirstClassCallable()) {
 			if ($node instanceof FuncCall) {
@@ -1707,10 +1705,10 @@ static function (Node $node, Scope $scope) use ($arrowScope, &$arrowFunctionImpu
 			}
 
 			if ($node instanceof Expr\PreInc) {
-				return $this->getType(new BinaryOp\Plus($node->var, new LNumber(1)));
+				return $this->getType(new BinaryOp\Plus($node->var, new Node\Scalar\Int_(1)));
 			}
 
-			return $this->getType(new BinaryOp\Minus($node->var, new LNumber(1)));
+			return $this->getType(new BinaryOp\Minus($node->var, new Node\Scalar\Int_(1)));
 		} elseif ($node instanceof Expr\Yield_) {
 			$functionReflection = $this->getFunction();
 			if ($functionReflection === null) {
@@ -1837,7 +1835,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'),
@@ -3455,9 +3453,6 @@ private function enterAnonymousFunctionWithoutReflection(
 				continue;
 			}
 			foreach ($variables as $variable) {
-				if (!$variable instanceof Variable) {
-					continue 2;
-				}
 				if (!is_string($variable->name)) {
 					continue 2;
 				}
@@ -4785,7 +4780,7 @@ private function processFinallyScopeVariableTypeHolders(
 	}
 
 	/**
-	 * @param Expr\ClosureUse[] $byRefUses
+	 * @param Node\ClosureUse[] $byRefUses
 	 */
 	public function processClosureScope(
 		self $closureScope,
diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php
index b22d651f99..8a992f5c13 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_;
@@ -445,7 +444,6 @@ private function processStmtNode(
 			&& !$stmt instanceof Foreach_
 			&& !$stmt instanceof Node\Stmt\Global_
 			&& !$stmt instanceof Node\Stmt\Property
-			&& !$stmt instanceof Node\Stmt\PropertyProperty
 			&& !$stmt instanceof Node\Stmt\ClassConst
 			&& !$stmt instanceof Node\Stmt\Const_
 		) {
@@ -474,7 +472,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);
 		}
 
@@ -493,7 +494,7 @@ private function processStmtNode(
 				$nodeCallback($declare->value, $scope);
 				if (
 					$declare->key->name !== 'strict_types'
-					|| !($declare->value instanceof Node\Scalar\LNumber)
+					|| !($declare->value instanceof Node\Scalar\Int_)
 					|| $declare->value->value !== 1
 				) {
 					continue;
@@ -790,6 +791,9 @@ private function processStmtNode(
 				new StatementExitPoint($stmt, $scope),
 			], $overridingThrowPoints ?? $throwPoints, $impurePoints);
 		} elseif ($stmt instanceof Node\Stmt\Expression) {
+			if ($stmt->expr instanceof Expr\Throw_) {
+				$scope = $stmtScope;
+			}
 			$earlyTerminationExpr = $this->findEarlyTerminatingExpr($stmt->expr, $scope);
 			$hasAssign = false;
 			$currentScope = $scope;
@@ -922,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();
@@ -1506,7 +1502,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) {
@@ -1560,8 +1556,7 @@ private function processStmtNode(
 							}
 							$throwNode = $throwPoint->getNode();
 							if (
-								!$throwNode instanceof Throw_
-								&& !$throwNode instanceof Expr\Throw_
+								!$throwNode instanceof Expr\Throw_
 								&& !($throwNode instanceof Node\Stmt\Expression && $throwNode->expr instanceof Expr\Throw_)
 							) {
 								$onlyExplicitIsThrow = false;
@@ -1668,7 +1663,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) {
@@ -1696,7 +1691,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();
@@ -1862,9 +1857,6 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
 				if ($const->namespacedName !== null) {
 					$constantName = new Name\FullyQualified($const->namespacedName->toString());
 				} else {
-					if ($const->name->toString() === '') {
-						throw new ShouldNotHappenException('Constant cannot have a empty name');
-					}
 					$constantName = new Name\FullyQualified($const->name->toString());
 				}
 				$scope = $scope->assignExpression(new ConstFetch($constantName), $scope->getType($const->value), $scope->getNativeType($const->value));
@@ -1902,6 +1894,8 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
 			$impurePoints = [
 				new ImpurePoint($scope, $stmt, 'betweenPhpTags', 'output between PHP opening and closing tags', true),
 			];
+		} elseif ($stmt instanceof Node\Stmt\Block) {
+			return $this->processStmtNodes($stmt, $stmt->stmts, $scope, $nodeCallback, $context);
 		} elseif ($stmt instanceof Node\Stmt\Nop) {
 			$hasYield = false;
 			$throwPoints = $overridingThrowPoints ?? [];
@@ -2037,7 +2031,7 @@ private function lookForExpressionCallback(MutatingScope $scope, Expr $expr, Clo
 			$scope = $this->lookForExpressionCallback($scope, $expr->var, $callback);
 		} elseif ($expr instanceof StaticPropertyFetch && $expr->class instanceof Expr) {
 			$scope = $this->lookForExpressionCallback($scope, $expr->class, $callback);
-		} elseif ($expr instanceof Array_ || $expr instanceof List_) {
+		} elseif ($expr instanceof List_) {
 			foreach ($expr->items as $item) {
 				if ($item === null) {
 					continue;
@@ -2942,11 +2936,14 @@ static function (): void {
 				$impurePoints = array_merge($impurePoints, $result->getImpurePoints());
 				$scope = $result->getScope();
 			}
-		} elseif ($expr instanceof Node\Scalar\Encapsed) {
+		} elseif ($expr instanceof Node\Scalar\InterpolatedString) {
 			$hasYield = false;
 			$throwPoints = [];
 			$impurePoints = [];
 			foreach ($expr->parts as $part) {
+				if (!$part instanceof Expr) {
+					continue;
+				}
 				$result = $this->processExprNode($stmt, $part, $scope, $nodeCallback, $context->enterDeep());
 				$hasYield = $hasYield || $result->hasYield();
 				$throwPoints = array_merge($throwPoints, $result->getThrowPoints());
@@ -2977,9 +2974,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());
@@ -3630,7 +3624,7 @@ static function (Node $node, Scope $scope) use ($nodeCallback): void {
 				} else {
 					$items = [];
 					foreach ($filteringExprs as $filteringExpr) {
-						$items[] = new ArrayItem($filteringExpr);
+						$items[] = new Node\ArrayItem($filteringExpr);
 					}
 					$filteringExpr = new FuncCall(
 						new Name\FullyQualified('in_array'),
@@ -4113,7 +4107,7 @@ private function getAssignedVariables(Expr $expr): array
 			return [];
 		}
 
-		if ($expr instanceof Expr\List_ || $expr instanceof Expr\Array_) {
+		if ($expr instanceof Expr\List_) {
 			$names = [];
 			foreach ($expr->items as $item) {
 				if ($item === null) {
@@ -5271,7 +5265,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());
@@ -5302,7 +5296,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;
 				}
@@ -5778,7 +5772,7 @@ private function processNodesForTraitUse($node, ClassReflection $traitReflection
 					$methodAst = clone $stmt;
 					$stmts[$i] = $methodAst;
 					if (array_key_exists($methodName, $methodModifiers)) {
-						$methodAst->flags = ($methodAst->flags & ~ Node\Stmt\Class_::VISIBILITY_MODIFIER_MASK) | $methodModifiers[$methodName];
+						$methodAst->flags = ($methodAst->flags & ~ Modifiers::VISIBILITY_MASK) | $methodModifiers[$methodName];
 					}
 
 					if (!array_key_exists($methodName, $methodNames)) {
@@ -5867,9 +5861,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/StatementResult.php b/src/Analyser/StatementResult.php
index bb9ae78f2e..985777317e 100644
--- a/src/Analyser/StatementResult.php
+++ b/src/Analyser/StatementResult.php
@@ -2,7 +2,7 @@
 
 namespace PHPStan\Analyser;
 
-use PhpParser\Node\Scalar\LNumber;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Stmt;
 
 /**
@@ -58,7 +58,7 @@ public function filterOutLoopExitPoints(): self
 			}
 
 			$num = $statement->num;
-			if (!$num instanceof LNumber) {
+			if (!$num instanceof Int_) {
 				return new self($this->scope, $this->hasYield, false, $this->exitPoints, $this->throwPoints, $this->impurePoints);
 			}
 
@@ -99,7 +99,7 @@ public function getExitPointsByType(string $stmtClass): array
 				continue;
 			}
 
-			if (!$value instanceof LNumber) {
+			if (!$value instanceof Int_) {
 				$exitPoints[] = $exitPoint;
 				continue;
 			}
@@ -130,7 +130,7 @@ public function getExitPointsForOuterLoop(): array
 			if ($statement->num === null) {
 				continue;
 			}
-			if (!$statement->num instanceof LNumber) {
+			if (!$statement->num instanceof Int_) {
 				continue;
 			}
 			$value = $statement->num->value;
@@ -140,7 +140,7 @@ public function getExitPointsForOuterLoop(): array
 
 			$newNode = null;
 			if ($value > 2) {
-				$newNode = new LNumber($value - 1);
+				$newNode = new Int_($value - 1);
 			}
 			if ($statement instanceof Stmt\Continue_) {
 				$newStatement = new Stmt\Continue_($newNode);
diff --git a/src/Dependency/DependencyResolver.php b/src/Dependency/DependencyResolver.php
index 57a80a5a2e..2c7d3f581a 100644
--- a/src/Dependency/DependencyResolver.php
+++ b/src/Dependency/DependencyResolver.php
@@ -479,10 +479,6 @@ private function considerArrayForCallableTest(Scope $scope, Array_ $arrayNode):
 			return false;
 		}
 
-		if ($items[0] === null) {
-			return false;
-		}
-
 		$itemType = $scope->getType($items[0]->value);
 		return $itemType->isClassStringType()->yes();
 	}
diff --git a/src/Dependency/ExportedNodeResolver.php b/src/Dependency/ExportedNodeResolver.php
index c9a0c52154..36a752735d 100644
--- a/src/Dependency/ExportedNodeResolver.php
+++ b/src/Dependency/ExportedNodeResolver.php
@@ -336,7 +336,7 @@ private function exportClassStatement(Node\Stmt $node, string $fileName, string
 			$docComment = $node->getDocComment();
 
 			return new ExportedPropertiesNode(
-				array_map(static fn (Node\Stmt\PropertyProperty $prop): string => $prop->name->toString(), $node->props),
+				array_map(static fn (Node\PropertyItem $prop): string => $prop->name->toString(), $node->props),
 				$this->exportPhpDocNode(
 					$fileName,
 					$namespacedName,
diff --git a/src/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/Node/ClassPropertiesNode.php b/src/Node/ClassPropertiesNode.php
index 7afc4bc874..0707a5bc6d 100644
--- a/src/Node/ClassPropertiesNode.php
+++ b/src/Node/ClassPropertiesNode.php
@@ -271,9 +271,6 @@ private function collectUninitializedProperties(array $constructors, array $unin
 				$statementResult = $executionEnd->getStatementResult();
 				$endNode = $executionEnd->getNode();
 				if ($statementResult->isAlwaysTerminating()) {
-					if ($endNode instanceof Node\Stmt\Throw_) {
-						continue;
-					}
 					if ($endNode instanceof Node\Stmt\Expression) {
 						$exprType = $statementResult->getScope()->getType($endNode->expr);
 						if ($exprType instanceof NeverType && $exprType->isExplicit()) {
diff --git a/src/Node/ClassPropertyNode.php b/src/Node/ClassPropertyNode.php
index d8aaea6218..f0ad86ff8c 100644
--- a/src/Node/ClassPropertyNode.php
+++ b/src/Node/ClassPropertyNode.php
@@ -2,11 +2,11 @@
 
 namespace PHPStan\Node;
 
+use PhpParser\Modifiers;
 use PhpParser\Node;
 use PhpParser\Node\Expr;
 use PhpParser\Node\Identifier;
 use PhpParser\Node\Name;
-use PhpParser\Node\Stmt\Class_;
 use PhpParser\NodeAbstract;
 use PHPStan\Reflection\ClassReflection;
 use PHPStan\Type\Type;
@@ -75,28 +75,28 @@ public function getPhpDocType(): ?Type
 
 	public function isPublic(): bool
 	{
-		return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0
-			|| ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0;
+		return ($this->flags & Modifiers::PUBLIC) !== 0
+			|| ($this->flags & Modifiers::VISIBILITY_MASK) === 0;
 	}
 
 	public function isProtected(): bool
 	{
-		return (bool) ($this->flags & Class_::MODIFIER_PROTECTED);
+		return (bool) ($this->flags & Modifiers::PROTECTED);
 	}
 
 	public function isPrivate(): bool
 	{
-		return (bool) ($this->flags & Class_::MODIFIER_PRIVATE);
+		return (bool) ($this->flags & Modifiers::PRIVATE);
 	}
 
 	public function isStatic(): bool
 	{
-		return (bool) ($this->flags & Class_::MODIFIER_STATIC);
+		return (bool) ($this->flags & Modifiers::STATIC);
 	}
 
 	public function isReadOnly(): bool
 	{
-		return (bool) ($this->flags & Class_::MODIFIER_READONLY) || $this->isReadonlyClass;
+		return (bool) ($this->flags & Modifiers::READONLY) || $this->isReadonlyClass;
 	}
 
 	public function isReadOnlyByPhpDoc(): bool
diff --git a/src/Node/ClassStatementsGatherer.php b/src/Node/ClassStatementsGatherer.php
index 55ef907799..7fb27f8351 100644
--- a/src/Node/ClassStatementsGatherer.php
+++ b/src/Node/ClassStatementsGatherer.php
@@ -221,9 +221,6 @@ private function gatherNodes(Node $node, Scope $scope): void
 			$this->propertyUsages[] = new PropertyWrite($node->expr, $scope, false);
 			return;
 		}
-		if ($node instanceof Node\Scalar\EncapsedStringPart) {
-			return;
-		}
 		if ($node instanceof FunctionCallableNode) {
 			$node = $node->getOriginalNode();
 		} elseif ($node instanceof InstantiationCallableNode) {
diff --git a/src/Node/LiteralArrayItem.php b/src/Node/LiteralArrayItem.php
index ea9be27be6..1ba0c04ef5 100644
--- a/src/Node/LiteralArrayItem.php
+++ b/src/Node/LiteralArrayItem.php
@@ -2,7 +2,7 @@
 
 namespace PHPStan\Node;
 
-use PhpParser\Node\Expr\ArrayItem;
+use PhpParser\Node\ArrayItem;
 use PHPStan\Analyser\Scope;
 
 /**
diff --git a/src/Parser/LastConditionVisitor.php b/src/Parser/LastConditionVisitor.php
index ce21f571fd..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 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Parser;
+
+use PhpParser\Lexer;
+use PhpParser\Parser\Php7;
+use PhpParser\Parser\Php8;
+use PhpParser\ParserAbstract;
+use PHPStan\Php\PhpVersion;
+
+final class PhpParserFactory
+{
+
+	public function __construct(private Lexer $lexer, private PhpVersion $phpVersion)
+	{
+	}
+
+	public function create(): ParserAbstract
+	{
+		$phpVersion = \PhpParser\PhpVersion::fromString($this->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 b5863a4b80..14ade510c3 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,7 +41,6 @@ final class RichParser implements Parser
 
 	public function __construct(
 		private \PhpParser\Parser $parser,
-		private Lexer $lexer,
 		private NameResolver $nameResolver,
 		private Container $container,
 		private IgnoreLexer $ignoreLexer,
@@ -72,8 +70,7 @@ public function parseString(string $sourceCode): array
 		$errorHandler = new Collecting();
 		$nodes = $this->parser->parse($sourceCode, $errorHandler);
 
-		/** @var list<string|array{0:int,1:string,2:int}> $tokens */
-		$tokens = $this->lexer->getTokens();
+		$tokens = $this->parser->getTokens();
 		if ($errorHandler->hasErrors()) {
 			throw new ParserErrorsException($errorHandler->getErrors(), null);
 		}
@@ -109,7 +106,7 @@ public function parseString(string $sourceCode): array
 	}
 
 	/**
-	 * @param list<string|array{0:int,1:string,2:int}> $tokens
+	 * @param Token[] $tokens
 	 * @return array{lines: array<int, non-empty-list<string>|null>, errors: array<int, non-empty-list<string>>}
 	 */
 	private function getLinesToIgnore(array $tokens): array
@@ -119,12 +116,8 @@ private function getLinesToIgnore(array $tokens): array
 		$pendingToken = null;
 		$errors = [];
 		foreach ($tokens as $token) {
-			if (is_string($token)) {
-				continue;
-			}
-
-			$type = $token[0];
-			$line = $token[2];
+			$type = $token->id;
+			$line = $token->line;
 			if ($type !== T_COMMENT && $type !== T_DOC_COMMENT) {
 				if ($type !== T_WHITESPACE) {
 					if ($pendingToken !== null) {
@@ -155,7 +148,7 @@ private function getLinesToIgnore(array $tokens): array
 				continue;
 			}
 
-			$text = $token[1];
+			$text = $token->text;
 			$isNextLine = str_contains($text, '@phpstan-ignore-next-line');
 			$isCurrentLine = str_contains($text, '@phpstan-ignore-line');
 
@@ -190,7 +183,7 @@ private function getLinesToIgnore(array $tokens): array
 					$line++;
 				}
 				if ($isNextLine || $isCurrentLine) {
-					$line += substr_count($token[1], "\n");
+					$line += substr_count($token->text, "\n");
 
 					$lines[$line] = null;
 					continue;
@@ -204,20 +197,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) {
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 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Parser;
+
+use PhpParser\Node;
+use PhpParser\NodeVisitorAbstract;
+
+final class StandaloneThrowExprVisitor extends NodeVisitorAbstract
+{
+
+	public const ATTRIBUTE_NAME = 'standaloneThrowExpr';
+
+	public function enterNode(Node $node): ?Node\Stmt\Expression
+	{
+		if (!$node instanceof Node\Stmt\Expression) {
+			return null;
+		}
+
+		if (!$node->expr instanceof Node\Expr\Throw_) {
+			return null;
+		}
+
+		$node->expr->setAttribute(self::ATTRIBUTE_NAME, true);
+
+		return $node;
+	}
+
+}
diff --git a/src/PhpDoc/StubValidator.php b/src/PhpDoc/StubValidator.php
index 43ecfdd0a5..7260542411 100644
--- a/src/PhpDoc/StubValidator.php
+++ b/src/PhpDoc/StubValidator.php
@@ -217,12 +217,15 @@ private function getRuleRegistry(Container $container): RuleRegistry
 			new InvalidPhpDocTagValueRule(
 				$container->getByType(Lexer::class),
 				$container->getByType(PhpDocParser::class),
-				$container->getParameter('featureToggles')['allInvalidPhpDocs'],
 				$container->getParameter('featureToggles')['invalidPhpDocTagLine'],
 			),
 			new IncompatibleParamImmediatelyInvokedCallableRule($fileTypeMapper),
 			new IncompatibleSelfOutTypeRule($unresolvableTypeHelper, $genericObjectTypeCheck),
 			new IncompatibleClassConstantPhpDocTypeRule($genericObjectTypeCheck, $unresolvableTypeHelper),
+			new InvalidPHPStanDocTagRule(
+				$container->getByType(Lexer::class),
+				$container->getByType(PhpDocParser::class),
+			),
 			new InvalidThrowsPhpDocValueRule($fileTypeMapper),
 
 			// level 6
@@ -240,14 +243,6 @@ private function getRuleRegistry(Container $container): RuleRegistry
 			$rules[] = new DuplicateFunctionDeclarationRule($reflector, $relativePathHelper);
 		}
 
-		if ((bool) $container->getParameter('featureToggles')['allInvalidPhpDocs']) {
-			$rules[] = new InvalidPHPStanDocTagRule(
-				$container->getByType(Lexer::class),
-				$container->getByType(PhpDocParser::class),
-				true,
-			);
-		}
-
 		if ((bool) $container->getParameter('featureToggles')['absentTypeChecks']) {
 			$rules[] = new MissingMethodSelfOutTypeRule($missingTypehintCheck);
 
diff --git a/src/Reflection/BetterReflection/BetterReflectionProvider.php b/src/Reflection/BetterReflection/BetterReflectionProvider.php
index 6ae28ec9c6..54b26ec9f8 100644
--- a/src/Reflection/BetterReflection/BetterReflectionProvider.php
+++ b/src/Reflection/BetterReflection/BetterReflectionProvider.php
@@ -204,6 +204,7 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $
 			$scopeFile,
 		);
 		$classNode->name = new Node\Identifier($className);
+		$classNode->namespacedName = null;
 
 		if (isset(self::$anonymousClasses[$className])) {
 			return self::$anonymousClasses[$className];
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/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php
index dae4e11140..174adae5c1 100644
--- a/src/Reflection/InitializerExprTypeResolver.php
+++ b/src/Reflection/InitializerExprTypeResolver.php
@@ -11,8 +11,8 @@
 use PhpParser\Node\Expr\PropertyFetch;
 use PhpParser\Node\Identifier;
 use PhpParser\Node\Name;
-use PhpParser\Node\Scalar\DNumber;
-use PhpParser\Node\Scalar\LNumber;
+use PhpParser\Node\Scalar\Float_;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Scalar\MagicConst;
 use PhpParser\Node\Scalar\MagicConst\Dir;
 use PhpParser\Node\Scalar\MagicConst\File;
@@ -113,10 +113,10 @@ public function getType(Expr $expr, InitializerExprContext $context): Type
 		if ($expr instanceof TypeExpr) {
 			return $expr->getExprType();
 		}
-		if ($expr instanceof LNumber) {
+		if ($expr instanceof Int_) {
 			return new ConstantIntegerType($expr->value);
 		}
-		if ($expr instanceof DNumber) {
+		if ($expr instanceof Float_) {
 			return new ConstantFloatType($expr->value);
 		}
 		if ($expr instanceof String_) {
@@ -525,10 +525,6 @@ public function getArrayType(Expr\Array_ $expr, callable $getTypeCallback): Type
 		$arrayBuilder = ConstantArrayTypeBuilder::createEmpty();
 		$isList = null;
 		foreach ($expr->items as $arrayItem) {
-			if ($arrayItem === null) {
-				continue;
-			}
-
 			$valueType = $getTypeCallback($arrayItem->value);
 			if ($arrayItem->unpack) {
 				$constantArrays = $valueType->getConstantArrays();
@@ -2048,7 +2044,7 @@ public function getUnaryMinusType(Expr $expr, callable $getTypeCallback): Type
 		}
 
 		if ($type instanceof IntegerRangeType) {
-			return $getTypeCallback(new Expr\BinaryOp\Mul($expr, new LNumber(-1)));
+			return $getTypeCallback(new Expr\BinaryOp\Mul($expr, new Int_(-1)));
 		}
 
 		return $type;
diff --git a/src/Rules/Arrays/ArrayDestructuringRule.php b/src/Rules/Arrays/ArrayDestructuringRule.php
index 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<IdentifierRuleError>
 	 */
-	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
index 0bfcebf956..dfe2a48d4b 100644
--- a/src/Rules/Arrays/EmptyArrayItemRule.php
+++ b/src/Rules/Arrays/EmptyArrayItemRule.php
@@ -9,6 +9,7 @@
 use PHPStan\Rules\RuleErrorBuilder;
 
 /**
+ * @deprecated Since PHP-Parser 5.0 this is a parse error.
  * @implements Rule<LiteralArrayNode>
  */
 final class EmptyArrayItemRule implements Rule
diff --git a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php
index 5b5f3545a9..fb4ab23162 100644
--- a/src/Rules/Arrays/InvalidKeyInArrayItemRule.php
+++ b/src/Rules/Arrays/InvalidKeyInArrayItemRule.php
@@ -11,7 +11,7 @@
 use function sprintf;
 
 /**
- * @implements Rule<Node\Expr\ArrayItem>
+ * @implements Rule<Node\ArrayItem>
  */
 final class InvalidKeyInArrayItemRule implements Rule
 {
@@ -22,7 +22,7 @@ public function __construct(private bool $reportMaybes)
 
 	public function getNodeType(): string
 	{
-		return Node\Expr\ArrayItem::class;
+		return Node\ArrayItem::class;
 	}
 
 	public function processNode(Node $node, Scope $scope): array
diff --git a/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php b/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php
index 5cf96d8ad2..a2c04dc054 100644
--- a/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php
+++ b/src/Rules/Cast/InvalidPartOfEncapsedStringRule.php
@@ -14,7 +14,7 @@
 use function sprintf;
 
 /**
- * @implements Rule<Node\Scalar\Encapsed>
+ * @implements Rule<Node\Scalar\InterpolatedString>
  */
 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/EnumSanityRule.php b/src/Rules/Classes/EnumSanityRule.php
index 2d193095d4..51c07fdfd8 100644
--- a/src/Rules/Classes/EnumSanityRule.php
+++ b/src/Rules/Classes/EnumSanityRule.php
@@ -143,7 +143,7 @@ public function processNode(Node $node, Scope $scope): array
 			}
 			$caseName = $stmt->name->name;
 
-			if ($stmt->expr instanceof Node\Scalar\LNumber || $stmt->expr instanceof Node\Scalar\String_) {
+			if ($stmt->expr instanceof Node\Scalar\Int_ || $stmt->expr instanceof Node\Scalar\String_) {
 				if ($enumNode->scalarType === null) {
 					$errors[] = RuleErrorBuilder::message(sprintf(
 						'Enum %s is not backed, but case %s has value %s.',
diff --git a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php
index 3777b5d6e5..4b43745923 100644
--- a/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php
+++ b/src/Rules/Comparison/DoWhileLoopConstantConditionRule.php
@@ -3,7 +3,7 @@
 namespace PHPStan\Rules\Comparison;
 
 use PhpParser\Node;
-use PhpParser\Node\Scalar\LNumber;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Stmt\Break_;
 use PhpParser\Node\Stmt\Continue_;
 use PHPStan\Analyser\Scope;
@@ -47,7 +47,7 @@ public function processNode(Node $node, Scope $scope): array
 					if ($statement->num === null) {
 						continue;
 					}
-					if (!$statement->num instanceof LNumber) {
+					if (!$statement->num instanceof Int_) {
 						continue;
 					}
 					$value = $statement->num->value;
diff --git a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php
index 68ac27fbf2..505c57d7c6 100644
--- a/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php
+++ b/src/Rules/Comparison/WhileLoopAlwaysTrueConditionRule.php
@@ -3,7 +3,7 @@
 namespace PHPStan\Rules\Comparison;
 
 use PhpParser\Node;
-use PhpParser\Node\Scalar\LNumber;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Stmt\Break_;
 use PhpParser\Node\Stmt\Continue_;
 use PHPStan\Analyser\Scope;
@@ -46,7 +46,7 @@ public function processNode(
 			if ($statement->num === null) {
 				continue;
 			}
-			if (!$statement->num instanceof LNumber) {
+			if (!$statement->num instanceof Int_) {
 				continue;
 			}
 			$value = $statement->num->value;
diff --git a/src/Rules/DeadCode/NoopRule.php b/src/Rules/DeadCode/NoopRule.php
deleted file mode 100644
index ff0d6eb8e7..0000000000
--- a/src/Rules/DeadCode/NoopRule.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\DeadCode;
-
-use PhpParser\Node;
-use PHPStan\Analyser\Scope;
-use PHPStan\Node\Printer\ExprPrinter;
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleErrorBuilder;
-use function sprintf;
-
-/**
- * @deprecated Replaced by PHPStan\Rules\DeadCode\BetterNoopRule
- * @implements Rule<Node\Stmt\Expression>
- */
-final class NoopRule implements Rule
-{
-
-	public function __construct(private ExprPrinter $exprPrinter, private bool $better)
-	{
-	}
-
-	public function getNodeType(): string
-	{
-		return Node\Stmt\Expression::class;
-	}
-
-	public function processNode(Node $node, Scope $scope): array
-	{
-		if ($this->better) {
-			// disabled in bleeding edge
-			return [];
-		}
-		$originalExpr = $node->expr;
-		$expr = $originalExpr;
-		if (
-			$expr instanceof Node\Expr\Cast
-			|| $expr instanceof Node\Expr\UnaryMinus
-			|| $expr instanceof Node\Expr\UnaryPlus
-			|| $expr instanceof Node\Expr\ErrorSuppress
-		) {
-			$expr = $expr->expr;
-		}
-
-		if (!$this->isNoopExpr($expr)) {
-			return [];
-		}
-
-		return [
-			RuleErrorBuilder::message(sprintf(
-				'Expression "%s" on a separate line does not do anything.',
-				$this->exprPrinter->printExpr($originalExpr),
-			))->line($expr->getStartLine())
-				->identifier('expr.resultUnused')
-				->build(),
-		];
-	}
-
-	public function isNoopExpr(Node\Expr $expr): bool
-	{
-		return $expr instanceof Node\Expr\Variable
-			|| $expr instanceof Node\Expr\PropertyFetch
-			|| $expr instanceof Node\Expr\StaticPropertyFetch
-			|| $expr instanceof Node\Expr\NullsafePropertyFetch
-			|| $expr instanceof Node\Expr\ArrayDimFetch
-			|| $expr instanceof Node\Scalar
-			|| $expr instanceof Node\Expr\Isset_
-			|| $expr instanceof Node\Expr\Empty_
-			|| $expr instanceof Node\Expr\ConstFetch
-			|| $expr instanceof Node\Expr\ClassConstFetch;
-	}
-
-}
diff --git a/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/FunctionDefinitionCheck.php b/src/Rules/FunctionDefinitionCheck.php
index 19a76e042c..a9ea3ff521 100644
--- a/src/Rules/FunctionDefinitionCheck.php
+++ b/src/Rules/FunctionDefinitionCheck.php
@@ -204,7 +204,7 @@ public function checkAnonymousFunction(
 		foreach ($returnType->getReferencedClasses() as $returnTypeClass) {
 			if (!$this->reflectionProvider->hasClass($returnTypeClass)) {
 				$errors[] = RuleErrorBuilder::message(sprintf($returnMessage, $returnTypeClass))
-					->line($returnTypeNode->getLine())
+					->line($returnTypeNode->getStartLine())
 					->identifier('class.notFound')
 					->build();
 				continue;
diff --git a/src/Rules/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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\Functions;
-
-use PhpParser\Node;
-use PhpParser\Node\Expr\FuncCall;
-use PHPStan\Analyser\Scope;
-use PHPStan\Reflection\ReflectionProvider;
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleErrorBuilder;
-use PHPStan\Rules\RuleLevelHelper;
-use PHPStan\Type\ErrorType;
-use PHPStan\Type\Type;
-use PHPStan\Type\VerbosityLevel;
-use function count;
-use function in_array;
-use function sprintf;
-
-/**
- * @deprecated Replaced by PHPStan\Rules\Functions\ImplodeParameterCastableToStringRuleTest
- * @implements Rule<Node\Expr\FuncCall>
- */
-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<string>, %s given.', $paramNo, $functionName, $typeResult->getType()->describe(VerbosityLevel::typeOnly())),
-			)->identifier('argument.type')->build(),
-		];
-	}
-
-}
diff --git a/src/Rules/Functions/UnusedClosureUsesRule.php b/src/Rules/Functions/UnusedClosureUsesRule.php
index 1494208b5b..c019d69240 100644
--- a/src/Rules/Functions/UnusedClosureUsesRule.php
+++ b/src/Rules/Functions/UnusedClosureUsesRule.php
@@ -34,7 +34,7 @@ public function processNode(Node $node, Scope $scope): array
 
 		return $this->check->getUnusedParameters(
 			$scope,
-			array_map(static function (Node\Expr\ClosureUse $use): string {
+			array_map(static function (Node\ClosureUse $use): string {
 				if (!is_string($use->var->name)) {
 					throw new ShouldNotHappenException();
 				}
diff --git a/src/Rules/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/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<string, string[]> $usedNames
 	 * @return list<IdentifierRuleError>
 	 */
@@ -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<IdentifierRuleError>
 	 */
 	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<IdentifierRuleError>
 	 */
 	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<IdentifierRuleError>
 	 */
 	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/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<Node>
+ * @implements Rule<Node\Stmt>
  */
 final class InvalidPHPStanDocTagRule implements Rule
 {
@@ -63,39 +63,23 @@ final class InvalidPHPStanDocTagRule implements Rule
 	public function __construct(
 		private Lexer $phpDocLexer,
 		private PhpDocParser $phpDocParser,
-		private bool $checkAllInvalidPhpDocs,
 	)
 	{
 	}
 
 	public function getNodeType(): string
 	{
-		return Node::class;
+		return Node\Stmt::class;
 	}
 
 	public function processNode(Node $node, Scope $scope): array
 	{
-		if (!$this->checkAllInvalidPhpDocs) {
-			if (
-				!$node instanceof Node\Stmt\ClassLike
-				&& !$node instanceof Node\FunctionLike
-				&& !$node instanceof Node\Stmt\Foreach_
-				&& !$node instanceof Node\Stmt\Property
-				&& !$node instanceof Node\Expr\Assign
-				&& !$node instanceof Node\Expr\AssignRef
-				&& !$node instanceof Node\Stmt\ClassConst
-			) {
-				return [];
-			}
-		} else {
-			// mirrored with InvalidPhpDocTagValueRule
-			if ($node instanceof VirtualNode) {
-				return [];
-			}
-			if ($node instanceof Node\Stmt\Expression) {
-				return [];
-			}
-			if ($node instanceof Node\Expr && !$node instanceof Node\Expr\Assign && !$node instanceof Node\Expr\AssignRef) {
+		// mirrored with InvalidPhpDocTagValueRule
+		if ($node instanceof VirtualNode) {
+			return [];
+		}
+		if ($node instanceof Node\Stmt\Expression) {
+			if (!$node->expr instanceof Node\Expr\Assign && !$node->expr instanceof Node\Expr\AssignRef) {
 				return [];
 			}
 		}
diff --git a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php
index fe40a1bd61..569c776df3 100644
--- a/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php
+++ b/src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php
@@ -18,7 +18,7 @@
 use function str_starts_with;
 
 /**
- * @implements Rule<Node>
+ * @implements Rule<Node\Stmt>
  */
 final class InvalidPhpDocTagValueRule implements Rule
 {
@@ -26,7 +26,6 @@ final class InvalidPhpDocTagValueRule implements Rule
 	public function __construct(
 		private Lexer $phpDocLexer,
 		private PhpDocParser $phpDocParser,
-		private bool $checkAllInvalidPhpDocs,
 		private bool $invalidPhpDocTagLine,
 	)
 	{
@@ -34,32 +33,17 @@ public function __construct(
 
 	public function getNodeType(): string
 	{
-		return Node::class;
+		return Node\Stmt::class;
 	}
 
 	public function processNode(Node $node, Scope $scope): array
 	{
-		if (!$this->checkAllInvalidPhpDocs) {
-			if (
-				!$node instanceof Node\Stmt\ClassLike
-				&& !$node instanceof Node\FunctionLike
-				&& !$node instanceof Node\Stmt\Foreach_
-				&& !$node instanceof Node\Stmt\Property
-				&& !$node instanceof Node\Expr\Assign
-				&& !$node instanceof Node\Expr\AssignRef
-				&& !$node instanceof Node\Stmt\ClassConst
-			) {
-				return [];
-			}
-		} else {
-			// mirrored with InvalidPHPStanDocTagRule
-			if ($node instanceof VirtualNode) {
-				return [];
-			}
-			if ($node instanceof Node\Stmt\Expression) {
-				return [];
-			}
-			if ($node instanceof Node\Expr && !$node instanceof Node\Expr\Assign && !$node instanceof Node\Expr\AssignRef) {
+		// mirrored with InvalidPHPStanDocTagRule
+		if ($node instanceof VirtualNode) {
+			return [];
+		}
+		if ($node instanceof Node\Stmt\Expression) {
+			if (!$node->expr instanceof Node\Expr\Assign && !$node->expr instanceof Node\Expr\AssignRef) {
 				return [];
 			}
 		}
diff --git a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php
index 4a227ffd07..81b4296100 100644
--- a/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php
+++ b/src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php
@@ -48,7 +48,6 @@ public function processNode(Node $node, Scope $scope): array
 	{
 		if (
 			$node instanceof Node\Stmt\Property
-			|| $node instanceof Node\Stmt\PropertyProperty
 			|| $node instanceof Node\Stmt\ClassConst
 			|| $node instanceof Node\Stmt\Const_
 		) {
diff --git a/src/Rules/PhpDoc/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..87784c71d6 100644
--- a/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php
+++ b/src/Rules/PhpDoc/WrongVariableNameInVarTagRule.php
@@ -51,7 +51,6 @@ public function processNode(Node $node, Scope $scope): array
 	{
 		if (
 			$node instanceof Node\Stmt\Property
-			|| $node instanceof Node\Stmt\PropertyProperty
 			|| $node instanceof Node\Stmt\ClassConst
 			|| $node instanceof Node\Stmt\Const_
 			|| ($node instanceof VirtualNode && !$node instanceof InFunctionNode && !$node instanceof InClassMethodNode && !$node instanceof InClassNode)
@@ -90,10 +89,13 @@ public function processNode(Node $node, Scope $scope): array
 		}
 
 		if ($node instanceof Node\Stmt\Expression) {
+			if ($node->expr instanceof Expr\Throw_) {
+				return $this->processStmt($scope, $varTags, $node->expr);
+			}
 			return $this->processExpression($scope, $node->expr, $varTags);
 		}
 
-		if ($node instanceof Node\Stmt\Throw_ || $node instanceof Node\Stmt\Return_) {
+		if ($node instanceof Node\Stmt\Return_) {
 			return $this->processStmt($scope, $varTags, $node->expr);
 		}
 
@@ -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) {
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/UnusedFunctionParametersCheck.php b/src/Rules/UnusedFunctionParametersCheck.php
index b85150e267..4fbe76d20d 100644
--- a/src/Rules/UnusedFunctionParametersCheck.php
+++ b/src/Rules/UnusedFunctionParametersCheck.php
@@ -69,7 +69,7 @@ private function getUsedVariables(Scope $scope, $node): array
 			if ($node instanceof Node\Expr\Variable && is_string($node->name) && $node->name !== 'this') {
 				return [$node->name];
 			}
-			if ($node instanceof Node\Expr\ClosureUse && is_string($node->var->name)) {
+			if ($node instanceof Node\ClosureUse && is_string($node->var->name)) {
 				return [$node->var->name];
 			}
 			if (
diff --git a/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php b/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php
index 177079ac6c..9b42e1909e 100644
--- a/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php
+++ b/src/Rules/Variables/ParameterOutExecutionEndTypeRule.php
@@ -57,9 +57,6 @@ public function processNode(Node $node, Scope $scope): array
 				return [];
 			}
 		}
-		if ($endNode instanceof Node\Stmt\Throw_) {
-			return [];
-		}
 
 		$variant = ParametersAcceptorSelector::selectSingle($inFunction->getVariants());
 		$parameters = $variant->getParameters();
diff --git a/src/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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\Variables;
-
-use PhpParser\Node;
-use PHPStan\Analyser\Scope;
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleErrorBuilder;
-use PHPStan\Rules\RuleLevelHelper;
-use PHPStan\Type\ErrorType;
-use PHPStan\Type\ObjectType;
-use PHPStan\Type\Type;
-use PHPStan\Type\VerbosityLevel;
-use Throwable;
-use function sprintf;
-
-/**
- * @implements Rule<Node\Stmt\Throw_>
- */
-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/TypeInferenceTestCase.php b/src/Testing/TypeInferenceTestCase.php
index 4194d4f4d3..874b601156 100644
--- a/src/Testing/TypeInferenceTestCase.php
+++ b/src/Testing/TypeInferenceTestCase.php
@@ -178,7 +178,7 @@ public static function gatherAssertTypes(string $file): array
 						'Expected type must be a literal string, %s given in %s on line %d.',
 						$expectedType->describe(VerbosityLevel::precise()),
 						$relativePathHelper->getRelativePath($file),
-						$node->getLine(),
+						$node->getStartLine(),
 					));
 				}
 				$actualType = $scope->getType($node->getArgs()[1]->value);
@@ -190,7 +190,7 @@ public static function gatherAssertTypes(string $file): array
 						'Expected type must be a literal string, %s given in %s on line %d.',
 						$expectedType->describe(VerbosityLevel::precise()),
 						$relativePathHelper->getRelativePath($file),
-						$node->getLine(),
+						$node->getStartLine(),
 					));
 				}
 
diff --git a/src/Type/Constant/OversizedArrayBuilder.php b/src/Type/Constant/OversizedArrayBuilder.php
index 02e1115e1d..e6ac71ded5 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();
 			}
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/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/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
index df1bf3499a..1c4436ca46 100644
--- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
+++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
@@ -65,9 +65,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
 		if ($arrayExpr instanceof Array_) {
 			$types = null;
 			foreach ($arrayExpr->items as $item) {
-				if ($item === null) {
-					continue;
-				}
 				if ($item->unpack) {
 					$types = null;
 					break;
diff --git a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php
index 472683ffb1..a571338e18 100644
--- a/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php
+++ b/src/Type/Php/IsCallableFunctionTypeSpecifyingExtension.php
@@ -51,10 +51,6 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
 			&& $valueType->isConstantArray()->yes()
 			&& !$valueType->isCallable()->no()
 		) {
-			if ($value->items[0] === null || $value->items[1] === null) {
-				throw new ShouldNotHappenException();
-			}
-
 			$functionCall = new FuncCall(new Name('method_exists'), [
 				new Arg($value->items[0]->value),
 				new Arg($value->items[1]->value),
diff --git a/src/Type/TypehintHelper.php b/src/Type/TypehintHelper.php
index 8f9f5616f3..5538370ccb 100644
--- a/src/Type/TypehintHelper.php
+++ b/src/Type/TypehintHelper.php
@@ -2,96 +2,25 @@
 
 namespace PHPStan\Type;
 
+use PhpParser\Node\Identifier;
+use PhpParser\Node\Name\FullyQualified;
+use PHPStan\BetterReflection\Reflection\Adapter\ReflectionIntersectionType;
+use PHPStan\BetterReflection\Reflection\Adapter\ReflectionNamedType;
+use PHPStan\BetterReflection\Reflection\Adapter\ReflectionUnionType;
 use PHPStan\Reflection\ClassReflection;
 use PHPStan\Reflection\ReflectionProviderStaticAccessor;
 use PHPStan\ShouldNotHappenException;
-use PHPStan\Type\Constant\ConstantBooleanType;
 use PHPStan\Type\Generic\TemplateTypeHelper;
-use ReflectionIntersectionType;
-use ReflectionNamedType;
 use ReflectionType;
-use ReflectionUnionType;
 use function array_map;
 use function count;
 use function get_class;
 use function is_string;
 use function sprintf;
-use function 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,
@@ -131,23 +60,21 @@ 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);
+		if (is_string($selfClass)) {
+			$reflectionProvider = ReflectionProviderStaticAccessor::getInstance();
+			if ($reflectionProvider->hasClass($selfClass)) {
+				$selfClass = $reflectionProvider->getClass($selfClass);
+			} else {
+				$selfClass = null;
+			}
+		}
+		$type = ParserNodeTypeToPHPStanType::resolve($typeNode, $selfClass);
 		if ($reflectionType->allowsNull()) {
 			$type = TypeCombinator::addNull($type);
 		} elseif ($phpDocType !== null) {
diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php
index b84ff5feb0..e3a3997bf3 100644
--- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php
+++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php
@@ -827,6 +827,10 @@ public function testBug7094(): void
 
 	public function testOffsetAccess(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$errors = $this->runAnalyse(__DIR__ . '/nsrt/offset-access.php');
 		$this->assertCount(1, $errors);
 		$this->assertSame('PHPDoc tag @return contains unresolvable type.', $errors[0]->getMessage());
@@ -1063,6 +1067,10 @@ public function testBug8376(): void
 
 	public function testAssertDocblock(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$errors = $this->runAnalyse(__DIR__ . '/nsrt/assert-docblock.php');
 		$this->assertCount(4, $errors);
 		$this->assertSame('Call to method AssertDocblock\A::testInt() with string will always evaluate to false.', $errors[0]->getMessage());
@@ -1396,6 +1404,10 @@ public function testBug11147(): void
 
 	public function testBug11283(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$errors = $this->runAnalyse(__DIR__ . '/data/bug-11283.php');
 		$this->assertNoErrors($errors);
 	}
diff --git a/tests/PHPStan/Analyser/AnalyserTest.php b/tests/PHPStan/Analyser/AnalyserTest.php
index f820c64aff..d59549b9da 100644
--- a/tests/PHPStan/Analyser/AnalyserTest.php
+++ b/tests/PHPStan/Analyser/AnalyserTest.php
@@ -745,13 +745,12 @@ private function createAnalyser(bool $enableIgnoreErrorsWithinPhpDocs): Analyser
 			self::getContainer()->getParameter('featureToggles')['preciseMissingReturn'],
 			self::getContainer()->getParameter('featureToggles')['explicitThrow'],
 		);
-		$lexer = new Lexer(['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos']]);
+		$lexer = new Lexer();
 		$fileAnalyser = new FileAnalyser(
 			$this->createScopeFactory($reflectionProvider, $typeSpecifier),
 			$nodeScopeResolver,
 			new RichParser(
 				new Php7($lexer),
-				$lexer,
 				new NameResolver(),
 				self::getContainer(),
 				new IgnoreLexer(),
diff --git a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php
index 59ebef356e..c76ca0ebca 100644
--- a/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php
+++ b/tests/PHPStan/Analyser/DynamicReturnTypeExtensionTypeInferenceTest.php
@@ -14,10 +14,10 @@ public function dataAsserts(): iterable
 
 		if (PHP_VERSION_ID >= 80000) {
 			yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-types-named-args.php');
+			yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-getsingle-conditional.php');
 		}
 
 		yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-compound-types.php');
-		yield from $this->gatherAssertTypes(__DIR__ . '/data/dynamic-method-return-getsingle-conditional.php');
 		yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7344.php');
 		yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-7391b.php');
 	}
diff --git a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
index 1d17f9ee48..f75730744d 100644
--- a/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
+++ b/tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php
@@ -6431,7 +6431,7 @@ public function dataMisleadingTypes(): array
 				'$foo->misleadingIntReturnType()',
 			],
 			[
-				'mixed',
+				PHP_VERSION_ID >= 80000 ? 'mixed' : 'MisleadingTypes\mixed',
 				'$foo->misleadingMixedReturnType()',
 			],
 		];
diff --git a/tests/PHPStan/Analyser/nsrt/abs.php b/tests/PHPStan/Analyser/nsrt/abs.php
index eb644eb4bd..506f436c02 100644
--- a/tests/PHPStan/Analyser/nsrt/abs.php
+++ b/tests/PHPStan/Analyser/nsrt/abs.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 8.0
+
+declare(strict_types = 1);
 
 namespace Abs;
 
diff --git a/tests/PHPStan/Analyser/nsrt/array-key-exists.php b/tests/PHPStan/Analyser/nsrt/array-key-exists.php
index ed6f552d15..17e49019c7 100644
--- a/tests/PHPStan/Analyser/nsrt/array-key-exists.php
+++ b/tests/PHPStan/Analyser/nsrt/array-key-exists.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace ArrayKeyExistsExtension;
 
diff --git a/tests/PHPStan/Analyser/nsrt/assert-conditional.php b/tests/PHPStan/Analyser/nsrt/assert-conditional.php
index 4e52490066..4a8567a2db 100644
--- a/tests/PHPStan/Analyser/nsrt/assert-conditional.php
+++ b/tests/PHPStan/Analyser/nsrt/assert-conditional.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace AssertConditional;
 
diff --git a/tests/PHPStan/Analyser/nsrt/assert-docblock.php b/tests/PHPStan/Analyser/nsrt/assert-docblock.php
index 1b094a1cd7..b6391d651a 100644
--- a/tests/PHPStan/Analyser/nsrt/assert-docblock.php
+++ b/tests/PHPStan/Analyser/nsrt/assert-docblock.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace AssertDocblock;
 
diff --git a/tests/PHPStan/Analyser/nsrt/assert-empty.php b/tests/PHPStan/Analyser/nsrt/assert-empty.php
index 12176791a3..73f15aade7 100644
--- a/tests/PHPStan/Analyser/nsrt/assert-empty.php
+++ b/tests/PHPStan/Analyser/nsrt/assert-empty.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace AssertInheritance;
 
diff --git a/tests/PHPStan/Analyser/nsrt/assert-intersected.php b/tests/PHPStan/Analyser/nsrt/assert-intersected.php
index a39ffe1436..17aa63957a 100644
--- a/tests/PHPStan/Analyser/nsrt/assert-intersected.php
+++ b/tests/PHPStan/Analyser/nsrt/assert-intersected.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace AssertIntersected;
 
diff --git a/tests/PHPStan/Analyser/nsrt/assert-invariant.php b/tests/PHPStan/Analyser/nsrt/assert-invariant.php
index b7368f06e9..4efe160b18 100644
--- a/tests/PHPStan/Analyser/nsrt/assert-invariant.php
+++ b/tests/PHPStan/Analyser/nsrt/assert-invariant.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 8.0
+
+declare(strict_types = 1);
 
 namespace AssertInvariant;
 
diff --git a/tests/PHPStan/Analyser/nsrt/bug-10037.php b/tests/PHPStan/Analyser/nsrt/bug-10037.php
index 58adb961c1..56c49c331b 100644
--- a/tests/PHPStan/Analyser/nsrt/bug-10037.php
+++ b/tests/PHPStan/Analyser/nsrt/bug-10037.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace Bug10473;
 
diff --git a/tests/PHPStan/Analyser/nsrt/bug-6293.php b/tests/PHPStan/Analyser/nsrt/bug-6293.php
index 0a5c8548be..993f7b470e 100644
--- a/tests/PHPStan/Analyser/nsrt/bug-6293.php
+++ b/tests/PHPStan/Analyser/nsrt/bug-6293.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace Bug6239;
 
diff --git a/tests/PHPStan/Analyser/nsrt/bug-7141.php b/tests/PHPStan/Analyser/nsrt/bug-7141.php
index 277b00d9e6..2cf34a5733 100644
--- a/tests/PHPStan/Analyser/nsrt/bug-7141.php
+++ b/tests/PHPStan/Analyser/nsrt/bug-7141.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 8.0
+
+declare(strict_types = 1);
 
 namespace Bug7141;
 
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 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace Bug7788;
 
diff --git a/tests/PHPStan/Analyser/nsrt/bug-7944.php b/tests/PHPStan/Analyser/nsrt/bug-7944.php
index 737ab3dcb8..0d219b40b3 100644
--- a/tests/PHPStan/Analyser/nsrt/bug-7944.php
+++ b/tests/PHPStan/Analyser/nsrt/bug-7944.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 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 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace Bug9472;
 
diff --git a/tests/PHPStan/Analyser/nsrt/bug-9764.php b/tests/PHPStan/Analyser/nsrt/bug-9764.php
index 15807d0b1e..f24b810fe8 100644
--- a/tests/PHPStan/Analyser/nsrt/bug-9764.php
+++ b/tests/PHPStan/Analyser/nsrt/bug-9764.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 declare(strict_types=1);
 
diff --git a/tests/PHPStan/Analyser/nsrt/class-implements.php b/tests/PHPStan/Analyser/nsrt/class-implements.php
index acd6a616ae..316c8e8ed4 100644
--- a/tests/PHPStan/Analyser/nsrt/class-implements.php
+++ b/tests/PHPStan/Analyser/nsrt/class-implements.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace ClassImplements;
 
diff --git a/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php b/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php
index 55335c6e2e..89bfa50a22 100644
--- a/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php
+++ b/tests/PHPStan/Analyser/nsrt/conditional-types-inference.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace ConditionalTypesInference;
 
diff --git a/tests/PHPStan/Analyser/nsrt/ctype-digit.php b/tests/PHPStan/Analyser/nsrt/ctype-digit.php
index 835ba4fdcc..00a803d52d 100644
--- a/tests/PHPStan/Analyser/nsrt/ctype-digit.php
+++ b/tests/PHPStan/Analyser/nsrt/ctype-digit.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types=1);
+<?php  // lint >= 8.0
+
+declare(strict_types=1);
 
 namespace CtypeDigit;
 
diff --git a/tests/PHPStan/Analyser/nsrt/enum_exists.php b/tests/PHPStan/Analyser/nsrt/enum_exists.php
index 33f1200924..37809016ad 100644
--- a/tests/PHPStan/Analyser/nsrt/enum_exists.php
+++ b/tests/PHPStan/Analyser/nsrt/enum_exists.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace EnumExists;
 
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 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace FalsyIsset;
 
diff --git a/tests/PHPStan/Analyser/nsrt/filter-input-array.php b/tests/PHPStan/Analyser/nsrt/filter-input-array.php
index 706a300680..d773c237f8 100644
--- a/tests/PHPStan/Analyser/nsrt/filter-input-array.php
+++ b/tests/PHPStan/Analyser/nsrt/filter-input-array.php
@@ -1,4 +1,6 @@
-<?php declare(strict_types=1);
+<?php // lint >= 8.0
+
+declare(strict_types=1);
 
 namespace FilterVarArray;
 
diff --git a/tests/PHPStan/Analyser/nsrt/filter-var-array.php b/tests/PHPStan/Analyser/nsrt/filter-var-array.php
index 52261b0e8a..38db914722 100644
--- a/tests/PHPStan/Analyser/nsrt/filter-var-array.php
+++ b/tests/PHPStan/Analyser/nsrt/filter-var-array.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace FilterVarArray;
 
diff --git a/tests/PHPStan/Analyser/nsrt/generic-callables.php b/tests/PHPStan/Analyser/nsrt/generic-callables.php
index 94bb3238a2..9fde822894 100644
--- a/tests/PHPStan/Analyser/nsrt/generic-callables.php
+++ b/tests/PHPStan/Analyser/nsrt/generic-callables.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace GenericMethodTags;
 
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 @@
-<?php
+<?php // lint >= 8.0
 
 namespace InArrayLoose;
 
diff --git a/tests/PHPStan/Analyser/nsrt/key-exists.php b/tests/PHPStan/Analyser/nsrt/key-exists.php
index 11c2ed6a2a..0c98f24b2b 100644
--- a/tests/PHPStan/Analyser/nsrt/key-exists.php
+++ b/tests/PHPStan/Analyser/nsrt/key-exists.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace KeyExists;
 
diff --git a/tests/PHPStan/Analyser/nsrt/mixed-typehint.php b/tests/PHPStan/Analyser/nsrt/mixed-typehint.php
index 8d7ce4ad16..5b3c17cbb1 100644
--- a/tests/PHPStan/Analyser/nsrt/mixed-typehint.php
+++ b/tests/PHPStan/Analyser/nsrt/mixed-typehint.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace MixedTypehint;
 
diff --git a/tests/PHPStan/Analyser/nsrt/offset-access.php b/tests/PHPStan/Analyser/nsrt/offset-access.php
index 505557b452..593dd799ab 100644
--- a/tests/PHPStan/Analyser/nsrt/offset-access.php
+++ b/tests/PHPStan/Analyser/nsrt/offset-access.php
@@ -1,4 +1,4 @@
-<?php
+<?php // lint >= 8.0
 
 namespace OffsetAccess;
 
diff --git a/tests/PHPStan/Parser/RichParserTest.php b/tests/PHPStan/Parser/RichParserTest.php
index 103eb129b4..69fc99cbab 100644
--- a/tests/PHPStan/Parser/RichParserTest.php
+++ b/tests/PHPStan/Parser/RichParserTest.php
@@ -193,7 +193,17 @@ public function dataLinesToIgnore(): iterable
 			PHP_EOL .
 			'/** @phpstan-ignore test */' . PHP_EOL,
 			[
-				3 => ['test'],
+				4 => ['test'],
+			],
+		];
+
+		yield [
+			'<?php' . PHP_EOL .
+			PHP_EOL .
+			'/** @phpstan-ignore test */' . PHP_EOL .
+			'doFoo();' . PHP_EOL,
+			[
+				4 => ['test'],
 			],
 		];
 
diff --git a/tests/PHPStan/Reflection/MixedTypeTest.php b/tests/PHPStan/Reflection/MixedTypeTest.php
index f6c511df33..869f3c2bf8 100644
--- a/tests/PHPStan/Reflection/MixedTypeTest.php
+++ b/tests/PHPStan/Reflection/MixedTypeTest.php
@@ -6,12 +6,17 @@
 use PhpParser\Node\Name;
 use PHPStan\Testing\PHPStanTestCase;
 use PHPStan\Type\MixedType;
+use const PHP_VERSION_ID;
 
 class MixedTypeTest extends PHPStanTestCase
 {
 
 	public function testMixedType(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$reflectionProvider = $this->createReflectionProvider();
 		$class = $reflectionProvider->getClass(Foo::class);
 		$propertyType = $class->getNativeProperty('fooProp')->getNativeType();
diff --git a/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php b/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php
index 51ba629e16..df14e33493 100644
--- a/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php
+++ b/tests/PHPStan/Rules/Arrays/EmptyArrayItemRuleTest.php
@@ -20,7 +20,7 @@ public function testRule(): void
 	{
 		$this->analyse([__DIR__ . '/data/empty-array-item.php'], [
 			[
-				'Literal array contains empty item.',
+				'Cannot use empty array elements in arrays on line 5',
 				5,
 			],
 		]);
diff --git a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php
index dbb64b29ca..31407e99be 100644
--- a/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php
+++ b/tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php
@@ -135,6 +135,10 @@ public function dataMixed(): array
 	 */
 	public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = $checkExplicitMixed;
 		$this->checkImplicitMixed = $checkImplicitMixed;
 		$this->analyse([__DIR__ . '/data/foreach-mixed.php'], $errors);
diff --git a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php
index ffc6aa26d5..bde2d1100e 100644
--- a/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php
+++ b/tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php
@@ -762,6 +762,10 @@ public function testBug10926(): void
 
 	public function testMixed(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = true;
 		$this->checkImplicitMixed = true;
 		$this->analyse([__DIR__ . '/data/offset-access-mixed.php'], [
diff --git a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php
index 32d4900686..c7de4bc7bf 100644
--- a/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php
+++ b/tests/PHPStan/Rules/Arrays/UnpackIterableInArrayRuleTest.php
@@ -107,6 +107,10 @@ public function dataMixed(): array
 	 */
 	public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = $checkExplicitMixed;
 		$this->checkImplicitMixed = $checkImplicitMixed;
 		$this->analyse([__DIR__ . '/data/unpack-mixed.php'], $errors);
diff --git a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php
index 5734b47928..bc7cd35acb 100644
--- a/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php
+++ b/tests/PHPStan/Rules/Cast/InvalidCastRuleTest.php
@@ -163,6 +163,10 @@ public function dataMixed(): array
 	 */
 	public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkImplicitMixed = $checkImplicitMixed;
 		$this->checkExplicitMixed = $checkExplicitMixed;
 		$this->analyse([__DIR__ . '/data/mixed-cast.php'], $errors);
diff --git a/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php b/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php
index 4018d2ca62..0e6d0b066f 100644
--- a/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php
+++ b/tests/PHPStan/Rules/Classes/ExistingClassInInstanceOfRuleTest.php
@@ -7,6 +7,7 @@
 use PHPStan\Rules\ClassNameCheck;
 use PHPStan\Rules\Rule;
 use PHPStan\Testing\RuleTestCase;
+use const PHP_VERSION_ID;
 
 /**
  * @extends RuleTestCase<ExistingClassInInstanceOfRule>
@@ -67,6 +68,10 @@ public function testClassExists(): void
 
 	public function testBug7720(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/bug-7720.php'], [
 			[
 				'Instanceof between mixed and trait Bug7720\FooBar will always evaluate to false.',
diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php
index 88d9315d84..38d61a57dd 100644
--- a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php
+++ b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeFunctionCallRuleTest.php
@@ -46,6 +46,10 @@ protected function shouldTreatPhpDocTypesAsCertain(): bool
 
 	public function testImpossibleCheckTypeFunctionCall(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkAlwaysTrueCheckTypeFunctionCall = true;
 		$this->treatPhpDocTypesAsCertain = true;
 		$this->analyse(
@@ -274,6 +278,10 @@ public function testBug7898(): void
 
 	public function testImpossibleCheckTypeFunctionCallWithoutAlwaysTrue(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkAlwaysTrueCheckTypeFunctionCall = false;
 		$this->treatPhpDocTypesAsCertain = true;
 		$this->analyse(
@@ -610,6 +618,10 @@ public function testBug7079(): void
 
 	public function testConditionalTypesInference(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkAlwaysTrueCheckTypeFunctionCall = true;
 		$this->treatPhpDocTypesAsCertain = true;
 		$this->analyse([__DIR__ . '/../../Analyser/nsrt/conditional-types-inference.php'], [
@@ -645,6 +657,10 @@ public function testBug6697(): void
 
 	public function testBug6443(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkAlwaysTrueCheckTypeFunctionCall = true;
 		$this->treatPhpDocTypesAsCertain = true;
 		$this->analyse([__DIR__ . '/data/bug-6443.php'], []);
diff --git a/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php b/tests/PHPStan/Rules/Comparison/ImpossibleCheckTypeMethodCallRuleTest.php
index 7a697e6ffa..29f63a6bf2 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<ImpossibleCheckTypeMethodCallRule>
@@ -199,19 +200,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/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 @@
-<?php declare(strict_types = 1);
+<?php // lint >= 8.0
+
+declare(strict_types = 1);
 
 namespace Bug8169;
 
diff --git a/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php b/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php
deleted file mode 100644
index edffaa5b9a..0000000000
--- a/tests/PHPStan/Rules/DeadCode/NoopRuleTest.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\DeadCode;
-
-use PHPStan\Node\Printer\ExprPrinter;
-use PHPStan\Node\Printer\Printer;
-use PHPStan\Rules\Rule;
-use PHPStan\Testing\RuleTestCase;
-
-/**
- * @extends RuleTestCase<NoopRule>
- */
-class NoopRuleTest extends RuleTestCase
-{
-
-	protected function getRule(): Rule
-	{
-		return new NoopRule(new ExprPrinter(new Printer()), false);
-	}
-
-	public function testRule(): void
-	{
-		$this->analyse([__DIR__ . '/data/noop.php'], [
-			[
-				'Expression "$arr" on a separate line does not do anything.',
-				9,
-			],
-			[
-				'Expression "$arr[\'test\']" on a separate line does not do anything.',
-				10,
-			],
-			[
-				'Expression "$foo::$test" on a separate line does not do anything.',
-				11,
-			],
-			[
-				'Expression "$foo->test" on a separate line does not do anything.',
-				12,
-			],
-			[
-				'Expression "\'foo\'" on a separate line does not do anything.',
-				14,
-			],
-			[
-				'Expression "1" on a separate line does not do anything.',
-				15,
-			],
-			[
-				'Expression "@\'foo\'" on a separate line does not do anything.',
-				17,
-			],
-			[
-				'Expression "+1" on a separate line does not do anything.',
-				18,
-			],
-			[
-				'Expression "-1" on a separate line does not do anything.',
-				19,
-			],
-			[
-				'Expression "isset($test)" on a separate line does not do anything.',
-				25,
-			],
-			[
-				'Expression "empty($test)" on a separate line does not do anything.',
-				26,
-			],
-			[
-				'Expression "true" on a separate line does not do anything.',
-				27,
-			],
-			[
-				'Expression "\DeadCodeNoop\Foo::TEST" on a separate line does not do anything.',
-				28,
-			],
-			[
-				'Expression "(string) 1" on a separate line does not do anything.',
-				30,
-			],
-		]);
-	}
-
-	public function testNullsafe(): void
-	{
-		$this->analyse([__DIR__ . '/data/nullsafe-property-fetch-noop.php'], [
-			[
-				'Expression "$ref?->name" on a separate line does not do anything.',
-				10,
-			],
-		]);
-	}
-
-}
diff --git a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php
index 8ef6277fe1..9ece8025a0 100644
--- a/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php
+++ b/tests/PHPStan/Rules/Exceptions/ThrowExprTypeRuleTest.php
@@ -23,16 +23,16 @@ public function testRule(): void
 		$this->analyse(
 			[__DIR__ . '/data/throw-values.php'],
 			[
-				/*[
+				[
 					'Invalid type int to throw.',
 					29,
 				],
 				[
-					'Invalid type ThrowValues\InvalidException to throw.',
+					'Invalid type ThrowExprValues\InvalidException to throw.',
 					32,
 				],
 				[
-					'Invalid type ThrowValues\InvalidInterfaceException to throw.',
+					'Invalid type ThrowExprValues\InvalidInterfaceException to throw.',
 					35,
 				],
 				[
@@ -40,10 +40,10 @@ public function testRule(): void
 					38,
 				],
 				[
-					'Throwing object of an unknown class ThrowValues\NonexistentClass.',
+					'Throwing object of an unknown class ThrowExprValues\NonexistentClass.',
 					44,
 					'Learn more at https://phpstan.org/user-guide/discovering-symbols',
-				],*/
+				],
 				[
 					'Invalid type int to throw.',
 					65,
@@ -64,10 +64,10 @@ public function testRuleWithNullsafeVariant(): void
 		}
 
 		$this->analyse([__DIR__ . '/data/throw-values-nullsafe.php'], [
-			/*[
+			[
 				'Invalid type Exception|null to throw.',
 				17,
-			],*/
+			],
 		]);
 	}
 
diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php
index bf46cd56a6..8e530c62aa 100644
--- a/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php
+++ b/tests/PHPStan/Rules/Functions/ArrowFunctionReturnTypeRuleTest.php
@@ -39,9 +39,20 @@ public function testRule(): void
 				'Anonymous function should return int but returns string.',
 				14,
 			],
+
+		]);
+	}
+
+	public function testRuleNever(): void
+	{
+		if (PHP_VERSION_ID < 80100) {
+			self::markTestSkipped('Test requires PHP 8.1.');
+		}
+
+		$this->analyse([__DIR__ . '/data/arrow-function-never-return.php'], [
 			[
 				'Anonymous function should never return but return statement found.',
-				44,
+				12,
 			],
 		]);
 	}
diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php
index d49987e3c5..174f8ece4a 100644
--- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php
+++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php
@@ -1417,6 +1417,10 @@ public function testBug2508(): void
 
 	public function testBug6175(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/bug-6175.php'], []);
 	}
 
@@ -1600,6 +1604,10 @@ public function testBug9580(): void
 
 	public function testBug7283(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/bug-7283.php'], []);
 	}
 
@@ -1670,6 +1678,10 @@ public function testParamClosureThis(): void
 
 	public function testBug10297(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/bug-10297.php'], []);
 	}
 
diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php
index 2417944d1a..a409df4391 100644
--- a/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php
+++ b/tests/PHPStan/Rules/Functions/ExistingClassesInArrowFunctionTypehintsRuleTest.php
@@ -243,6 +243,10 @@ public function dataRequiredParameterAfterOptional(): array
 	 */
 	public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->phpVersionId = $phpVersionId;
 		$this->analyse([__DIR__ . '/data/required-parameter-after-optional-arrow.php'], $errors);
 	}
@@ -289,7 +293,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 86f8725573..9b1c1c329d 100644
--- a/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php
+++ b/tests/PHPStan/Rules/Functions/ExistingClassesInClosureTypehintsRuleTest.php
@@ -287,6 +287,10 @@ public function dataRequiredParameterAfterOptional(): array
 	 */
 	public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->phpVersionId = $phpVersionId;
 		$this->analyse([__DIR__ . '/data/required-parameter-after-optional-closures.php'], $errors);
 	}
diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php
index 78415d4616..06957666f5 100644
--- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php
+++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php
@@ -368,6 +368,10 @@ public function dataRequiredParameterAfterOptional(): array
 	 */
 	public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->phpVersionId = $phpVersionId;
 		$this->analyse([__DIR__ . '/data/required-parameter-after-optional.php'], $errors);
 	}
@@ -421,19 +425,28 @@ public function dataTrueTypes(): array
 		];
 	}
 
-	/**
-	 * @dataProvider dataTrueTypes
-	 * @param list<array{0: string, 1: int, 2?: string}> $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 +457,10 @@ public function testConditionalReturnType(): void
 
 	public function testTemplateInParamOut(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/param-out.php'], [
 			[
 				'Template type S of function ParamOutTemplate\uselessGeneric() is not referenced in a parameter.',
diff --git a/tests/PHPStan/Rules/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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\Functions;
-
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleLevelHelper;
-use PHPStan\Testing\RuleTestCase;
-
-/**
- * @extends RuleTestCase<ImplodeFunctionRule>
- */
-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<string>, array<int, array<int, string>|string> given.',
-				9,
-			],
-			[
-				'Parameter #1 $array of function implode expects array<string>, array<int, array<int, string>> given.',
-				11,
-			],
-			[
-				'Parameter #1 $array of function implode expects array<string>, array<int, array<int, int>> given.',
-				12,
-			],
-			[
-				'Parameter #1 $array of function implode expects array<string>, array<int, array<int, int|true>> given.',
-				13,
-			],
-			[
-				'Parameter #2 $array of function implode expects array<string>, array<int, array<int, string>> given.',
-				15,
-			],
-			[
-				'Parameter #2 $array of function join expects array<string>, array<int, array<int, string>> 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/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php
index f16d288869..53476ec81b 100644
--- a/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php
+++ b/tests/PHPStan/Rules/Functions/ReturnTypeRuleTest.php
@@ -257,6 +257,10 @@ public function testBug8683(): void
 
 	public function testBug7984(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = true;
 		$this->checkNullables = true;
 		$this->analyse([__DIR__ . '/data/bug-7984.php'], []);
diff --git a/tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php b/tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php
new file mode 100644
index 0000000000..5a9641fb06
--- /dev/null
+++ b/tests/PHPStan/Rules/Functions/data/arrow-function-never-return.php
@@ -0,0 +1,15 @@
+<?php // lint >= 8.1
+
+namespace ArrowFunctionNeverReturn;
+
+class Baz
+{
+
+	public function doFoo(): void
+	{
+		$f = fn () => throw new \Exception();
+		$g = fn (): never => throw new \Exception();
+		$g = fn (): never => 1;
+	}
+
+}
diff --git a/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php b/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php
index 552bf901c6..4a18708fba 100644
--- a/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php
+++ b/tests/PHPStan/Rules/Functions/data/arrow-functions-return-type.php
@@ -33,15 +33,3 @@ public function doBar(): void
 }
 
 static fn (int $value): iterable => yield $value;
-
-class Baz
-{
-
-	public function doFoo(): void
-	{
-		$f = fn () => throw new \Exception();
-		$g = fn (): never => throw new \Exception();
-		$g = fn (): never => 1;
-	}
-
-}
diff --git a/tests/PHPStan/Rules/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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\Methods;
-
-use PHPStan\Php\PhpVersion;
-use PHPStan\Rules\FunctionCallParametersCheck;
-use PHPStan\Rules\NullsafeCheck;
-use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper;
-use PHPStan\Rules\Properties\PropertyReflectionFinder;
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleLevelHelper;
-use PHPStan\Testing\RuleTestCase;
-use const PHP_VERSION_ID;
-
-/**
- * @extends RuleTestCase<CallMethodsRule>
- */
-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<int, int>, GenericsInferCollection\ArrayCollection<int, string> 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<int, int>, GenericsInferCollection\ArrayCollection<int, string> 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 3f29976a12..b5565f4d40 100644
--- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
@@ -1595,6 +1595,10 @@ public function dataExplicitMixed(): array
 	 */
 	public function testExplicitMixed(bool $checkExplicitMixed, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkThisOnly = false;
 		$this->checkNullables = true;
 		$this->checkUnionTypes = true;
@@ -2708,6 +2712,10 @@ public function testBug1517(): void
 
 	public function testBug7593(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkThisOnly = false;
 		$this->checkNullables = true;
 		$this->checkUnionTypes = true;
@@ -3088,6 +3096,10 @@ public function testObjectShapes(): void
 
 	public function testBug9951(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkThisOnly = false;
 		$this->checkNullables = true;
 		$this->checkUnionTypes = true;
diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php
index 27718dc9c7..d46969bdf3 100644
--- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php
@@ -758,6 +758,10 @@ public function dataMixed(): array
 	 */
 	public function testMixed(bool $checkExplicitMixed, bool $checkImplicitMixed, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkThisOnly = false;
 		$this->checkExplicitMixed = $checkExplicitMixed;
 		$this->checkImplicitMixed = $checkImplicitMixed;
diff --git a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php
index b86302f453..f4a561e097 100644
--- a/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/ExistingClassesInTypehintsRuleTest.php
@@ -362,6 +362,10 @@ public function dataRequiredParameterAfterOptional(): array
 	 */
 	public function testRequiredParameterAfterOptional(int $phpVersionId, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->phpVersionId = $phpVersionId;
 		$this->analyse([__DIR__ . '/data/required-parameter-after-optional.php'], $errors);
 	}
@@ -429,26 +433,71 @@ public function testEnums(): void
 		]);
 	}
 
-	public function dataTrueTypes(): array
-	{
-		return [
-			[80200, []],
-		];
-	}
-
-	/**
-	 * @dataProvider dataTrueTypes
-	 * @param list<array{0: string, 1: int, 2?: string}> $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() 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 +513,10 @@ public function testBug7519(): void
 
 	public function testTemplateInParamOut(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/param-out.php'], [
 			[
 				'Template type T of method ParamOutTemplate\FooBar::uselessLocalTemplate() is not referenced in a parameter.',
diff --git a/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php b/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php
index e55eb6eede..0f6d5b81f1 100644
--- a/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/IncompatibleDefaultParameterTypeRuleTest.php
@@ -4,6 +4,7 @@
 
 use PHPStan\Rules\Rule;
 use PHPStan\Testing\RuleTestCase;
+use const PHP_VERSION_ID;
 
 /**
  * @extends RuleTestCase<IncompatibleDefaultParameterTypeRule>
@@ -75,6 +76,10 @@ public function testDefaultValueForPromotedProperty(): void
 
 	public function testBug10956(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/bug-10956.php'], []);
 	}
 
diff --git a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php
index 826586689a..75f9465e74 100644
--- a/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/OverridingMethodRuleTest.php
@@ -238,6 +238,10 @@ public function testParameterContravariance(
 		array $expectedErrors,
 	): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->phpVersionId = $phpVersion;
 		$this->analyse([$file], $expectedErrors);
 	}
diff --git a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php
index 6303bdcdc4..f080bd4be8 100644
--- a/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/ReturnTypeRuleTest.php
@@ -283,8 +283,31 @@ public function testReturnTypeRule(): void
 		]);
 	}
 
+	public function testMisleadingMixedType(): void
+	{
+		if (PHP_VERSION_ID >= 80000) {
+			$errors = [];
+		} else {
+			$errors = [
+				[
+					'Method MethodMisleadingMixedReturn\Foo::misleadingMixedReturnType() should return MethodMisleadingMixedReturn\mixed but returns int.',
+					11,
+				],
+				[
+					'Method MethodMisleadingMixedReturn\Foo::misleadingMixedReturnType() should return MethodMisleadingMixedReturn\mixed but returns true.',
+					14,
+				],
+			];
+		}
+		$this->analyse([__DIR__ . '/data/method-misleading-mixed-return.php'], $errors);
+	}
+
 	public function testMisleadingTypehintsInClassWithoutNamespace(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/misleadingTypehints.php'], [
 			[
 				'Method FooWithoutNamespace::misleadingBoolReturnType() should return boolean but returns true.',
@@ -522,6 +545,10 @@ public function testBug2573(): void
 
 	public function testBug4603(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->analyse([__DIR__ . '/data/bug-4603.php'], []);
 	}
 
@@ -774,6 +801,10 @@ public function testBug6358(): void
 
 	public function testBug8071(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = true;
 		$this->analyse([__DIR__ . '/data/bug-8071.php'], [
 			[
diff --git a/tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php b/tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php
new file mode 100644
index 0000000000..e7c1b2141a
--- /dev/null
+++ b/tests/PHPStan/Rules/Methods/data/method-misleading-mixed-return.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace MethodMisleadingMixedReturn;
+
+class Foo
+{
+
+	public function misleadingMixedReturnType(): mixed
+	{
+		if (rand(0, 1)) {
+			return 1;
+		}
+		if (rand(0, 1)) {
+			return true;
+		}
+		if (rand(0, 1)) {
+			return new mixed();
+		}
+	}
+
+}
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/Missing/MissingReturnRuleTest.php b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php
index ad9fc94be5..533ad774eb 100644
--- a/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php
+++ b/tests/PHPStan/Rules/Missing/MissingReturnRuleTest.php
@@ -265,6 +265,10 @@ public function dataCheckPhpDocMissingReturn(): array
 	 */
 	public function testCheckPhpDocMissingReturn(bool $checkPhpDocMissingReturn, array $errors): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixedMissingReturn = true;
 		$this->checkPhpDocMissingReturn = $checkPhpDocMissingReturn;
 		$this->analyse([__DIR__ . '/data/check-phpdoc-missing-return.php'], $errors);
@@ -287,6 +291,10 @@ public function dataModelMixin(): array
 	 */
 	public function testModelMixin(bool $checkExplicitMixedMissingReturn): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixedMissingReturn = $checkExplicitMixedMissingReturn;
 		$this->checkPhpDocMissingReturn = true;
 		$this->analyse([__DIR__ . '/../../Analyser/nsrt/model-mixin.php'], [
diff --git a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php
index 41c947e937..190b83798b 100644
--- a/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php
+++ b/tests/PHPStan/Rules/Operators/InvalidBinaryOperationRuleTest.php
@@ -306,6 +306,10 @@ public function testBug5309(): void
 
 	public function testBinaryMixed(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = true;
 		$this->checkImplicitMixed = true;
 		$this->analyse([__DIR__ . '/data/invalid-binary-mixed.php'], [
diff --git a/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php
index 5042bb336c..a70d03a6e7 100644
--- a/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php
+++ b/tests/PHPStan/Rules/Operators/InvalidIncDecOperationRuleTest.php
@@ -5,6 +5,7 @@
 use PHPStan\Rules\Rule;
 use PHPStan\Rules\RuleLevelHelper;
 use PHPStan\Testing\RuleTestCase;
+use const PHP_VERSION_ID;
 
 /**
  * @extends RuleTestCase<InvalidIncDecOperationRule>
@@ -69,6 +70,10 @@ public function testRule(): void
 
 	public function testMixed(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkExplicitMixed = true;
 		$this->checkImplicitMixed = true;
 		$this->analyse([__DIR__ . '/data/invalid-inc-dec-mixed.php'], [
diff --git a/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php b/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php
index 2475fa3a80..ddc41ed337 100644
--- a/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php
+++ b/tests/PHPStan/Rules/Operators/InvalidUnaryOperationRuleTest.php
@@ -5,6 +5,7 @@
 use PHPStan\Rules\Rule;
 use PHPStan\Rules\RuleLevelHelper;
 use PHPStan\Testing\RuleTestCase;
+use const PHP_VERSION_ID;
 
 /**
  * @extends RuleTestCase<InvalidUnaryOperationRule>
@@ -96,6 +97,10 @@ public function testRule(): void
 
 	public function testMixed(): void
 	{
+		if (PHP_VERSION_ID < 80000) {
+			self::markTestSkipped('Test requires PHP 8.0.');
+		}
+
 		$this->checkImplicitMixed = true;
 		$this->checkExplicitMixed = true;
 		$this->analyse([__DIR__ . '/data/invalid-unary-mixed.php'], [
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<InvalidPHPStanDocTagRule>
@@ -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<array{0: string, 1: int, 2?: string}> $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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\PhpDoc;
-
-use PHPStan\PhpDocParser\Lexer\Lexer;
-use PHPStan\PhpDocParser\Parser\PhpDocParser;
-use PHPStan\Rules\Rule;
-use PHPStan\Testing\RuleTestCase;
-use function array_merge;
-
-/**
- * @extends RuleTestCase<InvalidPhpDocTagValueRule>
- */
-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<array{0: string, 1: int, 2?: string}> $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..405e3668a8 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<InvalidPhpDocTagValueRule>
@@ -14,21 +13,18 @@
 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 +93,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<array{0: string, 1: int, 2?: string}> $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,7 +122,6 @@ public function testInvalidTypeInTypeAlias(): void
 
 	public function testIgnoreWithinPhpDoc(): void
 	{
-		$this->checkAllInvalidPhpDocs = true;
 		$this->analyse([__DIR__ . '/data/ignore-line-within-phpdoc.php'], []);
 	}
 
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<FunctionNeverRule>
@@ -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<MethodNeverRule>
@@ -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/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/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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\Properties;
-
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleLevelHelper;
-use PHPStan\Testing\RuleTestCase;
-
-/**
- * @extends RuleTestCase<TypesAssignedToPropertiesRule>
- */
-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<int, int>) does not accept GenericObjectUnspecifiedTemplateTypes\ArrayCollection<int, string>.',
-				67,
-			],
-		]);
-	}
-
-	public function testGenericObjectWithUnspecifiedTemplateTypesLevel8(): void
-	{
-		$this->checkExplicitMixed = false;
-		$this->analyse([__DIR__ . '/data/generic-object-unspecified-template-types.php'], [
-			[
-				'Property GenericObjectUnspecifiedTemplateTypes\Bar::$ints (GenericObjectUnspecifiedTemplateTypes\ArrayCollection<int, int>) does not accept GenericObjectUnspecifiedTemplateTypes\ArrayCollection<int, string>.',
-				67,
-			],
-		]);
-	}
-
-	public static function getAdditionalConfigFiles(): array
-	{
-		// no bleeding edge
-		return [];
-	}
-
-}
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 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Rules\Variables;
-
-use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleLevelHelper;
-use PHPStan\Testing\RuleTestCase;
-use const PHP_VERSION_ID;
-
-/**
- * @extends RuleTestCase<ThrowTypeRule>
- */
-class ThrowTypeRuleTest extends RuleTestCase
-{
-
-	protected function getRule(): Rule
-	{
-		return new ThrowTypeRule(new RuleLevelHelper($this->createReflectionProvider(), true, false, true, false, false, true, false));
-	}
-
-	public function testRule(): void
-	{
-		$this->analyse(
-			[__DIR__ . '/data/throw-values.php'],
-			[
-				[
-					'Invalid type int to throw.',
-					29,
-				],
-				[
-					'Invalid type ThrowValues\InvalidException to throw.',
-					32,
-				],
-				[
-					'Invalid type ThrowValues\InvalidInterfaceException to throw.',
-					35,
-				],
-				[
-					'Invalid type Exception|null to throw.',
-					38,
-				],
-				[
-					'Throwing object of an unknown class ThrowValues\NonexistentClass.',
-					44,
-					'Learn more at https://phpstan.org/user-guide/discovering-symbols',
-				],
-			],
-		);
-	}
-
-	public function testClassExists(): void
-	{
-		$this->analyse([__DIR__ . '/data/throw-class-exists.php'], []);
-	}
-
-	public function testRuleWithNullsafeVariant(): void
-	{
-		if (PHP_VERSION_ID < 80000) {
-			$this->markTestSkipped('Test requires PHP 8.0.');
-		}
-
-		$this->analyse([__DIR__ . '/data/throw-values-nullsafe.php'], [
-			[
-				'Invalid type Exception|null to throw.',
-				17,
-			],
-		]);
-	}
-
-}
diff --git a/tests/PHPStan/Rules/Variables/data/throw-class-exists.php b/tests/PHPStan/Rules/Variables/data/throw-class-exists.php
deleted file mode 100644
index f819307398..0000000000
--- a/tests/PHPStan/Rules/Variables/data/throw-class-exists.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-namespace ThrowClassExists;
-
-use function class_exists;
-
-class Foo
-{
-
-	public function doFoo(): void
-	{
-		if (!class_exists(Bar::class)) {
-			return;
-		}
-
-		throw new Bar();
-	}
-
-}
diff --git a/tests/PHPStan/Rules/Variables/data/throw-values-nullsafe.php b/tests/PHPStan/Rules/Variables/data/throw-values-nullsafe.php
deleted file mode 100644
index 24ace167df..0000000000
--- a/tests/PHPStan/Rules/Variables/data/throw-values-nullsafe.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php // lint >= 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 @@
-<?php
-
-namespace ThrowValues;
-
-class InvalidException {};
-interface InvalidInterfaceException {};
-interface ValidInterfaceException extends \Throwable {};
-
-/**
- * @template T of \Exception
- * @param class-string<T> $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;
-};