diff --git a/build/baseline-7.4.neon b/build/baseline-7.4.neon index 82e6b89e0c..b28b9f9f5d 100644 --- a/build/baseline-7.4.neon +++ b/build/baseline-7.4.neon @@ -77,7 +77,3 @@ parameters: message: "#^Class PHPStan\\\\Reflection\\\\BetterReflection\\\\SourceLocator\\\\CachingVisitor has an uninitialized property \\$constantNodes\\. Give it default value or assign it in the constructor\\.$#" count: 1 path: ../src/Reflection/BetterReflection/SourceLocator/CachingVisitor.php - - - message: "#^Class PHPStan\\\\Reflection\\\\ReflectionProvider\\\\SetterReflectionProviderProvider has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#" - count: 1 - path: ../src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php diff --git a/build/phpstan.neon b/build/phpstan.neon index bf0a4652ac..3d099857e2 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 @@ -71,6 +72,22 @@ parameters: - '#should be contravariant with parameter \$node \(PhpParser\\Node\) of method PHPStan\\Rules\\Rule::processNode\(\)$#' - '#Variable property access on PhpParser\\Node#' - '#Test::data[a-zA-Z0-9_]+\(\) return type has no value type specified in iterable type#' + - + identifier: shipmonk.deadMethod + message: '#^Unused .*?Factory::create#' # likely used in DIC + - + identifier: shipmonk.deadMethod + paths: + - ../tests/PHPStan/Tests + - ../tests/e2e + - + identifier: shipmonk.deadConstant + paths: + - ../tests/PHPStan/Fixture + reportUnmatched: false # constants on enums, not reported on PHP8- + - + identifier: shipmonk.deadMethod + path: ../src/Reflection/BetterReflection/SourceLocator/FileReadTrapStreamWrapper.php - message: '#Fetching class constant class of deprecated class DeprecatedAnnotations\\DeprecatedFoo.#' path: ../tests/PHPStan/Reflection/Annotations/DeprecatedAnnotationsTest.php diff --git a/composer.json b/composer.json index d10f417491..11a1ee76b7 100644 --- a/composer.json +++ b/composer.json @@ -62,6 +62,7 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^9.6", "shipmonk/composer-dependency-analyser": "^1.5", + "shipmonk/dead-code-detector": "^0.12.0", "shipmonk/name-collision-detector": "^2.0" }, "config": { diff --git a/composer.lock b/composer.lock index b893805aba..59365ba683 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": "baacfd9f6f313439fbc41174b0ac33c8", + "content-hash": "3048aa1c538e9ea0ccfcddbb6a95c705", "packages": [ { "name": "clue/ndjson-react", @@ -6338,6 +6338,81 @@ }, "time": "2024-08-08T08:12:32+00:00" }, + { + "name": "shipmonk/dead-code-detector", + "version": "0.12.0", + "source": { + "type": "git", + "url": "https://github.com/shipmonk-rnd/dead-code-detector.git", + "reference": "1f0c70ec4e9868c785f6505592dfb01ef53af2ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/shipmonk-rnd/dead-code-detector/zipball/1f0c70ec4e9868c785f6505592dfb01ef53af2ca", + "reference": "1f0c70ec4e9868c785f6505592dfb01ef53af2ca", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.9" + }, + "require-dev": { + "composer-runtime-api": "^2.0", + "composer/semver": "^3.4", + "doctrine/orm": "^2.19 || ^3.0", + "editorconfig-checker/editorconfig-checker": "^10.6.0", + "ergebnis/composer-normalize": "^2.45.0", + "nette/application": "^3.1", + "nette/component-model": "^3.0", + "nette/utils": "^3.0 || ^4.0", + "nikic/php-parser": "^5.4.0", + "phpstan/phpstan-phpunit": "^2.0.4", + "phpstan/phpstan-strict-rules": "^2.0.3", + "phpstan/phpstan-symfony": "^2.0.2", + "phpunit/phpunit": "^9.6.22", + "shipmonk/composer-dependency-analyser": "^1.8.2", + "shipmonk/name-collision-detector": "^2.1.1", + "shipmonk/phpstan-rules": "^4.1.0", + "slevomat/coding-standard": "^8.16.0", + "symfony/contracts": "^2.5 || ^3.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/doctrine-bridge": "^5.4 || ^6.0 || ^7.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", + "symfony/validator": "^5.4 || ^6.0 || ^7.0", + "twig/twig": "^3.0" + }, + "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. Can automatically remove dead PHP code. Supports libraries like Symfony, Doctrine, PHPUnit etc. Detects dead cycles. Can detect dead code that is tested.", + "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/0.12.0" + }, + "time": "2025-05-16T13:02:10+00:00" + }, { "name": "shipmonk/name-collision-detector", "version": "2.1.1", diff --git a/src/Command/FixerApplication.php b/src/Command/FixerApplication.php index 1a9e64d7fe..f6c62244c0 100644 --- a/src/Command/FixerApplication.php +++ b/src/Command/FixerApplication.php @@ -465,7 +465,7 @@ private function analyse( }); }); - $process = new ProcessPromise($loop, 'changedFileAnalysis', ProcessHelper::getWorkerCommand( + $process = new ProcessPromise($loop, ProcessHelper::getWorkerCommand( $mainScript, 'fixer:worker', $projectConfigFile, diff --git a/src/Command/Symfony/SymfonyStyle.php b/src/Command/Symfony/SymfonyStyle.php index e8782a5f59..4008ec0b2a 100644 --- a/src/Command/Symfony/SymfonyStyle.php +++ b/src/Command/Symfony/SymfonyStyle.php @@ -15,11 +15,6 @@ public function __construct(private StyleInterface $symfonyStyle) { } - public function getSymfonyStyle(): StyleInterface - { - return $this->symfonyStyle; - } - public function title(string $message): void { $this->symfonyStyle->title($message); diff --git a/src/DependencyInjection/BleedingEdgeToggle.php b/src/DependencyInjection/BleedingEdgeToggle.php index 29170f7fe9..98e9a52d41 100644 --- a/src/DependencyInjection/BleedingEdgeToggle.php +++ b/src/DependencyInjection/BleedingEdgeToggle.php @@ -7,7 +7,7 @@ final class BleedingEdgeToggle private static bool $bleedingEdge = false; - public static function isBleedingEdge(): bool + public static function isBleedingEdge(): bool // @phpstan-ignore shipmonk.deadMethod (kept for future use) { return self::$bleedingEdge; } diff --git a/src/DependencyInjection/NeonAdapter.php b/src/DependencyInjection/NeonAdapter.php index 0cd90db645..a6d189a7ba 100644 --- a/src/DependencyInjection/NeonAdapter.php +++ b/src/DependencyInjection/NeonAdapter.php @@ -4,7 +4,6 @@ use Nette\DI\Config\Adapter; use Nette\DI\Config\Helpers; -use Nette\DI\Definitions\Reference; use Nette\DI\Definitions\Statement; use Nette\DI\InvalidConfigurationException; use Nette\Neon\Entity; @@ -14,7 +13,6 @@ use PHPStan\File\FileHelper; use PHPStan\File\FileReader; use function array_values; -use function array_walk_recursive; use function count; use function dirname; use function implode; @@ -155,58 +153,6 @@ public function process(array $arr, string $fileKey, string $file): array return $res; } - /** - * @param mixed[] $data - */ - public function dump(array $data): string - { - array_walk_recursive( - $data, - static function (&$val): void { - if (!($val instanceof Statement)) { - return; - } - - $val = self::statementToEntity($val); - }, - ); - return "# generated by Nette\n\n" . Neon::encode($data, Neon::BLOCK); - } - - private static function statementToEntity(Statement $val): Entity - { - array_walk_recursive( - $val->arguments, - static function (&$val): void { - if ($val instanceof Statement) { - $val = self::statementToEntity($val); - } elseif ($val instanceof Reference) { - $val = '@' . $val->getValue(); - } - }, - ); - - $entity = $val->getEntity(); - if ($entity instanceof Reference) { - $entity = '@' . $entity->getValue(); - } elseif (is_array($entity)) { - if ($entity[0] instanceof Statement) { - return new Entity( - Neon::CHAIN, - [ - self::statementToEntity($entity[0]), - new Entity('::' . $entity[1], $val->arguments), - ], - ); - } elseif ($entity[0] instanceof Reference) { - $entity = '@' . $entity[0]->getValue() . '::' . $entity[1]; - } elseif (is_string($entity[0])) { - $entity = $entity[0] . '::' . $entity[1]; - } - } - return new Entity($entity, $val->arguments); - } - private function createFileHelperByFile(string $file): FileHelper { $dir = dirname($file); diff --git a/src/File/FileMonitor.php b/src/File/FileMonitor.php index 6fd0eaf8ef..3f8b9f0d3c 100644 --- a/src/File/FileMonitor.php +++ b/src/File/FileMonitor.php @@ -5,7 +5,6 @@ use PHPStan\ShouldNotHappenException; use function array_key_exists; use function array_keys; -use function count; use function sha1_file; final class FileMonitor @@ -75,7 +74,6 @@ public function getChanges(): FileMonitorResult $newFiles, $changedFiles, $deletedFiles, - count($fileHashes), ); } diff --git a/src/File/FileMonitorResult.php b/src/File/FileMonitorResult.php index 8c7e405dc0..f76ae9dde4 100644 --- a/src/File/FileMonitorResult.php +++ b/src/File/FileMonitorResult.php @@ -16,7 +16,6 @@ public function __construct( private array $newFiles, private array $changedFiles, private array $deletedFiles, - private int $totalFilesCount, ) { } @@ -36,9 +35,4 @@ public function hasAnyChanges(): bool || count($this->deletedFiles) > 0; } - public function getTotalFilesCount(): int - { - return $this->totalFilesCount; - } - } diff --git a/src/PhpDoc/PhpDocBlock.php b/src/PhpDoc/PhpDocBlock.php index 8036cd78ee..434770b42d 100644 --- a/src/PhpDoc/PhpDocBlock.php +++ b/src/PhpDoc/PhpDocBlock.php @@ -27,7 +27,6 @@ private function __construct( private ?string $file, private ClassReflection $classReflection, private ?string $trait, - private bool $explicit, private array $parameterNameMapping, private array $parents, ) @@ -54,11 +53,6 @@ public function getTrait(): ?string return $this->trait; } - public function isExplicit(): bool - { - return $this->explicit; - } - /** * @return array */ @@ -115,7 +109,6 @@ public static function resolvePhpDocBlockForProperty( ?string $trait, string $propertyName, ?string $file, - ?bool $explicit, ): self { $docBlocksFromParents = []; @@ -123,7 +116,6 @@ public static function resolvePhpDocBlockForProperty( $oneResult = self::resolvePropertyPhpDocBlockFromClass( $parentReflection, $propertyName, - $explicit ?? $docComment !== null, ); if ($oneResult === null) { // Null if it is private or from a wrong trait. @@ -138,7 +130,6 @@ public static function resolvePhpDocBlockForProperty( $file, $classReflection, $trait, - $explicit ?? true, [], $docBlocksFromParents, ); @@ -149,7 +140,6 @@ public static function resolvePhpDocBlockForConstant( ClassReflection $classReflection, string $constantName, ?string $file, - ?bool $explicit, ): self { $docBlocksFromParents = []; @@ -157,7 +147,6 @@ public static function resolvePhpDocBlockForConstant( $oneResult = self::resolveConstantPhpDocBlockFromClass( $parentReflection, $constantName, - $explicit ?? $docComment !== null, ); if ($oneResult === null) { // Null if it is private or from a wrong trait. @@ -172,7 +161,6 @@ public static function resolvePhpDocBlockForConstant( $file, $classReflection, null, - $explicit ?? true, [], $docBlocksFromParents, ); @@ -188,7 +176,6 @@ public static function resolvePhpDocBlockForMethod( ?string $trait, string $methodName, ?string $file, - ?bool $explicit, array $originalPositionalParameterNames, array $newPositionalParameterNames, ): self @@ -198,7 +185,6 @@ public static function resolvePhpDocBlockForMethod( $oneResult = self::resolveMethodPhpDocBlockFromClass( $parentReflection, $methodName, - $explicit ?? $docComment !== null, $newPositionalParameterNames, ); @@ -234,7 +220,6 @@ public static function resolvePhpDocBlockForMethod( $classReflection->getFileName(), $classReflection, $traitReflection->getName(), - $explicit ?? $traitMethod->getDocComment() !== null, self::remapParameterNames($newPositionalParameterNames, $positionalMethodParameterNames), [], ); @@ -245,7 +230,6 @@ public static function resolvePhpDocBlockForMethod( $file, $classReflection, $trait, - $explicit ?? true, self::remapParameterNames($originalPositionalParameterNames, $newPositionalParameterNames), $docBlocksFromParents, ); @@ -294,7 +278,6 @@ private static function getParentReflections(ClassReflection $classReflection): private static function resolveConstantPhpDocBlockFromClass( ClassReflection $classReflection, string $name, - bool $explicit, ): ?self { if ($classReflection->hasConstant($name)) { @@ -310,7 +293,6 @@ private static function resolveConstantPhpDocBlockFromClass( $classReflection, $name, $classReflection->getFileName(), - $explicit, ); } @@ -320,7 +302,6 @@ private static function resolveConstantPhpDocBlockFromClass( private static function resolvePropertyPhpDocBlockFromClass( ClassReflection $classReflection, string $name, - bool $explicit, ): ?self { if ($classReflection->hasNativeProperty($name)) { @@ -342,7 +323,6 @@ private static function resolvePropertyPhpDocBlockFromClass( $trait, $name, $classReflection->getFileName(), - $explicit, ); } @@ -355,7 +335,6 @@ private static function resolvePropertyPhpDocBlockFromClass( private static function resolveMethodPhpDocBlockFromClass( ClassReflection $classReflection, string $name, - bool $explicit, array $positionalParameterNames, ): ?self { @@ -396,7 +375,6 @@ private static function resolveMethodPhpDocBlockFromClass( $trait, $name, $classReflection->getFileName(), - $explicit, $positionalParameterNames, $positionalMethodParameterNames, ); diff --git a/src/PhpDoc/PhpDocInheritanceResolver.php b/src/PhpDoc/PhpDocInheritanceResolver.php index 5b6aaacc3b..b240a79322 100644 --- a/src/PhpDoc/PhpDocInheritanceResolver.php +++ b/src/PhpDoc/PhpDocInheritanceResolver.php @@ -32,7 +32,6 @@ public function resolvePhpDocForProperty( null, $propertyName, $classReflectionFileName, - null, ); return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, $declaringTraitName, null, $propertyName, null); @@ -50,7 +49,6 @@ public function resolvePhpDocForConstant( $classReflection, $constantName, $classReflectionFileName, - null, ); return $this->docBlockTreeToResolvedDocBlock($phpDocBlock, null, null, null, $constantName); @@ -74,7 +72,6 @@ public function resolvePhpDocForMethod( $declaringTraitName, $methodName, $fileName, - null, $positionalParameterNames, $positionalParameterNames, ); diff --git a/src/Process/ProcessPromise.php b/src/Process/ProcessPromise.php index 5a526b771e..afc50f087d 100644 --- a/src/Process/ProcessPromise.php +++ b/src/Process/ProcessPromise.php @@ -22,18 +22,13 @@ final class ProcessPromise private bool $canceled = false; - public function __construct(private LoopInterface $loop, private string $name, private string $command) + public function __construct(private LoopInterface $loop, private string $command) { $this->deferred = new Deferred(function (): void { $this->cancel(); }); } - public function getName(): string - { - return $this->name; - } - /** * @return PromiseInterface */ diff --git a/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php b/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php deleted file mode 100644 index 2ae0d7c9ff..0000000000 --- a/src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php +++ /dev/null @@ -1,22 +0,0 @@ -reflectionProvider = $reflectionProvider; - } - - public function getReflectionProvider(): ReflectionProvider - { - return $this->reflectionProvider; - } - -} diff --git a/src/Reflection/ResolvedPropertyReflection.php b/src/Reflection/ResolvedPropertyReflection.php index 8b54c0785a..7646de8651 100644 --- a/src/Reflection/ResolvedPropertyReflection.php +++ b/src/Reflection/ResolvedPropertyReflection.php @@ -2,7 +2,6 @@ namespace PHPStan\Reflection; -use PHPStan\Reflection\Php\PhpPropertyReflection; use PHPStan\TrinaryLogic; use PHPStan\Type\Generic\TemplateTypeHelper; use PHPStan\Type\Generic\TemplateTypeMap; @@ -40,15 +39,6 @@ public function getDeclaringClass(): ClassReflection return $this->reflection->getDeclaringClass(); } - public function getDeclaringTrait(): ?ClassReflection - { - if ($this->reflection instanceof PhpPropertyReflection) { - return $this->reflection->getDeclaringTrait(); - } - - return null; - } - public function isStatic(): bool { return $this->reflection->isStatic(); diff --git a/src/Type/Generic/TemplateTypeTrait.php b/src/Type/Generic/TemplateTypeTrait.php index 52c13a9680..a35451b64f 100644 --- a/src/Type/Generic/TemplateTypeTrait.php +++ b/src/Type/Generic/TemplateTypeTrait.php @@ -297,11 +297,6 @@ public function getStrategy(): TemplateTypeStrategy return $this->strategy; } - protected function shouldGeneralizeInferredType(): bool - { - return true; - } - public function traverse(callable $cb): Type { $bound = $cb($this->getBound()); diff --git a/src/Type/SimultaneousTypeTraverser.php b/src/Type/SimultaneousTypeTraverser.php index 046727de88..d9a3d69783 100644 --- a/src/Type/SimultaneousTypeTraverser.php +++ b/src/Type/SimultaneousTypeTraverser.php @@ -2,6 +2,9 @@ namespace PHPStan\Type; +/** + * @api + */ final class SimultaneousTypeTraverser { diff --git a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php index f03764a657..a1a6beb6d0 100644 --- a/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ExistingClassesInTypehintsRuleTest.php @@ -416,16 +416,6 @@ public function testIntersectionTypes(int $phpVersion, array $errors): void $this->analyse([__DIR__ . '/data/intersection-types.php'], $errors); } - public function dataTrueTypes(): array - { - return [ - [ - 80200, - [], - ], - ]; - } - public function testTrueTypehint(): void { if (PHP_VERSION_ID >= 80200) {