diff --git a/.gitattributes b/.gitattributes index 48387724..45a67c45 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,6 +6,5 @@ tmp export-ignore .gitattributes export-ignore .gitignore export-ignore Makefile export-ignore -phpcs.xml export-ignore phpstan.neon export-ignore phpunit.xml export-ignore diff --git a/.github/renovate.json b/.github/renovate.json index b775cc18..d3f5961e 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -10,11 +10,6 @@ "enabled": true, "groupName": "root-composer" }, - { - "matchPaths": ["build-cs/**"], - "enabled": true, - "groupName": "build-cs" - }, { "matchPaths": [".github/**"], "enabled": true, diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba258b6c..0bb37b0d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: - name: "Lint" run: "make lint" - coding-standards: + coding-standard: name: "Coding Standard" runs-on: "ubuntu-latest" @@ -55,11 +55,17 @@ jobs: - name: "Checkout" uses: actions/checkout@v3 + - name: "Checkout build-cs" + uses: actions/checkout@v3 + with: + repository: "phpstan/build-cs" + path: "build-cs" + - name: "Install PHP" uses: "shivammathur/setup-php@v2" with: coverage: "none" - php-version: "8.0" + php-version: "8.2" - name: "Validate Composer" run: "composer validate" @@ -67,6 +73,10 @@ jobs: - name: "Install dependencies" run: "composer install --no-interaction --no-progress" + - name: "Install build-cs dependencies" + working-directory: "build-cs" + run: "composer install --no-interaction --no-progress" + - name: "Lint" run: "make lint" diff --git a/.gitignore b/.gitignore index 2db21315..7de9f3c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /tests/tmp +/build-cs /vendor /composer.lock .phpunit.result.cache diff --git a/Makefile b/Makefile index fe917d3b..a175843c 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,19 @@ lint: php vendor/bin/parallel-lint --colors \ src tests +.PHONY: cs-install +cs-install: + git clone https://github.com/phpstan/build-cs.git || true + git -C build-cs fetch origin && git -C build-cs reset --hard origin/main + composer install --working-dir build-cs + .PHONY: cs cs: - composer install --working-dir build-cs && php build-cs/vendor/bin/phpcs + php build-cs/vendor/bin/phpcs --standard=build-cs/phpcs.xml src tests .PHONY: cs-fix cs-fix: - php build-cs/vendor/bin/phpcbf + php build-cs/vendor/bin/phpcbf --standard=build-cs/phpcs.xml src tests .PHONY: phpstan phpstan: diff --git a/README.md b/README.md index 246c0c84..9dee7781 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ * Require calling parent constructor * Disallow usage of backtick operator (`` $ls = `ls -la` ``) * Closure should use `$this` directly instead of using `$this` variable indirectly +* Report useless casts +* Disallow explicit casting of potential `null` values (with [https://phpstan.org/blog/what-is-bleeding-edge](bleeding edge) enabled) Additional rules are coming in subsequent releases! @@ -65,6 +67,7 @@ parameters: disallowedLooseComparison: false booleansInConditions: false uselessCast: false + nullCast: false requireParentConstructorCall: false disallowedConstructs: false overwriteVariablesWithLoop: false diff --git a/build-cs/.gitignore b/build-cs/.gitignore deleted file mode 100644 index 61ead866..00000000 --- a/build-cs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/vendor diff --git a/build-cs/composer.json b/build-cs/composer.json deleted file mode 100644 index 16a240bc..00000000 --- a/build-cs/composer.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "require-dev": { - "consistence-community/coding-standard": "^3.11.0", - "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", - "slevomat/coding-standard": "^8.8.0", - "squizlabs/php_codesniffer": "^3.5.3" - }, - "config": { - "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true - } - } -} diff --git a/build-cs/composer.lock b/build-cs/composer.lock deleted file mode 100644 index b52da6f8..00000000 --- a/build-cs/composer.lock +++ /dev/null @@ -1,331 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "e69c1916405a7e3c8001c1b609a0ee61", - "packages": [], - "packages-dev": [ - { - "name": "consistence-community/coding-standard", - "version": "3.11.2", - "source": { - "type": "git", - "url": "https://github.com/consistence-community/coding-standard.git", - "reference": "adb4be482e76990552bf624309d2acc8754ba1bd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/consistence-community/coding-standard/zipball/adb4be482e76990552bf624309d2acc8754ba1bd", - "reference": "adb4be482e76990552bf624309d2acc8754ba1bd", - "shasum": "" - }, - "require": { - "php": "~8.0", - "slevomat/coding-standard": "~8.0", - "squizlabs/php_codesniffer": "~3.7.0" - }, - "replace": { - "consistence/coding-standard": "3.10.*" - }, - "require-dev": { - "phing/phing": "2.17.0", - "php-parallel-lint/php-parallel-lint": "1.3.1", - "phpunit/phpunit": "9.5.10" - }, - "type": "library", - "autoload": { - "psr-4": { - "Consistence\\": [ - "Consistence" - ] - }, - "classmap": [ - "Consistence" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "VaĊĦek Purchart", - "email": "me@vasekpurchart.cz", - "homepage": "http://vasekpurchart.cz" - } - ], - "description": "Consistence - Coding Standard - PHP Code Sniffer rules", - "keywords": [ - "Coding Standard", - "PHPCodeSniffer", - "codesniffer", - "coding", - "cs", - "phpcs", - "ruleset", - "sniffer", - "standard" - ], - "support": { - "issues": "https://github.com/consistence-community/coding-standard/issues", - "source": "https://github.com/consistence-community/coding-standard/tree/3.11.2" - }, - "time": "2022-06-21T08:36:36+00:00" - }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "*", - "ext-json": "*", - "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0", - "yoast/phpunit-polyfills": "^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcbf", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "source": "https://github.com/PHPCSStandards/composer-installer" - }, - "time": "2023-01-05T11:28:13+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.16.1", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" - }, - "time": "2023-02-07T18:11:17+00:00" - }, - { - "name": "slevomat/coding-standard", - "version": "8.9.0", - "source": { - "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "8f11e0f5ff984d6862bb9d83aa513dc05a1773ef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/8f11e0f5ff984d6862bb9d83aa513dc05a1773ef", - "reference": "8f11e0f5ff984d6862bb9d83aa513dc05a1773ef", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", - "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": ">=1.16.0 <1.17.0", - "squizlabs/php_codesniffer": "^3.7.1" - }, - "require-dev": { - "phing/phing": "2.17.4", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.4.10|1.10.8", - "phpstan/phpstan-deprecation-rules": "1.1.3", - "phpstan/phpstan-phpunit": "1.0.0|1.3.10", - "phpstan/phpstan-strict-rules": "1.5.0", - "phpunit/phpunit": "7.5.20|8.5.21|9.6.5" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-master": "8.x-dev" - } - }, - "autoload": { - "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", - "keywords": [ - "dev", - "phpcs" - ], - "support": { - "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.9.0" - }, - "funding": [ - { - "url": "https://github.com/kukulich", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", - "type": "tidelift" - } - ], - "time": "2023-03-25T15:52:37+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.7.2", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", - "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" - }, - "time": "2023-02-22T23:07:41+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.3.0" -} diff --git a/composer.json b/composer.json index 9cf4e652..83dbeb9e 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ ], "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.11" }, "require-dev": { "nikic/php-parser": "^4.13.0", diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index 95032a6e..00000000 --- a/phpcs.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - - src - tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10 - - - - - - 10 - - - - - - - - 10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tests/*/data - diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index 84faab10..00000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,478 +0,0 @@ - - -parameters: - ignoreErrors: - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanNotRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\BooleanNot\\) of method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanNotRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInElseIfConditionRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Stmt\\\\ElseIf_\\) of method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInElseIfConditionRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInIfConditionRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInIfConditionRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Stmt\\\\If_\\) of method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInIfConditionRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInIfConditionRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInTernaryOperatorRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\Ternary\\) of method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInTernaryOperatorRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Cast\\\\UselessCastRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Cast/UselessCastRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\Cast\\) of method PHPStan\\\\Rules\\\\Cast\\\\UselessCastRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/Cast/UselessCastRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Classes\\\\RequireParentConstructCallRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Classes/RequireParentConstructCallRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Stmt\\\\ClassMethod\\) of method PHPStan\\\\Rules\\\\Classes\\\\RequireParentConstructCallRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/Classes/RequireParentConstructCallRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedBacktickRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/DisallowedConstructs/DisallowedBacktickRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\Empty_\\) of method PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedBacktickRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/DisallowedConstructs/DisallowedBacktickRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedEmptyRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/DisallowedConstructs/DisallowedEmptyRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\Empty_\\) of method PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedEmptyRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/DisallowedConstructs/DisallowedEmptyRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedImplicitArrayCreationRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\Assign\\) of method PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedImplicitArrayCreationRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\ForeachLoop\\\\OverwriteVariablesWithForeachRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Stmt\\\\Foreach_\\) of method PHPStan\\\\Rules\\\\ForeachLoop\\\\OverwriteVariablesWithForeachRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticAdditionRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Operators/OperandsInArithmeticAdditionRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticDivisionRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Operators/OperandsInArithmeticDivisionRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticExponentiationRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Operators/OperandsInArithmeticExponentiationRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticModuloRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Operators/OperandsInArithmeticModuloRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticMultiplicationRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticSubtractionRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/Operators/OperandsInArithmeticSubtractionRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\StrictCalls\\\\DynamicCallOnStaticMethodsRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\MethodCall\\) of method PHPStan\\\\Rules\\\\StrictCalls\\\\DynamicCallOnStaticMethodsRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\StrictCalls\\\\StrictFunctionCallsRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/StrictCalls/StrictFunctionCallsRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\FuncCall\\) of method PHPStan\\\\Rules\\\\StrictCalls\\\\StrictFunctionCallsRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/StrictCalls/StrictFunctionCallsRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableMethodCallRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/VariableVariables/VariableMethodCallRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\MethodCall\\) of method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableMethodCallRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/VariableVariables/VariableMethodCallRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariablePropertyFetchRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/VariableVariables/VariablePropertyFetchRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\PropertyFetch\\) of method PHPStan\\\\Rules\\\\VariableVariables\\\\VariablePropertyFetchRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/VariableVariables/VariablePropertyFetchRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticMethodCallRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/VariableVariables/VariableStaticMethodCallRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\StaticCall\\) of method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticMethodCallRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/VariableVariables/VariableStaticMethodCallRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticPropertyFetchRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\StaticPropertyFetch\\) of method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticPropertyFetchRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableVariablesRule implements generic interface PHPStan\\\\Rules\\\\Rule but does not specify its types\\: TNodeType$#" - count: 1 - path: src/Rules/VariableVariables/VariableVariablesRule.php - - - - message: "#^Parameter \\#1 \\$node \\(PhpParser\\\\Node\\\\Expr\\\\Variable\\) of method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableVariablesRule\\:\\:processNode\\(\\) should be contravariant with parameter \\$node \\(PhpParser\\\\Node\\) of method PHPStan\\\\Rules\\\\Rule\\\\:\\:processNode\\(\\)$#" - count: 1 - path: src/Rules/VariableVariables/VariableVariablesRule.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanNotRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInBooleanNotRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInElseIfConditionRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInElseIfConditionRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInElseIfConditionRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInElseIfConditionRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInIfConditionRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInIfConditionRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInIfConditionRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInIfConditionRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInTernaryOperatorRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInTernaryOperatorRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\BooleansInConditions\\\\BooleanInTernaryOperatorRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/BooleansInConditions/BooleanInTernaryOperatorRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Cast\\\\UselessCastRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Cast/UselessCastRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Cast\\\\UselessCastRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Cast/UselessCastRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Classes\\\\RequireParentConstructCallRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Classes/RequireParentConstructCallRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Classes\\\\RequireParentConstructCallRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Classes/RequireParentConstructCallRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedBacktickRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/DisallowedConstructs/DisallowedBacktickRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedBacktickRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/DisallowedConstructs/DisallowedBacktickRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedEmptyRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/DisallowedConstructs/DisallowedEmptyRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedEmptyRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/DisallowedConstructs/DisallowedEmptyRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedImplicitArrayCreationRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\DisallowedConstructs\\\\DisallowedImplicitArrayCreationRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\ForeachLoop\\\\OverwriteVariablesWithForeachRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/ForeachLoop/OverwriteVariablesWithForeachRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\ForeachLoop\\\\OverwriteVariablesWithForeachRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/ForeachLoop/OverwriteVariablesWithForeachRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Methods\\\\WrongCaseOfInheritedMethodRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Methods/WrongCaseOfInheritedMethodRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Methods\\\\WrongCaseOfInheritedMethodRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Methods/WrongCaseOfInheritedMethodRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticIncrementOrDecrementRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticIncrementOrDecrementRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticIncrementOrDecrementRuleTest\\:\\:createRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticPostDecrementRuleTest\\:\\:createRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticPostDecrementRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticPostIncrementRuleTest\\:\\:createRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticPostIncrementRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticPreDecrementRuleTest\\:\\:createRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticPreDecrementRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandInArithmeticPreIncrementRuleTest\\:\\:createRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandInArithmeticPreIncrementRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticAdditionRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticAdditionRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticDivisionRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticDivisionRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticExponentiationRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticExponentiationRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticModuloRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticModuloRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticModuloRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticModuloRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticMultiplicationRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticMultiplicationRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticMultiplicationRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticMultiplicationRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticSubtractionRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticSubtractionRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\Operators\\\\OperandsInArithmeticSubtractionRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/Operators/OperandsInArithmeticSubtractionRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\StrictCalls\\\\DynamicCallOnStaticMethodsRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\StrictCalls\\\\DynamicCallOnStaticMethodsRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\StrictCalls\\\\StrictFunctionCallsRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/StrictCalls/StrictFunctionCallsRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\StrictCalls\\\\StrictFunctionCallsRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/StrictCalls/StrictFunctionCallsRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableMethodCallRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/VariableVariables/VariableMethodCallRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableMethodCallRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/VariableVariables/VariableMethodCallRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariablePropertyFetchRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/VariableVariables/VariablePropertyFetchRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\VariableVariables\\\\VariablePropertyFetchRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/VariableVariables/VariablePropertyFetchRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticMethodCallRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/VariableVariables/VariableStaticMethodCallRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticMethodCallRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/VariableVariables/VariableStaticMethodCallRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticPropertyFetchRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/VariableVariables/VariableStaticPropertyFetchRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableStaticPropertyFetchRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/VariableVariables/VariableStaticPropertyFetchRuleTest.php - - - - message: "#^Class PHPStan\\\\Rules\\\\VariableVariables\\\\VariableVariablesRuleTest extends generic class PHPStan\\\\Testing\\\\RuleTestCase but does not specify its types\\: TRule$#" - count: 1 - path: tests/Rules/VariableVariables/VariableVariablesRuleTest.php - - - - message: "#^Method PHPStan\\\\Rules\\\\VariableVariables\\\\VariableVariablesRuleTest\\:\\:getRule\\(\\) return type with generic interface PHPStan\\\\Rules\\\\Rule does not specify its types\\: TNodeType$#" - count: 1 - path: tests/Rules/VariableVariables/VariableVariablesRuleTest.php diff --git a/phpstan.neon b/phpstan.neon index f3caa84a..cc5bc263 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,7 +4,6 @@ includes: - vendor/phpstan/phpstan-phpunit/rules.neon - rules.neon - phar://phpstan.phar/conf/bleedingEdge.neon - - phpstan-baseline.neon parameters: excludePaths: diff --git a/rules.neon b/rules.neon index 46632c0c..ba0c7d07 100644 --- a/rules.neon +++ b/rules.neon @@ -20,6 +20,7 @@ parameters: disallowedLooseComparison: [%strictRules.allRules%, %featureToggles.bleedingEdge%] booleansInConditions: %strictRules.allRules% uselessCast: %strictRules.allRules% + nullCast: [%strictRules.allRules%, %featureToggles.bleedingEdge%] requireParentConstructorCall: %strictRules.allRules% disallowedConstructs: %strictRules.allRules% overwriteVariablesWithLoop: %strictRules.allRules% @@ -36,6 +37,7 @@ parametersSchema: disallowedLooseComparison: anyOf(bool(), arrayOf(bool())), booleansInConditions: anyOf(bool(), arrayOf(bool())) uselessCast: anyOf(bool(), arrayOf(bool())) + nullCast: anyOf(bool(), arrayOf(bool())) requireParentConstructorCall: anyOf(bool(), arrayOf(bool())) disallowedConstructs: anyOf(bool(), arrayOf(bool())) overwriteVariablesWithLoop: anyOf(bool(), arrayOf(bool())) @@ -64,6 +66,8 @@ conditionalTags: phpstan.rules.rule: %strictRules.booleansInConditions% PHPStan\Rules\Cast\UselessCastRule: phpstan.rules.rule: %strictRules.uselessCast% + PHPStan\Rules\Cast\NullCastRule: + phpstan.rules.rule: %strictRules.nullCast% PHPStan\Rules\Classes\RequireParentConstructCallRule: phpstan.rules.rule: %strictRules.requireParentConstructorCall% PHPStan\Rules\DisallowedConstructs\DisallowedBacktickRule: @@ -142,12 +146,16 @@ services: - class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanAndRule + arguments: + bleedingEdge: %featureToggles.bleedingEdge% - class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule - class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanOrRule + arguments: + bleedingEdge: %featureToggles.bleedingEdge% - class: PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule @@ -163,6 +171,11 @@ services: arguments: treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% + - + class: PHPStan\Rules\Cast\NullCastRule + arguments: + treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% + - class: PHPStan\Rules\Classes\RequireParentConstructCallRule diff --git a/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php b/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php index 53140ccf..aebe8add 100644 --- a/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php +++ b/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\BooleanAndNode; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; @@ -18,9 +19,13 @@ class BooleanInBooleanAndRule implements Rule /** @var BooleanRuleHelper */ private $helper; - public function __construct(BooleanRuleHelper $helper) + /** @var bool */ + private $bleedingEdge; + + public function __construct(BooleanRuleHelper $helper, bool $bleedingEdge) { $this->helper = $helper; + $this->bleedingEdge = $bleedingEdge; } public function getNodeType(): string @@ -32,21 +37,25 @@ public function processNode(Node $node, Scope $scope): array { $originalNode = $node->getOriginalNode(); $messages = []; + $nodeText = $this->bleedingEdge ? $originalNode->getOperatorSigil() : '&&'; + $identifierType = $originalNode instanceof Node\Expr\BinaryOp\BooleanAnd ? 'booleanAnd' : 'logicalAnd'; if (!$this->helper->passesAsBoolean($scope, $originalNode->left)) { $leftType = $scope->getType($originalNode->left); - $messages[] = sprintf( - 'Only booleans are allowed in &&, %s given on the left side.', + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the left side.', + $nodeText, $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier(sprintf('%s.leftNotBoolean', $identifierType))->build(); } $rightScope = $node->getRightScope(); if (!$this->helper->passesAsBoolean($rightScope, $originalNode->right)) { $rightType = $rightScope->getType($originalNode->right); - $messages[] = sprintf( - 'Only booleans are allowed in &&, %s given on the right side.', + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the right side.', + $nodeText, $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier(sprintf('%s.rightNotBoolean', $identifierType))->build(); } return $messages; diff --git a/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php b/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php index 0e53c873..6fcdd06c 100644 --- a/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php +++ b/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php @@ -6,9 +6,13 @@ use PhpParser\Node\Expr\BooleanNot; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class BooleanInBooleanNotRule implements Rule { @@ -25,10 +29,6 @@ public function getNodeType(): string return BooleanNot::class; } - /** - * @param BooleanNot $node - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($this->helper->passesAsBoolean($scope, $node->expr)) { @@ -38,10 +38,10 @@ public function processNode(Node $node, Scope $scope): array $expressionType = $scope->getType($node->expr); return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Only booleans are allowed in a negated boolean, %s given.', $expressionType->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('booleanNot.exprNotBoolean')->build(), ]; } diff --git a/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php b/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php index bf98c5cd..e03911cf 100644 --- a/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php +++ b/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\BooleanOrNode; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; @@ -18,9 +19,13 @@ class BooleanInBooleanOrRule implements Rule /** @var BooleanRuleHelper */ private $helper; - public function __construct(BooleanRuleHelper $helper) + /** @var bool */ + private $bleedingEdge; + + public function __construct(BooleanRuleHelper $helper, bool $bleedingEdge) { $this->helper = $helper; + $this->bleedingEdge = $bleedingEdge; } public function getNodeType(): string @@ -32,21 +37,25 @@ public function processNode(Node $node, Scope $scope): array { $originalNode = $node->getOriginalNode(); $messages = []; + $nodeText = $this->bleedingEdge ? $originalNode->getOperatorSigil() : '||'; + $identifierType = $originalNode instanceof Node\Expr\BinaryOp\BooleanOr ? 'booleanOr' : 'logicalOr'; if (!$this->helper->passesAsBoolean($scope, $originalNode->left)) { $leftType = $scope->getType($originalNode->left); - $messages[] = sprintf( - 'Only booleans are allowed in ||, %s given on the left side.', + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the left side.', + $nodeText, $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier(sprintf('%s.leftNotBoolean', $identifierType))->build(); } $rightScope = $node->getRightScope(); if (!$this->helper->passesAsBoolean($rightScope, $originalNode->right)) { $rightType = $rightScope->getType($originalNode->right); - $messages[] = sprintf( - 'Only booleans are allowed in ||, %s given on the right side.', + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the right side.', + $nodeText, $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier(sprintf('%s.rightNotBoolean', $identifierType))->build(); } return $messages; diff --git a/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php b/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php index 8dfe3dac..2501b828 100644 --- a/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php +++ b/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php @@ -6,9 +6,13 @@ use PhpParser\Node\Stmt\ElseIf_; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class BooleanInElseIfConditionRule implements Rule { @@ -25,10 +29,6 @@ public function getNodeType(): string return ElseIf_::class; } - /** - * @param ElseIf_ $node - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($this->helper->passesAsBoolean($scope, $node->cond)) { @@ -38,10 +38,10 @@ public function processNode(Node $node, Scope $scope): array $conditionExpressionType = $scope->getType($node->cond); return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Only booleans are allowed in an elseif condition, %s given.', $conditionExpressionType->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('elseif.condNotBoolean')->build(), ]; } diff --git a/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php b/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php index 7b1cbfb8..5adb10ed 100644 --- a/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php +++ b/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php @@ -6,9 +6,13 @@ use PhpParser\Node\Stmt\If_; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class BooleanInIfConditionRule implements Rule { @@ -25,10 +29,6 @@ public function getNodeType(): string return If_::class; } - /** - * @param If_ $node - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($this->helper->passesAsBoolean($scope, $node->cond)) { @@ -38,10 +38,10 @@ public function processNode(Node $node, Scope $scope): array $conditionExpressionType = $scope->getType($node->cond); return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Only booleans are allowed in an if condition, %s given.', $conditionExpressionType->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('if.condNotBoolean')->build(), ]; } diff --git a/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php b/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php index 5d389b7a..e1ac9ccb 100644 --- a/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php +++ b/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php @@ -6,9 +6,13 @@ use PhpParser\Node\Expr\Ternary; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class BooleanInTernaryOperatorRule implements Rule { @@ -25,10 +29,6 @@ public function getNodeType(): string return Ternary::class; } - /** - * @param Ternary $node - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node->if === null) { @@ -42,10 +42,10 @@ public function processNode(Node $node, Scope $scope): array $conditionExpressionType = $scope->getType($node->cond); return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Only booleans are allowed in a ternary operator condition, %s given.', $conditionExpressionType->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('ternary.condNotBoolean')->build(), ]; } diff --git a/src/Rules/Cast/NullCastRule.php b/src/Rules/Cast/NullCastRule.php new file mode 100644 index 00000000..17b5859e --- /dev/null +++ b/src/Rules/Cast/NullCastRule.php @@ -0,0 +1,80 @@ + + */ +class NullCastRule implements Rule +{ + + /** @var bool */ + private $treatPhpDocTypesAsCertain; + + public function __construct(bool $treatPhpDocTypesAsCertain) + { + $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; + } + + public function getNodeType(): string + { + return Cast::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $castType = $scope->getType($node); + if ($castType instanceof ErrorType) { + return []; + } + $castType = $castType->generalize(GeneralizePrecision::lessSpecific()); + + if ($this->treatPhpDocTypesAsCertain) { + $expressionType = $scope->getType($node->expr); + } else { + $expressionType = $scope->getNativeType($node->expr); + } + + // This is handled by PhpStan at level 9 + if ($expressionType->isSuperTypeOf(new MixedType())->yes()) { + return []; + } + + if (!$expressionType->isNull()->no()) { + $addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, $node): RuleErrorBuilder { + if (!$this->treatPhpDocTypesAsCertain) { + return $ruleErrorBuilder; + } + + $expressionTypeWithoutPhpDoc = $scope->getNativeType($node->expr); + if (!(new NullType())->isSuperTypeOf($expressionTypeWithoutPhpDoc)->no()) { + return $ruleErrorBuilder; + } + + return $ruleErrorBuilder->tip('Because the type is coming from a PHPDoc, you can turn off this check by setting treatPhpDocTypesAsCertain: false in your %configurationFile%.'); + }; + return [ + $addTip(RuleErrorBuilder::message(sprintf( + 'Only non-null values should be cast to %s, %s given.', + $castType->describe(VerbosityLevel::typeOnly()), + $expressionType->describe(VerbosityLevel::typeOnly()) + )))->identifier('cast.null')->build(), + ]; + } + + return []; + } + +} diff --git a/src/Rules/Cast/UselessCastRule.php b/src/Rules/Cast/UselessCastRule.php index c156a09a..adc20e14 100644 --- a/src/Rules/Cast/UselessCastRule.php +++ b/src/Rules/Cast/UselessCastRule.php @@ -6,13 +6,15 @@ use PhpParser\Node\Expr\Cast; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; -use PHPStan\Rules\RuleError; use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\ErrorType; use PHPStan\Type\GeneralizePrecision; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class UselessCastRule implements Rule { @@ -29,10 +31,6 @@ public function getNodeType(): string return Cast::class; } - /** - * @param Cast $node - * @return RuleError[] errors - */ public function processNode(Node $node, Scope $scope): array { $castType = $scope->getType($node); @@ -64,7 +62,7 @@ public function processNode(Node $node, Scope $scope): array 'Casting to %s something that\'s already %s.', $castType->describe(VerbosityLevel::typeOnly()), $expressionType->describe(VerbosityLevel::typeOnly()) - )))->build(), + )))->identifier('cast.useless')->build(), ]; } diff --git a/src/Rules/Classes/RequireParentConstructCallRule.php b/src/Rules/Classes/RequireParentConstructCallRule.php index c07e04e4..76d3d16c 100644 --- a/src/Rules/Classes/RequireParentConstructCallRule.php +++ b/src/Rules/Classes/RequireParentConstructCallRule.php @@ -10,10 +10,14 @@ use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClass; use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; use function property_exists; use function sprintf; +/** + * @implements Rule + */ class RequireParentConstructCallRule implements Rule { @@ -22,10 +26,6 @@ public function getNodeType(): string return ClassMethod::class; } - /** - * @param ClassMethod $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if (!$scope->isInClass()) { @@ -50,34 +50,18 @@ public function processNode(Node $node, Scope $scope): array } if ($this->callsParentConstruct($node)) { - if ($classReflection->getParentClass() === false) { - return [ - sprintf( - '%s::__construct() calls parent constructor but does not extend any class.', - $classReflection->getName() - ), - ]; - } + return []; + } - if ($this->getParentConstructorClass($classReflection) === false) { - return [ - sprintf( - '%s::__construct() calls parent constructor but parent does not have one.', - $classReflection->getName() - ), - ]; - } - } else { - $parentClass = $this->getParentConstructorClass($classReflection); - if ($parentClass !== false) { - return [ - sprintf( - '%s::__construct() does not call parent constructor from %s.', - $classReflection->getName(), - $parentClass->getName() - ), - ]; - } + $parentClass = $this->getParentConstructorClass($classReflection); + if ($parentClass !== false) { + return [ + RuleErrorBuilder::message(sprintf( + '%s::__construct() does not call parent constructor from %s.', + $classReflection->getName(), + $parentClass->getName() + ))->identifier('constructor.missingParentCall')->build(), + ]; } return []; diff --git a/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php b/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php index aab3824d..76e401ce 100644 --- a/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php +++ b/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php @@ -3,11 +3,14 @@ namespace PHPStan\Rules\DisallowedConstructs; use PhpParser\Node; -use PhpParser\Node\Expr\Empty_; use PhpParser\Node\Expr\ShellExec; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; +/** + * @implements Rule + */ class DisallowedBacktickRule implements Rule { @@ -16,14 +19,12 @@ public function getNodeType(): string return ShellExec::class; } - /** - * @param Empty_ $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { return [ - 'Backtick operator is not allowed. Use shell_exec() instead.', + RuleErrorBuilder::message('Backtick operator is not allowed. Use shell_exec() instead.') + ->identifier('backtick.notAllowed') + ->build(), ]; } diff --git a/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php b/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php index 9a867cd5..d19f5ea2 100644 --- a/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php +++ b/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php @@ -6,7 +6,11 @@ use PhpParser\Node\Expr\Empty_; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; +/** + * @implements Rule + */ class DisallowedEmptyRule implements Rule { @@ -15,14 +19,12 @@ public function getNodeType(): string return Empty_::class; } - /** - * @param Empty_ $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { return [ - 'Construct empty() is not allowed. Use more strict comparison.', + RuleErrorBuilder::message('Construct empty() is not allowed. Use more strict comparison.') + ->identifier('empty.notAllowed') + ->build(), ]; } diff --git a/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php b/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php index 322d0dac..cee777ce 100644 --- a/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php +++ b/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php @@ -8,9 +8,13 @@ use PhpParser\Node\Expr\Variable; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use function is_string; use function sprintf; +/** + * @implements Rule + */ class DisallowedImplicitArrayCreationRule implements Rule { @@ -19,10 +23,6 @@ public function getNodeType(): string return Assign::class; } - /** - * @param Assign $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if (!$node->var instanceof ArrayDimFetch) { @@ -45,13 +45,17 @@ public function processNode(Node $node, Scope $scope): array $certainty = $scope->hasVariableType($node->name); if ($certainty->no()) { return [ - sprintf('Implicit array creation is not allowed - variable $%s does not exist.', $node->name), + RuleErrorBuilder::message(sprintf('Implicit array creation is not allowed - variable $%s does not exist.', $node->name)) + ->identifier('variable.implicitArray') + ->build(), ]; } if ($certainty->maybe()) { return [ - sprintf('Implicit array creation is not allowed - variable $%s might not exist.', $node->name), + RuleErrorBuilder::message(sprintf('Implicit array creation is not allowed - variable $%s might not exist.', $node->name)) + ->identifier('variable.implicitArray') + ->build(), ]; } diff --git a/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php b/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php index a1425c76..9b709be9 100644 --- a/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php +++ b/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php @@ -27,14 +27,18 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message( 'Loose comparison via "==" is not allowed.' - )->tip('Use strict comparison via "===" instead.')->build(), + )->tip('Use strict comparison via "===" instead.') + ->identifier('equal.notAllowed') + ->build(), ]; } if ($node instanceof NotEqual) { return [ RuleErrorBuilder::message( 'Loose comparison via "!=" is not allowed.' - )->tip('Use strict comparison via "!==" instead.')->build(), + )->tip('Use strict comparison via "!==" instead.') + ->identifier('notEqual.notAllowed') + ->build(), ]; } diff --git a/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php b/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php index 59db24ac..fac42790 100644 --- a/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php +++ b/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr\Ternary; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; /** * @implements Rule @@ -25,7 +26,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - 'Short ternary operator is not allowed. Use null coalesce operator if applicable or consider using long ternary.', + RuleErrorBuilder::message('Short ternary operator is not allowed. Use null coalesce operator if applicable or consider using long ternary.') + ->identifier('ternary.shortNotAllowed') + ->build(), ]; } diff --git a/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php b/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php index ca8f631c..f710474e 100644 --- a/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php +++ b/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php @@ -7,7 +7,9 @@ use PhpParser\Node\Expr\Assign; use PhpParser\Node\Stmt\For_; use PHPStan\Analyser\Scope; +use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use function is_string; use function sprintf; @@ -22,10 +24,6 @@ public function getNodeType(): string return For_::class; } - /** - * @param For_ $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { $errors = []; @@ -43,7 +41,7 @@ public function processNode(Node $node, Scope $scope): array } /** - * @return string[] + * @return list */ private function checkValueVar(Scope $scope, Expr $expr): array { @@ -53,7 +51,9 @@ private function checkValueVar(Scope $scope, Expr $expr): array && is_string($expr->name) && $scope->hasVariableType($expr->name)->yes() ) { - $errors[] = sprintf('For loop initial assignment overwrites variable $%s.', $expr->name); + $errors[] = RuleErrorBuilder::message(sprintf('For loop initial assignment overwrites variable $%s.', $expr->name)) + ->identifier('for.variableOverwrite') + ->build(); } if ( diff --git a/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php b/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php index dbf16d25..0cf620c3 100644 --- a/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php +++ b/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php @@ -6,22 +6,23 @@ use PhpParser\Node\Expr; use PhpParser\Node\Stmt\Foreach_; use PHPStan\Analyser\Scope; +use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use function is_string; use function sprintf; +/** + * @implements Rule + */ class OverwriteVariablesWithForeachRule implements Rule { public function getNodeType(): string { - return Node\Stmt\Foreach_::class; + return Foreach_::class; } - /** - * @param Foreach_ $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { $errors = []; @@ -30,7 +31,9 @@ public function processNode(Node $node, Scope $scope): array && is_string($node->keyVar->name) && $scope->hasVariableType($node->keyVar->name)->yes() ) { - $errors[] = sprintf('Foreach overwrites $%s with its key variable.', $node->keyVar->name); + $errors[] = RuleErrorBuilder::message(sprintf('Foreach overwrites $%s with its key variable.', $node->keyVar->name)) + ->identifier('foreach.keyOverwrite') + ->build(); } foreach ($this->checkValueVar($scope, $node->valueVar) as $error) { @@ -41,7 +44,7 @@ public function processNode(Node $node, Scope $scope): array } /** - * @return string[] + * @return list */ private function checkValueVar(Scope $scope, Expr $expr): array { @@ -51,7 +54,9 @@ private function checkValueVar(Scope $scope, Expr $expr): array && is_string($expr->name) && $scope->hasVariableType($expr->name)->yes() ) { - $errors[] = sprintf('Foreach overwrites $%s with its value variable.', $expr->name); + $errors[] = RuleErrorBuilder::message(sprintf('Foreach overwrites $%s with its value variable.', $expr->name)) + ->identifier('foreach.valueOverwrite') + ->build(); } if ( diff --git a/src/Rules/Functions/ClosureUsesThisRule.php b/src/Rules/Functions/ClosureUsesThisRule.php index fbce62f9..d2cb4a45 100644 --- a/src/Rules/Functions/ClosureUsesThisRule.php +++ b/src/Rules/Functions/ClosureUsesThisRule.php @@ -43,6 +43,7 @@ public function processNode(Node $node, Scope $scope): array $messages[] = RuleErrorBuilder::message(sprintf('Anonymous function uses $this assigned to variable $%s. Use $this directly in the function body.', $closureUse->var->name)) ->line($closureUse->getLine()) + ->identifier('closure.useThis') ->build(); } return $messages; diff --git a/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php b/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php index be62e245..1cca26ed 100644 --- a/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php +++ b/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php @@ -6,7 +6,9 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\InClassMethodNode; use PHPStan\Reflection\ClassReflection; +use PHPStan\Rules\IdentifierRuleError; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use function sprintf; /** @@ -50,9 +52,6 @@ public function processNode( continue; } - /** @var string $interfaceMessage */ - $interfaceMessage = $interfaceMessage; - $messages[] = $interfaceMessage; } @@ -63,7 +62,7 @@ private function findMethod( ClassReflection $declaringClass, ClassReflection $classReflection, string $methodName - ): ?string + ): ?IdentifierRuleError { if (!$classReflection->hasNativeMethod($methodName)) { return null; @@ -74,14 +73,14 @@ private function findMethod( return null; } - return sprintf( + return RuleErrorBuilder::message(sprintf( 'Method %s::%s() does not match %s method name: %s::%s().', $declaringClass->getDisplayName(), $methodName, $classReflection->isInterface() ? 'interface' : 'parent', $classReflection->getDisplayName(), $parentMethod->getName() - ); + ))->identifier('method.nameCase')->build(); } } diff --git a/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php b/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php index 13364758..af82a08c 100644 --- a/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php +++ b/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php @@ -9,6 +9,7 @@ use PhpParser\Node\Expr\PreInc; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; @@ -28,8 +29,7 @@ public function __construct(OperatorRuleHelper $helper) } /** - * @param PreInc|PreDec|PostInc|PostDec $node - * @return string[] errors + * @param TNodeType $node */ public function processNode(Node $node, Scope $scope): array { @@ -42,11 +42,11 @@ public function processNode(Node $node, Scope $scope): array || ($node instanceof PreDec || $node instanceof PostDec) && !$this->helper->isValidForDecrement($scope, $node->var) ) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in %s, %s given.', $this->describeOperation(), $varType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier(sprintf('%s.nonNumeric', $this->getIdentifier()))->build(); } return $messages; @@ -54,4 +54,9 @@ public function processNode(Node $node, Scope $scope): array abstract protected function describeOperation(): string; + /** + * @return 'preInc'|'postInc'|'preDec'|'postDec' + */ + abstract protected function getIdentifier(): string; + } diff --git a/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php b/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php index 88298ec9..d0e08099 100644 --- a/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php +++ b/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php @@ -20,4 +20,9 @@ protected function describeOperation(): string return 'post-decrement'; } + protected function getIdentifier(): string + { + return 'postDec'; + } + } diff --git a/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php b/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php index e9367dcb..400d8288 100644 --- a/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php +++ b/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php @@ -20,4 +20,9 @@ protected function describeOperation(): string return 'post-increment'; } + protected function getIdentifier(): string + { + return 'postInc'; + } + } diff --git a/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php b/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php index 643f8d31..9d583560 100644 --- a/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php +++ b/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php @@ -20,4 +20,9 @@ protected function describeOperation(): string return 'pre-decrement'; } + protected function getIdentifier(): string + { + return 'preDec'; + } + } diff --git a/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php b/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php index 3ad29af7..d5d81f2a 100644 --- a/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php +++ b/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php @@ -20,4 +20,9 @@ protected function describeOperation(): string return 'pre-increment'; } + protected function getIdentifier(): string + { + return 'preInc'; + } + } diff --git a/src/Rules/Operators/OperandsInArithmeticAdditionRule.php b/src/Rules/Operators/OperandsInArithmeticAdditionRule.php index ba29b5a7..246b609d 100644 --- a/src/Rules/Operators/OperandsInArithmeticAdditionRule.php +++ b/src/Rules/Operators/OperandsInArithmeticAdditionRule.php @@ -8,10 +8,14 @@ use PhpParser\Node\Expr\BinaryOp\Plus as BinaryOpPlus; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function count; use function sprintf; +/** + * @implements Rule + */ class OperandsInArithmeticAdditionRule implements Rule { @@ -32,9 +36,6 @@ public function getNodeType(): string return Expr::class; } - /** - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node instanceof BinaryOpPlus) { @@ -55,16 +56,16 @@ public function processNode(Node $node, Scope $scope): array $messages = []; if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in +, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('plus.leftNonNumeric')->build(); } if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in +, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('plus.rightNonNumeric')->build(); } return $messages; diff --git a/src/Rules/Operators/OperandsInArithmeticDivisionRule.php b/src/Rules/Operators/OperandsInArithmeticDivisionRule.php index 663ff36e..8a146ded 100644 --- a/src/Rules/Operators/OperandsInArithmeticDivisionRule.php +++ b/src/Rules/Operators/OperandsInArithmeticDivisionRule.php @@ -8,9 +8,13 @@ use PhpParser\Node\Expr\BinaryOp\Div as BinaryOpDiv; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class OperandsInArithmeticDivisionRule implements Rule { @@ -31,9 +35,6 @@ public function getNodeType(): string return Expr::class; } - /** - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node instanceof BinaryOpDiv) { @@ -49,18 +50,18 @@ public function processNode(Node $node, Scope $scope): array $messages = []; $leftType = $scope->getType($left); if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in /, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('div.leftNonNumeric')->build(); } $rightType = $scope->getType($right); if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in /, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('div.rightNonNumeric')->build(); } return $messages; diff --git a/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php b/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php index 40f7ae7e..fe809ef7 100644 --- a/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php +++ b/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php @@ -8,9 +8,13 @@ use PhpParser\Node\Expr\BinaryOp\Pow as BinaryOpPow; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class OperandsInArithmeticExponentiationRule implements Rule { @@ -31,9 +35,6 @@ public function getNodeType(): string return Expr::class; } - /** - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node instanceof BinaryOpPow) { @@ -49,18 +50,18 @@ public function processNode(Node $node, Scope $scope): array $messages = []; $leftType = $scope->getType($left); if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in **, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('pow.leftNonNumeric')->build(); } $rightType = $scope->getType($right); if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in **, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('pow.rightNonNumeric')->build(); } return $messages; diff --git a/src/Rules/Operators/OperandsInArithmeticModuloRule.php b/src/Rules/Operators/OperandsInArithmeticModuloRule.php index 38e0d38d..4aad3661 100644 --- a/src/Rules/Operators/OperandsInArithmeticModuloRule.php +++ b/src/Rules/Operators/OperandsInArithmeticModuloRule.php @@ -8,9 +8,13 @@ use PhpParser\Node\Expr\BinaryOp\Mod as BinaryOpMod; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class OperandsInArithmeticModuloRule implements Rule { @@ -31,9 +35,6 @@ public function getNodeType(): string return Expr::class; } - /** - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node instanceof BinaryOpMod) { @@ -49,18 +50,18 @@ public function processNode(Node $node, Scope $scope): array $messages = []; $leftType = $scope->getType($left); if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in %%, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('mod.leftNonNumeric')->build(); } $rightType = $scope->getType($right); if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in %%, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('mod.rightNonNumeric')->build(); } return $messages; diff --git a/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php b/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php index f1e4c064..f662bdce 100644 --- a/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php +++ b/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php @@ -8,9 +8,13 @@ use PhpParser\Node\Expr\BinaryOp\Mul as BinaryOpMul; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class OperandsInArithmeticMultiplicationRule implements Rule { @@ -31,9 +35,6 @@ public function getNodeType(): string return Expr::class; } - /** - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node instanceof BinaryOpMul) { @@ -49,18 +50,18 @@ public function processNode(Node $node, Scope $scope): array $messages = []; $leftType = $scope->getType($left); if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in *, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('mul.leftNonNumeric')->build(); } $rightType = $scope->getType($right); if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in *, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('mul.rightNonNumeric')->build(); } return $messages; diff --git a/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php b/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php index 5333c2a1..9bec287d 100644 --- a/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php +++ b/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php @@ -8,9 +8,13 @@ use PhpParser\Node\Expr\BinaryOp\Minus as BinaryOpMinus; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class OperandsInArithmeticSubtractionRule implements Rule { @@ -31,9 +35,6 @@ public function getNodeType(): string return Expr::class; } - /** - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if ($node instanceof BinaryOpMinus) { @@ -49,18 +50,18 @@ public function processNode(Node $node, Scope $scope): array $messages = []; $leftType = $scope->getType($left); if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in -, %s given on the left side.', $leftType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('minus.leftNonNumeric')->build(); } $rightType = $scope->getType($right); if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { - $messages[] = sprintf( + $messages[] = RuleErrorBuilder::message(sprintf( 'Only numeric types are allowed in -, %s given on the right side.', $rightType->describe(VerbosityLevel::typeOnly()) - ); + ))->identifier('minus.rightNonNumeric')->build(); } return $messages; diff --git a/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php b/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php index 95e27fec..d14b5678 100644 --- a/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php +++ b/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\MethodCallableNode; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Type\ErrorType; use PHPStan\Type\Type; @@ -52,11 +53,13 @@ static function (Type $type) use ($name): bool { $methodReflection = $type->getMethod($name, $scope); if ($methodReflection->isStatic()) { - return [sprintf( - 'Dynamic call to static method %s::%s().', - $methodReflection->getDeclaringClass()->getDisplayName(), - $methodReflection->getName() - )]; + return [ + RuleErrorBuilder::message(sprintf( + 'Dynamic call to static method %s::%s().', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName() + ))->identifier('staticMethod.dynamicCall')->build(), + ]; } return []; diff --git a/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php b/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php index 5319c3a8..44b180c0 100644 --- a/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php +++ b/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\PHPStanTestCase; use PHPStan\Testing\TypeInferenceTestCase; @@ -14,6 +15,9 @@ use function in_array; use function sprintf; +/** + * @implements Rule + */ class DynamicCallOnStaticMethodsRule implements Rule { @@ -30,10 +34,6 @@ public function getNodeType(): string return MethodCall::class; } - /** - * @param MethodCall $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if (!$node->name instanceof Node\Identifier) { @@ -64,11 +64,13 @@ static function (Type $type) use ($name): bool { return []; } - return [sprintf( - 'Dynamic call to static method %s::%s().', - $methodReflection->getDeclaringClass()->getDisplayName(), - $methodReflection->getName() - )]; + return [ + RuleErrorBuilder::message(sprintf( + 'Dynamic call to static method %s::%s().', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName() + ))->identifier('staticMethod.dynamicCall')->build(), + ]; } return []; diff --git a/src/Rules/StrictCalls/StrictFunctionCallsRule.php b/src/Rules/StrictCalls/StrictFunctionCallsRule.php index b27c25fe..2b6cd899 100644 --- a/src/Rules/StrictCalls/StrictFunctionCallsRule.php +++ b/src/Rules/StrictCalls/StrictFunctionCallsRule.php @@ -8,11 +8,15 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\Constant\ConstantBooleanType; use function array_key_exists; use function sprintf; use function strtolower; +/** + * @implements Rule + */ class StrictFunctionCallsRule implements Rule { @@ -37,10 +41,6 @@ public function getNodeType(): string return FuncCall::class; } - /** - * @param FuncCall $node - * @return string[] errors - */ public function processNode(Node $node, Scope $scope): array { if (!$node->name instanceof Name) { @@ -62,13 +62,25 @@ public function processNode(Node $node, Scope $scope): array $argumentPosition = $this->functionArguments[$functionName]; if (!array_key_exists($argumentPosition, $node->getArgs())) { - return [sprintf('Call to function %s() requires parameter #%d to be set.', $functionName, $argumentPosition + 1)]; + return [ + RuleErrorBuilder::message(sprintf( + 'Call to function %s() requires parameter #%d to be set.', + $functionName, + $argumentPosition + 1 + ))->identifier('function.strict')->build(), + ]; } $argumentType = $scope->getType($node->getArgs()[$argumentPosition]->value); $trueType = new ConstantBooleanType(true); if (!$trueType->isSuperTypeOf($argumentType)->yes()) { - return [sprintf('Call to function %s() requires parameter #%d to be true.', $functionName, $argumentPosition + 1)]; + return [ + RuleErrorBuilder::message(sprintf( + 'Call to function %s() requires parameter #%d to be true.', + $functionName, + $argumentPosition + 1 + ))->identifier('function.strict')->build(), + ]; } return []; diff --git a/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php b/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php index bb4bebbf..e52195a1 100644 --- a/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php +++ b/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php @@ -49,7 +49,10 @@ public function processNode(Node $node, Scope $scope): array $conditionType->describe(VerbosityLevel::value()), $this->printer->prettyPrintExpr($case->cond), $caseType->describe(VerbosityLevel::typeOnly()) - ))->line($case->getLine())->build(); + )) + ->line($case->getLine()) + ->identifier('switch.type') + ->build(); } return $messages; diff --git a/src/Rules/VariableVariables/VariableMethodCallRule.php b/src/Rules/VariableVariables/VariableMethodCallRule.php index 4221cfa8..f92f84c1 100644 --- a/src/Rules/VariableVariables/VariableMethodCallRule.php +++ b/src/Rules/VariableVariables/VariableMethodCallRule.php @@ -6,21 +6,21 @@ use PhpParser\Node\Expr\MethodCall; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class VariableMethodCallRule implements Rule { public function getNodeType(): string { - return Node\Expr\MethodCall::class; + return MethodCall::class; } - /** - * @param MethodCall $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if ($node->name instanceof Node\Identifier) { @@ -28,10 +28,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Variable method call on %s.', $scope->getType($node->var)->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('method.dynamicName')->build(), ]; } diff --git a/src/Rules/VariableVariables/VariableMethodCallableRule.php b/src/Rules/VariableVariables/VariableMethodCallableRule.php index f293b562..6a5fd518 100644 --- a/src/Rules/VariableVariables/VariableMethodCallableRule.php +++ b/src/Rules/VariableVariables/VariableMethodCallableRule.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\MethodCallableNode; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; @@ -27,10 +28,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Variable method call on %s.', $scope->getType($node->getVar())->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('method.dynamicName')->build(), ]; } diff --git a/src/Rules/VariableVariables/VariablePropertyFetchRule.php b/src/Rules/VariableVariables/VariablePropertyFetchRule.php index 1b7fe52d..73ff0888 100644 --- a/src/Rules/VariableVariables/VariablePropertyFetchRule.php +++ b/src/Rules/VariableVariables/VariablePropertyFetchRule.php @@ -8,9 +8,13 @@ use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class VariablePropertyFetchRule implements Rule { @@ -31,13 +35,9 @@ public function __construct(ReflectionProvider $reflectionProvider, array $unive public function getNodeType(): string { - return Node\Expr\PropertyFetch::class; + return PropertyFetch::class; } - /** - * @param PropertyFetch $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if ($node->name instanceof Node\Identifier) { @@ -56,10 +56,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Variable property access on %s.', $fetchedOnType->describe(VerbosityLevel::typeOnly()) - ), + ))->identifier('property.dynamicName')->build(), ]; } diff --git a/src/Rules/VariableVariables/VariableStaticMethodCallRule.php b/src/Rules/VariableVariables/VariableStaticMethodCallRule.php index 0d6b8202..eb3a770c 100644 --- a/src/Rules/VariableVariables/VariableStaticMethodCallRule.php +++ b/src/Rules/VariableVariables/VariableStaticMethodCallRule.php @@ -6,21 +6,21 @@ use PhpParser\Node\Expr\StaticCall; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class VariableStaticMethodCallRule implements Rule { public function getNodeType(): string { - return Node\Expr\StaticCall::class; + return StaticCall::class; } - /** - * @param StaticCall $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if ($node->name instanceof Node\Identifier) { @@ -34,10 +34,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Variable static method call on %s.', $methodCalledOn - ), + ))->identifier('staticMethod.dynamicName')->build(), ]; } diff --git a/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php b/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php index 8ede1f00..f765da66 100644 --- a/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php +++ b/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php @@ -6,6 +6,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Node\StaticMethodCallableNode; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; @@ -33,10 +34,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Variable static method call on %s.', $methodCalledOn - ), + ))->identifier('staticMethod.dynamicName')->build(), ]; } diff --git a/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php b/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php index 4b410a7f..f27c7792 100644 --- a/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php +++ b/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php @@ -6,21 +6,21 @@ use PhpParser\Node\Expr\StaticPropertyFetch; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\VerbosityLevel; use function sprintf; +/** + * @implements Rule + */ class VariableStaticPropertyFetchRule implements Rule { public function getNodeType(): string { - return Node\Expr\StaticPropertyFetch::class; + return StaticPropertyFetch::class; } - /** - * @param StaticPropertyFetch $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if ($node->name instanceof Node\Identifier) { @@ -34,10 +34,10 @@ public function processNode(Node $node, Scope $scope): array } return [ - sprintf( + RuleErrorBuilder::message(sprintf( 'Variable static property access on %s.', $propertyAccessedOn - ), + ))->identifier('staticProperty.dynamicName')->build(), ]; } diff --git a/src/Rules/VariableVariables/VariableVariablesRule.php b/src/Rules/VariableVariables/VariableVariablesRule.php index 9768f21b..f78e4ef4 100644 --- a/src/Rules/VariableVariables/VariableVariablesRule.php +++ b/src/Rules/VariableVariables/VariableVariablesRule.php @@ -6,20 +6,20 @@ use PhpParser\Node\Expr\Variable; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use function is_string; +/** + * @implements Rule + */ class VariableVariablesRule implements Rule { public function getNodeType(): string { - return Node\Expr\Variable::class; + return Variable::class; } - /** - * @param Variable $node - * @return string[] - */ public function processNode(Node $node, Scope $scope): array { if (is_string($node->name)) { @@ -27,7 +27,9 @@ public function processNode(Node $node, Scope $scope): array } return [ - 'Variable variables are not allowed.', + RuleErrorBuilder::message('Variable variables are not allowed.') + ->identifier('variable.dynamicName') + ->build(), ]; } diff --git a/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php index c9244204..c0f448dd 100644 --- a/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInBooleanAndRuleTest.php @@ -17,7 +17,8 @@ protected function getRule(): Rule return new BooleanInBooleanAndRule( new BooleanRuleHelper( self::getContainer()->getByType(RuleLevelHelper::class) - ) + ), + true ); } @@ -44,6 +45,14 @@ public function testRule(): void 'Only booleans are allowed in &&, mixed given on the right side.', 19, ], + [ + 'Only booleans are allowed in and, mixed given on the right side.', + 47, + ], + [ + 'Only booleans are allowed in and, mixed given on the left side.', + 48, + ], ]); } @@ -61,11 +70,11 @@ public function testLogicalAnd(): void { $this->analyse([__DIR__ . '/data/logical-and.php'], [ [ - 'Only booleans are allowed in &&, string|false given on the left side.', + 'Only booleans are allowed in and, string|false given on the left side.', 14, ], [ - 'Only booleans are allowed in &&, mixed given on the right side.', + 'Only booleans are allowed in and, mixed given on the right side.', 14, ], ]); diff --git a/tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php index 33dd205c..1d5e017d 100644 --- a/tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInBooleanNotRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class BooleanInBooleanNotRuleTest extends RuleTestCase { diff --git a/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php index 1a4fafb0..c9d7ed45 100644 --- a/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInBooleanOrRuleTest.php @@ -17,7 +17,8 @@ protected function getRule(): Rule return new BooleanInBooleanOrRule( new BooleanRuleHelper( self::getContainer()->getByType(RuleLevelHelper::class) - ) + ), + true ); } @@ -40,6 +41,14 @@ public function testRule(): void 'Only booleans are allowed in ||, mixed given on the right side.', 29, ], + [ + 'Only booleans are allowed in or, mixed given on the right side.', + 49, + ], + [ + 'Only booleans are allowed in or, mixed given on the left side.', + 50, + ], ]); } diff --git a/tests/Rules/BooleansInConditions/BooleanInElseIfConditionRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInElseIfConditionRuleTest.php index b2df79fc..43cd364b 100644 --- a/tests/Rules/BooleansInConditions/BooleanInElseIfConditionRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInElseIfConditionRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class BooleanInElseIfConditionRuleTest extends RuleTestCase { diff --git a/tests/Rules/BooleansInConditions/BooleanInIfConditionRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInIfConditionRuleTest.php index 196af111..59324856 100644 --- a/tests/Rules/BooleansInConditions/BooleanInIfConditionRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInIfConditionRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class BooleanInIfConditionRuleTest extends RuleTestCase { diff --git a/tests/Rules/BooleansInConditions/BooleanInTernaryOperatorRuleTest.php b/tests/Rules/BooleansInConditions/BooleanInTernaryOperatorRuleTest.php index 76bd4ad0..a7149e00 100644 --- a/tests/Rules/BooleansInConditions/BooleanInTernaryOperatorRuleTest.php +++ b/tests/Rules/BooleansInConditions/BooleanInTernaryOperatorRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class BooleanInTernaryOperatorRuleTest extends RuleTestCase { diff --git a/tests/Rules/BooleansInConditions/data/conditions.php b/tests/Rules/BooleansInConditions/data/conditions.php index 3af62400..968867ff 100644 --- a/tests/Rules/BooleansInConditions/data/conditions.php +++ b/tests/Rules/BooleansInConditions/data/conditions.php @@ -43,3 +43,8 @@ $bool ? 1 : 2; $string ? 1 : 2; $string ?: null; + +$bool and $explicitMixed; +$explicitMixed and $bool; +$bool or $explicitMixed; +$explicitMixed or $bool; diff --git a/tests/Rules/Cast/NullCastRuleTest.php b/tests/Rules/Cast/NullCastRuleTest.php new file mode 100644 index 00000000..a8d1caf9 --- /dev/null +++ b/tests/Rules/Cast/NullCastRuleTest.php @@ -0,0 +1,87 @@ + + */ +class NullCastRuleTest extends RuleTestCase +{ + + /** @var bool */ + private $treatPhpDocTypesAsCertain; + + protected function getRule(): Rule + { + return new NullCastRule($this->treatPhpDocTypesAsCertain); + } + + protected function shouldTreatPhpDocTypesAsCertain(): bool + { + return $this->treatPhpDocTypesAsCertain; + } + + public function testNullCast(): void + { + require_once __DIR__ . '/data/null-cast.php'; + $this->treatPhpDocTypesAsCertain = true; + $this->analyse( + [__DIR__ . '/data/null-cast.php'], + [ + [ + 'Only non-null values should be cast to int, int|null given.', + 6, + ], + [ + 'Only non-null values should be cast to int, string|null given.', + 8, + ], + [ + 'Only non-null values should be cast to float, int|null given.', + 9, + ], + [ + 'Only non-null values should be cast to float, string|null given.', + 11, + ], + [ + 'Only non-null values should be cast to string, string|null given.', + 12, + ], + [ + 'Only non-null values should be cast to stdClass, string|null given.', + 13, + ], + [ + 'Only non-null values should be cast to stdClass, null given.', + 15, + ], + [ + 'Only non-null values should be cast to array, null given.', + 17, + ], + ] + ); + } + + public function testDoNotReportPhpDoc(): void + { + $this->treatPhpDocTypesAsCertain = false; + $this->analyse([__DIR__ . '/data/null-cast-not-phpdoc.php'], []); + } + + public function testReportPhpDoc(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/null-cast-not-phpdoc.php'], [ + [ + 'Only non-null values should be cast to int, int|null given.', + 17, + ], + ]); + } + +} diff --git a/tests/Rules/Cast/UselessCastRuleTest.php b/tests/Rules/Cast/UselessCastRuleTest.php index c1affdde..0d26a4ec 100644 --- a/tests/Rules/Cast/UselessCastRuleTest.php +++ b/tests/Rules/Cast/UselessCastRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class UselessCastRuleTest extends RuleTestCase { diff --git a/tests/Rules/Cast/data/null-cast-not-phpdoc.php b/tests/Rules/Cast/data/null-cast-not-phpdoc.php new file mode 100644 index 00000000..42f2bf22 --- /dev/null +++ b/tests/Rules/Cast/data/null-cast-not-phpdoc.php @@ -0,0 +1,20 @@ += 8.0 + +namespace NullCast; + +function foo(?int $a, string $b, ?string $c, mixed $d) { + (int)$a; + (int)$b; + (int)$c; + (float)$a; + (float)$b; + (float)$c; + (string)$c; + (object)$c; + (object)'null'; + (object)null; + (array)'null'; + (array)null; + (int)$d; +} diff --git a/tests/Rules/Classes/RequireParentConstructCallRuleTest.php b/tests/Rules/Classes/RequireParentConstructCallRuleTest.php index caeee5c8..e8d63620 100644 --- a/tests/Rules/Classes/RequireParentConstructCallRuleTest.php +++ b/tests/Rules/Classes/RequireParentConstructCallRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Testing\RuleTestCase; use const PHP_VERSION_ID; +/** + * @extends RuleTestCase + */ class RequireParentConstructCallRuleTest extends RuleTestCase { @@ -17,10 +20,6 @@ protected function getRule(): Rule public function testCallToParentConstructor(): void { $this->analyse([__DIR__ . '/data/call-to-parent-constructor.php'], [ - [ - 'IpsumCallToParentConstructor::__construct() calls parent constructor but parent does not have one.', - 31, - ], [ 'BCallToParentConstructor::__construct() does not call parent constructor from ACallToParentConstructor.', 51, @@ -50,12 +49,7 @@ public function testCallsParentButHasNotParent(): void if (PHP_VERSION_ID >= 70400) { self::markTestSkipped('This test does not support PHP 7.4 or higher.'); } - $this->analyse([__DIR__ . '/data/call-to-parent-constructor-php-lt-74.php'], [ - [ - 'CCallToParentConstructor::__construct() calls parent constructor but does not extend any class.', - 6, - ], - ]); + $this->analyse([__DIR__ . '/data/call-to-parent-constructor-php-lt-74.php'], []); } } diff --git a/tests/Rules/DisallowedConstructs/DisallowedBacktickRuleTest.php b/tests/Rules/DisallowedConstructs/DisallowedBacktickRuleTest.php index 1b697e0a..e370f3e7 100644 --- a/tests/Rules/DisallowedConstructs/DisallowedBacktickRuleTest.php +++ b/tests/Rules/DisallowedConstructs/DisallowedBacktickRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class DisallowedBacktickRuleTest extends RuleTestCase { diff --git a/tests/Rules/DisallowedConstructs/DisallowedEmptyRuleTest.php b/tests/Rules/DisallowedConstructs/DisallowedEmptyRuleTest.php index 5ffc7f67..172093ba 100644 --- a/tests/Rules/DisallowedConstructs/DisallowedEmptyRuleTest.php +++ b/tests/Rules/DisallowedConstructs/DisallowedEmptyRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class DisallowedEmptyRuleTest extends RuleTestCase { diff --git a/tests/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRuleTest.php b/tests/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRuleTest.php index 6092a5f4..69c25a7a 100644 --- a/tests/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRuleTest.php +++ b/tests/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class DisallowedImplicitArrayCreationRuleTest extends RuleTestCase { diff --git a/tests/Rules/ForeachLoop/OverwriteVariablesWithForeachRuleTest.php b/tests/Rules/ForeachLoop/OverwriteVariablesWithForeachRuleTest.php index 5d483d55..031aa148 100644 --- a/tests/Rules/ForeachLoop/OverwriteVariablesWithForeachRuleTest.php +++ b/tests/Rules/ForeachLoop/OverwriteVariablesWithForeachRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class OverwriteVariablesWithForeachRuleTest extends RuleTestCase { diff --git a/tests/Rules/Methods/WrongCaseOfInheritedMethodRuleTest.php b/tests/Rules/Methods/WrongCaseOfInheritedMethodRuleTest.php index b2425faf..d4235b6b 100644 --- a/tests/Rules/Methods/WrongCaseOfInheritedMethodRuleTest.php +++ b/tests/Rules/Methods/WrongCaseOfInheritedMethodRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class WrongCaseOfInheritedMethodRuleTest extends RuleTestCase { diff --git a/tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTest.php b/tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTestCase.php similarity index 79% rename from tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTest.php rename to tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTestCase.php index 02e38f43..0efa83a7 100644 --- a/tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTest.php +++ b/tests/Rules/Operators/OperandInArithmeticIncrementOrDecrementRuleTestCase.php @@ -6,7 +6,11 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; -abstract class OperandInArithmeticIncrementOrDecrementRuleTest extends RuleTestCase +/** + * @template T of Rule + * @extends RuleTestCase + */ +abstract class OperandInArithmeticIncrementOrDecrementRuleTestCase extends RuleTestCase { protected function getRule(): Rule @@ -23,6 +27,9 @@ public function testRule(): void $this->analyse([__DIR__ . '/data/increment-decrement.php'], $this->getExpectedErrors()); } + /** + * @return T + */ abstract protected function createRule(OperatorRuleHelper $helper): Rule; /** diff --git a/tests/Rules/Operators/OperandInArithmeticPostDecrementRuleTest.php b/tests/Rules/Operators/OperandInArithmeticPostDecrementRuleTest.php index 0a441d8a..c4ea1569 100644 --- a/tests/Rules/Operators/OperandInArithmeticPostDecrementRuleTest.php +++ b/tests/Rules/Operators/OperandInArithmeticPostDecrementRuleTest.php @@ -4,7 +4,10 @@ use PHPStan\Rules\Rule; -class OperandInArithmeticPostDecrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTest +/** + * @extends OperandInArithmeticIncrementOrDecrementRuleTestCase + */ +class OperandInArithmeticPostDecrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTestCase { protected function createRule(OperatorRuleHelper $helper): Rule diff --git a/tests/Rules/Operators/OperandInArithmeticPostIncrementRuleTest.php b/tests/Rules/Operators/OperandInArithmeticPostIncrementRuleTest.php index 0b18f3a9..94357e60 100644 --- a/tests/Rules/Operators/OperandInArithmeticPostIncrementRuleTest.php +++ b/tests/Rules/Operators/OperandInArithmeticPostIncrementRuleTest.php @@ -4,7 +4,10 @@ use PHPStan\Rules\Rule; -class OperandInArithmeticPostIncrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTest +/** + * @extends OperandInArithmeticIncrementOrDecrementRuleTestCase + */ +class OperandInArithmeticPostIncrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTestCase { protected function createRule(OperatorRuleHelper $helper): Rule diff --git a/tests/Rules/Operators/OperandInArithmeticPreDecrementRuleTest.php b/tests/Rules/Operators/OperandInArithmeticPreDecrementRuleTest.php index 2e695f89..2bb021a9 100644 --- a/tests/Rules/Operators/OperandInArithmeticPreDecrementRuleTest.php +++ b/tests/Rules/Operators/OperandInArithmeticPreDecrementRuleTest.php @@ -4,7 +4,10 @@ use PHPStan\Rules\Rule; -class OperandInArithmeticPreDecrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTest +/** + * @extends OperandInArithmeticIncrementOrDecrementRuleTestCase + */ +class OperandInArithmeticPreDecrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTestCase { protected function createRule(OperatorRuleHelper $helper): Rule diff --git a/tests/Rules/Operators/OperandInArithmeticPreIncrementRuleTest.php b/tests/Rules/Operators/OperandInArithmeticPreIncrementRuleTest.php index 47449369..2ffe1bb6 100644 --- a/tests/Rules/Operators/OperandInArithmeticPreIncrementRuleTest.php +++ b/tests/Rules/Operators/OperandInArithmeticPreIncrementRuleTest.php @@ -4,7 +4,10 @@ use PHPStan\Rules\Rule; -class OperandInArithmeticPreIncrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTest +/** + * @extends OperandInArithmeticIncrementOrDecrementRuleTestCase + */ +class OperandInArithmeticPreIncrementRuleTest extends OperandInArithmeticIncrementOrDecrementRuleTestCase { protected function createRule(OperatorRuleHelper $helper): Rule diff --git a/tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php b/tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php index 892db77f..0d25e12c 100644 --- a/tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php +++ b/tests/Rules/Operators/OperandsInArithmeticAdditionRuleTest.php @@ -8,6 +8,9 @@ use function array_merge; use const PHP_VERSION_ID; +/** + * @extends RuleTestCase + */ class OperandsInArithmeticAdditionRuleTest extends RuleTestCase { diff --git a/tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php b/tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php index 0571e38d..74e21357 100644 --- a/tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php +++ b/tests/Rules/Operators/OperandsInArithmeticDivisionRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class OperandsInArithmeticDivisionRuleTest extends RuleTestCase { diff --git a/tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php b/tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php index 56492a36..2ae96a42 100644 --- a/tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php +++ b/tests/Rules/Operators/OperandsInArithmeticExponentiationRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class OperandsInArithmeticExponentiationRuleTest extends RuleTestCase { diff --git a/tests/Rules/Operators/OperandsInArithmeticModuloRuleTest.php b/tests/Rules/Operators/OperandsInArithmeticModuloRuleTest.php index 953732ca..e58e489e 100644 --- a/tests/Rules/Operators/OperandsInArithmeticModuloRuleTest.php +++ b/tests/Rules/Operators/OperandsInArithmeticModuloRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class OperandsInArithmeticModuloRuleTest extends RuleTestCase { diff --git a/tests/Rules/Operators/OperandsInArithmeticMultiplicationRuleTest.php b/tests/Rules/Operators/OperandsInArithmeticMultiplicationRuleTest.php index a0015d27..51c6a8c3 100644 --- a/tests/Rules/Operators/OperandsInArithmeticMultiplicationRuleTest.php +++ b/tests/Rules/Operators/OperandsInArithmeticMultiplicationRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class OperandsInArithmeticMultiplicationRuleTest extends RuleTestCase { diff --git a/tests/Rules/Operators/OperandsInArithmeticSubtractionRuleTest.php b/tests/Rules/Operators/OperandsInArithmeticSubtractionRuleTest.php index cbe8e08d..3b7cf00f 100644 --- a/tests/Rules/Operators/OperandsInArithmeticSubtractionRuleTest.php +++ b/tests/Rules/Operators/OperandsInArithmeticSubtractionRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class OperandsInArithmeticSubtractionRuleTest extends RuleTestCase { diff --git a/tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php b/tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php index a35919a2..a009b1e4 100644 --- a/tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php +++ b/tests/Rules/StrictCalls/DynamicCallOnStaticMethodsRuleTest.php @@ -6,6 +6,9 @@ use PHPStan\Rules\RuleLevelHelper; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class DynamicCallOnStaticMethodsRuleTest extends RuleTestCase { diff --git a/tests/Rules/StrictCalls/StrictFunctionCallsRuleTest.php b/tests/Rules/StrictCalls/StrictFunctionCallsRuleTest.php index 8a1ce29c..fa08fe7a 100644 --- a/tests/Rules/StrictCalls/StrictFunctionCallsRuleTest.php +++ b/tests/Rules/StrictCalls/StrictFunctionCallsRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class StrictFunctionCallsRuleTest extends RuleTestCase { diff --git a/tests/Rules/VariableVariables/VariableMethodCallRuleTest.php b/tests/Rules/VariableVariables/VariableMethodCallRuleTest.php index 150df3fb..36304bbb 100644 --- a/tests/Rules/VariableVariables/VariableMethodCallRuleTest.php +++ b/tests/Rules/VariableVariables/VariableMethodCallRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class VariableMethodCallRuleTest extends RuleTestCase { diff --git a/tests/Rules/VariableVariables/VariablePropertyFetchRuleTest.php b/tests/Rules/VariableVariables/VariablePropertyFetchRuleTest.php index 2cf7e17d..9126d836 100644 --- a/tests/Rules/VariableVariables/VariablePropertyFetchRuleTest.php +++ b/tests/Rules/VariableVariables/VariablePropertyFetchRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class VariablePropertyFetchRuleTest extends RuleTestCase { diff --git a/tests/Rules/VariableVariables/VariableStaticMethodCallRuleTest.php b/tests/Rules/VariableVariables/VariableStaticMethodCallRuleTest.php index d55bd585..35796bf3 100644 --- a/tests/Rules/VariableVariables/VariableStaticMethodCallRuleTest.php +++ b/tests/Rules/VariableVariables/VariableStaticMethodCallRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class VariableStaticMethodCallRuleTest extends RuleTestCase { diff --git a/tests/Rules/VariableVariables/VariableStaticPropertyFetchRuleTest.php b/tests/Rules/VariableVariables/VariableStaticPropertyFetchRuleTest.php index 7fe3dde0..91a8f71d 100644 --- a/tests/Rules/VariableVariables/VariableStaticPropertyFetchRuleTest.php +++ b/tests/Rules/VariableVariables/VariableStaticPropertyFetchRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class VariableStaticPropertyFetchRuleTest extends RuleTestCase { diff --git a/tests/Rules/VariableVariables/VariableVariablesRuleTest.php b/tests/Rules/VariableVariables/VariableVariablesRuleTest.php index 1b9fdef6..fcc73913 100644 --- a/tests/Rules/VariableVariables/VariableVariablesRuleTest.php +++ b/tests/Rules/VariableVariables/VariableVariablesRuleTest.php @@ -5,6 +5,9 @@ use PHPStan\Rules\Rule; use PHPStan\Testing\RuleTestCase; +/** + * @extends RuleTestCase + */ class VariableVariablesRuleTest extends RuleTestCase {