diff --git a/composer.json b/composer.json index 879870963e8..38b96ad6737 100644 --- a/composer.json +++ b/composer.json @@ -50,13 +50,13 @@ "phpunit/phpunit": "^13.3", "rector/swiss-knife": "^2.7", "shipmonk/composer-dependency-analyser": "^1.8", + "shipmonk/dead-code-detector": "^1.4", "symfony/process": "^8.1", "symplify/easy-coding-standard": "^13.2.13", "symplify/phpstan-rules": "^14.18", "tomasvotruba/class-leak": "^2.1", "tomasvotruba/fast-unit": "^0.1", "tomasvotruba/type-coverage": "^2.3.6", - "tomasvotruba/unused-public": "^2.2", "tracy/tracy": "^2.12" }, "replace": { diff --git a/phpstan.neon b/phpstan.neon index 4d738e20e15..dd1e3bf83b4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -67,13 +67,24 @@ parameters: narrow_param: true narrow_return: true - # see https://github.com/TomasVotruba/unused-public - unused_public: - methods: true - properties: true - constants: true + # offload breaks cold-cache parallel runs, keep collector data in result cache + shipmonkDeadCode: + cache: + offloadCollectorData: false ignoreErrors: + # called magically by parent + - + message: '#^Unused Rector\\PhpParser\\Printer\\BetterStandardPrinter\:\:(pInterpolatedStringPart|pStmt_FileNode)$#' + identifier: shipmonk.deadMethod + path: src/PhpParser/Printer/BetterStandardPrinter.php + + # deprecated, to be removed + - + message: '#^Unused Rector\\Set\\Contract\\SetInterface\:\:(.*?)$#' + identifier: shipmonk.deadMethod + path: src/Set/Contract/SetInterface.php + # the deprecated set objects are still resolved internally, until every extension bonds its rules - message: '#deprecated (class|interface) Rector\\(Set|Bridge)\\#' diff --git a/rules/Php80/Contract/StrStartWithMatchAndRefactorInterface.php b/rules/Php80/Contract/StrStartWithMatchAndRefactorInterface.php index 5a9eadde45f..639de06ce29 100644 --- a/rules/Php80/Contract/StrStartWithMatchAndRefactorInterface.php +++ b/rules/Php80/Contract/StrStartWithMatchAndRefactorInterface.php @@ -15,9 +15,13 @@ interface StrStartWithMatchAndRefactorInterface { + /** + * @api implemented by child classes + */ public function match(Identical|NotIdentical|Equal|NotEqual $binaryOp): ?StrStartsWith; /** + * @api implemented by child classes * @return FuncCall|BooleanNot|null */ public function refactorStrStartsWith(StrStartsWith $strStartsWith): ?Node; diff --git a/src/BetterPhpDocParser/Contract/PhpDocParser/PhpDocNodeDecoratorInterface.php b/src/BetterPhpDocParser/Contract/PhpDocParser/PhpDocNodeDecoratorInterface.php index 7d556956015..c95b4bc56b4 100644 --- a/src/BetterPhpDocParser/Contract/PhpDocParser/PhpDocNodeDecoratorInterface.php +++ b/src/BetterPhpDocParser/Contract/PhpDocParser/PhpDocNodeDecoratorInterface.php @@ -9,5 +9,8 @@ interface PhpDocNodeDecoratorInterface { + /** + * @api implemented by child classes + */ public function decorate(PhpDocNode $phpDocNode, Node $phpNode): void; } diff --git a/src/Parallel/Contract/SerializableInterface.php b/src/Parallel/Contract/SerializableInterface.php index 250986e4c66..a08a6a9e890 100644 --- a/src/Parallel/Contract/SerializableInterface.php +++ b/src/Parallel/Contract/SerializableInterface.php @@ -9,6 +9,7 @@ interface SerializableInterface extends JsonSerializable { /** + * @api implemented by child classes * @param array $json */ public static function decode(array $json): self; diff --git a/tests/BetterPhpDocParser/PhpDocInfo/PhpDocInfoPrinter/AbstractPhpDocInfoPrinterTestCase.php b/tests/BetterPhpDocParser/PhpDocInfo/PhpDocInfoPrinter/AbstractPhpDocInfoPrinterTestCase.php index 997b88b4c5c..b93c336d408 100644 --- a/tests/BetterPhpDocParser/PhpDocInfo/PhpDocInfoPrinter/AbstractPhpDocInfoPrinterTestCase.php +++ b/tests/BetterPhpDocParser/PhpDocInfo/PhpDocInfoPrinter/AbstractPhpDocInfoPrinterTestCase.php @@ -9,13 +9,10 @@ use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo; use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory; use Rector\BetterPhpDocParser\Printer\PhpDocInfoPrinter; -use Rector\FileSystem\FilePathHelper; use Rector\Testing\PHPUnit\AbstractLazyTestCase; abstract class AbstractPhpDocInfoPrinterTestCase extends AbstractLazyTestCase { - protected FilePathHelper $filePathHelper; - protected PhpDocInfoPrinter $phpDocInfoPrinter; private PhpDocInfoFactory $phpDocInfoFactory; @@ -24,7 +21,6 @@ protected function setUp(): void { parent::setUp(); - $this->filePathHelper = $this->make(FilePathHelper::class); $this->phpDocInfoFactory = $this->make(PhpDocInfoFactory::class); $this->phpDocInfoPrinter = $this->make(PhpDocInfoPrinter::class); } diff --git a/tests/Caching/ValueObject/Storage/FileCacheStorageTest.php b/tests/Caching/ValueObject/Storage/FileCacheStorageTest.php index 3eb792855cb..54411bd6767 100644 --- a/tests/Caching/ValueObject/Storage/FileCacheStorageTest.php +++ b/tests/Caching/ValueObject/Storage/FileCacheStorageTest.php @@ -77,9 +77,4 @@ public function testSaveLeavesConcurrentReaderOnCompleteFile(): void $this->fileCacheStorage->clean('aaK1STfY'); } - - public function provideConfigFilePath(): string - { - return __DIR__ . '/config.php'; - } } diff --git a/utils/phpstan/src/Rule/NoScopeFetchBeforeCheapGuardRule.php b/utils/phpstan/src/Rule/NoScopeFetchBeforeCheapGuardRule.php index b891ccca98a..6f4ed34c916 100644 --- a/utils/phpstan/src/Rule/NoScopeFetchBeforeCheapGuardRule.php +++ b/utils/phpstan/src/Rule/NoScopeFetchBeforeCheapGuardRule.php @@ -7,8 +7,11 @@ use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Assign; +use PhpParser\Node\Expr\ConstFetch; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; @@ -102,7 +105,7 @@ private function matchScopeFetchVariableName(Stmt $stmt): ?string } $staticCall = $assign->expr; - if (! $staticCall->class instanceof Node\Name) { + if (! $staticCall->class instanceof Name) { return null; } @@ -110,7 +113,7 @@ private function matchScopeFetchVariableName(Stmt $stmt): ?string return null; } - if (! $staticCall->name instanceof Node\Identifier || $staticCall->name->toString() !== 'fetch') { + if (! $staticCall->name instanceof Identifier || $staticCall->name->toString() !== 'fetch') { return null; } @@ -128,17 +131,17 @@ private function isReturnNullGuard(If_ $if): bool return false; } - return $onlyStmt->expr === null || $this->isNullConstant($onlyStmt->expr); + return ! $onlyStmt->expr instanceof Expr || $this->isNullConstant($onlyStmt->expr); } private function isNullConstant(Expr $expr): bool { - return $expr instanceof Node\Expr\ConstFetch && $expr->name->toLowerString() === 'null'; + return $expr instanceof ConstFetch && $expr->name->toLowerString() === 'null'; } private function usesVariable(Expr $expr, string $variableName): bool { - $foundVariable = (new NodeFinder())->findFirst( + $foundVariable = new NodeFinder()->findFirst( [$expr], static fn (Node $subNode): bool => $subNode instanceof Variable && $subNode->name === $variableName );