diff --git a/.github/workflows/bare_run.yaml b/.github/workflows/bare_run.yaml index 648da5344..e3a1fd9cd 100644 --- a/.github/workflows/bare_run.yaml +++ b/.github/workflows/bare_run.yaml @@ -1,9 +1,10 @@ name: Bare Run on various PHP versions on: + pull_request: null push: - tags: - - '*' + branches: + - main jobs: bare_run: @@ -12,12 +13,21 @@ jobs: strategy: fail-fast: false matrix: - php_version: ['7.4', '8.0', '8.1'] + php_version: ['7.4', '8.2', '8.5'] steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php }} + php-version: ${{ matrix.php_version }} coverage: none - - run: composer require rector/swiss-knife --dev --ansi + # verify sources parse on the target PHP version + - run: find bin src -name '*.php' -print0 | xargs -0 -n1 -P4 php -l + + # install prod dependencies only; dev tooling targets 8.x and is irrelevant here + - run: composer install --no-dev --ignore-platform-reqs --ansi + + # smoke-test the binary + - run: bin/swiss-knife diff --git a/.gitignore b/.gitignore index f6b653c76..ce18cf5bc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ composer.lock /vendor .phpunit.cache +.phpunit.result.cache tmp diff --git a/composer.json b/composer.json index 2e2497051..f6ead92c0 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "bin/swiss-knife" ], "require": { - "php": ">=8.4", + "php": ">=7.4", "ext-tokenizer": "*", "entropy/entropy": "^0.4.23", "nikic/php-parser": "^5.9" @@ -14,7 +14,7 @@ "require-dev": { "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.2", - "phpunit/phpunit": "^12.5", + "phpunit/phpunit": "^9.6", "rector/jack": "^1.1", "rector/rector": "^2.4", "shipmonk/composer-dependency-analyser": "^1.8", diff --git a/phpunit.xml b/phpunit.xml index e89aa98b4..9d1c4cb14 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -4,7 +4,6 @@ xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" - cacheDirectory=".phpunit.cache" > diff --git a/src/Analyzer/NeedsFinalizeAnalyzer.php b/src/Analyzer/NeedsFinalizeAnalyzer.php index 991b8f088..b4bd854d4 100644 --- a/src/Analyzer/NeedsFinalizeAnalyzer.php +++ b/src/Analyzer/NeedsFinalizeAnalyzer.php @@ -10,10 +10,21 @@ use Rector\SwissKnife\PhpParser\NodeTraverserFactory; use Rector\SwissKnife\PhpParser\NodeVisitor\NeedForFinalizeNodeVisitor; -final readonly class NeedsFinalizeAnalyzer +final class NeedsFinalizeAnalyzer { + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + + /** + * @readonly + */ private NodeTraverser $finalizingNodeTraverser; + /** + * @readonly + */ private NeedForFinalizeNodeVisitor $needForFinalizeNodeVisitor; /** @@ -21,8 +32,9 @@ */ public function __construct( array $excludedClasses, - private CachedPhpParser $cachedPhpParser + CachedPhpParser $cachedPhpParser ) { + $this->cachedPhpParser = $cachedPhpParser; Assert::allString($excludedClasses); $this->needForFinalizeNodeVisitor = new NeedForFinalizeNodeVisitor($excludedClasses); diff --git a/src/Command/CheckCommentedCodeCommand.php b/src/Command/CheckCommentedCodeCommand.php index 52bef075e..2e67c299a 100644 --- a/src/Command/CheckCommentedCodeCommand.php +++ b/src/Command/CheckCommentedCodeCommand.php @@ -11,14 +11,27 @@ use Rector\SwissKnife\Comments\CommentedCodeAnalyzer; use Rector\SwissKnife\Finder\PhpFilesFinder; -final readonly class CheckCommentedCodeCommand implements CommandInterface +final class CheckCommentedCodeCommand implements CommandInterface { - private const int DEFAULT_LINE_LIMIT = 5; + /** + * @readonly + */ + private CommentedCodeAnalyzer $commentedCodeAnalyzer; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; - public function __construct( - private CommentedCodeAnalyzer $commentedCodeAnalyzer, - private OutputPrinter $outputPrinter, - ) { + /** + * @var int + */ + private const DEFAULT_LINE_LIMIT = 5; + + public function __construct(CommentedCodeAnalyzer $commentedCodeAnalyzer, OutputPrinter $outputPrinter) + { + $this->commentedCodeAnalyzer = $commentedCodeAnalyzer; + $this->outputPrinter = $outputPrinter; } /** diff --git a/src/Command/CheckConflictsCommand.php b/src/Command/CheckConflictsCommand.php index 8c650f246..458324308 100644 --- a/src/Command/CheckConflictsCommand.php +++ b/src/Command/CheckConflictsCommand.php @@ -10,12 +10,22 @@ use Rector\SwissKnife\Finder\FilesFinder; use Rector\SwissKnife\Git\ConflictResolver; -final readonly class CheckConflictsCommand implements CommandInterface +final class CheckConflictsCommand implements CommandInterface { - public function __construct( - private ConflictResolver $conflictResolver, - private OutputPrinter $outputPrinter, - ) { + /** + * @readonly + */ + private ConflictResolver $conflictResolver; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + public function __construct(ConflictResolver $conflictResolver, OutputPrinter $outputPrinter) + { + $this->conflictResolver = $conflictResolver; + $this->outputPrinter = $outputPrinter; } /** diff --git a/src/Command/DuplicatedCodeCommand.php b/src/Command/DuplicatedCodeCommand.php index f8cfd0e3d..c9b3b2169 100644 --- a/src/Command/DuplicatedCodeCommand.php +++ b/src/Command/DuplicatedCodeCommand.php @@ -10,15 +10,26 @@ use Rector\SwissKnife\DuplicatedCode\CloneDetector; use Rector\SwissKnife\Finder\PhpFilesFinder; -final readonly class DuplicatedCodeCommand implements CommandInterface +final class DuplicatedCodeCommand implements CommandInterface { - private const int DEFAULT_MIN_LINES = 5; + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @var int + */ + private const DEFAULT_MIN_LINES = 5; - private const int DEFAULT_MIN_TOKENS = 70; + /** + * @var int + */ + private const DEFAULT_MIN_TOKENS = 70; - public function __construct( - private OutputPrinter $outputPrinter, - ) { + public function __construct(OutputPrinter $outputPrinter) + { + $this->outputPrinter = $outputPrinter; } /** diff --git a/src/Command/FeaturesCommand.php b/src/Command/FeaturesCommand.php index 811f84dda..962efd9aa 100644 --- a/src/Command/FeaturesCommand.php +++ b/src/Command/FeaturesCommand.php @@ -13,14 +13,34 @@ use Rector\SwissKnife\Lines\Finder\ProjectFilesFinder; use Rector\SwissKnife\Lines\OutputFormatter\JsonOutputFormatter; -final readonly class FeaturesCommand implements CommandInterface +final class FeaturesCommand implements CommandInterface { - public function __construct( - private OutputPrinter $outputPrinter, - private FeatureCounterAnalyzer $featureCounterAnalyzer, - private ResultPrinter $resultPrinter, - private JsonOutputFormatter $jsonOutputFormatter, - ) { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private FeatureCounterAnalyzer $featureCounterAnalyzer; + + /** + * @readonly + */ + private ResultPrinter $resultPrinter; + + /** + * @readonly + */ + private JsonOutputFormatter $jsonOutputFormatter; + + public function __construct(OutputPrinter $outputPrinter, FeatureCounterAnalyzer $featureCounterAnalyzer, ResultPrinter $resultPrinter, JsonOutputFormatter $jsonOutputFormatter) + { + $this->outputPrinter = $outputPrinter; + $this->featureCounterAnalyzer = $featureCounterAnalyzer; + $this->resultPrinter = $resultPrinter; + $this->jsonOutputFormatter = $jsonOutputFormatter; } /** diff --git a/src/Command/FinalizeClassesCommand.php b/src/Command/FinalizeClassesCommand.php index b008ca5df..19c8c5703 100644 --- a/src/Command/FinalizeClassesCommand.php +++ b/src/Command/FinalizeClassesCommand.php @@ -18,20 +18,46 @@ use Rector\SwissKnife\ParentClassResolver; use Rector\SwissKnife\PhpParser\CachedPhpParser; -final readonly class FinalizeClassesCommand implements CommandInterface +final class FinalizeClassesCommand implements CommandInterface { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private ParentClassResolver $parentClassResolver; + + /** + * @readonly + */ + private EntityClassResolver $entityClassResolver; + + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + + /** + * @readonly + */ + private MockedClassResolver $mockedClassResolver; + /** * @see https://regex101.com/r/Q5Nfbo/1 + * @var string */ - private const string NEWLINE_CLASS_START_REGEX = '#^(readonly )?class\s#m'; - - public function __construct( - private OutputPrinter $outputPrinter, - private ParentClassResolver $parentClassResolver, - private EntityClassResolver $entityClassResolver, - private CachedPhpParser $cachedPhpParser, - private MockedClassResolver $mockedClassResolver, - ) { + private const NEWLINE_CLASS_START_REGEX = '#^(readonly )?class\s#m'; + + public function __construct(OutputPrinter $outputPrinter, ParentClassResolver $parentClassResolver, EntityClassResolver $entityClassResolver, CachedPhpParser $cachedPhpParser, MockedClassResolver $mockedClassResolver) + { + $this->outputPrinter = $outputPrinter; + $this->parentClassResolver = $parentClassResolver; + $this->entityClassResolver = $entityClassResolver; + $this->cachedPhpParser = $cachedPhpParser; + $this->mockedClassResolver = $mockedClassResolver; } /** diff --git a/src/Command/FindMultiClassesCommand.php b/src/Command/FindMultiClassesCommand.php index e7b0cc907..fd20df642 100644 --- a/src/Command/FindMultiClassesCommand.php +++ b/src/Command/FindMultiClassesCommand.php @@ -11,12 +11,22 @@ use Rector\SwissKnife\Finder\MultipleClassInOneFileFinder; use Rector\SwissKnife\Finder\PhpFilesFinder; -final readonly class FindMultiClassesCommand implements CommandInterface +final class FindMultiClassesCommand implements CommandInterface { - public function __construct( - private MultipleClassInOneFileFinder $multipleClassInOneFileFinder, - private OutputPrinter $outputPrinter, - ) { + /** + * @readonly + */ + private MultipleClassInOneFileFinder $multipleClassInOneFileFinder; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + public function __construct(MultipleClassInOneFileFinder $multipleClassInOneFileFinder, OutputPrinter $outputPrinter) + { + $this->multipleClassInOneFileFinder = $multipleClassInOneFileFinder; + $this->outputPrinter = $outputPrinter; } /** diff --git a/src/Command/GenerateSymfonySmokeTestsCommand.php b/src/Command/GenerateSymfonySmokeTestsCommand.php index 9db622b46..08e509128 100644 --- a/src/Command/GenerateSymfonySmokeTestsCommand.php +++ b/src/Command/GenerateSymfonySmokeTestsCommand.php @@ -16,14 +16,34 @@ use Rector\SwissKnife\SmokeTestgen\Utils\TestPathResolver; use RuntimeException; -final readonly class GenerateSymfonySmokeTestsCommand implements CommandInterface +final class GenerateSymfonySmokeTestsCommand implements CommandInterface { - public function __construct( - private TestsDirectoryResolver $testsDirectoryResolver, - private TestTemplateResolver $testTemplateResolver, - private TemplateDecorator $templateDecorator, - private OutputPrinter $outputPrinter, - ) { + /** + * @readonly + */ + private TestsDirectoryResolver $testsDirectoryResolver; + + /** + * @readonly + */ + private TestTemplateResolver $testTemplateResolver; + + /** + * @readonly + */ + private TemplateDecorator $templateDecorator; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + public function __construct(TestsDirectoryResolver $testsDirectoryResolver, TestTemplateResolver $testTemplateResolver, TemplateDecorator $templateDecorator, OutputPrinter $outputPrinter) + { + $this->testsDirectoryResolver = $testsDirectoryResolver; + $this->testTemplateResolver = $testTemplateResolver; + $this->templateDecorator = $templateDecorator; + $this->outputPrinter = $outputPrinter; } public function getName(): string diff --git a/src/Command/MeasureCommand.php b/src/Command/MeasureCommand.php index f19001092..2fff35abe 100644 --- a/src/Command/MeasureCommand.php +++ b/src/Command/MeasureCommand.php @@ -13,14 +13,34 @@ use Rector\SwissKnife\Lines\OutputFormatter\JsonOutputFormatter; use Rector\SwissKnife\Lines\OutputFormatter\TextOutputFormatter; -final readonly class MeasureCommand implements CommandInterface +final class MeasureCommand implements CommandInterface { - public function __construct( - private OutputPrinter $outputPrinter, - private Analyser $analyser, - private JsonOutputFormatter $jsonOutputFormatter, - private TextOutputFormatter $textOutputFormatter, - ) { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private Analyser $analyser; + + /** + * @readonly + */ + private JsonOutputFormatter $jsonOutputFormatter; + + /** + * @readonly + */ + private TextOutputFormatter $textOutputFormatter; + + public function __construct(OutputPrinter $outputPrinter, Analyser $analyser, JsonOutputFormatter $jsonOutputFormatter, TextOutputFormatter $textOutputFormatter) + { + $this->outputPrinter = $outputPrinter; + $this->analyser = $analyser; + $this->jsonOutputFormatter = $jsonOutputFormatter; + $this->textOutputFormatter = $textOutputFormatter; } /** diff --git a/src/Command/NamespaceToPSR4Command.php b/src/Command/NamespaceToPSR4Command.php index 3825add22..334deeff9 100644 --- a/src/Command/NamespaceToPSR4Command.php +++ b/src/Command/NamespaceToPSR4Command.php @@ -15,11 +15,16 @@ /** * @see \Rector\SwissKnife\Tests\Command\NamespaceToPSR4CommandTest */ -final readonly class NamespaceToPSR4Command implements CommandInterface +final class NamespaceToPSR4Command implements CommandInterface { - public function __construct( - private OutputPrinter $outputPrinter, - ) { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + public function __construct(OutputPrinter $outputPrinter) + { + $this->outputPrinter = $outputPrinter; } /** @@ -42,7 +47,7 @@ public function run(string $path, string $namespaceRoot): int $expectedNamespaceLine = 'namespace ' . $expectedNamespace . ';'; // 1. got the correct namespace - if (\str_contains($fileInfo->getContents(), $expectedNamespaceLine)) { + if (strpos($fileInfo->getContents(), $expectedNamespaceLine) !== false) { continue; } @@ -105,7 +110,7 @@ private function findFilesInPath(string $path): array } // filter classes - return str_contains($fileInfo->getContents(), 'class '); + return strpos($fileInfo->getContents(), 'class ') !== false; }); } diff --git a/src/Command/PrivatizeConstantsCommand.php b/src/Command/PrivatizeConstantsCommand.php index 617a4e52e..d985de608 100644 --- a/src/Command/PrivatizeConstantsCommand.php +++ b/src/Command/PrivatizeConstantsCommand.php @@ -21,15 +21,40 @@ use Rector\SwissKnife\ValueObject\VisibilityChangeStats; use Rector\SwissKnife\YAML\YamlConfigConstantExtractor; -final readonly class PrivatizeConstantsCommand implements CommandInterface +final class PrivatizeConstantsCommand implements CommandInterface { - public function __construct( - private OutputPrinter $outputPrinter, - private ClassConstantFetchFinder $classConstantFetchFinder, - private ClassConstFinder $classConstFinder, - private TwigTemplateConstantExtractor $twigTemplateConstantExtractor, - private YamlConfigConstantExtractor $yamlConfigConstantExtractor - ) { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private ClassConstantFetchFinder $classConstantFetchFinder; + + /** + * @readonly + */ + private ClassConstFinder $classConstFinder; + + /** + * @readonly + */ + private TwigTemplateConstantExtractor $twigTemplateConstantExtractor; + + /** + * @readonly + */ + private YamlConfigConstantExtractor $yamlConfigConstantExtractor; + + public function __construct(OutputPrinter $outputPrinter, ClassConstantFetchFinder $classConstantFetchFinder, ClassConstFinder $classConstFinder, TwigTemplateConstantExtractor $twigTemplateConstantExtractor, YamlConfigConstantExtractor $yamlConfigConstantExtractor) + { + $this->outputPrinter = $outputPrinter; + $this->classConstantFetchFinder = $classConstantFetchFinder; + $this->classConstFinder = $classConstFinder; + $this->twigTemplateConstantExtractor = $twigTemplateConstantExtractor; + $this->yamlConfigConstantExtractor = $yamlConfigConstantExtractor; } public function getName(): string diff --git a/src/Command/SplitSymfonyConfigToPerPackageCommand.php b/src/Command/SplitSymfonyConfigToPerPackageCommand.php index 386c95c97..e6cb2c339 100644 --- a/src/Command/SplitSymfonyConfigToPerPackageCommand.php +++ b/src/Command/SplitSymfonyConfigToPerPackageCommand.php @@ -21,14 +21,29 @@ use Rector\SwissKnife\PhpParser\NodeVisitor\AddImportConfigMethodCallNodeVisitor; use Rector\SwissKnife\PhpParser\NodeVisitor\ExtractSymfonyExtensionCallNodeVisitor; -final readonly class SplitSymfonyConfigToPerPackageCommand implements CommandInterface +final class SplitSymfonyConfigToPerPackageCommand implements CommandInterface { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private SplitConfigClosureFactory $splitConfigClosureFactory; + + /** + * @readonly + */ private Standard $printerStandard; public function __construct( - private OutputPrinter $outputPrinter, - private SplitConfigClosureFactory $splitConfigClosureFactory, + OutputPrinter $outputPrinter, + SplitConfigClosureFactory $splitConfigClosureFactory ) { + $this->outputPrinter = $outputPrinter; + $this->splitConfigClosureFactory = $splitConfigClosureFactory; $this->printerStandard = new Standard(); } diff --git a/src/Comments/CommentedCodeAnalyzer.php b/src/Comments/CommentedCodeAnalyzer.php index a4b0ffa9c..c6150ee35 100644 --- a/src/Comments/CommentedCodeAnalyzer.php +++ b/src/Comments/CommentedCodeAnalyzer.php @@ -15,8 +15,9 @@ final class CommentedCodeAnalyzer /** * @see https://regex101.com/r/5OlGjG/1 * @see https://3v4l.org/Y8pSD + * @var string */ - private const string NEWLINE_REGEX = '#\r?\n#'; + private const NEWLINE_REGEX = '#\r?\n#'; /** * @return int[] @@ -30,7 +31,7 @@ public function process(string $filePath, int $commentedLinesCountLimit): array $commentLinesCount = 0; foreach ($fileLines as $key => $fileLine) { - $isCommentLine = str_starts_with(trim((string) $fileLine), '//'); + $isCommentLine = strncmp(trim((string) $fileLine), '//', strlen('//')) === 0; if ($isCommentLine) { ++$commentLinesCount; } else { diff --git a/src/DuplicatedCode/CloneDetector.php b/src/DuplicatedCode/CloneDetector.php index 49476dbae..a94f87d01 100644 --- a/src/DuplicatedCode/CloneDetector.php +++ b/src/DuplicatedCode/CloneDetector.php @@ -14,12 +14,27 @@ */ final class CloneDetector { + /** + * @readonly + */ + private int $minLines; + + /** + * @readonly + */ + private int $minTokens; + + /** + * @readonly + */ + private bool $fuzzy; + /** * Tokens that carry no structural meaning for clone detection. * * @var array */ - private const array IGNORED_TOKENS = [ + private const IGNORED_TOKENS = [ T_INLINE_HTML => true, T_COMMENT => true, T_DOC_COMMENT => true, @@ -31,8 +46,9 @@ final class CloneDetector /** * Bytes contributed by each kept token to the signature: 1 type byte + 4 CRC32 bytes. + * @var int */ - private const int BYTES_PER_TOKEN = 5; + private const BYTES_PER_TOKEN = 5; /** * First seen location per window hash: hash => [filePath, tokenIndex]. @@ -53,11 +69,11 @@ final class CloneDetector */ private array $clones = []; - public function __construct( - private readonly int $minLines, - private readonly int $minTokens, - private readonly bool $fuzzy - ) { + public function __construct(int $minLines, int $minTokens, bool $fuzzy) + { + $this->minLines = $minLines; + $this->minTokens = $minTokens; + $this->fuzzy = $fuzzy; } /** @@ -97,7 +113,7 @@ private function processFile(string $filePath): void $originToken = 0; for ($i = 0; $i <= $lastWindow; ++$i) { - $hash = substr(md5(substr($signature, $i * self::BYTES_PER_TOKEN, $windowBytes), true), 0, 8); + $hash = substr(md5((string) substr($signature, $i * self::BYTES_PER_TOKEN, $windowBytes), true), 0, 8); if (isset($this->hashes[$hash])) { if (! $found) { diff --git a/src/DuplicatedCode/ValueObject/CodeClone.php b/src/DuplicatedCode/ValueObject/CodeClone.php index c4ad52a6a..fbe36f032 100644 --- a/src/DuplicatedCode/ValueObject/CodeClone.php +++ b/src/DuplicatedCode/ValueObject/CodeClone.php @@ -4,13 +4,33 @@ namespace Rector\SwissKnife\DuplicatedCode\ValueObject; -final readonly class CodeClone +final class CodeClone { - public function __construct( - public CodeCloneFile $firstFile, - public CodeCloneFile $secondFile, - public int $lines, - public int $tokens - ) { + /** + * @readonly + */ + public CodeCloneFile $firstFile; + + /** + * @readonly + */ + public CodeCloneFile $secondFile; + + /** + * @readonly + */ + public int $lines; + + /** + * @readonly + */ + public int $tokens; + + public function __construct(CodeCloneFile $firstFile, CodeCloneFile $secondFile, int $lines, int $tokens) + { + $this->firstFile = $firstFile; + $this->secondFile = $secondFile; + $this->lines = $lines; + $this->tokens = $tokens; } } diff --git a/src/DuplicatedCode/ValueObject/CodeCloneFile.php b/src/DuplicatedCode/ValueObject/CodeCloneFile.php index 57e238dd5..f58378c43 100644 --- a/src/DuplicatedCode/ValueObject/CodeCloneFile.php +++ b/src/DuplicatedCode/ValueObject/CodeCloneFile.php @@ -4,12 +4,27 @@ namespace Rector\SwissKnife\DuplicatedCode\ValueObject; -final readonly class CodeCloneFile +final class CodeCloneFile { - public function __construct( - public string $filePath, - public int $startLine, - public int $endLine - ) { + /** + * @readonly + */ + public string $filePath; + + /** + * @readonly + */ + public int $startLine; + + /** + * @readonly + */ + public int $endLine; + + public function __construct(string $filePath, int $startLine, int $endLine) + { + $this->filePath = $filePath; + $this->startLine = $startLine; + $this->endLine = $endLine; } } diff --git a/src/EntityClassResolver.php b/src/EntityClassResolver.php index b0894478b..d77b02507 100644 --- a/src/EntityClassResolver.php +++ b/src/EntityClassResolver.php @@ -17,16 +17,22 @@ /** * @see \Rector\SwissKnife\Tests\EntityClassResolver\EntityClassResolverTest */ -final readonly class EntityClassResolver +final class EntityClassResolver { + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + /** * @see https://regex101.com/r/YFbH1x/1 + * @var string */ - private const string YAML_ENTITY_CLASS_NAME_REGEX = '#^(?[\w+\\\\]+)\:\n#m'; + private const YAML_ENTITY_CLASS_NAME_REGEX = '#^(?[\w+\\\\]+)\:\n#m'; - public function __construct( - private CachedPhpParser $cachedPhpParser - ) { + public function __construct(CachedPhpParser $cachedPhpParser) + { + $this->cachedPhpParser = $cachedPhpParser; } /** diff --git a/src/Enum/StaticAccessor.php b/src/Enum/StaticAccessor.php index a16623dd2..5ee622f1f 100644 --- a/src/Enum/StaticAccessor.php +++ b/src/Enum/StaticAccessor.php @@ -6,7 +6,13 @@ final class StaticAccessor { - public const string STATIC = 'static'; + /** + * @var string + */ + public const STATIC = 'static'; - public const string SELF = 'self'; + /** + * @var string + */ + public const SELF = 'self'; } diff --git a/src/Enum/SymfonyClass.php b/src/Enum/SymfonyClass.php index e01828b9c..5b4754586 100644 --- a/src/Enum/SymfonyClass.php +++ b/src/Enum/SymfonyClass.php @@ -8,5 +8,8 @@ final class SymfonyClass { - public const string CONTAINER_CONFIGURATOR_CLASS = ContainerConfigurator::class; + /** + * @var string + */ + public const CONTAINER_CONFIGURATOR_CLASS = ContainerConfigurator::class; } diff --git a/src/Finder/FilesFinder.php b/src/Finder/FilesFinder.php index 750bbf2ea..17720ecb3 100644 --- a/src/Finder/FilesFinder.php +++ b/src/Finder/FilesFinder.php @@ -16,7 +16,7 @@ final class FilesFinder /** * @var string[] */ - private const array SKIPPED_DIRECTORIES = ['node_modules', 'vendor', 'var/cache']; + private const SKIPPED_DIRECTORIES = ['node_modules', 'vendor', 'var/cache']; /** * @param string[] $sources @@ -36,7 +36,7 @@ public static function find(array $sources, array $excludedPaths = []): array // not our code $normalizedRelativePath = '/' . str_replace('\\', '/', $fileInfo->getRelativePathname()); foreach (self::SKIPPED_DIRECTORIES as $skippedDirectory) { - if (str_contains($normalizedRelativePath, '/' . $skippedDirectory . '/')) { + if (strpos($normalizedRelativePath, '/' . $skippedDirectory . '/') !== false) { return false; } } @@ -81,11 +81,11 @@ public static function findYamlFiles(array $paths): array private static function isExcluded(string $realPath, array $excludedPaths): bool { foreach ($excludedPaths as $excludedPath) { - if (str_contains($realPath, $excludedPath)) { + if (strpos($realPath, $excludedPath) !== false) { return true; } - if (str_contains($excludedPath, '*') && fnmatch($excludedPath, $realPath)) { + if (strpos($excludedPath, '*') !== false && fnmatch($excludedPath, $realPath)) { return true; } } diff --git a/src/Finder/MultipleClassInOneFileFinder.php b/src/Finder/MultipleClassInOneFileFinder.php index 9c18d123e..b82ae4d23 100644 --- a/src/Finder/MultipleClassInOneFileFinder.php +++ b/src/Finder/MultipleClassInOneFileFinder.php @@ -6,11 +6,16 @@ use Rector\SwissKnife\RobotLoader\PhpClassLoader; -final readonly class MultipleClassInOneFileFinder +final class MultipleClassInOneFileFinder { - public function __construct( - private PhpClassLoader $phpClassLoader - ) { + /** + * @readonly + */ + private PhpClassLoader $phpClassLoader; + + public function __construct(PhpClassLoader $phpClassLoader) + { + $this->phpClassLoader = $phpClassLoader; } /** diff --git a/src/Finder/PhpFilesFinder.php b/src/Finder/PhpFilesFinder.php index daeda016d..2594da43c 100644 --- a/src/Finder/PhpFilesFinder.php +++ b/src/Finder/PhpFilesFinder.php @@ -16,7 +16,7 @@ final class PhpFilesFinder /** * @var string[] */ - private const array SKIPPED_DIRECTORIES = ['vendor', 'var', 'data-fixtures', 'node_modules']; + private const SKIPPED_DIRECTORIES = ['vendor', 'var', 'data-fixtures', 'node_modules']; /** * @param string[] $paths @@ -32,7 +32,7 @@ public static function find(array $paths, array $excludedPaths = []): array $excludedFileNames = []; foreach ($excludedPaths as $excludedPath) { - if (! str_contains($excludedPath, '*')) { + if (strpos($excludedPath, '*') === false) { $excludedFileNames[] = $excludedPath; } } @@ -46,7 +46,7 @@ public static function find(array $paths, array $excludedPaths = []): array $normalizedRelativePath = '/' . str_replace('\\', '/', $fileInfo->getRelativePathname()); foreach (self::SKIPPED_DIRECTORIES as $skippedDirectory) { - if (str_contains($normalizedRelativePath, '/' . $skippedDirectory . '/')) { + if (strpos($normalizedRelativePath, '/' . $skippedDirectory . '/') !== false) { return false; } } @@ -54,11 +54,11 @@ public static function find(array $paths, array $excludedPaths = []): array $realPath = (string) $fileInfo->getRealPath(); foreach ($excludedPaths as $excludedPath) { - if (str_contains($realPath, $excludedPath)) { + if (strpos($realPath, $excludedPath) !== false) { return false; } - if (str_contains($excludedPath, '*') && fnmatch($excludedPath, $realPath)) { + if (strpos($excludedPath, '*') !== false && fnmatch($excludedPath, $realPath)) { return false; } } diff --git a/src/Git/ConflictResolver.php b/src/Git/ConflictResolver.php index a2b265c50..47b9d79a4 100644 --- a/src/Git/ConflictResolver.php +++ b/src/Git/ConflictResolver.php @@ -14,8 +14,9 @@ final class ConflictResolver { /** * @see https://regex101.com/r/L2CThC/1 + * @var string */ - private const string CONFLICT_REGEX = '#^(<<<<<<<|>>>>>>>)#m'; + private const CONFLICT_REGEX = '#^(<<<<<<<|>>>>>>>)#m'; /** * @api @@ -43,7 +44,7 @@ public function extractFromFileInfos(array $filePaths): array } // test fixtures, that should be ignored - if (str_contains((string) realpath($filePath), '/tests/Git/ConflictResolver/Fixture')) { + if (strpos((string) realpath($filePath), '/tests/Git/ConflictResolver/Fixture') !== false) { continue; } diff --git a/src/Lines/Analyser.php b/src/Lines/Analyser.php index 865113471..e4b1984c6 100644 --- a/src/Lines/Analyser.php +++ b/src/Lines/Analyser.php @@ -14,11 +14,16 @@ /** * @see \Rector\SwissKnife\Tests\Lines\AnalyserTest */ -final readonly class Analyser +final class Analyser { - public function __construct( - private Parser $parser, - ) { + /** + * @readonly + */ + private Parser $parser; + + public function __construct(Parser $parser) + { + $this->parser = $parser; } /** @@ -52,7 +57,7 @@ private function measureFile(Measurements $measurements, string $filePath): void try { // avoid stop on invalid file contents $stmts = $this->parser->parse($fileContents); - } catch (Throwable) { + } catch (Throwable $throwable) { return; } diff --git a/src/Lines/FeatureCounter/Enum/PhpVersion.php b/src/Lines/FeatureCounter/Enum/PhpVersion.php index 877387ae0..d258235b9 100644 --- a/src/Lines/FeatureCounter/Enum/PhpVersion.php +++ b/src/Lines/FeatureCounter/Enum/PhpVersion.php @@ -6,21 +6,48 @@ final class PhpVersion { - public const string PHP_70 = '7.0'; - - public const string PHP_71 = '7.1'; - - public const string PHP_72 = '7.2'; - - public const string PHP_74 = '7.4'; - - public const string PHP_80 = '8.0'; - - public const string PHP_81 = '8.1'; - - public const string PHP_82 = '8.2'; - - public const string PHP_83 = '8.3'; - - public const string PHP_84 = '8.4'; + /** + * @var string + */ + public const PHP_70 = '7.0'; + + /** + * @var string + */ + public const PHP_71 = '7.1'; + + /** + * @var string + */ + public const PHP_72 = '7.2'; + + /** + * @var string + */ + public const PHP_74 = '7.4'; + + /** + * @var string + */ + public const PHP_80 = '8.0'; + + /** + * @var string + */ + public const PHP_81 = '8.1'; + + /** + * @var string + */ + public const PHP_82 = '8.2'; + + /** + * @var string + */ + public const PHP_83 = '8.3'; + + /** + * @var string + */ + public const PHP_84 = '8.4'; } diff --git a/src/Lines/FeatureCounter/FeatureCounterAnalyzer.php b/src/Lines/FeatureCounter/FeatureCounterAnalyzer.php index c81fc5a1b..5887d3c65 100644 --- a/src/Lines/FeatureCounter/FeatureCounterAnalyzer.php +++ b/src/Lines/FeatureCounter/FeatureCounterAnalyzer.php @@ -16,13 +16,22 @@ /** * @see \Rector\SwissKnife\Tests\Lines\FeatureCounter\FeatureCounterAnalyzerTest */ -final readonly class FeatureCounterAnalyzer +final class FeatureCounterAnalyzer { + /** + * @readonly + */ + private FeatureCollector $featureCollector; + + /** + * @readonly + */ private Parser $parser; public function __construct( - private FeatureCollector $featureCollector, + FeatureCollector $featureCollector ) { + $this->featureCollector = $featureCollector; $parserFactory = new ParserFactory(); $this->parser = $parserFactory->createForNewestSupportedVersion(); } diff --git a/src/Lines/FeatureCounter/NodeVisitor/FeatureCollectorNodeVisitor.php b/src/Lines/FeatureCounter/NodeVisitor/FeatureCollectorNodeVisitor.php index 669267ac4..55e2ae8b6 100644 --- a/src/Lines/FeatureCounter/NodeVisitor/FeatureCollectorNodeVisitor.php +++ b/src/Lines/FeatureCounter/NodeVisitor/FeatureCollectorNodeVisitor.php @@ -10,9 +10,14 @@ final class FeatureCollectorNodeVisitor extends NodeVisitorAbstract { - public function __construct( - private readonly FeatureCollector $featureCollector - ) { + /** + * @readonly + */ + private FeatureCollector $featureCollector; + + public function __construct(FeatureCollector $featureCollector) + { + $this->featureCollector = $featureCollector; } public function enterNode(Node $node): ?Node diff --git a/src/Lines/FeatureCounter/ResultPrinter.php b/src/Lines/FeatureCounter/ResultPrinter.php index 0e8a5bbec..71407b47e 100644 --- a/src/Lines/FeatureCounter/ResultPrinter.php +++ b/src/Lines/FeatureCounter/ResultPrinter.php @@ -8,12 +8,22 @@ use Entropy\Console\Output\OutputPrinter; use Rector\SwissKnife\Lines\FeatureCounter\ValueObject\FeatureCollector; -final readonly class ResultPrinter +final class ResultPrinter { - public function __construct( - private OutputPrinter $outputPrinter, - private ConsoleTable $consoleTable, - ) { + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private ConsoleTable $consoleTable; + + public function __construct(OutputPrinter $outputPrinter, ConsoleTable $consoleTable) + { + $this->outputPrinter = $outputPrinter; + $this->consoleTable = $consoleTable; } public function print(FeatureCollector $featureCollector): void diff --git a/src/Lines/FeatureCounter/ValueObject/PhpFeature.php b/src/Lines/FeatureCounter/ValueObject/PhpFeature.php index 87af8f63e..04e807c39 100644 --- a/src/Lines/FeatureCounter/ValueObject/PhpFeature.php +++ b/src/Lines/FeatureCounter/ValueObject/PhpFeature.php @@ -8,16 +8,34 @@ final class PhpFeature { + /** + * @var PhpVersion::* + * @readonly + */ + private string $phpVersion; + + /** + * @readonly + */ + private string $name; + + /** + * @var callable + */ + private $nodeTrigger; + + private int $count; + /** * @param PhpVersion::* $phpVersion * @param callable $nodeTrigger */ - public function __construct( - private readonly string $phpVersion, - private readonly string $name, - private $nodeTrigger, - private int $count = 0 - ) { + public function __construct(string $phpVersion, string $name, $nodeTrigger, int $count = 0) + { + $this->phpVersion = $phpVersion; + $this->name = $name; + $this->nodeTrigger = $nodeTrigger; + $this->count = $count; } public function getPhpVersion(): string diff --git a/src/Lines/Finder/MeasureFileFinder.php b/src/Lines/Finder/MeasureFileFinder.php index 729abd065..50b82377c 100644 --- a/src/Lines/Finder/MeasureFileFinder.php +++ b/src/Lines/Finder/MeasureFileFinder.php @@ -42,17 +42,17 @@ static function (FileInfo $fileInfo) use ($excludes, $allowVendor): bool { $normalizedRelativePath = '/' . str_replace('\\', '/', $fileInfo->getRelativePathname()); // symfony cache dir - if (str_contains($normalizedRelativePath, '/var/')) { + if (strpos($normalizedRelativePath, '/var/') !== false) { return false; } - if (! $allowVendor && str_contains($normalizedRelativePath, '/vendor/')) { + if (! $allowVendor && strpos($normalizedRelativePath, '/vendor/') !== false) { return false; } $realPath = (string) $fileInfo->getRealPath(); foreach ($excludes as $exclude) { - if (str_contains($realPath, $exclude)) { + if (strpos($realPath, $exclude) !== false) { return false; } } diff --git a/src/Lines/Finder/ProjectFilesFinder.php b/src/Lines/Finder/ProjectFilesFinder.php index 953efcafd..939b24deb 100644 --- a/src/Lines/Finder/ProjectFilesFinder.php +++ b/src/Lines/Finder/ProjectFilesFinder.php @@ -12,7 +12,7 @@ final class ProjectFilesFinder /** * @var string[] */ - private const array SKIPPED_DIRECTORIES = ['vendor', 'stubs', 'bin', 'migrations', 'data-fixtures', 'build']; + private const SKIPPED_DIRECTORIES = ['vendor', 'stubs', 'bin', 'migrations', 'data-fixtures', 'build']; /** * @return FileInfo[] @@ -26,7 +26,7 @@ public static function find(string $projectDirectory): array $normalizedRelativePath = '/' . str_replace('\\', '/', $fileInfo->getRelativePathname()); foreach (self::SKIPPED_DIRECTORIES as $skippedDirectory) { - if (str_contains($normalizedRelativePath, '/' . $skippedDirectory . '/')) { + if (strpos($normalizedRelativePath, '/' . $skippedDirectory . '/') !== false) { return false; } } diff --git a/src/Lines/NodeVisitor/StructureNodeVisitor.php b/src/Lines/NodeVisitor/StructureNodeVisitor.php index 7885cdbcc..a34e79e99 100644 --- a/src/Lines/NodeVisitor/StructureNodeVisitor.php +++ b/src/Lines/NodeVisitor/StructureNodeVisitor.php @@ -21,9 +21,14 @@ final class StructureNodeVisitor extends NodeVisitorAbstract { - public function __construct( - private readonly Measurements $measurements - ) { + /** + * @readonly + */ + private Measurements $measurements; + + public function __construct(Measurements $measurements) + { + $this->measurements = $measurements; } public function enterNode(Node $node): ?Node diff --git a/src/Lines/NumberFormat.php b/src/Lines/NumberFormat.php index 81a1fc541..f2ffe0107 100644 --- a/src/Lines/NumberFormat.php +++ b/src/Lines/NumberFormat.php @@ -6,17 +6,26 @@ final class NumberFormat { - public static function pretty(int|float $number): string + /** + * @param int|float $number + */ + public static function pretty($number): string { return number_format($number, 0, '.', ' '); } - public static function singleDecimal(float|int $number): float + /** + * @param float|int $number + */ + public static function singleDecimal($number): float { return (float) number_format($number, 1); } - public static function percent(float|int $number): string + /** + * @param float|int $number + */ + public static function percent($number): string { return self::singleDecimal($number) . ' %'; } diff --git a/src/Lines/OutputFormatter/TextOutputFormatter.php b/src/Lines/OutputFormatter/TextOutputFormatter.php index 601066612..9dfe61582 100644 --- a/src/Lines/OutputFormatter/TextOutputFormatter.php +++ b/src/Lines/OutputFormatter/TextOutputFormatter.php @@ -12,12 +12,22 @@ use Rector\SwissKnife\Lines\Measurements; use Rector\SwissKnife\Lines\NumberFormat; -final readonly class TextOutputFormatter +final class TextOutputFormatter { - public function __construct( - private ViewRenderer $viewRenderer, - private OutputPrinter $outputPrinter, - ) { + /** + * @readonly + */ + private ViewRenderer $viewRenderer; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + public function __construct(ViewRenderer $viewRenderer, OutputPrinter $outputPrinter) + { + $this->viewRenderer = $viewRenderer; + $this->outputPrinter = $outputPrinter; } public function printMeasurement(Measurements $measurements, bool $isShort, bool $showLongestFiles): void diff --git a/src/MockedClassResolver.php b/src/MockedClassResolver.php index 26b1fed4e..1203b3216 100644 --- a/src/MockedClassResolver.php +++ b/src/MockedClassResolver.php @@ -12,11 +12,16 @@ use Rector\SwissKnife\PhpParser\NodeTraverserFactory; use Rector\SwissKnife\PhpParser\NodeVisitor\MockedClassNameCollectingNodeVisitor; -final readonly class MockedClassResolver +final class MockedClassResolver { - public function __construct( - private CachedPhpParser $cachedPhpParser - ) { + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + + public function __construct(CachedPhpParser $cachedPhpParser) + { + $this->cachedPhpParser = $cachedPhpParser; } /** diff --git a/src/ParentClassResolver.php b/src/ParentClassResolver.php index 70ef7d689..8be5623ba 100644 --- a/src/ParentClassResolver.php +++ b/src/ParentClassResolver.php @@ -10,11 +10,16 @@ use Rector\SwissKnife\PhpParser\NodeTraverserFactory; use Rector\SwissKnife\PhpParser\NodeVisitor\ParentClassNameCollectingNodeVisitor; -final readonly class ParentClassResolver +final class ParentClassResolver { - public function __construct( - private CachedPhpParser $cachedPhpParser, - ) { + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + + public function __construct(CachedPhpParser $cachedPhpParser) + { + $this->cachedPhpParser = $cachedPhpParser; } /** diff --git a/src/PhpParser/CachedPhpParser.php b/src/PhpParser/CachedPhpParser.php index d267090c1..0346101d1 100644 --- a/src/PhpParser/CachedPhpParser.php +++ b/src/PhpParser/CachedPhpParser.php @@ -16,14 +16,19 @@ */ final class CachedPhpParser { + /** + * @readonly + */ + private Parser $phpParser; + /** * @var array */ private array $cachedStmts = []; - public function __construct( - private readonly Parser $phpParser - ) { + public function __construct(Parser $phpParser) + { + $this->phpParser = $phpParser; } /** diff --git a/src/PhpParser/Finder/ClassConstFinder.php b/src/PhpParser/Finder/ClassConstFinder.php index 8b896ffc8..b1f56ab99 100644 --- a/src/PhpParser/Finder/ClassConstFinder.php +++ b/src/PhpParser/Finder/ClassConstFinder.php @@ -12,11 +12,16 @@ /** * @see \Rector\SwissKnife\Tests\PhpParser\Finder\ClassConstFinder\ClassConstFinderTest */ -final readonly class ClassConstFinder +final class ClassConstFinder { - public function __construct( - private CachedPhpParser $cachedPhpParser - ) { + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + + public function __construct(CachedPhpParser $cachedPhpParser) + { + $this->cachedPhpParser = $cachedPhpParser; } /** diff --git a/src/PhpParser/Finder/ClassConstantFetchFinder.php b/src/PhpParser/Finder/ClassConstantFetchFinder.php index b98f64e49..1eb3022c2 100644 --- a/src/PhpParser/Finder/ClassConstantFetchFinder.php +++ b/src/PhpParser/Finder/ClassConstantFetchFinder.php @@ -17,12 +17,22 @@ /** * @see \Rector\SwissKnife\Tests\PhpParser\ClassConstantFetchFinder\ClassConstantFetchFinderTest */ -final readonly class ClassConstantFetchFinder +final class ClassConstantFetchFinder { - public function __construct( - private CachedPhpParser $cachedPhpParser, - private OutputPrinter $outputPrinter, - ) { + /** + * @readonly + */ + private CachedPhpParser $cachedPhpParser; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + public function __construct(CachedPhpParser $cachedPhpParser, OutputPrinter $outputPrinter) + { + $this->cachedPhpParser = $cachedPhpParser; + $this->outputPrinter = $outputPrinter; } /** diff --git a/src/PhpParser/NodeVisitor/AddImportConfigMethodCallNodeVisitor.php b/src/PhpParser/NodeVisitor/AddImportConfigMethodCallNodeVisitor.php index 5f3fca705..9c63e646e 100644 --- a/src/PhpParser/NodeVisitor/AddImportConfigMethodCallNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/AddImportConfigMethodCallNodeVisitor.php @@ -17,12 +17,17 @@ final class AddImportConfigMethodCallNodeVisitor extends NodeVisitorAbstract { - public function __construct( - private readonly string $outputDirectory - ) { + /** + * @readonly + */ + private string $outputDirectory; + + public function __construct(string $outputDirectory) + { + $this->outputDirectory = $outputDirectory; } - public function enterNode(Node $node): int|null + public function enterNode(Node $node): ?int { if (! $node instanceof Closure) { return null; diff --git a/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php b/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php index 030def73d..b1f644019 100644 --- a/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php @@ -16,12 +16,12 @@ final class EntityClassNameCollectingNodeVisitor extends NodeVisitorAbstract /** * @var string[] */ - private const array ODM_SUFFIXES = ['Document', 'EmbeddedDocument']; + private const ODM_SUFFIXES = ['Document', 'EmbeddedDocument']; /** * @var string[] */ - private const array ORM_SUFFIXES = ['Entity', 'Embeddable']; + private const ORM_SUFFIXES = ['Entity', 'Embeddable']; /** * @var string[] @@ -68,12 +68,12 @@ private function hasDocBlockSuffixes(Class_ $class, array $suffixes): bool $docComment = $class->getDocComment(); if ($docComment instanceof Doc) { // dummy check - if (! str_contains($docComment->getText(), '@')) { + if (strpos($docComment->getText(), '@') === false) { return false; } foreach ($suffixes as $suffix) { - if (str_contains($docComment->getText(), $suffix)) { + if (strpos($docComment->getText(), $suffix) !== false) { return true; } } @@ -92,7 +92,7 @@ private function hasAttributeSuffixes(Class_ $class, array $suffixes): bool foreach ($class->attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { foreach ($suffixes as $suffix) { - if (str_ends_with($attr->name->toString(), $suffix)) { + if (substr_compare($attr->name->toString(), $suffix, -strlen($suffix)) === 0) { return true; } } diff --git a/src/PhpParser/NodeVisitor/ExtractSymfonyExtensionCallNodeVisitor.php b/src/PhpParser/NodeVisitor/ExtractSymfonyExtensionCallNodeVisitor.php index 362e1d530..31f2220e9 100644 --- a/src/PhpParser/NodeVisitor/ExtractSymfonyExtensionCallNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/ExtractSymfonyExtensionCallNodeVisitor.php @@ -12,14 +12,17 @@ final class ExtractSymfonyExtensionCallNodeVisitor extends NodeVisitorAbstract { - private const string EXTENSION_METHOD_NAME = 'extension'; + /** + * @var string + */ + private const EXTENSION_METHOD_NAME = 'extension'; /** * @var MethodCall[] */ private array $extensionMethodCalls = []; - public function enterNode(Node $node): int|null + public function enterNode(Node $node): ?int { if (! $node instanceof Expression) { return null; diff --git a/src/PhpParser/NodeVisitor/FindClassConstFetchNodeVisitor.php b/src/PhpParser/NodeVisitor/FindClassConstFetchNodeVisitor.php index 69a898ae2..a08a30471 100644 --- a/src/PhpParser/NodeVisitor/FindClassConstFetchNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/FindClassConstFetchNodeVisitor.php @@ -34,7 +34,10 @@ final class FindClassConstFetchNodeVisitor extends NodeVisitorAbstract */ private array $classConstantFetches = []; - public function enterNode(Node $node): Node|int|null + /** + * @return Node|int|null + */ + public function enterNode(Node $node) { if ($node instanceof Interface_ || $node instanceof Trait_ || $node instanceof Enum_) { return NodeTraverser::DONT_TRAVERSE_CHILDREN; @@ -148,7 +151,7 @@ private function isVendorClassName(string $className): bool } $reflectionClass = new ReflectionClass($className); - return str_contains((string) $reflectionClass->getFileName(), 'vendor'); + return strpos((string) $reflectionClass->getFileName(), 'vendor') !== false; } private function isCurrentClassConstant(Class_ $currentClass, string $constantName): bool diff --git a/src/PhpParser/NodeVisitor/FindNonPrivateClassConstNodeVisitor.php b/src/PhpParser/NodeVisitor/FindNonPrivateClassConstNodeVisitor.php index 21a2d21e3..805d336ad 100644 --- a/src/PhpParser/NodeVisitor/FindNonPrivateClassConstNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/FindNonPrivateClassConstNodeVisitor.php @@ -69,10 +69,15 @@ private function isConstantDefinedInParentClassAlso(Class_ $class, string $const } } - return array_any( - $class->implements, - fn (Name $name): bool => in_array($constantName, $this->getClassConstantNames($name->toString()), true) - ); + $found = false; + foreach ($class->implements as $name) { + if (in_array($constantName, $this->getClassConstantNames($name->toString()), true)) { + $found = true; + break; + } + } + + return $found; } /** diff --git a/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php b/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php index f95fbf162..b53b9a79f 100644 --- a/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php @@ -11,14 +11,20 @@ final class NeedForFinalizeNodeVisitor extends NodeVisitorAbstract { + /** + * @var string[] + * @readonly + */ + private array $excludedClasses; + private bool $isNeeded = false; /** * @param string[] $excludedClasses */ - public function __construct( - private readonly array $excludedClasses - ) { + public function __construct(array $excludedClasses) + { + $this->excludedClasses = $excludedClasses; } /** diff --git a/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php b/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php index f0124cd29..3b5385084 100644 --- a/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php @@ -42,20 +42,20 @@ public function getParentClassNames(): array // remove native classes $namespacedClassNames = array_filter( $uniqueParentClassNames, - static fn (string $parentClassName): bool => str_contains($parentClassName, '\\') + static fn (string $parentClassName): bool => strpos($parentClassName, '\\') !== false ); // remove obviously vendor names $namespacedClassNames = array_filter($namespacedClassNames, static function (string $className): bool { - if (str_contains($className, 'Symfony\\')) { + if (strpos($className, 'Symfony\\') !== false) { return false; } - if (str_contains($className, 'PHPStan\\')) { + if (strpos($className, 'PHPStan\\') !== false) { return false; } - return ! str_contains($className, 'PhpParser\\'); + return strpos($className, 'PhpParser\\') === false; }); return array_values($namespacedClassNames); diff --git a/src/Testing/Command/DetectUnitTestsCommand.php b/src/Testing/Command/DetectUnitTestsCommand.php index 81b7559ec..8d8e82df4 100644 --- a/src/Testing/Command/DetectUnitTestsCommand.php +++ b/src/Testing/Command/DetectUnitTestsCommand.php @@ -12,15 +12,33 @@ use Rector\SwissKnife\Testing\Printer\PHPUnitXmlPrinter; use Rector\SwissKnife\Testing\UnitTestFilePathsFinder; -final readonly class DetectUnitTestsCommand implements CommandInterface +final class DetectUnitTestsCommand implements CommandInterface { - private const string OUTPUT_FILENAME = 'phpunit-unit-files.xml'; + /** + * @readonly + */ + private PHPUnitXmlPrinter $phpUnitXmlPrinter; + + /** + * @readonly + */ + private OutputPrinter $outputPrinter; + + /** + * @readonly + */ + private UnitTestFilePathsFinder $unitTestFilePathsFinder; + + /** + * @var string + */ + private const OUTPUT_FILENAME = 'phpunit-unit-files.xml'; - public function __construct( - private PHPUnitXmlPrinter $phpunitXmlPrinter, - private OutputPrinter $outputPrinter, - private UnitTestFilePathsFinder $unitTestFilePathsFinder, - ) { + public function __construct(PHPUnitXmlPrinter $phpunitXmlPrinter, OutputPrinter $outputPrinter, UnitTestFilePathsFinder $unitTestFilePathsFinder) + { + $this->phpUnitXmlPrinter = $phpunitXmlPrinter; + $this->outputPrinter = $outputPrinter; + $this->unitTestFilePathsFinder = $unitTestFilePathsFinder; } /** @@ -38,7 +56,7 @@ public function run(array $sources): int return ExitCode::SUCCESS; } - $filesPHPUnitXmlContents = $this->phpunitXmlPrinter->printFiles($unitTestCasesClassesToFilePaths); + $filesPHPUnitXmlContents = $this->phpUnitXmlPrinter->printFiles($unitTestCasesClassesToFilePaths); FileSystem::write(self::OUTPUT_FILENAME, $filesPHPUnitXmlContents); diff --git a/src/Testing/UnitTestFilePathsFinder.php b/src/Testing/UnitTestFilePathsFinder.php index 409b27d13..954e11018 100644 --- a/src/Testing/UnitTestFilePathsFinder.php +++ b/src/Testing/UnitTestFilePathsFinder.php @@ -9,12 +9,22 @@ /** * @see \Rector\SwissKnife\Tests\Testing\UnitTestFilePathsFinder\UnitTestFilePathsFinderTest */ -final readonly class UnitTestFilePathsFinder +final class UnitTestFilePathsFinder { - public function __construct( - private TestCaseClassFinder $testCaseClassFinder, - private UnitTestFilter $unitTestFilter, - ) { + /** + * @readonly + */ + private TestCaseClassFinder $testCaseClassFinder; + + /** + * @readonly + */ + private UnitTestFilter $unitTestFilter; + + public function __construct(TestCaseClassFinder $testCaseClassFinder, UnitTestFilter $unitTestFilter) + { + $this->testCaseClassFinder = $testCaseClassFinder; + $this->unitTestFilter = $unitTestFilter; } /** diff --git a/src/Testing/UnitTestFilter.php b/src/Testing/UnitTestFilter.php index c36504c3f..9acbdc670 100644 --- a/src/Testing/UnitTestFilter.php +++ b/src/Testing/UnitTestFilter.php @@ -11,7 +11,7 @@ final class UnitTestFilter /** * @var string[]|class-string[] */ - private const array NON_UNIT_TEST_CASE_CLASSES = [ + private const NON_UNIT_TEST_CASE_CLASSES = [ KernelTestCase::class, 'Symfony\Component\Form\Test\TypeTestCase', ]; @@ -22,7 +22,11 @@ final class UnitTestFilter */ public function filter(array $testClassesToFilePaths): array { - return array_filter($testClassesToFilePaths, $this->isUnitTest(...), ARRAY_FILTER_USE_KEY); + return array_filter( + $testClassesToFilePaths, + fn (string $class): bool => $this->isUnitTest($class), + ARRAY_FILTER_USE_KEY + ); } private function isUnitTest(string $class): bool @@ -31,9 +35,14 @@ private function isUnitTest(string $class): bool return false; } - return array_all( - self::NON_UNIT_TEST_CASE_CLASSES, - fn (string $nonUnitTestCaseClass): bool => ! is_a($class, $nonUnitTestCaseClass, true) - ); + $found = true; + foreach (self::NON_UNIT_TEST_CASE_CLASSES as $nonUnitTestCaseClass) { + if (is_a($class, $nonUnitTestCaseClass, true)) { + $found = false; + break; + } + } + + return $found; } } diff --git a/src/Twig/TwigTemplateConstantExtractor.php b/src/Twig/TwigTemplateConstantExtractor.php index 0c00a5080..02d601ab0 100644 --- a/src/Twig/TwigTemplateConstantExtractor.php +++ b/src/Twig/TwigTemplateConstantExtractor.php @@ -47,7 +47,7 @@ private function findClassConstantFetchesInFile(string $filePath): array $constantMatchValue = $constantMatch['constant']; // global constant → skip - if (! str_contains((string) $constantMatchValue, '::')) { + if (strpos((string) $constantMatchValue, '::') === false) { continue; } diff --git a/src/ValueObject/ClassConstant.php b/src/ValueObject/ClassConstant.php index fbcadf914..6dca27fa4 100644 --- a/src/ValueObject/ClassConstant.php +++ b/src/ValueObject/ClassConstant.php @@ -6,15 +6,28 @@ use Entropy\Validation\Assert; -final readonly class ClassConstant +final class ClassConstant { + /** + * @var class-string + * @readonly + */ + private string $className; + + /** + * @readonly + */ + private string $constantName; + /** * @param class-string $className */ public function __construct( - private string $className, - private string $constantName, + string $className, + string $constantName ) { + $this->className = $className; + $this->constantName = $constantName; Assert::notEmpty($constantName); Assert::notEmpty($className); } diff --git a/src/ValueObject/ClassConstantFetch/AbstractClassConstantFetch.php b/src/ValueObject/ClassConstantFetch/AbstractClassConstantFetch.php index ddeb50349..3712e6335 100644 --- a/src/ValueObject/ClassConstantFetch/AbstractClassConstantFetch.php +++ b/src/ValueObject/ClassConstantFetch/AbstractClassConstantFetch.php @@ -9,10 +9,20 @@ abstract class AbstractClassConstantFetch implements ClassConstantFetchInterface { - public function __construct( - private readonly string $className, - private readonly string $constantName - ) { + /** + * @readonly + */ + private string $className; + + /** + * @readonly + */ + private string $constantName; + + public function __construct(string $className, string $constantName) + { + $this->className = $className; + $this->constantName = $constantName; } public function getClassName(): string diff --git a/tests/EntityClassResolver/EntityClassResolverTest.php b/tests/EntityClassResolver/EntityClassResolverTest.php index c3b2afd24..e482b6bfb 100644 --- a/tests/EntityClassResolver/EntityClassResolverTest.php +++ b/tests/EntityClassResolver/EntityClassResolverTest.php @@ -4,7 +4,6 @@ namespace Rector\SwissKnife\Tests\EntityClassResolver; -use Override; use Rector\SwissKnife\EntityClassResolver; use Rector\SwissKnife\Tests\AbstractTestCase; use Rector\SwissKnife\Tests\EntityClassResolver\Fixture\Anything\SomeAttributeDocument; @@ -15,7 +14,6 @@ final class EntityClassResolverTest extends AbstractTestCase { private EntityClassResolver $entityClassResolver; - #[Override] protected function setUp(): void { parent::setUp(); diff --git a/tests/Git/ConflictResolver/ConflictResolverTest.php b/tests/Git/ConflictResolver/ConflictResolverTest.php index 6fadf5ad0..fab7e66b3 100644 --- a/tests/Git/ConflictResolver/ConflictResolverTest.php +++ b/tests/Git/ConflictResolver/ConflictResolverTest.php @@ -5,7 +5,6 @@ namespace Rector\SwissKnife\Tests\Git\ConflictResolver; use Iterator; -use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Rector\SwissKnife\Git\ConflictResolver; @@ -18,7 +17,9 @@ protected function setUp(): void $this->conflictResolver = new ConflictResolver(); } - #[DataProvider('provideData')] + /** + * @dataProvider provideData + */ public function test(string $filePath, int $expectedConflictCount): void { $unresolvedConflictCount = $this->conflictResolver->extractFromFileInfo($filePath); diff --git a/tests/NeedsFinalizeAnalyzer/NeedsFinalizeAnalyzerTest.php b/tests/NeedsFinalizeAnalyzer/NeedsFinalizeAnalyzerTest.php index 03d0f2798..3a6095c04 100644 --- a/tests/NeedsFinalizeAnalyzer/NeedsFinalizeAnalyzerTest.php +++ b/tests/NeedsFinalizeAnalyzer/NeedsFinalizeAnalyzerTest.php @@ -4,8 +4,6 @@ namespace Rector\SwissKnife\Tests\NeedsFinalizeAnalyzer; -use Override; -use PHPUnit\Framework\Attributes\DataProvider; use Rector\SwissKnife\Analyzer\NeedsFinalizeAnalyzer; use Rector\SwissKnife\PhpParser\CachedPhpParser; use Rector\SwissKnife\Tests\AbstractTestCase; @@ -14,18 +12,19 @@ final class NeedsFinalizeAnalyzerTest extends AbstractTestCase { private NeedsFinalizeAnalyzer $needsFinalizeAnalyzer; - #[Override] protected function setUp(): void { parent::setUp(); $this->needsFinalizeAnalyzer = new NeedsFinalizeAnalyzer( - excludedClasses: ['Rector\SwissKnife\Tests\NeedsFinalizeAnalyzer\Fixture\ExcludedClass'], - cachedPhpParser: $this->make(CachedPhpParser::class), + ['Rector\SwissKnife\Tests\NeedsFinalizeAnalyzer\Fixture\ExcludedClass'], + $this->make(CachedPhpParser::class), ); } - #[DataProvider('provideData')] + /** + * @dataProvider provideData + */ public function test(string $filePath, bool $expected): void { $this->assertSame($expected, $this->needsFinalizeAnalyzer->isNeeded($filePath)); diff --git a/tests/ParentClassResolver/ParentClassResolverTest.php b/tests/ParentClassResolver/ParentClassResolverTest.php index 91347734e..541d7e285 100644 --- a/tests/ParentClassResolver/ParentClassResolverTest.php +++ b/tests/ParentClassResolver/ParentClassResolverTest.php @@ -4,7 +4,6 @@ namespace Rector\SwissKnife\Tests\ParentClassResolver; -use Override; use Rector\SwissKnife\Finder\PhpFilesFinder; use Rector\SwissKnife\ParentClassResolver; use Rector\SwissKnife\Tests\AbstractTestCase; @@ -16,7 +15,6 @@ final class ParentClassResolverTest extends AbstractTestCase { private ParentClassResolver $parentClassResolver; - #[Override] protected function setUp(): void { parent::setUp(); diff --git a/tests/PhpParser/Finder/ClassConstFinder/ClassConstFinderTest.php b/tests/PhpParser/Finder/ClassConstFinder/ClassConstFinderTest.php index 0a17396df..ff3f54eb2 100644 --- a/tests/PhpParser/Finder/ClassConstFinder/ClassConstFinderTest.php +++ b/tests/PhpParser/Finder/ClassConstFinder/ClassConstFinderTest.php @@ -5,8 +5,6 @@ namespace Rector\SwissKnife\Tests\PhpParser\Finder\ClassConstFinder; use Iterator; -use Override; -use PHPUnit\Framework\Attributes\DataProvider; use Rector\SwissKnife\PhpParser\Finder\ClassConstFinder; use Rector\SwissKnife\Tests\AbstractTestCase; @@ -14,7 +12,6 @@ final class ClassConstFinderTest extends AbstractTestCase { private ClassConstFinder $classConstFinder; - #[Override] protected function setUp(): void { parent::setUp(); @@ -22,7 +19,9 @@ protected function setUp(): void $this->classConstFinder = $this->make(ClassConstFinder::class); } - #[DataProvider('provideData')] + /** + * @dataProvider provideData + */ public function test(string $filePath, int $expectedClassConstantCount): void { $classConstants = $this->classConstFinder->find($filePath); diff --git a/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php b/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php index d50551ced..15f193fa6 100644 --- a/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php +++ b/tests/PhpParser/Finder/ClassConstantFetchFinder/ClassConstantFetchFinderTest.php @@ -5,7 +5,6 @@ namespace Rector\SwissKnife\Tests\PhpParser\Finder\ClassConstantFetchFinder; use Entropy\Console\Output\ProgressBar; -use Override; use Rector\SwissKnife\Contract\ClassConstantFetchInterface; use Rector\SwissKnife\Finder\PhpFilesFinder; use Rector\SwissKnife\PhpParser\Finder\ClassConstantFetchFinder; @@ -18,7 +17,6 @@ final class ClassConstantFetchFinderTest extends AbstractTestCase { private ClassConstantFetchFinder $classConstantFetchFinder; - #[Override] protected function setUp(): void { parent::setUp(); diff --git a/tests/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor/MockedClassNameCollectingNodeVisitorTest.php b/tests/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor/MockedClassNameCollectingNodeVisitorTest.php index bd6ba62cc..3eda1f1b8 100644 --- a/tests/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor/MockedClassNameCollectingNodeVisitorTest.php +++ b/tests/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor/MockedClassNameCollectingNodeVisitorTest.php @@ -7,7 +7,6 @@ use Iterator; use PhpParser\NodeTraverser; use PhpParser\ParserFactory; -use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Rector\SwissKnife\PhpParser\NodeVisitor\MockedClassNameCollectingNodeVisitor; @@ -15,22 +14,19 @@ final class MockedClassNameCollectingNodeVisitorTest extends TestCase { /** * @param string[] $expectedClassNames + * @dataProvider provideData */ - #[DataProvider('provideData')] public function test(string $filePath, array $expectedClassNames): void { $mockedClassNameCollectingNodeVisitor = new MockedClassNameCollectingNodeVisitor(); - $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor($mockedClassNameCollectingNodeVisitor); - $parser = new ParserFactory() + $parser = (new ParserFactory()) ->createForNewestSupportedVersion(); $stmts = $parser->parse((string) file_get_contents($filePath)); $this->assertNotNull($stmts); - $nodeTraverser->traverse($stmts); - $this->assertSame($expectedClassNames, $mockedClassNameCollectingNodeVisitor->getMockedClassNames()); } diff --git a/tests/Twig/TwigTemplateConstantExtractor/TwigTemplateConstantExtractorTest.php b/tests/Twig/TwigTemplateConstantExtractor/TwigTemplateConstantExtractorTest.php index b90d46711..ef5caf36e 100644 --- a/tests/Twig/TwigTemplateConstantExtractor/TwigTemplateConstantExtractorTest.php +++ b/tests/Twig/TwigTemplateConstantExtractor/TwigTemplateConstantExtractorTest.php @@ -4,7 +4,6 @@ namespace Rector\SwissKnife\Tests\Twig\TwigTemplateConstantExtractor; -use Override; use Rector\SwissKnife\Contract\ClassConstantFetchInterface; use Rector\SwissKnife\Tests\AbstractTestCase; use Rector\SwissKnife\Tests\Twig\TwigTemplateConstantExtractor\Fixture\SomeTemplateUsedConstant; @@ -14,7 +13,6 @@ final class TwigTemplateConstantExtractorTest extends AbstractTestCase { private TwigTemplateConstantExtractor $twigTemplateConstantExtractor; - #[Override] protected function setUp(): void { parent::setUp(); diff --git a/tests/YAML/YamlConfigConstantExtractor/YamlConfigConstantExtractorTest.php b/tests/YAML/YamlConfigConstantExtractor/YamlConfigConstantExtractorTest.php index 50e6b9649..e12b46691 100644 --- a/tests/YAML/YamlConfigConstantExtractor/YamlConfigConstantExtractorTest.php +++ b/tests/YAML/YamlConfigConstantExtractor/YamlConfigConstantExtractorTest.php @@ -4,7 +4,6 @@ namespace Rector\SwissKnife\Tests\YAML\YamlConfigConstantExtractor; -use Override; use Rector\SwissKnife\Tests\AbstractTestCase; use Rector\SwissKnife\Tests\YAML\YamlConfigConstantExtractor\Fixture\SomeClassWithConstant; use Rector\SwissKnife\YAML\YamlConfigConstantExtractor; @@ -13,7 +12,6 @@ final class YamlConfigConstantExtractorTest extends AbstractTestCase { private YamlConfigConstantExtractor $yamlConfigConstantExtractor; - #[Override] protected function setUp(): void { parent::setUp();