diff --git a/.github/workflows/php-static-analysis.yml b/.github/workflows/php-static-analysis.yml new file mode 100644 index 0000000000000..9b15ee6f9f0fe --- /dev/null +++ b/.github/workflows/php-static-analysis.yml @@ -0,0 +1,100 @@ +name: PHPStan Static Analysis + +on: + # PHPStan testing was introduced in @todo. + push: + branches: + - trunk + - '6.9' + - '[7-9].[0-9]' + tags: + - '6.9' + - '6.9.[0-9]+' + - '[7-9].[0-9]' + - '[7-9]+.[0-9].[0-9]+' + pull_request: + branches: + - trunk + - '6.9' + - '[7-9].[0-9]' + paths: + # This workflow only scans PHP files. + - '**.php' + # These files configure Composer. Changes could affect the outcome. + - 'composer.*' + # These files configure PHPStan. Changes could affect the outcome. + - 'phpstan.neon.dist' + - 'tests/phpstan/base.neon' + # Confirm any changes to relevant workflow files. + - '.github/workflows/php-static-analysis.yml' + - '.github/workflows/reusable-php-static-analysis.yml' + workflow_dispatch: + +# Cancels all previous workflow runs for pull requests that have not completed. +concurrency: + # The concurrency group contains the workflow name and the branch name for pull requests + # or the commit hash for any other events. + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Runs PHPStan Static Analysis. + phpstan: + name: PHP coding standards + uses: ./.github/workflows/reusable-php-static-analysis.yml + permissions: + contents: read + if: ${{ github.repository == 'WordPress/wordpress-develop' || ( github.event_name == 'pull_request' && github.actor != 'dependabot[bot]' ) }} + + slack-notifications: + name: Slack Notifications + uses: ./.github/workflows/slack-notifications.yml + permissions: + actions: read + contents: read + needs: [ phpstan ] + if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} + with: + calling_status: ${{ contains( needs.*.result, 'cancelled' ) && 'cancelled' || contains( needs.*.result, 'failure' ) && 'failure' || 'success' }} + secrets: + SLACK_GHA_SUCCESS_WEBHOOK: ${{ secrets.SLACK_GHA_SUCCESS_WEBHOOK }} + SLACK_GHA_CANCELLED_WEBHOOK: ${{ secrets.SLACK_GHA_CANCELLED_WEBHOOK }} + SLACK_GHA_FIXED_WEBHOOK: ${{ secrets.SLACK_GHA_FIXED_WEBHOOK }} + SLACK_GHA_FAILURE_WEBHOOK: ${{ secrets.SLACK_GHA_FAILURE_WEBHOOK }} + + failed-workflow: + name: Failed workflow tasks + runs-on: ubuntu-24.04 + permissions: + actions: write + needs: [ slack-notifications ] + if: | + always() && + github.repository == 'WordPress/wordpress-develop' && + github.event_name != 'pull_request' && + github.run_attempt < 2 && + ( + contains( needs.*.result, 'cancelled' ) || + contains( needs.*.result, 'failure' ) + ) + + steps: + - name: Dispatch workflow run + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + retries: 2 + retry-exempt-status-codes: 418 + script: | + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'failed-workflow.yml', + ref: 'trunk', + inputs: { + run_id: `${context.runId}`, + } + }); diff --git a/.github/workflows/reusable-php-static-analysis.yml b/.github/workflows/reusable-php-static-analysis.yml new file mode 100644 index 0000000000000..5e8d592ed2c62 --- /dev/null +++ b/.github/workflows/reusable-php-static-analysis.yml @@ -0,0 +1,95 @@ +## +# A reusable workflow that runs PHP Static Analysis tests. +## +name: PHP Static Analysis + +on: + workflow_call: + inputs: + php-version: + description: 'The PHP version to use.' + required: false + type: 'string' + default: 'latest' + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Runs PHP static analysis tests. + # + # Violations are reported inline with annotations. + # + # Performs the following steps: + # - Checks out the repository. + # - Sets up PHP. + # - Logs debug information. + # - Installs Composer dependencies. + # - Configures caching for PHP static analysis scans. + # - Make Composer packages available globally. + # - Runs PHPStan static analysis (with Pull Request annotations). + # - Saves the PHPStan result cache. + # - Ensures version-controlled files are not modified or deleted. + phpstan: + name: Run PHP static analysis + runs-on: ubuntu-24.04 + permissions: + contents: read + timeout-minutes: 20 + + steps: + - name: Checkout repository + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false + + - name: Set up PHP + uses: shivammathur/setup-php@20529878ed81ef8e78ddf08b480401e6101a850f # v2.35.3 + with: + php-version: ${{ inputs.php-version }} + coverage: none + tools: cs2pr + + - name: Log debug information + run: | + composer --version + + # This date is used to ensure that the Composer cache is cleared at least once every week. + # http://man7.org/linux/man-pages/man1/date.1.html + - name: "Get last Monday's date" + id: get-date + run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> "$GITHUB_OUTPUT" + + # Since Composer dependencies are installed using `composer update` and no lock file is in version control, + # passing a custom cache suffix ensures that the cache is flushed at least once per week. + - name: Install Composer dependencies + uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3.1.1 + with: + custom-cache-suffix: ${{ steps.get-date.outputs.date }} + + - name: Make Composer packages available globally + run: echo "${PWD}/vendor/bin" >> "$GITHUB_PATH" + + - name: Cache PHP Static Analysis scan cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: .cache # This is defined in the base.neon file. + key: "phpstan-result-cache-${{ github.run_id }}" + restore-keys: | + phpstan-result-cache- + + - name: Run PHP static analysis tests + id: phpstan + run: phpstan analyse -vvv --error-format=checkstyle | cs2pr + + - name: "Save result cache" + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + if: ${{ !cancelled() }} + with: + path: .cache + key: "phpstan-result-cache-${{ github.run_id }}" + + - name: Ensure version-controlled files are not modified or deleted + run: git diff --exit-code diff --git a/.gitignore b/.gitignore index 01314e1a67139..ed8ecebd0f3e5 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ wp-tests-config.php /build /tests/phpunit/build /wp-cli.local.yml +/phpstan.neon /jsdoc /composer.lock /vendor diff --git a/composer.json b/composer.json index c636b2e7e680f..07b84ee4add17 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "squizlabs/php_codesniffer": "3.13.2", "wp-coding-standards/wpcs": "~3.2.0", "phpcompatibility/phpcompatibility-wp": "~2.1.3", + "phpstan/phpstan": "~1.12.32", "yoast/phpunit-polyfills": "^1.1.0" }, "config": { @@ -32,6 +33,7 @@ "lock": false }, "scripts": { + "analyse": "@php ./vendor/bin/phpstan analyse --memory-limit=2G", "compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source", "format": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf --report=summary,source", "lint": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --report=summary,source", diff --git a/package.json b/package.json index 7e2bab7284f68..b3a46f4f09dd6 100644 --- a/package.json +++ b/package.json @@ -192,6 +192,7 @@ "env:logs": "node ./tools/local-env/scripts/docker.js logs", "env:pull": "node ./tools/local-env/scripts/docker.js pull", "test:performance": "wp-scripts test-playwright --config tests/performance/playwright.config.js", + "test:php:stan": "node ./tools/local-env/scripts/docker.js run --rm php ./vendor/bin/phpstan analyse --memory-limit=2G", "test:php": "node ./tools/local-env/scripts/docker.js run --rm php ./vendor/bin/phpunit", "test:coverage": "npm run test:php -- --coverage-html ./coverage/html/ --coverage-php ./coverage/php/report.php --coverage-text=./coverage/text/report.txt", "test:e2e": "wp-scripts test-playwright --config tests/e2e/playwright.config.js", diff --git a/phpcs.xml.dist b/phpcs.xml.dist index a8387b3604c9b..efb679fb6c13b 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -81,6 +81,9 @@ /tests/phpunit/build* /tests/phpunit/data/* + + /tests/phpstan/* + /tools/* diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000000000..2bffeb442454f --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,35 @@ +# PHPStan configuration for WordPress Core. +# +# To overload this configuration, copy this file to phpstan.neon and adjust as needed. +# +# https://phpstan.org/config-reference + +includes: + # The WordPress Core configuration file includes the base configuration for the WordPress codebase. + - tests/phpstan/base.neon + # The baseline file includes preexisting errors in the codebase that should be ignored. + # https://phpstan.org/user-guide/baseline + - tests/phpstan/baseline.php + +parameters: + # https://phpstan.org/user-guide/rule-levels + level: 0 + reportUnmatchedIgnoredErrors: false + + ignoreErrors: + # Level 0: + - # Inner functions arent supported by PHPstan. + message: '#Function wxr_[a-z_]+ not found#' + path: src/wp-admin/includes/export.php + - + identifier: function.inner + path: src/wp-admin/includes/export.php + count: 13 + - + identifier: function.inner + path: src/wp-admin/includes/file.php + count: 1 + - + identifier: function.inner + path: src/wp-includes/canonical.php + count: 1 diff --git a/src/wp-admin/includes/class-wp-filesystem-ssh2.php b/src/wp-admin/includes/class-wp-filesystem-ssh2.php index 9e0cb885b0bcc..30bd38c3cf2f2 100644 --- a/src/wp-admin/includes/class-wp-filesystem-ssh2.php +++ b/src/wp-admin/includes/class-wp-filesystem-ssh2.php @@ -672,6 +672,7 @@ public function size( $file ) { * Default 0. */ public function touch( $file, $time = 0, $atime = 0 ) { + // @phpstan-ignore-next-line // Not implemented. } diff --git a/src/wp-admin/press-this.php b/src/wp-admin/press-this.php index c91df1c96b84b..45021964364a3 100644 --- a/src/wp-admin/press-this.php +++ b/src/wp-admin/press-this.php @@ -22,8 +22,8 @@ function wp_load_press_this() { 403 ); } elseif ( is_plugin_active( $plugin_file ) ) { - include WP_PLUGIN_DIR . '/press-this/class-wp-press-this-plugin.php'; - $wp_press_this = new WP_Press_This_Plugin(); + include WP_PLUGIN_DIR . '/press-this/class-wp-press-this-plugin.php'; // @phpstan-ignore include.fileNotFound + $wp_press_this = new WP_Press_This_Plugin(); // @phpstan-ignore class.notFound $wp_press_this->html(); } elseif ( current_user_can( 'activate_plugins' ) ) { if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_file ) ) { diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 598f3ba918536..1e91fd3c39876 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -3365,7 +3365,7 @@ public function get_svg_filters( $origins ) { * @param array $theme_json The theme.json like structure to inspect. * @param array $path Path to inspect. * @param bool|array $override Data to compute whether to override the preset. - * @return bool + * @return bool|null True if the preset should override the defaults, false if not. Null if the override parameter is invalid. */ protected static function should_override_preset( $theme_json, $path, $override ) { _deprecated_function( __METHOD__, '6.0.0', 'get_metadata_boolean' ); @@ -3400,6 +3400,8 @@ protected static function should_override_preset( $theme_json, $path, $override return true; } + + return null; } /** diff --git a/src/wp-includes/customize/class-wp-customize-background-image-setting.php b/src/wp-includes/customize/class-wp-customize-background-image-setting.php index f56810e6aab4b..641540660c45d 100644 --- a/src/wp-includes/customize/class-wp-customize-background-image-setting.php +++ b/src/wp-includes/customize/class-wp-customize-background-image-setting.php @@ -28,6 +28,7 @@ final class WP_Customize_Background_Image_Setting extends WP_Customize_Setting { * @since 3.4.0 * * @param mixed $value The value to update. Not used. + * @return bool|void Nothing is returned. */ public function update( $value ) { remove_theme_mod( 'background_image_thumb' ); diff --git a/src/wp-includes/customize/class-wp-customize-filter-setting.php b/src/wp-includes/customize/class-wp-customize-filter-setting.php index ad70f4f853288..cf0ce2b2fb7ab 100644 --- a/src/wp-includes/customize/class-wp-customize-filter-setting.php +++ b/src/wp-includes/customize/class-wp-customize-filter-setting.php @@ -24,6 +24,7 @@ class WP_Customize_Filter_Setting extends WP_Customize_Setting { * @since 3.4.0 * * @param mixed $value The value to update. + * @return bool|void Nothing is returned. */ public function update( $value ) {} } diff --git a/src/wp-includes/customize/class-wp-customize-header-image-setting.php b/src/wp-includes/customize/class-wp-customize-header-image-setting.php index 80333a54128af..cdf5128322717 100644 --- a/src/wp-includes/customize/class-wp-customize-header-image-setting.php +++ b/src/wp-includes/customize/class-wp-customize-header-image-setting.php @@ -32,6 +32,7 @@ final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting { * @global Custom_Image_Header $custom_image_header * * @param mixed $value The value to update. + * @return bool|void Nothing is returned. */ public function update( $value ) { global $custom_image_header; diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index be41add6590b6..36fe095cb8394 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -4118,7 +4118,7 @@ function get_taxonomies_for_attachments( $output = 'names' ) { * false otherwise. */ function is_gd_image( $image ) { - if ( $image instanceof GdImage + if ( $image instanceof GdImage // @phpstan-ignore class.notFound (Only available with PHP8+.) || is_resource( $image ) && 'gd' === get_resource_type( $image ) ) { return true; diff --git a/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php b/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php index 4a82f28b8a41e..4cc7546cf39e5 100644 --- a/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php +++ b/src/wp-includes/style-engine/class-wp-style-engine-css-rules-store.php @@ -56,6 +56,7 @@ public static function get_store( $store_name = 'default' ) { return; } if ( ! isset( static::$stores[ $store_name ] ) ) { + // @phpstan-ignore new.static (In PHPStan 2.x we can enforce with `@phpstan-consistent-constructor`) static::$stores[ $store_name ] = new static(); // Set the store name. static::$stores[ $store_name ]->set_name( $store_name ); diff --git a/src/wp-includes/template.php b/src/wp-includes/template.php index 81b35fadf4883..3eda413710494 100644 --- a/src/wp-includes/template.php +++ b/src/wp-includes/template.php @@ -796,7 +796,7 @@ function load_template( $_template_file, $load_once = true, $args = array() ) { } if ( isset( $s ) ) { - $s = esc_attr( $s ); + $s = esc_attr( $s ); // @phpstan-ignore variable.undefined (It's extracted from query vars.) } /** diff --git a/tests/phpstan/README.md b/tests/phpstan/README.md new file mode 100644 index 0000000000000..8776ba37e6f8d --- /dev/null +++ b/tests/phpstan/README.md @@ -0,0 +1,84 @@ +# PHPStan + +PHPStan is a static analysis tool for PHP that checks your code for errors without needing to execute the specific lines or write extra tests. + +## Running the tests + +PHPStan requires PHP and Composer dependencies to be installed. + +If you don't already have an environment ready, you can set one up by following [these instructions](https://github.com/WordPress/wordpress-develop/blob/master/README.md). + +Then you can launch the tests by running: + +``` +npm run test:php:stan +``` + +which will run PHPStan in the Docker container. + +Additional flags supported by PHPStan can be passed by passing `--` followed by the flags themselves. For example, + +``` +# to increase the memory limit from the default 2G to 4G: +npm run test:php:stan -- --memory-limit=4G + +# to analyse only a specific file: +npm run test:php:stan -- tests/phpstan/src/wp-includes/template.php + +# To scan with verbose debugging output: +npm run test:php:stan -- -vvv --debug + +``` + +If you are not using the Docker environment, you can run PHPStan via Composer directly: + +``` +composer run analyse + +compose run analyse -- --memory-limit=4G +compose run analyse -- tests/phpstan/src/wp-includes/template.php +compose run analyse -- -vvv --debug +``` + +For available flags, see https://phpstan.org/user-guide/command-line-usage. + +## The PHPStan configuration + +The PHPStan configuration file is located at [`phpstan.neon.dist`](../../phpstan.neon.dist). + +You can create a local copy at `phpstan.neon` to override the default configuration. + +For more information about configuring PHPStan, see the [PHPStan documentation's Config reference](https://phpstan.org/config-reference). + +## Ignoring errors + +As we adopt PHPStan iteratively, you may be faced with false positives due to legacy code, or code that is not worth changing at this time. + +PHPStan errors can be ignored in the following ways: + +- Using the `@phpstan-ignore {error-identifier} (Reason for ignoring)` annotation in the code. This should be used when addressing false positives. + +- Adding the error pattern to the `ignoreErrors` section of the `phpstan.neon` configuration file. This should be used when addressing conflicts between WordPress coding standards, or legacy code that is not worth refactoring just to satisfy the tests. + +- Adding an error to the "tech debt" baseline. This should be used for code that needs to be addressed eventually - by fixing, refactoring, or ignoring via one of the above methods - but is not worth addressing right now. + + Baselines are a useful triage tool for handling PHPStan errors in legacy code, as they allow us to enforce stricter code quality checks on new code, while gradually chipping away at the existing issues over time. You should avoid adding PHPStan errors from new code whenever possible. + + Baselining is done by running: + + ``` + npm run test:php:stan -- --generate-baseline=tests/phpstan/baseline.php + + # or, with Composer directly: + composer run analyse -- --generate-baseline=tests/phpstan/baseline.php + ``` + + This will regenerate the baseline file with any new errors added to the existing ones. You can then commit the updated baseline file. + +## Performance and troubleshooting + +PHPStan can be resource-intensive, especially on large codebases like WordPress. If you encounter memory limit issues, you can increase the memory limit by passing the `--memory-limit` flag as shown above. + +PHPStan caches analysis results to speed up subsequent runs. You can see information about the results cache by running `analyse` with the `-vv` flag. + +Sometimes, due to the lack of type information in legacy code, PHPStan may still struggle to analyse certain parts of the codebase. In such cases, you can use the `--debug` flag to disable caching and see which files are causing issues. diff --git a/tests/phpstan/base.neon b/tests/phpstan/base.neon new file mode 100644 index 0000000000000..92372d0e4ded9 --- /dev/null +++ b/tests/phpstan/base.neon @@ -0,0 +1,125 @@ +# Base PHPStan configuration for WordPress Core. +# +# This is kept separate from the main PHPStan configuration file to allow for easy overloading while baseline errors are being fixed. +# +# https://phpstan.org/config-reference + +parameters: + # Cache is stored locally, so it's available for CI. + tmpDir: ../../.cache + + # The Minimum PHP Version + phpVersion: 70224 + + # If it's not enforced by PHP we can't assume users are passing valid values. + treatPhpDocTypesAsCertain: false + + # These config options are explained in https://phpstan.org/config-reference + checkFunctionNameCase: true + inferPrivatePropertyTypeFromConstructor: true + + # Constants whose values may differ depending on the install. + dynamicConstantNames: + - ALLOW_SUBDIRECTORY_INSTALL + - AUTH_SALT + - AUTOMATIC_UPDATER_DISABLED + - COOKIEPATH + - CUSTOM_TAGS + - DISALLOW_FILE_EDIT + - DISALLOW_UNFILTERED_HTML + - EMPTY_TRASH_DAYS + - ENFORCE_GZIP + - FORCE_SSL_LOGIN + - MEDIA_TRASH + - MULTISITE + - NOBLOGREDIRECT + - SAVEQUERIES + - SCRIPT_DEBUG + - SECRET_KEY + - SECRET_SALT + - SHORTINIT + - SITECOOKIEPATH + - UPLOADBLOGSDIR + - WP_ALLOW_MULTISITE + - WP_CACHE + - WP_DEBUG + - WP_DEBUG_DISPLAY + - WP_DEBUG_LOG + - WP_LANG_DIR + - WP_NETWORK_ADMIN + - WP_POST_REVISIONS + - WP_SITEURL + - WP_USE_THEMES + - WP_USER_ADMIN + - WPLANG + - WPMU_ACCEL_REDIRECT + - WPMU_PLUGIN_DIR + - WPMU_SENDFILE + + # What directories and files should be scanned. + paths: + - ../../src + bootstrapFiles: + - bootstrap.php + scanFiles: + - ../../wp-config-sample.php + - ../../src/wp-admin/includes/ms.php + scanDirectories: + - ../../src/wp-includes + - ../../src/wp-admin + excludePaths: + analyseAndScan: + - ../../src/wp-admin/includes/noop.php + # These files are not part of the WordPress Core codebase. + - ../../src/wp-content + # JavaScript/CSS/Asset files. + - ../../src/wp-admin/css + - ../../src/wp-admin/images + # These are built from js/_enqueues. + - ../../src/wp-admin/js (?) + - ../../src/wp-includes/js (?) + analyse: + # These files are deprecated. + - ../../src/wp-admin/includes/deprecated.php + - ../../src/wp-admin/includes/ms-deprecated.php + - ../../src/wp-includes/deprecated.php + - ../../src/wp-includes/ms-deprecated.php + - ../../src/wp-includes/pluggable-deprecated.php + # These files are sourced by wordpress/gutenberg in `tools/release/sync-stable-blocks.js`. + - ../../src/wp-includes/blocks + # Third-party libraries. + - ../../src/js/_enqueues/vendor + - ../../src/wp-admin/includes/class-ftp-pure.php + - ../../src/wp-admin/includes/class-ftp-sockets.php + - ../../src/wp-admin/includes/class-ftp.php + - ../../src/wp-admin/includes/class-pclzip.php + - ../../src/wp-includes/atomlib.php + - ../../src/wp-includes/class-avif-info.php + - ../../src/wp-includes/class-IXR.php + - ../../src/wp-includes/class-json.php + - ../../src/wp-includes/class-phpass.php + - ../../src/wp-includes/class-pop3.php + - ../../src/wp-includes/class-requests.php + - ../../src/wp-includes/class-simplepie.php + - ../../src/wp-includes/class-snoopy.php + - ../../src/wp-includes/class-wp-feed-cache.php + - ../../src/wp-includes/class-wp-http-ixr-client.php + - ../../src/wp-includes/class-wp-http-requests-hooks.php + - ../../src/wp-includes/class-wp-http-requests-response.php + - ../../src/wp-includes/class-wp-simplepie-file.php + - ../../src/wp-includes/class-wp-simplepie-sanitize-kses.php + - ../../src/wp-includes/class-wp-text-diff-renderer-inline.php + - ../../src/wp-includes/class-wp-text-diff-renderer-table.php + - ../../src/wp-includes/rss.php + - ../../src/wp-includes/ID3 + - ../../src/wp-includes/IXR + - ../../src/wp-includes/PHPMailer + - ../../src/wp-includes/pomo + - ../../src/wp-includes/Requests + - ../../src/wp-includes/SimplePie + - ../../src/wp-includes/sodium_compat + - ../../src/wp-includes/Text + # Contains errors that cannot be ignored by PHPStan. + - ../../src/wp-includes/html-api/class-wp-html-processor.php + # Setting `$metadata['user_pass'] = ''` (https://core.trac.wordpress.org/ticket/22114) causes PHPStan to hang + - ../../src/wp-includes/user.php diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php new file mode 100644 index 0000000000000..646cbdbef630c --- /dev/null +++ b/tests/phpstan/baseline.php @@ -0,0 +1,3 @@ +