From 9b27a98d5bc5d864bc269639133348cf9d861d0c Mon Sep 17 00:00:00 2001 From: Chauncey McAskill Date: Wed, 15 Mar 2023 14:04:14 -0400 Subject: [PATCH] Add conditional baselines for PHPStan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the PHP version and installed package versions. Added conditionally included baselines for PHP 5–7 and 8+, Composer 1 and 2, Dotenv 3–5. This conditional functionality can be greatly reduced if we drop support for older versions of PHP, Composer, and other dependencies. To resolve these conditional baselines, we have to replace the initial data of {@see \Composer\InstalledVersions} which contains PHPStan's dependencies, since the context is its PHAR. To accomplish this, we have to retrieve the contents of the project's installed dependencies from either: 1. `vendor/composer/installed.php` — Composer v2 PHP format. 2. `vendor/composer/installed.json` — Either Composer v1 or v2 JSON format. The JSON format is tricky because it changes drastically between Composer v1 and v2 and the v2 PHP format. Both JSON formats must be remapped to the PHP format expected by `InstalledVersions`. If the project's installed dependencies cannot be loaded, this file returns only the PHP baselines. If the project's installed dependencies can be loaded, the extra baselines are resolved and the initial data of `InstalledVersions` is restored. --- build/baseline-composer-1.neon | 41 ++++++ build/baseline-composer-2.neon | 31 +++++ build/baseline-php-7.neon | 21 +++ build/baseline-php-8.neon | 16 +++ build/baseline-phpdotenv-3.neon | 11 ++ build/baseline-phpdotenv-4.neon | 16 +++ build/baseline-phpdotenv-5.neon | 11 ++ ...nore-errors-by-installed-versions.neon.php | 130 ++++++++++++++++++ phpstan.neon.dist | 2 + 9 files changed, 279 insertions(+) create mode 100644 build/baseline-composer-1.neon create mode 100644 build/baseline-composer-2.neon create mode 100644 build/baseline-php-7.neon create mode 100644 build/baseline-php-8.neon create mode 100644 build/baseline-phpdotenv-3.neon create mode 100644 build/baseline-phpdotenv-4.neon create mode 100644 build/baseline-phpdotenv-5.neon create mode 100644 build/ignore-errors-by-installed-versions.neon.php diff --git a/build/baseline-composer-1.neon b/build/baseline-composer-1.neon new file mode 100644 index 0000000..d0f72fd --- /dev/null +++ b/build/baseline-composer-1.neon @@ -0,0 +1,41 @@ +parameters: + ignoreErrors: + - + message: "#^Call to an undefined method Composer\\\\Plugin\\\\PreFileDownloadEvent\\:\\:getContext\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\Plugin\\\\PreFileDownloadEvent\\:\\:getType\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\Plugin\\\\PreFileDownloadEvent\\:\\:setCustomCacheKey\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\Plugin\\\\PreFileDownloadEvent\\:\\:setProcessedUrl\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\DependencyResolver\\\\Operation\\\\OperationInterface\\:\\:getPackage\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\DependencyResolver\\\\Operation\\\\OperationInterface\\:\\:getTargetPackage\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^If condition is always true\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: ../src/Installer.php \ No newline at end of file diff --git a/build/baseline-composer-2.neon b/build/baseline-composer-2.neon new file mode 100644 index 0000000..29fec9d --- /dev/null +++ b/build/baseline-composer-2.neon @@ -0,0 +1,31 @@ +parameters: + ignoreErrors: + - + message: "#^If condition is always false\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\DependencyResolver\\\\Operation\\\\OperationInterface\\:\\:getJobType\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\DependencyResolver\\\\Operation\\\\OperationInterface\\:\\:getPackage\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\DependencyResolver\\\\Operation\\\\OperationInterface\\:\\:getTargetPackage\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\Plugin\\\\PreFileDownloadEvent\\:\\:getRemoteFilesystem\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined method Composer\\\\Plugin\\\\PreFileDownloadEvent\\:\\:setRemoteFilesystem\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php \ No newline at end of file diff --git a/build/baseline-php-7.neon b/build/baseline-php-7.neon new file mode 100644 index 0000000..31636b9 --- /dev/null +++ b/build/baseline-php-7.neon @@ -0,0 +1,21 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$ch of function curl_close expects resource, CurlHandle\\|resource given\\.$#" + count: 1 + path: ../src/Http.php + + - + message: "#^Parameter \\#1 \\$ch of function curl_errno expects resource, CurlHandle\\|resource given\\.$#" + count: 1 + path: ../src/Http.php + + - + message: "#^Parameter \\#1 \\$ch of function curl_exec expects resource, CurlHandle\\|resource given\\.$#" + count: 1 + path: ../src/Http.php + + - + message: "#^Parameter \\$curl_handle of method Junaidbhura\\\\Composer\\\\WPProPlugins\\\\Http\\:\\:request\\(\\) has invalid type CurlHandle\\.$#" + count: 1 + path: ../src/Http.php \ No newline at end of file diff --git a/build/baseline-php-8.neon b/build/baseline-php-8.neon new file mode 100644 index 0000000..a87e960 --- /dev/null +++ b/build/baseline-php-8.neon @@ -0,0 +1,16 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$handle of function curl_close expects CurlHandle, CurlHandle\\|resource given\\.$#" + count: 1 + path: ../src/Http.php + + - + message: "#^Parameter \\#1 \\$handle of function curl_errno expects CurlHandle, CurlHandle\\|resource given\\.$#" + count: 1 + path: ../src/Http.php + + - + message: "#^Parameter \\#1 \\$handle of function curl_exec expects CurlHandle, CurlHandle\\|resource given\\.$#" + count: 1 + path: ../src/Http.php \ No newline at end of file diff --git a/build/baseline-phpdotenv-3.neon b/build/baseline-phpdotenv-3.neon new file mode 100644 index 0000000..59c56ea --- /dev/null +++ b/build/baseline-phpdotenv-3.neon @@ -0,0 +1,11 @@ +parameters: + ignoreErrors: + - + message: "#^Call to an undefined static method Dotenv\\\\Dotenv\\:\\:createImmutable\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Call to an undefined static method Dotenv\\\\Dotenv\\:\\:createUnsafeImmutable\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php \ No newline at end of file diff --git a/build/baseline-phpdotenv-4.neon b/build/baseline-phpdotenv-4.neon new file mode 100644 index 0000000..75af81f --- /dev/null +++ b/build/baseline-phpdotenv-4.neon @@ -0,0 +1,16 @@ +parameters: + ignoreErrors: + - + message: "#^Call to an undefined static method Dotenv\\\\Dotenv\\:\\:createUnsafeImmutable\\(\\)\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Parameter \\#1 \\$repository of static method Dotenv\\\\Dotenv\\:\\:create\\(\\) expects Dotenv\\\\Repository\\\\RepositoryInterface, string given\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Static method Dotenv\\\\Dotenv\\:\\:create\\(\\) invoked with 1 parameter, 2\\-4 required\\.$#" + count: 1 + path: ../src/Installer.php \ No newline at end of file diff --git a/build/baseline-phpdotenv-5.neon b/build/baseline-phpdotenv-5.neon new file mode 100644 index 0000000..539dd1d --- /dev/null +++ b/build/baseline-phpdotenv-5.neon @@ -0,0 +1,11 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$repository of static method Dotenv\\\\Dotenv\\:\\:create\\(\\) expects Dotenv\\\\Repository\\\\RepositoryInterface, string given\\.$#" + count: 1 + path: ../src/Installer.php + + - + message: "#^Static method Dotenv\\\\Dotenv\\:\\:create\\(\\) invoked with 1 parameter, 2\\-5 required\\.$#" + count: 1 + path: ../src/Installer.php \ No newline at end of file diff --git a/build/ignore-errors-by-installed-versions.neon.php b/build/ignore-errors-by-installed-versions.neon.php new file mode 100644 index 0000000..62b7f20 --- /dev/null +++ b/build/ignore-errors-by-installed-versions.neon.php @@ -0,0 +1,130 @@ += 80000 ) { + $config['includes'][] = __DIR__ . '/baseline-php-8.neon'; +} else { + $config['includes'][] = __DIR__ . '/baseline-php-7.neon'; +} + +$cwd = getcwd(); +if ( ! is_string( $cwd ) ) { + return $config; +} + +if ( file_exists( $cwd . '/vendor/composer/installed.php' ) ) { + $projectInstalled = require $cwd . '/vendor/composer/installed.php'; +} elseif ( file_exists( $cwd . '/vendor/composer/installed.json' ) ) { + $json = file_get_contents( $cwd . '/vendor/composer/installed.json' ); + if ( ! is_string( $json ) ) { + return $config; + } + + $installed = json_decode( $json, true ); + if ( ! is_array( $installed ) ) { + return $config; + } + + $projectInstalled = array( + 'root' => array(), + 'versions' => array(), + ); + + $packages = isset( $installed['packages'] ) ? $installed['packages'] : $installed; + + if ( is_array( $packages ) ) { + foreach ( $packages as $package ) { + $projectInstalled['versions'][ $package['name'] ] = array( + 'pretty_version' => $package['version'], + 'version' => $package['version_normalized'], + 'reference' => ( + isset( $package['dist']['reference'] ) + ? $package['dist']['reference'] + : ( + isset( $package['source']['reference'] ) + ? $package['source']['reference'] + : null + ) + ), + 'type' => $package['type'], + 'install_path' => ( + isset( $package['install-path'] ) + ? __DIR__ . '/' . $package['install-path'] + : null + ), + 'aliases' => ( + isset( $package['extra']['branch-alias'] ) + ? array_values( $package['extra']['branch-alias'] ) + : array() + ), + 'dev_requirement' => ( + isset( $installed['dev-package-names'] ) + ? in_array( $package['name'], $installed['dev-package-names'], true ) + : false + ), + ); + } + } +} + +if ( empty( $projectInstalled['versions'] ) ) { + return $config; +} + +$pharInstalled = InstalledVersions::getAllRawData(); +InstalledVersions::reload( $projectInstalled ); + +$versionParser = new VersionParser(); + +if ( InstalledVersions::isInstalled( 'composer/composer' ) ) { + if ( InstalledVersions::satisfies( $versionParser, 'composer/composer', '^1') ) { + $config['includes'][] = __DIR__ . '/baseline-composer-1.neon'; + } else { + $config['includes'][] = __DIR__ . '/baseline-composer-2.neon'; + } +} + +if ( InstalledVersions::isInstalled( 'vlucas/phpdotenv' ) ) { + if ( InstalledVersions::satisfies( $versionParser, 'vlucas/phpdotenv', '^3') ) { + $config['includes'][] = __DIR__ . '/baseline-phpdotenv-3.neon'; + } elseif ( InstalledVersions::satisfies( $versionParser, 'vlucas/phpdotenv', '^4') ) { + $config['includes'][] = __DIR__ . '/baseline-phpdotenv-4.neon'; + } else { + $config['includes'][] = __DIR__ . '/baseline-phpdotenv-5.neon'; + } +} + +InstalledVersions::reload( $pharInstalled ? end( $pharInstalled[0] ) : array() ); + +return $config; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 478362b..5cbfc7f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,3 +1,5 @@ +includes: + - build/ignore-errors-by-installed-versions.neon.php parameters: level: max paths: