diff --git a/config/set/downgrade-php80.php b/config/set/downgrade-php80.php index d28a2a4fae9..8fe3d2e5e10 100644 --- a/config/set/downgrade-php80.php +++ b/config/set/downgrade-php80.php @@ -37,5 +37,6 @@ return static function (\RectorPrefix20210530\Symfony\Component\DependencyInject $services->set(\Rector\DowngradePhp80\Rector\ClassConstFetch\DowngradeClassOnObjectToGetClassRector::class); $services->set(\Rector\DowngradePhp80\Rector\NullsafeMethodCall\DowngradeNullsafeToTernaryOperatorRector::class); $services->set(\Rector\DowngradePhp80\Rector\ClassMethod\DowngradeTrailingCommasInParamUseRector::class); - $services->set(\Rector\DowngradePhp80\Rector\Class_\DowngradeAttributeToAnnotationRector::class); + $services->set(\Rector\DowngradePhp80\Rector\FuncCall\DowngradeStrStartsWithRector::class); + $services->set(\Rector\DowngradePhp80\Rector\FuncCall\DowngradeStrEndsWithRector::class); }; diff --git a/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php b/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php index 74214f4a4f2..de207b61149 100644 --- a/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php +++ b/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php @@ -84,7 +84,7 @@ final class ClassAnnotationMatcher return $useUse->name->toString(); } $unaliasedShortClass = \RectorPrefix20210530\Nette\Utils\Strings::substring($tag, \RectorPrefix20210530\Nette\Utils\Strings::length($useUse->alias->toString())); - if (\str_starts_with($unaliasedShortClass, '\\')) { + if (\strncmp($unaliasedShortClass, '\\', \strlen('\\')) === 0) { return $useUse->name . $unaliasedShortClass; } return $useUse->name . '\\' . $unaliasedShortClass; diff --git a/packages/ChangesReporting/Annotation/AnnotationExtractor.php b/packages/ChangesReporting/Annotation/AnnotationExtractor.php index 6e6484f0089..c37e675f1bb 100644 --- a/packages/ChangesReporting/Annotation/AnnotationExtractor.php +++ b/packages/ChangesReporting/Annotation/AnnotationExtractor.php @@ -21,8 +21,9 @@ final class AnnotationExtractor if (!\is_string($docComment)) { return null; } - // @see https://regex101.com/r/oYGaWU/1 - $pattern = '#' . \preg_quote($annotation, '#') . '\\s+(?.*?)$#m'; + // @see https://3v4l.org/ouYfB + // uses 'r?\n' instead of '$' because windows compat + $pattern = '#' . \preg_quote($annotation, '#') . '\\s+(?.*?)\\r?\\n#m'; $matches = \RectorPrefix20210530\Nette\Utils\Strings::match($docComment, $pattern); return $matches['content'] ?? null; } diff --git a/packages/Comments/CommentRemover.php b/packages/Comments/CommentRemover.php index 7fcb3166a43..445d69d7647 100644 --- a/packages/Comments/CommentRemover.php +++ b/packages/Comments/CommentRemover.php @@ -22,10 +22,10 @@ final class CommentRemover $this->commentRemovingNodeTraverser = $commentRemovingNodeTraverser; } /** - * @param Node[]|Node|null $node - * @return Node[]|null + * @return mixed[]|null + * @param mixed[]|\PhpParser\Node|null $node */ - public function removeFromNode($node) : ?array + public function removeFromNode($node) { if ($node === null) { return null; diff --git a/packages/FileFormatter/Formatter/XmlFileFormatter.php b/packages/FileFormatter/Formatter/XmlFileFormatter.php index ab5f912aad0..bd3f34e1283 100644 --- a/packages/FileFormatter/Formatter/XmlFileFormatter.php +++ b/packages/FileFormatter/Formatter/XmlFileFormatter.php @@ -69,7 +69,7 @@ final class XmlFileFormatter implements \Rector\FileFormatter\Contract\Formatter $output = ''; $this->depth = 0; $parts = $this->getXmlParts($xml); - if (\str_starts_with($parts[0], 'string, ' '); + return \strncmp($this->string, ' ', \strlen(' ')) === 0; } } diff --git a/packages/FileSystemRector/ValueObjectFactory/AddedFileWithNodesFactory.php b/packages/FileSystemRector/ValueObjectFactory/AddedFileWithNodesFactory.php index aa24c33c955..03443a76d8a 100644 --- a/packages/FileSystemRector/ValueObjectFactory/AddedFileWithNodesFactory.php +++ b/packages/FileSystemRector/ValueObjectFactory/AddedFileWithNodesFactory.php @@ -60,7 +60,7 @@ final class AddedFileWithNodesFactory } // is already in the right group $currentNamespaceName = $currentNamespace->name->toString(); - if (\str_ends_with($currentNamespaceName, '\\' . $desiredGroupName)) { + if (\substr_compare($currentNamespaceName, '\\' . $desiredGroupName, -\strlen('\\' . $desiredGroupName)) === 0) { return null; } $oldClassName = $currentNamespaceName . '\\' . $this->fileInfoDeletionAnalyzer->clearNameFromTestingPrefix($oldFileInfo->getBasenameWithoutSuffix()); diff --git a/packages/NodeCollector/NodeCollector/NodeRepository.php b/packages/NodeCollector/NodeCollector/NodeRepository.php index 6ab6ccd19cc..d501107d161 100644 --- a/packages/NodeCollector/NodeCollector/NodeRepository.php +++ b/packages/NodeCollector/NodeCollector/NodeRepository.php @@ -269,7 +269,7 @@ final class NodeRepository { $classNodes = []; foreach ($this->parsedNodeCollector->getClasses() as $className => $classNode) { - if (!\str_ends_with($className, $suffix)) { + if (\substr_compare($className, $suffix, -\strlen($suffix)) !== 0) { continue; } $classNodes[] = $classNode; diff --git a/packages/NodeCollector/NodeCollector/ParsedNodeCollector.php b/packages/NodeCollector/NodeCollector/ParsedNodeCollector.php index b55a8d5d03a..115ea1b4df4 100644 --- a/packages/NodeCollector/NodeCollector/ParsedNodeCollector.php +++ b/packages/NodeCollector/NodeCollector/ParsedNodeCollector.php @@ -114,7 +114,7 @@ final class ParsedNodeCollector public function findByShortName(string $shortName) : ?\PhpParser\Node\Stmt\Class_ { foreach ($this->classes as $className => $classNode) { - if (\str_ends_with($className, '\\' . $shortName)) { + if (\substr_compare($className, '\\' . $shortName, -\strlen('\\' . $shortName)) === 0) { return $classNode; } } diff --git a/packages/NodeRemoval/NodeRemover.php b/packages/NodeRemoval/NodeRemover.php index 148cfc4cc65..d9953bd7303 100644 --- a/packages/NodeRemoval/NodeRemover.php +++ b/packages/NodeRemoval/NodeRemover.php @@ -43,12 +43,12 @@ final class NodeRemover $this->rectorChangeCollector->notifyNodeFileInfo($node); } /** - * @param Class_|ClassMethod|Function_ $nodeWithStatements + * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_ $nodeWithStatements */ - public function removeNodeFromStatements(\PhpParser\Node $nodeWithStatements, \PhpParser\Node $nodeToRemove) : void + public function removeNodeFromStatements($nodeWithStatements, \PhpParser\Node $toBeRemovedNode) : void { foreach ((array) $nodeWithStatements->stmts as $key => $stmt) { - if ($nodeToRemove !== $stmt) { + if ($toBeRemovedNode !== $stmt) { continue; } unset($nodeWithStatements->stmts[$key]); diff --git a/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php b/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php index 189f0dc050d..62e79b45453 100644 --- a/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php +++ b/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php @@ -6,7 +6,6 @@ namespace Rector\NodeTypeResolver\PHPStan\Scope; use RectorPrefix20210530\Nette\Utils\Strings; use PhpParser\Node; use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Trait_; use PhpParser\NodeTraverser; @@ -141,9 +140,9 @@ final class PHPStanNodeScopeResolver $nodeTraverser->traverse($nodes); } /** - * @param Class_|Interface_ $classLike + * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_ $classLike */ - private function resolveClassOrInterfaceScope(\PhpParser\Node\Stmt\ClassLike $classLike, \PHPStan\Analyser\Scope $scope) : \PHPStan\Analyser\Scope + private function resolveClassOrInterfaceScope($classLike, \PHPStan\Analyser\Scope $scope) : \PHPStan\Analyser\Scope { $className = $this->resolveClassName($classLike); // is anonymous class? - not possible to enter it since PHPStan 0.12.33, see https://github.com/phpstan/phpstan-src/commit/e87fb0ec26f9c8552bbeef26a868b1e5d8185e91 @@ -184,9 +183,9 @@ final class PHPStanNodeScopeResolver $this->changedFilesDetector->addFileWithDependencies($smartFileInfo, $dependentFiles); } /** - * @param Class_|Interface_|Trait_ $classLike + * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Trait_ $classLike */ - private function resolveClassName(\PhpParser\Node\Stmt\ClassLike $classLike) : string + private function resolveClassName($classLike) : string { if (\property_exists($classLike, 'namespacedName')) { return (string) $classLike->namespacedName; diff --git a/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php b/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php index b82ab2183af..6b6a7a4122e 100644 --- a/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php +++ b/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php @@ -69,7 +69,7 @@ final class UnderscoreRenamePhpDocNodeVisitor extends \RectorPrefix20210530\Symp if (!$staticType instanceof \PHPStan\Type\ObjectType) { return \true; } - if (!\str_starts_with($staticType->getClassName(), $pseudoNamespaceToNamespace->getNamespacePrefix())) { + if (\strncmp($staticType->getClassName(), $pseudoNamespaceToNamespace->getNamespacePrefix(), \strlen($pseudoNamespaceToNamespace->getNamespacePrefix())) !== 0) { return \true; } // excluded? diff --git a/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php b/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php index 1318b417b1f..79cd08823e3 100644 --- a/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php +++ b/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php @@ -3,10 +3,9 @@ declare (strict_types=1); namespace Rector\PHPStanStaticTypeMapper; -use PhpParser\Node; use PhpParser\Node\Name; use PhpParser\Node\NullableType; -use PhpParser\Node\UnionType as PhpParserUnionType; +use PhpParser\Node\UnionType; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use PHPStan\Type\Type; use Rector\Core\Exception\NotImplementedYetException; @@ -35,9 +34,9 @@ final class PHPStanStaticTypeMapper throw new \Rector\Core\Exception\NotImplementedYetException(__METHOD__ . ' for ' . \get_class($type)); } /** - * @return Name|NullableType|PhpParserUnionType|null + * @return \PhpParser\Node\Name|\PhpParser\Node\NullableType|\PhpParser\Node\UnionType|null */ - public function mapToPhpParserNode(\PHPStan\Type\Type $type, ?string $kind = null) : ?\PhpParser\Node + public function mapToPhpParserNode(\PHPStan\Type\Type $type, ?string $kind = null) { foreach ($this->typeMappers as $typeMapper) { if (!\is_a($type, $typeMapper->getNodeClass(), \true)) { diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php index 2662bf30412..6507318791d 100644 --- a/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php +++ b/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php @@ -146,9 +146,9 @@ final class UnionTypeMapper implements \Rector\PHPStanStaticTypeMapper\Contract\ return $unionTypeAnalysis->hasArray(); } /** - * @return Name|NullableType|null + * @return \PhpParser\Node\Name|\PhpParser\Node\NullableType|null */ - private function matchArrayTypes(\PHPStan\Type\UnionType $unionType) : ?\PhpParser\Node + private function matchArrayTypes(\PHPStan\Type\UnionType $unionType) { $unionTypeAnalysis = $this->unionTypeAnalyzer->analyseForNullableAndIterable($unionType); if (!$unionTypeAnalysis instanceof \Rector\PHPStanStaticTypeMapper\ValueObject\UnionTypeAnalysis) { diff --git a/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php b/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php index a0e7d70e6a7..675d82c000d 100644 --- a/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php +++ b/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php @@ -40,6 +40,6 @@ final class FullyQualifiedNodeMapper implements \Rector\StaticTypeMapper\Contrac if ($originalName === $fullyQualifiedName) { return \false; } - return !\str_ends_with($fullyQualifiedName, '\\' . $originalName); + return \substr_compare($fullyQualifiedName, '\\' . $originalName, -\strlen('\\' . $originalName)) !== 0; } } diff --git a/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php b/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php index 482e319d262..7ba236fb112 100644 --- a/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php +++ b/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php @@ -128,9 +128,9 @@ CODE_SAMPLE return $this->isObjectType($classLike, $objectType); } /** - * @param ClassMethod|MethodCall|StaticCall $node + * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $node */ - private function processPositionWithDefaultValues(\PhpParser\Node $node, \Rector\Arguments\ValueObject\ArgumentAdder $argumentAdder) : void + private function processPositionWithDefaultValues($node, \Rector\Arguments\ValueObject\ArgumentAdder $argumentAdder) : void { if ($this->shouldSkipParameter($node, $argumentAdder)) { return; diff --git a/rules/Autodiscovery/Rector/Class_/MoveValueObjectsToValueObjectDirectoryRector.php b/rules/Autodiscovery/Rector/Class_/MoveValueObjectsToValueObjectDirectoryRector.php index 7d98a299dfd..ca10c68c10c 100644 --- a/rules/Autodiscovery/Rector/Class_/MoveValueObjectsToValueObjectDirectoryRector.php +++ b/rules/Autodiscovery/Rector/Class_/MoveValueObjectsToValueObjectDirectoryRector.php @@ -167,7 +167,7 @@ CODE_SAMPLE return \false; } foreach ($this->suffixes as $suffix) { - if (\str_ends_with($className, $suffix)) { + if (\substr_compare($className, $suffix, -\strlen($suffix)) === 0) { return \true; } } @@ -176,7 +176,7 @@ CODE_SAMPLE private function isKnownServiceType(string $className) : bool { foreach (self::COMMON_SERVICE_SUFFIXES as $commonServiceSuffix) { - if (\str_ends_with($className, $commonServiceSuffix)) { + if (\substr_compare($className, $commonServiceSuffix, -\strlen($commonServiceSuffix)) === 0) { return \true; } } diff --git a/rules/CodeQuality/Rector/Include_/AbsolutizeRequireAndIncludePathRector.php b/rules/CodeQuality/Rector/Include_/AbsolutizeRequireAndIncludePathRector.php index a33ebc32244..47130acefd0 100644 --- a/rules/CodeQuality/Rector/Include_/AbsolutizeRequireAndIncludePathRector.php +++ b/rules/CodeQuality/Rector/Include_/AbsolutizeRequireAndIncludePathRector.php @@ -63,15 +63,15 @@ CODE_SAMPLE /** @var string $includeValue */ $includeValue = $this->valueResolver->getValue($node->expr); // skip phar - if (\str_starts_with($includeValue, 'phar://')) { + if (\strncmp($includeValue, 'phar://', \strlen('phar://')) === 0) { return null; } // skip absolute paths - if (\str_starts_with($includeValue, '/')) { + if (\strncmp($includeValue, '/', \strlen('/')) === 0) { return null; } // add preslash to string - if (\str_starts_with($includeValue, './')) { + if (\strncmp($includeValue, './', \strlen('./')) === 0) { $node->expr->value = \RectorPrefix20210530\Nette\Utils\Strings::substring($includeValue, 1); } else { $node->expr->value = '/' . $includeValue; diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php index d3fec058c66..d68f00c8556 100644 --- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php +++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php @@ -32,7 +32,7 @@ final class AliasClassNameImportSkipVoter implements \Rector\CodingStyle\Contrac foreach ($aliasedUses as $aliasedUse) { $aliasedUseLowered = \strtolower($aliasedUse); // its aliased, we cannot just rename it - if (\str_ends_with($aliasedUseLowered, '\\' . $fullyQualifiedObjectType->getShortNameLowered())) { + if (\substr_compare($aliasedUseLowered, '\\' . $fullyQualifiedObjectType->getShortNameLowered(), -\strlen('\\' . $fullyQualifiedObjectType->getShortNameLowered())) === 0) { return \true; } } diff --git a/rules/CodingStyle/Naming/ClassNaming.php b/rules/CodingStyle/Naming/ClassNaming.php index a15f5421d99..4ad1d1ab621 100644 --- a/rules/CodingStyle/Naming/ClassNaming.php +++ b/rules/CodingStyle/Naming/ClassNaming.php @@ -27,7 +27,7 @@ final class ClassNaming return \lcfirst($shortName); } /** - * @param string|Name|Identifier|ClassLike $name + * @param string|\PhpParser\Node\Name|\PhpParser\Node\Identifier|\PhpParser\Node\Stmt\ClassLike $name */ public function getShortName($name) : string { @@ -69,7 +69,7 @@ final class ClassNaming } public function replaceSuffix(string $content, string $oldSuffix, string $newSuffix) : string { - if (!\str_ends_with($content, $oldSuffix)) { + if (\substr_compare($content, $oldSuffix, -\strlen($oldSuffix)) !== 0) { return $content . $newSuffix; } $contentWithoutOldSuffix = \RectorPrefix20210530\Nette\Utils\Strings::substring($content, 0, -\RectorPrefix20210530\Nette\Utils\Strings::length($oldSuffix)); diff --git a/rules/CodingStyle/Naming/NameRenamer.php b/rules/CodingStyle/Naming/NameRenamer.php index 8b7837195c0..81243151069 100644 --- a/rules/CodingStyle/Naming/NameRenamer.php +++ b/rules/CodingStyle/Naming/NameRenamer.php @@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\TraitUse; +use PhpParser\Node\UnionType; use Rector\CodingStyle\ValueObject\NameAndParent; use Rector\NodeNameResolver\NodeNameResolver; final class NameRenamer @@ -54,6 +55,9 @@ final class NameRenamer if ($parentNode instanceof \PhpParser\Node\Expr\StaticCall) { $this->renameStaticCall($lastName, $parentNode); } + if ($parentNode instanceof \PhpParser\Node\UnionType) { + $this->renameUnionType($lastName, $parentNode, $usedName); + } } } /** @@ -98,6 +102,18 @@ final class NameRenamer } $param->type = new \PhpParser\Node\Name($lastName); } + private function renameUnionType(string $lastName, \PhpParser\Node\UnionType $unionType, \PhpParser\Node $usedNameNode) : void + { + foreach ($unionType->types as $key => $unionedType) { + if (!$this->nodeNameResolver->areNamesEqual($unionedType, $usedNameNode)) { + continue; + } + if (!$unionedType instanceof \PhpParser\Node\Name) { + continue; + } + $unionType->types[$key] = new \PhpParser\Node\Name($lastName); + } + } /** * @param Name|Identifier $usedNameNode */ diff --git a/rules/CodingStyle/Rector/Assign/PHPStormVarAnnotationRector.php b/rules/CodingStyle/Rector/Assign/PHPStormVarAnnotationRector.php index cbc488e9598..cc7dbb7df45 100644 --- a/rules/CodingStyle/Rector/Assign/PHPStormVarAnnotationRector.php +++ b/rules/CodingStyle/Rector/Assign/PHPStormVarAnnotationRector.php @@ -122,7 +122,7 @@ CODE_SAMPLE $docContent = $this->getDocContent($node); // normalize content // starts with "/*", instead of "/**" - if (\str_starts_with($docContent, '/* ')) { + if (\strncmp($docContent, '/* ', \strlen('/* ')) === 0) { $docContent = \RectorPrefix20210530\Nette\Utils\Strings::replace($docContent, self::SINGLE_ASTERISK_COMMENT_START_REGEX, '/** '); } // $value is first, instead of type is first diff --git a/rules/CodingStyle/Rector/Include_/FollowRequireByDirRector.php b/rules/CodingStyle/Rector/Include_/FollowRequireByDirRector.php index fbdc2d3ae6d..061535bf681 100644 --- a/rules/CodingStyle/Rector/Include_/FollowRequireByDirRector.php +++ b/rules/CodingStyle/Rector/Include_/FollowRequireByDirRector.php @@ -64,7 +64,7 @@ CODE_SAMPLE } private function isRefactorableStringPath(\PhpParser\Node\Scalar\String_ $string) : bool { - return !\str_starts_with($string->value, 'phar://'); + return \strncmp($string->value, 'phar://', \strlen('phar://')) !== 0; } private function prefixWithDir(\PhpParser\Node\Scalar\String_ $string) : \PhpParser\Node\Expr\BinaryOp\Concat { @@ -77,14 +77,14 @@ CODE_SAMPLE */ private function removeExtraDotSlash(\PhpParser\Node\Scalar\String_ $string) : void { - if (!\str_starts_with($string->value, './')) { + if (\strncmp($string->value, './', \strlen('./')) !== 0) { return; } $string->value = \RectorPrefix20210530\Nette\Utils\Strings::replace($string->value, '#^\\.\\/#', '/'); } private function prependSlashIfMissing(\PhpParser\Node\Scalar\String_ $string) : void { - if (\str_starts_with($string->value, '/')) { + if (\strncmp($string->value, '/', \strlen('/')) === 0) { return; } $string->value = '/' . $string->value; diff --git a/rules/DependencyInjection/Rector/Variable/ReplaceVariableByPropertyFetchRector.php b/rules/DependencyInjection/Rector/Variable/ReplaceVariableByPropertyFetchRector.php index b45de0fd73c..5af9360685e 100644 --- a/rules/DependencyInjection/Rector/Variable/ReplaceVariableByPropertyFetchRector.php +++ b/rules/DependencyInjection/Rector/Variable/ReplaceVariableByPropertyFetchRector.php @@ -101,7 +101,7 @@ CODE_SAMPLE if ($className === null) { return \false; } - if (!\str_ends_with($className, 'Controller')) { + if (\substr_compare($className, 'Controller', -\strlen('Controller')) !== 0) { return \false; } $classMethod = $variable->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::METHOD_NODE); diff --git a/rules/DowngradePhp70/Rector/String_/DowngradeGeneratedScalarTypesRector.php b/rules/DowngradePhp70/Rector/String_/DowngradeGeneratedScalarTypesRector.php index 5f382075fbf..66c50648ac3 100644 --- a/rules/DowngradePhp70/Rector/String_/DowngradeGeneratedScalarTypesRector.php +++ b/rules/DowngradePhp70/Rector/String_/DowngradeGeneratedScalarTypesRector.php @@ -119,7 +119,7 @@ CODE_SAMPLE return \true; } foreach (self::FILES_TO_INCLUDE as $fileToInclude) { - if (\str_ends_with($fileInfo->getRealPath(), $fileToInclude)) { + if (\substr_compare($fileInfo->getRealPath(), $fileToInclude, -\strlen($fileToInclude)) === 0) { return \true; } } diff --git a/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrEndsWithRector.php b/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrEndsWithRector.php new file mode 100644 index 00000000000..972765942ff --- /dev/null +++ b/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrEndsWithRector.php @@ -0,0 +1,64 @@ +> + */ + public function getNodeTypes() : array + { + return [\PhpParser\Node\Expr\FuncCall::class, \PhpParser\Node\Expr\BooleanNot::class]; + } + /** + * @param FuncCall|BooleanNot $node + */ + public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node + { + if ($node instanceof \PhpParser\Node\Expr\FuncCall && $this->isName($node->name, 'str_ends_with')) { + return new \PhpParser\Node\Expr\BinaryOp\Identical($this->createSubstrCompareFuncCall($node), new \PhpParser\Node\Scalar\LNumber(0)); + } + if ($node instanceof \PhpParser\Node\Expr\BooleanNot) { + $funcCall = $node->expr; + if ($funcCall instanceof \PhpParser\Node\Expr\FuncCall && $this->isName($funcCall->name, 'str_ends_with')) { + return new \PhpParser\Node\Expr\BinaryOp\NotIdentical($this->createSubstrCompareFuncCall($funcCall), new \PhpParser\Node\Scalar\LNumber(0)); + } + } + return null; + } + private function createSubstrCompareFuncCall(\PhpParser\Node\Expr\FuncCall $funcCall) : \PhpParser\Node\Expr\FuncCall + { + $args = $funcCall->args; + $strlenFuncCall = $this->createStrlenFuncCall($funcCall->args[1]->value); + $args[] = new \PhpParser\Node\Arg(new \PhpParser\Node\Expr\UnaryMinus($strlenFuncCall)); + return new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('substr_compare'), $args); + } + private function createStrlenFuncCall(\PhpParser\Node\Expr $expr) : \PhpParser\Node\Expr\FuncCall + { + return new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('strlen'), [new \PhpParser\Node\Arg($expr)]); + } +} diff --git a/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrStartsWithRector.php b/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrStartsWithRector.php new file mode 100644 index 00000000000..1e3004d08dd --- /dev/null +++ b/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrStartsWithRector.php @@ -0,0 +1,73 @@ +> + */ + public function getNodeTypes() : array + { + return [\PhpParser\Node\Expr\FuncCall::class, \PhpParser\Node\Expr\BooleanNot::class]; + } + /** + * @param FuncCall|BooleanNot $node + */ + public function refactor(\PhpParser\Node $node) : ?\PhpParser\Node + { + if ($node instanceof \PhpParser\Node\Expr\FuncCall && $this->isName($node, 'str_starts_with')) { + return $this->createIdentical($node); + } + if ($node instanceof \PhpParser\Node\Expr\BooleanNot) { + $negatedCall = $node->expr; + if ($negatedCall instanceof \PhpParser\Node\Expr\FuncCall && $this->isName($negatedCall, 'str_starts_with')) { + return $this->createNotIdenticalStrncmpFuncCall($negatedCall); + } + } + return null; + } + private function createIdentical(\PhpParser\Node\Expr\FuncCall $funcCall) : \PhpParser\Node\Expr\BinaryOp\Identical + { + $strlenFuncCall = $this->createStrlenFuncCall($funcCall); + $strncmpFuncCall = $this->createStrncmpFuncCall($funcCall, $strlenFuncCall); + return new \PhpParser\Node\Expr\BinaryOp\Identical($strncmpFuncCall, new \PhpParser\Node\Scalar\LNumber(0)); + } + private function createNotIdenticalStrncmpFuncCall(\PhpParser\Node\Expr\FuncCall $funcCall) : \PhpParser\Node\Expr\BinaryOp\NotIdentical + { + $strlenFuncCall = $this->createStrlenFuncCall($funcCall); + $strncmpFuncCall = $this->createStrncmpFuncCall($funcCall, $strlenFuncCall); + return new \PhpParser\Node\Expr\BinaryOp\NotIdentical($strncmpFuncCall, new \PhpParser\Node\Scalar\LNumber(0)); + } + private function createStrlenFuncCall(\PhpParser\Node\Expr\FuncCall $funcCall) : \PhpParser\Node\Expr\FuncCall + { + return new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('strlen'), [$funcCall->args[1]]); + } + private function createStrncmpFuncCall(\PhpParser\Node\Expr\FuncCall $funcCall, \PhpParser\Node\Expr\FuncCall $strlenFuncCall) : \PhpParser\Node\Expr\FuncCall + { + $newArgs = $funcCall->args; + $newArgs[] = new \PhpParser\Node\Arg($strlenFuncCall); + return new \PhpParser\Node\Expr\FuncCall(new \PhpParser\Node\Name('strncmp'), $newArgs); + } +} diff --git a/rules/Naming/Guard/BreakingVariableRenameGuard.php b/rules/Naming/Guard/BreakingVariableRenameGuard.php index ff99170c879..506e6db48a0 100644 --- a/rules/Naming/Guard/BreakingVariableRenameGuard.php +++ b/rules/Naming/Guard/BreakingVariableRenameGuard.php @@ -74,7 +74,7 @@ final class BreakingVariableRenameGuard { // is the suffix? → also accepted $expectedNameCamelCase = \ucfirst($expectedName); - if (\str_ends_with($currentName, $expectedNameCamelCase)) { + if (\substr_compare($currentName, $expectedNameCamelCase, -\strlen($expectedNameCamelCase)) === 0) { return \true; } if ($this->conflictingNameResolver->checkNameIsInFunctionLike($expectedName, $functionLike)) { @@ -101,7 +101,7 @@ final class BreakingVariableRenameGuard { // is the suffix? → also accepted $expectedNameCamelCase = \ucfirst($expectedName); - if (\str_ends_with($currentName, $expectedNameCamelCase)) { + if (\substr_compare($currentName, $expectedNameCamelCase, -\strlen($expectedNameCamelCase)) === 0) { return \true; } $conflictingNames = $this->conflictingNameResolver->resolveConflictingVariableNamesForParam($classMethod); diff --git a/rules/Naming/NamespaceMatcher.php b/rules/Naming/NamespaceMatcher.php index 6824fcf7610..c1fd2b8fb35 100644 --- a/rules/Naming/NamespaceMatcher.php +++ b/rules/Naming/NamespaceMatcher.php @@ -14,7 +14,7 @@ final class NamespaceMatcher \krsort($oldToNewNamespace); /** @var string $oldNamespace */ foreach ($oldToNewNamespace as $oldNamespace => $newNamespace) { - if (\str_starts_with($name, $oldNamespace)) { + if (\strncmp($name, $oldNamespace, \strlen($oldNamespace)) === 0) { return new \Rector\Renaming\ValueObject\RenamedNamespace($name, $oldNamespace, $newNamespace); } } diff --git a/rules/Naming/Naming/PropertyNaming.php b/rules/Naming/Naming/PropertyNaming.php index c188fb4801e..6412a4960aa 100644 --- a/rules/Naming/Naming/PropertyNaming.php +++ b/rules/Naming/Naming/PropertyNaming.php @@ -169,7 +169,7 @@ final class PropertyNaming private function removePrefixesAndSuffixes(string $shortClassName) : string { // is SomeInterface - if (\str_ends_with($shortClassName, self::INTERFACE)) { + if (\substr_compare($shortClassName, self::INTERFACE, -\strlen(self::INTERFACE)) === 0) { $shortClassName = \RectorPrefix20210530\Nette\Utils\Strings::substring($shortClassName, 0, -\strlen(self::INTERFACE)); } // is ISomeClass @@ -177,7 +177,7 @@ final class PropertyNaming $shortClassName = \RectorPrefix20210530\Nette\Utils\Strings::substring($shortClassName, 1); } // is AbstractClass - if (\str_starts_with($shortClassName, 'Abstract')) { + if (\strncmp($shortClassName, 'Abstract', \strlen('Abstract')) === 0) { $shortClassName = \RectorPrefix20210530\Nette\Utils\Strings::substring($shortClassName, \strlen('Abstract')); } return $shortClassName; @@ -220,7 +220,7 @@ final class PropertyNaming } /** @var string $lastNamePart */ $lastNamePart = \RectorPrefix20210530\Nette\Utils\Strings::after($fqn, '\\', -1); - if (\str_ends_with($lastNamePart, self::INTERFACE)) { + if (\substr_compare($lastNamePart, self::INTERFACE, -\strlen(self::INTERFACE)) === 0) { return \RectorPrefix20210530\Nette\Utils\Strings::substring($lastNamePart, 0, -\strlen(self::INTERFACE)); } return $lastNamePart; @@ -235,7 +235,7 @@ final class PropertyNaming if (\RectorPrefix20210530\Nette\Utils\Strings::match($shortName, self::I_PREFIX_REGEX)) { return \RectorPrefix20210530\Nette\Utils\Strings::substring($shortName, 1); } - if (\str_ends_with($shortName, self::INTERFACE)) { + if (\substr_compare($shortName, self::INTERFACE, -\strlen(self::INTERFACE)) === 0) { return \RectorPrefix20210530\Nette\Utils\Strings::substring($shortName, -\strlen(self::INTERFACE)); } return $shortName; @@ -270,7 +270,7 @@ final class PropertyNaming if (\strlen($shortClassName) <= 3) { return \false; } - if (!\str_starts_with($shortClassName, 'I')) { + if (\strncmp($shortClassName, 'I', \strlen('I')) !== 0) { return \false; } if (!\ctype_upper($shortClassName[1])) { diff --git a/rules/Order/StmtVisibilitySorter.php b/rules/Order/StmtVisibilitySorter.php index 5aee5d8a747..7eef4f72d58 100644 --- a/rules/Order/StmtVisibilitySorter.php +++ b/rules/Order/StmtVisibilitySorter.php @@ -3,7 +3,6 @@ declare (strict_types=1); namespace Rector\Order; -use PhpParser\Node\Stmt; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassConst; use PhpParser\Node\Stmt\ClassLike; @@ -27,10 +26,10 @@ final class StmtVisibilitySorter $this->nodeNameResolver = $nodeNameResolver; } /** - * @param Class_|Trait_ $classLike * @return string[] + * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Trait_ $classLike */ - public function sortProperties(\PhpParser\Node\Stmt\ClassLike $classLike) : array + public function sortProperties($classLike) : array { $propertyRankeables = []; foreach ($classLike->stmts as $position => $propertyStmt) { @@ -60,10 +59,10 @@ final class StmtVisibilitySorter return $this->sortByRanksAndGetNames($classMethodsRankeables); } /** - * @param Class_|Interface_ $classLike * @return string[] + * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_ $classLike */ - public function sortConstants(\PhpParser\Node\Stmt\ClassLike $classLike) : array + public function sortConstants($classLike) : array { $classConstsRankeables = []; foreach ($classLike->stmts as $position => $constantStmt) { @@ -77,9 +76,9 @@ final class StmtVisibilitySorter return $this->sortByRanksAndGetNames($classConstsRankeables); } /** - * @param ClassMethod|Property|ClassConst $stmt + * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Property|\PhpParser\Node\Stmt\ClassConst $stmt */ - private function getVisibilityLevelOrder(\PhpParser\Node\Stmt $stmt) : int + private function getVisibilityLevelOrder($stmt) : int { if ($stmt->isPrivate()) { return 2; diff --git a/rules/PSR4/Composer/PSR4NamespaceMatcher.php b/rules/PSR4/Composer/PSR4NamespaceMatcher.php index 778d5e12791..bf8e30e3f89 100644 --- a/rules/PSR4/Composer/PSR4NamespaceMatcher.php +++ b/rules/PSR4/Composer/PSR4NamespaceMatcher.php @@ -27,7 +27,7 @@ final class PSR4NamespaceMatcher implements \Rector\PSR4\Contract\PSR4AutoloadNa $paths = \is_array($path) ? $path : [$path]; foreach ($paths as $path) { $path = \rtrim($path, '/'); - if (!\str_starts_with($smartFileInfo->getRelativeDirectoryPath(), $path)) { + if (\strncmp($smartFileInfo->getRelativeDirectoryPath(), $path, \strlen($path)) !== 0) { continue; } $expectedNamespace = $namespace . $this->resolveExtraNamespace($smartFileInfo, $path); diff --git a/rules/PSR4/FileRelocationResolver.php b/rules/PSR4/FileRelocationResolver.php index 49c471ec09b..8ab398e9ddb 100644 --- a/rules/PSR4/FileRelocationResolver.php +++ b/rules/PSR4/FileRelocationResolver.php @@ -54,7 +54,7 @@ final class FileRelocationResolver */ private function resolveRootDirectory(\Symplify\SmartFileSystem\SmartFileInfo $smartFileInfo, string $suffixName, array $groupNames) : string { - if (\str_starts_with($smartFileInfo->getRealPathDirectory(), '/tmp')) { + if (\strncmp($smartFileInfo->getRealPathDirectory(), '/tmp', \strlen('/tmp')) === 0) { $currentTraversePath = $smartFileInfo->getRealPathDirectory(); } else { $currentTraversePath = $smartFileInfo->getRelativeDirectoryPath(); diff --git a/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php b/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php index b767863d44a..a0693c70fc7 100644 --- a/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php +++ b/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php @@ -100,7 +100,7 @@ final class EregToPregMatchRector extends \Rector\Core\Rector\AbstractRector */ private function processSplitLimitArgument(\PhpParser\Node\Expr\FuncCall $funcCall, string $functionName) : void { - if (!\str_starts_with($functionName, 'split')) { + if (\strncmp($functionName, 'split', \strlen('split')) !== 0) { return; } // 3rd argument - $limit, 0 → 1 diff --git a/rules/PhpSpecToPHPUnit/Naming/PhpSpecRenaming.php b/rules/PhpSpecToPHPUnit/Naming/PhpSpecRenaming.php index 27748a29cd0..54d994cc881 100644 --- a/rules/PhpSpecToPHPUnit/Naming/PhpSpecRenaming.php +++ b/rules/PhpSpecToPHPUnit/Naming/PhpSpecRenaming.php @@ -50,7 +50,7 @@ final class PhpSpecRenaming // from PhpSpec to PHPUnit method naming convention $classMethodName = $this->stringFormatConverter->underscoreAndHyphenToCamelCase($classMethodName); // add "test", so PHPUnit runs the method - if (!\str_starts_with($classMethodName, 'test')) { + if (\strncmp($classMethodName, 'test', \strlen('test')) !== 0) { $classMethodName = 'test' . \ucfirst($classMethodName); } $classMethod->name = new \PhpParser\Node\Identifier($classMethodName); diff --git a/rules/Removing/NodeManipulator/ComplexNodeRemover.php b/rules/Removing/NodeManipulator/ComplexNodeRemover.php index 34257c5449d..b017af8476a 100644 --- a/rules/Removing/NodeManipulator/ComplexNodeRemover.php +++ b/rules/Removing/NodeManipulator/ComplexNodeRemover.php @@ -4,7 +4,6 @@ declare (strict_types=1); namespace Rector\Removing\NodeManipulator; use PhpParser\Node; -use PhpParser\Node\Expr; use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\PropertyFetch; use PhpParser\Node\Expr\StaticPropertyFetch; @@ -95,10 +94,10 @@ final class ComplexNodeRemover $this->nodeRemover->removeNode($property); } /** - * @param StaticPropertyFetch|PropertyFetch $expr * @param string[] $classMethodNamesToSkip + * @param \PhpParser\Node\Expr\StaticPropertyFetch|\PhpParser\Node\Expr\PropertyFetch $expr */ - private function shouldSkipPropertyForClassMethod(\PhpParser\Node\Expr $expr, array $classMethodNamesToSkip) : bool + private function shouldSkipPropertyForClassMethod($expr, array $classMethodNamesToSkip) : bool { $classMethodNode = $expr->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::METHOD_NODE); if (!$classMethodNode instanceof \PhpParser\Node\Stmt\ClassMethod) { @@ -108,9 +107,9 @@ final class ComplexNodeRemover return \in_array($classMethodName, $classMethodNamesToSkip, \true); } /** - * @param PropertyFetch|StaticPropertyFetch $expr + * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $expr */ - private function resolveAssign(\PhpParser\Node\Expr $expr) : ?\PhpParser\Node\Expr\Assign + private function resolveAssign($expr) : ?\PhpParser\Node\Expr\Assign { $assign = $expr->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::PARENT_NODE); while ($assign !== null && !$assign instanceof \PhpParser\Node\Expr\Assign) { diff --git a/rules/TypeDeclaration/PHPStan/Type/ObjectTypeSpecifier.php b/rules/TypeDeclaration/PHPStan/Type/ObjectTypeSpecifier.php index a56c9ab74bf..a7c7c1a80ba 100644 --- a/rules/TypeDeclaration/PHPStan/Type/ObjectTypeSpecifier.php +++ b/rules/TypeDeclaration/PHPStan/Type/ObjectTypeSpecifier.php @@ -145,7 +145,7 @@ final class ObjectTypeSpecifier private function matchPartialNamespaceObjectType(\PHPStan\Type\ObjectType $objectType, \PhpParser\Node\Stmt\UseUse $useUse) : ?\Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType { // partial namespace - if (!\str_starts_with($objectType->getClassName(), $useUse->name->getLast() . '\\')) { + if (\strncmp($objectType->getClassName(), $useUse->name->getLast() . '\\', \strlen($useUse->name->getLast() . '\\')) !== 0) { return null; } $classNameWithoutLastUsePart = \RectorPrefix20210530\Nette\Utils\Strings::after($objectType->getClassName(), '\\', 1); diff --git a/rules/TypeDeclaration/PhpDocParser/NonInformativeReturnTagRemover.php b/rules/TypeDeclaration/PhpDocParser/NonInformativeReturnTagRemover.php index d0af7ed5385..860479119c4 100644 --- a/rules/TypeDeclaration/PhpDocParser/NonInformativeReturnTagRemover.php +++ b/rules/TypeDeclaration/PhpDocParser/NonInformativeReturnTagRemover.php @@ -112,7 +112,7 @@ final class NonInformativeReturnTagRemover if (!$nullabledReturnTagValueNode instanceof \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode) { return; } - if (!\str_ends_with($nullabledReturnType->getClassName(), $nullabledReturnTagValueNode->name)) { + if (\substr_compare($nullabledReturnType->getClassName(), $nullabledReturnTagValueNode->name, -\strlen($nullabledReturnTagValueNode->name)) !== 0) { return; } $phpDocInfo->removeByType(\PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode::class); @@ -184,6 +184,6 @@ final class NonInformativeReturnTagRemover if ('\\' . $className === $returnTagValueNodeType) { return \true; } - return \str_ends_with($className, '\\' . $returnTagValueNodeType); + return \substr_compare($className, '\\' . $returnTagValueNodeType, -\strlen('\\' . $returnTagValueNodeType)) === 0; } } diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php index 318b331a5d8..451f4c3821d 100644 --- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php +++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php @@ -9,6 +9,7 @@ use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\FunctionLike; +use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; use PhpParser\Node\NullableType; @@ -121,9 +122,9 @@ CODE_SAMPLE return $node; } /** - * @param ClassMethod|Function_|Closure $node + * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node */ - private function isSkipped(\PhpParser\Node $node) : bool + private function isSkipped($node) : bool { if (!$this->phpVersionProvider->isAtLeastPhpVersion(\Rector\Core\ValueObject\PhpVersionFeature::SCALAR_TYPES)) { return \true; @@ -135,7 +136,7 @@ CODE_SAMPLE } /** * @param Return_[] $returns - * @return array + * @return array */ private function collectStrictReturnTypes(array $returns) : array { @@ -186,9 +187,9 @@ CODE_SAMPLE return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType); } /** - * @return Name|NullableType|PhpParserUnionType|null + * @return \PhpParser\Node\Name|\PhpParser\Node\NullableType|PhpParserUnionType|null */ - private function resolveFuncCallReturnNode(\PhpParser\Node\Expr\FuncCall $funcCall) : ?\PhpParser\Node + private function resolveFuncCallReturnNode(\PhpParser\Node\Expr\FuncCall $funcCall) { $returnType = $this->reflectionTypeResolver->resolveFuncCallReturnType($funcCall); if (!$returnType instanceof \PHPStan\Type\Type) { @@ -197,10 +198,10 @@ CODE_SAMPLE return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType); } /** - * @param ClassMethod|Function_|Closure $functionLike - * @param Name|NullableType|PhpParserUnionType $returnedStrictTypeNode + * @param \PhpParser\Node\Identifier|\PhpParser\Node\Name|\PhpParser\Node\NullableType|PhpParserUnionType $returnedStrictTypeNode + * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $functionLike */ - private function refactorSingleReturnType(\PhpParser\Node\Stmt\Return_ $return, \PhpParser\Node $returnedStrictTypeNode, \PhpParser\Node\FunctionLike $functionLike) : \PhpParser\Node\FunctionLike + private function refactorSingleReturnType(\PhpParser\Node\Stmt\Return_ $return, $returnedStrictTypeNode, $functionLike) : \PhpParser\Node\FunctionLike { $resolvedType = $this->nodeTypeResolver->resolve($return); if ($resolvedType instanceof \PHPStan\Type\UnionType) { diff --git a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php index 86fde71560b..5038afff86b 100644 --- a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php +++ b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/ConstructorPropertyTypeInferer.php @@ -180,7 +180,7 @@ final class ConstructorPropertyTypeInferer implements \Rector\TypeDeclaration\Co return null; } // if the FQN has different ending than the original, it was aliased and we need to return the alias - if (!\str_ends_with($fullyQualifiedName, '\\' . $originalName->toString())) { + if (\substr_compare($fullyQualifiedName, '\\' . $originalName->toString(), -\strlen('\\' . $originalName->toString())) !== 0) { $className = $originalName->toString(); if ($this->reflectionProvider->hasClass($className)) { return new \Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType($className); diff --git a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php index 6650afca085..2fe0691f1e0 100644 --- a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php +++ b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/DoctrineRelationPropertyTypeInferer.php @@ -81,7 +81,7 @@ final class DoctrineRelationPropertyTypeInferer implements \Rector\TypeDeclarati if ($targetEntity === null) { return new \PHPStan\Type\MixedType(); } - if (\str_ends_with($targetEntity, '::class')) { + if (\substr_compare($targetEntity, '::class', -\strlen('::class')) === 0) { $targetEntity = \RectorPrefix20210530\Nette\Utils\Strings::before($targetEntity, '::class'); } // resolve to FQN diff --git a/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/YieldNodesReturnTypeInferer.php b/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/YieldNodesReturnTypeInferer.php index 919d344bdb4..e13c7c14850 100644 --- a/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/YieldNodesReturnTypeInferer.php +++ b/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/YieldNodesReturnTypeInferer.php @@ -91,9 +91,9 @@ final class YieldNodesReturnTypeInferer implements \Rector\TypeDeclaration\Contr return $yieldNodes; } /** - * @param Yield_|YieldFrom $yieldExpr + * @param \PhpParser\Node\Expr\Yield_|\PhpParser\Node\Expr\YieldFrom $yieldExpr */ - private function resolveYieldValue(\PhpParser\Node\Expr $yieldExpr) : ?\PhpParser\Node\Expr + private function resolveYieldValue($yieldExpr) : ?\PhpParser\Node\Expr { if ($yieldExpr instanceof \PhpParser\Node\Expr\Yield_) { return $yieldExpr->value; diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php index 5247a12f73e..0176fc54296 100644 --- a/src/Application/VersionResolver.php +++ b/src/Application/VersionResolver.php @@ -16,11 +16,11 @@ final class VersionResolver /** * @var string */ - public const PACKAGE_VERSION = '223ad8fca8280a298b02dce0226b91269e3b3535'; + public const PACKAGE_VERSION = 'f7e99868356cf76b167e1010d5f9b3694202596e'; /** * @var string */ - public const RELEASE_DATE = '2021-05-30 09:42:32'; + public const RELEASE_DATE = '2021-05-30 10:02:38'; public static function resolvePackageVersion() : string { $process = new \RectorPrefix20210530\Symfony\Component\Process\Process(['git', 'log', '--pretty="%H"', '-n1', 'HEAD'], __DIR__); diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php index 775889dc340..1be7cd2cc04 100644 --- a/src/Console/Command/ProcessCommand.php +++ b/src/Console/Command/ProcessCommand.php @@ -180,7 +180,7 @@ final class ProcessCommand extends \RectorPrefix20210530\Symfony\Component\Conso foreach ($files as $file) { $smartFileInfo = $file->getSmartFileInfo(); $pathName = $smartFileInfo->getPathname(); - if (\str_ends_with($pathName, '.php')) { + if (\substr_compare($pathName, '.php', -\strlen('.php')) === 0) { $filePaths[] = $pathName; } } diff --git a/src/DependencyInjection/CompilerPass/VerifyRectorServiceExistsCompilerPass.php b/src/DependencyInjection/CompilerPass/VerifyRectorServiceExistsCompilerPass.php index b594448dd00..174e53e603c 100644 --- a/src/DependencyInjection/CompilerPass/VerifyRectorServiceExistsCompilerPass.php +++ b/src/DependencyInjection/CompilerPass/VerifyRectorServiceExistsCompilerPass.php @@ -16,7 +16,7 @@ final class VerifyRectorServiceExistsCompilerPass implements \RectorPrefix202105 if ($class === null) { continue; } - if (!\str_ends_with($class, 'Rector')) { + if (\substr_compare($class, 'Rector', -\strlen('Rector')) !== 0) { continue; } if (!\is_a($class, \Rector\Core\Contract\Rector\RectorInterface::class, \true)) { diff --git a/src/FileSystem/PhpFilesFinder.php b/src/FileSystem/PhpFilesFinder.php index 7b5429d7970..edbc66a0afd 100644 --- a/src/FileSystem/PhpFilesFinder.php +++ b/src/FileSystem/PhpFilesFinder.php @@ -35,7 +35,7 @@ final class PhpFilesFinder $phpFileInfos = $this->filesFinder->findInDirectoriesAndFiles($paths, $this->configuration->getFileExtensions()); // filter out non-PHP php files, e.g. blade templates in Laravel $phpFileInfos = \array_filter($phpFileInfos, function (\Symplify\SmartFileSystem\SmartFileInfo $smartFileInfo) : bool { - return !\str_ends_with($smartFileInfo->getPathname(), '.blade.php'); + return \substr_compare($smartFileInfo->getPathname(), '.blade.php', -\strlen('.blade.php')) !== 0; }); return $this->cachedFileInfoFilterAndReporter->filterFileInfos($phpFileInfos); } diff --git a/src/NodeManipulator/VariableManipulator.php b/src/NodeManipulator/VariableManipulator.php index c784f9e4905..2aad2fe0096 100644 --- a/src/NodeManipulator/VariableManipulator.php +++ b/src/NodeManipulator/VariableManipulator.php @@ -100,7 +100,7 @@ final class VariableManipulator { /** @var string $className */ $className = $variable->getAttribute(\Rector\NodeTypeResolver\Node\AttributeKey::CLASS_NAME); - if (!\str_ends_with($className, 'Test')) { + if (\substr_compare($className, 'Test', -\strlen('Test')) !== 0) { return \false; } return $this->nodeNameResolver->isName($variable, 'expect*'); diff --git a/src/NonPhpFile/NonPhpFileProcessor.php b/src/NonPhpFile/NonPhpFileProcessor.php index b5aca2c9db6..9e29614dba4 100644 --- a/src/NonPhpFile/NonPhpFileProcessor.php +++ b/src/NonPhpFile/NonPhpFileProcessor.php @@ -37,7 +37,7 @@ final class NonPhpFileProcessor implements \Rector\Core\Contract\Processor\FileP $smartFileInfo = $file->getSmartFileInfo(); // bug in path extension foreach ($this->getSupportedFileExtensions() as $supportedFileExtension) { - if (\str_ends_with($smartFileInfo->getPathname(), '.' . $supportedFileExtension)) { + if (\substr_compare($smartFileInfo->getPathname(), '.' . $supportedFileExtension, -\strlen('.' . $supportedFileExtension)) === 0) { return \true; } } diff --git a/src/Php/PhpVersionProvider.php b/src/Php/PhpVersionProvider.php index 4799537fed8..814ab448864 100644 --- a/src/Php/PhpVersionProvider.php +++ b/src/Php/PhpVersionProvider.php @@ -27,9 +27,8 @@ final class PhpVersionProvider } public function provide() : int { - /** @var int|null $phpVersionFeatures */ - $phpVersionFeatures = $this->parameterProvider->provideParameter(\Rector\Core\Configuration\Option::PHP_VERSION_FEATURES); - if ($phpVersionFeatures !== null) { + $phpVersionFeatures = $this->parameterProvider->provideIntParameter(\Rector\Core\Configuration\Option::PHP_VERSION_FEATURES); + if ($phpVersionFeatures > 0) { return $phpVersionFeatures; } // for tests diff --git a/src/Rector/AbstractRector.php b/src/Rector/AbstractRector.php index 0b321c9deed..c360a4e09e5 100644 --- a/src/Rector/AbstractRector.php +++ b/src/Rector/AbstractRector.php @@ -438,11 +438,11 @@ abstract class AbstractRector extends \PhpParser\NodeVisitorAbstract implements $this->nodeRemover->removeNode($node); } /** - * @param Class_|ClassMethod|Function_ $nodeWithStatements + * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_ $nodeWithStatements */ - protected function removeNodeFromStatements(\PhpParser\Node $nodeWithStatements, \PhpParser\Node $nodeToRemove) : void + protected function removeNodeFromStatements($nodeWithStatements, \PhpParser\Node $toBeRemovedNode) : void { - $this->nodeRemover->removeNodeFromStatements($nodeWithStatements, $nodeToRemove); + $this->nodeRemover->removeNodeFromStatements($nodeWithStatements, $toBeRemovedNode); } /** * @param Node[] $nodes diff --git a/src/Util/StaticRectorStrings.php b/src/Util/StaticRectorStrings.php index 63983cf1b40..38bd067bff6 100644 --- a/src/Util/StaticRectorStrings.php +++ b/src/Util/StaticRectorStrings.php @@ -44,7 +44,7 @@ final class StaticRectorStrings public static function removePrefixes(string $value, array $prefixesToRemove) : string { foreach ($prefixesToRemove as $prefixToRemove) { - if (\str_starts_with($value, $prefixToRemove)) { + if (\strncmp($value, $prefixToRemove, \strlen($prefixToRemove)) === 0) { $value = \RectorPrefix20210530\Nette\Utils\Strings::substring($value, \RectorPrefix20210530\Nette\Utils\Strings::length($prefixToRemove)); } } @@ -56,7 +56,7 @@ final class StaticRectorStrings public static function removeSuffixes(string $value, array $suffixesToRemove) : string { foreach ($suffixesToRemove as $suffixToRemove) { - if (\str_ends_with($value, $suffixToRemove)) { + if (\substr_compare($value, $suffixToRemove, -\strlen($suffixToRemove)) === 0) { $value = \RectorPrefix20210530\Nette\Utils\Strings::substring($value, 0, -\RectorPrefix20210530\Nette\Utils\Strings::length($suffixToRemove)); } } diff --git a/vendor/autoload.php b/vendor/autoload.php index a9ffe034950..e604bd0bc28 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367::getLoader(); +return ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 15b0b4fef1d..504b5e057f9 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -2129,6 +2129,8 @@ return array( 'Rector\\DowngradePhp80\\Rector\\Class_\\DowngradePropertyPromotionRector' => $baseDir . '/rules/DowngradePhp80/Rector/Class_/DowngradePropertyPromotionRector.php', 'Rector\\DowngradePhp80\\Rector\\Expression\\DowngradeMatchToSwitchRector' => $baseDir . '/rules/DowngradePhp80/Rector/Expression/DowngradeMatchToSwitchRector.php', 'Rector\\DowngradePhp80\\Rector\\FuncCall\\DowngradeStrContainsRector' => $baseDir . '/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrContainsRector.php', + 'Rector\\DowngradePhp80\\Rector\\FuncCall\\DowngradeStrEndsWithRector' => $baseDir . '/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrEndsWithRector.php', + 'Rector\\DowngradePhp80\\Rector\\FuncCall\\DowngradeStrStartsWithRector' => $baseDir . '/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrStartsWithRector.php', 'Rector\\DowngradePhp80\\Rector\\FunctionLike\\DowngradeMixedTypeDeclarationRector' => $baseDir . '/rules/DowngradePhp80/Rector/FunctionLike/DowngradeMixedTypeDeclarationRector.php', 'Rector\\DowngradePhp80\\Rector\\FunctionLike\\DowngradeUnionTypeDeclarationRector' => $baseDir . '/rules/DowngradePhp80/Rector/FunctionLike/DowngradeUnionTypeDeclarationRector.php', 'Rector\\DowngradePhp80\\Rector\\NullsafeMethodCall\\DowngradeNullsafeToTernaryOperatorRector' => $baseDir . '/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php', diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index d1e18d86e63..0860bd36954 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367 +class ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da { private static $loader; @@ -22,15 +22,15 @@ class ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); - spl_autoload_unregister(array('ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit97f4f51a084df5e9a8869348edb2e8da::getInitializer($loader)); } else { $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { @@ -42,19 +42,19 @@ class ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367 $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367::$files; + $includeFiles = Composer\Autoload\ComposerStaticInit97f4f51a084df5e9a8869348edb2e8da::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequireb3c3f0bc3b39123d94667d6b15846367($fileIdentifier, $file); + composerRequire97f4f51a084df5e9a8869348edb2e8da($fileIdentifier, $file); } return $loader; } } -function composerRequireb3c3f0bc3b39123d94667d6b15846367($fileIdentifier, $file) +function composerRequire97f4f51a084df5e9a8869348edb2e8da($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 3ca69572d96..c5324c2f610 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367 +class ComposerStaticInit97f4f51a084df5e9a8869348edb2e8da { public static $files = array ( 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', @@ -2478,6 +2478,8 @@ class ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367 'Rector\\DowngradePhp80\\Rector\\Class_\\DowngradePropertyPromotionRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/Class_/DowngradePropertyPromotionRector.php', 'Rector\\DowngradePhp80\\Rector\\Expression\\DowngradeMatchToSwitchRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/Expression/DowngradeMatchToSwitchRector.php', 'Rector\\DowngradePhp80\\Rector\\FuncCall\\DowngradeStrContainsRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrContainsRector.php', + 'Rector\\DowngradePhp80\\Rector\\FuncCall\\DowngradeStrEndsWithRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrEndsWithRector.php', + 'Rector\\DowngradePhp80\\Rector\\FuncCall\\DowngradeStrStartsWithRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/FuncCall/DowngradeStrStartsWithRector.php', 'Rector\\DowngradePhp80\\Rector\\FunctionLike\\DowngradeMixedTypeDeclarationRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/FunctionLike/DowngradeMixedTypeDeclarationRector.php', 'Rector\\DowngradePhp80\\Rector\\FunctionLike\\DowngradeUnionTypeDeclarationRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/FunctionLike/DowngradeUnionTypeDeclarationRector.php', 'Rector\\DowngradePhp80\\Rector\\NullsafeMethodCall\\DowngradeNullsafeToTernaryOperatorRector' => __DIR__ . '/../..' . '/rules/DowngradePhp80/Rector/NullsafeMethodCall/DowngradeNullsafeToTernaryOperatorRector.php', @@ -3824,9 +3826,9 @@ class ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInitb3c3f0bc3b39123d94667d6b15846367::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit97f4f51a084df5e9a8869348edb2e8da::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit97f4f51a084df5e9a8869348edb2e8da::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit97f4f51a084df5e9a8869348edb2e8da::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/scoper-autoload.php b/vendor/scoper-autoload.php index 8673d139c0a..71cdad8d219 100644 --- a/vendor/scoper-autoload.php +++ b/vendor/scoper-autoload.php @@ -21,8 +21,8 @@ if (!class_exists('SomeTestCase', false) && !interface_exists('SomeTestCase', fa if (!class_exists('CheckoutEntityFactory', false) && !interface_exists('CheckoutEntityFactory', false) && !trait_exists('CheckoutEntityFactory', false)) { spl_autoload_call('RectorPrefix20210530\CheckoutEntityFactory'); } -if (!class_exists('ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367', false) && !interface_exists('ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367', false) && !trait_exists('ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367', false)) { - spl_autoload_call('RectorPrefix20210530\ComposerAutoloaderInitb3c3f0bc3b39123d94667d6b15846367'); +if (!class_exists('ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da', false) && !interface_exists('ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da', false) && !trait_exists('ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da', false)) { + spl_autoload_call('RectorPrefix20210530\ComposerAutoloaderInit97f4f51a084df5e9a8869348edb2e8da'); } if (!class_exists('Doctrine\Inflector\Inflector', false) && !interface_exists('Doctrine\Inflector\Inflector', false) && !trait_exists('Doctrine\Inflector\Inflector', false)) { spl_autoload_call('RectorPrefix20210530\Doctrine\Inflector\Inflector'); @@ -3320,9 +3320,9 @@ if (!function_exists('print_node')) { return \RectorPrefix20210530\print_node(...func_get_args()); } } -if (!function_exists('composerRequireb3c3f0bc3b39123d94667d6b15846367')) { - function composerRequireb3c3f0bc3b39123d94667d6b15846367() { - return \RectorPrefix20210530\composerRequireb3c3f0bc3b39123d94667d6b15846367(...func_get_args()); +if (!function_exists('composerRequire97f4f51a084df5e9a8869348edb2e8da')) { + function composerRequire97f4f51a084df5e9a8869348edb2e8da() { + return \RectorPrefix20210530\composerRequire97f4f51a084df5e9a8869348edb2e8da(...func_get_args()); } } if (!function_exists('parseArgs')) {