diff --git a/build/PHPStan/Build/ApiPhpDocEntrypointProvider.php b/build/PHPStan/Build/ApiPhpDocEntrypointProvider.php new file mode 100644 index 0000000000..a2862d7485 --- /dev/null +++ b/build/PHPStan/Build/ApiPhpDocEntrypointProvider.php @@ -0,0 +1,69 @@ +getDeclaringClass(); + $methodName = $method->getName(); + + if ($this->isApiClass($reflectionClass)) { + return true; + } + + do { + if ($this->isApiMethod($reflectionClass, $methodName)) { + return true; + } + + foreach ($reflectionClass->getInterfaces() as $interface) { + if ($this->isApiClass($interface)) { + return true; + } + + if ($this->isApiMethod($interface, $methodName)) { + return true; + } + } + + $reflectionClass = $reflectionClass->getParentClass(); + } while ($reflectionClass !== false); + + return false; + } + + private function isApiClass(\ReflectionClass $reflection): bool + { + $phpDoc = $reflection->getDocComment(); + if ($phpDoc !== false && str_contains($phpDoc, '@api')) { + return true; + } + + return false; + } + + private function isApiMethod(\ReflectionClass $reflectionClass, string $methodName): bool + { + if (!$reflectionClass->hasMethod($methodName)) { + return false; + } + + $phpDoc = $reflectionClass->getMethod($methodName)->getDocComment(); + if ($phpDoc !== false && str_contains($phpDoc, '@api')) { + return true; + } + + return false; + } +} diff --git a/build/phpstan.neon b/build/phpstan.neon index 95526db694..062a43a56c 100644 --- a/build/phpstan.neon +++ b/build/phpstan.neon @@ -4,6 +4,7 @@ includes: - ../vendor/phpstan/phpstan-phpunit/extension.neon - ../vendor/phpstan/phpstan-phpunit/rules.neon - ../vendor/phpstan/phpstan-strict-rules/rules.neon + - ../vendor/shipmonk/dead-code-detector/rules.neon - ../conf/bleedingEdge.neon - ../phpstan-baseline.neon - ../phpstan-baseline.php @@ -91,6 +92,10 @@ parameters: path: ../src/Diagnose/PHPStanDiagnoseExtension.php - '#^Parameter \#1 \$offsetType of class PHPStan\\Type\\Accessory\\HasOffsetType constructor expects PHPStan\\Type\\Constant\\ConstantIntegerType\|PHPStan\\Type\\Constant\\ConstantStringType#' - '#^Short ternary operator is not allowed#' + + - '#^Unused .*?Factory::create$#' # likely used in DIC + - '#^Unused .*?::__construct$#' # disable dead construct analysis, DIC services might not be autowired + reportStaticMethodSignatures: true tmpDir: %rootDir%/tmp stubFiles: @@ -111,3 +116,7 @@ services: class: PHPStan\Internal\ContainerDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Build\ApiPhpDocEntrypointProvider + tags: + - shipmonk.deadCode.entrypointProvider diff --git a/composer.json b/composer.json index 2614dcf584..1b3685b0d6 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,7 @@ "phpstan/phpstan-strict-rules": "^1.6", "phpunit/phpunit": "^9.5.4", "shipmonk/composer-dependency-analyser": "^1.5", + "shipmonk/dead-code-detector": "dev-master", "shipmonk/name-collision-detector": "^2.0" }, "config": { diff --git a/composer.lock b/composer.lock index c0f104e2b7..6974f2cff9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "674f9ec5e66603e465b9ef2aaa90189a", + "content-hash": "c3be42ae2bb62bce3d8c4ddd8efcdea4", "packages": [ { "name": "clue/ndjson-react", @@ -6469,6 +6469,75 @@ }, "time": "2024-08-08T08:12:32+00:00" }, + { + "name": "shipmonk/dead-code-detector", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/shipmonk-rnd/dead-code-detector.git", + "reference": "fc01208e573c00ab89cfa41d23c893fdb8d56d9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shipmonk-rnd/dead-code-detector/zipball/fc01208e573c00ab89cfa41d23c893fdb8d56d9a", + "reference": "fc01208e573c00ab89cfa41d23c893fdb8d56d9a", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^1.11.0" + }, + "require-dev": { + "doctrine/orm": "^2.19 || ^3.0", + "editorconfig-checker/editorconfig-checker": "^10.3.0", + "ergebnis/composer-normalize": "^2.28", + "nette/application": "^3.1", + "nette/component-model": "^3.0", + "nette/utils": "^3.0 || ^4.0", + "phpstan/phpstan-phpunit": "^1.1.1", + "phpstan/phpstan-strict-rules": "^1.2.3", + "phpstan/phpstan-symfony": "^1.4", + "phpunit/phpunit": "^9.5.20", + "shipmonk/composer-dependency-analyser": "^1.6", + "shipmonk/name-collision-detector": "^2.0.0", + "shipmonk/phpstan-rules": "^3.1", + "slevomat/coding-standard": "^8.15.0", + "symfony/contracts": "^2.5 || ^3.0", + "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/routing": "^5.4 || ^6.0 || ^7.0" + }, + "default-branch": true, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "ShipMonk\\PHPStan\\DeadCode\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Dead code detector to find unused PHP code via PHPStan extension.", + "keywords": [ + "PHPStan", + "dead code", + "static analysis", + "unused code" + ], + "support": { + "issues": "https://github.com/shipmonk-rnd/dead-code-detector/issues", + "source": "https://github.com/shipmonk-rnd/dead-code-detector/tree/master" + }, + "time": "2024-10-24T08:20:54+00:00" + }, { "name": "shipmonk/name-collision-detector", "version": "2.1.1", @@ -6581,7 +6650,8 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { - "jetbrains/phpstorm-stubs": 20 + "jetbrains/phpstorm-stubs": 20, + "shipmonk/dead-code-detector": 20 }, "prefer-stable": true, "prefer-lowest": false,