diff --git a/packages-tests/NodeCollector/BinaryOpConditionsCollectorTest.php b/packages-tests/NodeCollector/BinaryOpConditionsCollectorTest.php index 7af76f33814..d5f546f06ce 100644 --- a/packages-tests/NodeCollector/BinaryOpConditionsCollectorTest.php +++ b/packages-tests/NodeCollector/BinaryOpConditionsCollectorTest.php @@ -24,7 +24,7 @@ public function testLeftAssociative(): void $result = $binaryOpConditionsCollector->findConditions($abcPlus, Plus::class); - $this->assertEquals([ + $this->assertSame([ 2 => $a, 1 => $b, 0 => $c, @@ -44,7 +44,7 @@ public function testRightAssociative(): void $result = $binaryOpConditionsCollector->findConditions($abcPlus, Plus::class); - $this->assertEquals([ + $this->assertSame([ 1 => $a, 0 => $bcPlus, ], $result); @@ -62,7 +62,7 @@ public function testWrongRootOp(): void $result = $binaryOpConditionsCollector->findConditions($abcMinus, Plus::class); - $this->assertEquals([ + $this->assertSame([ 0 => $abcMinus, ], $result); } @@ -75,7 +75,7 @@ public function testTrivialCase(): void $result = $binaryOpConditionsCollector->findConditions($variable, Plus::class); - $this->assertEquals([ + $this->assertSame([ 0 => $variable, ], $result); } @@ -93,7 +93,7 @@ public function testInnerNodeDifferentOp(): void $result = $binaryOpConditionsCollector->findConditions($abcPlus, Plus::class); - $this->assertEquals([ + $this->assertSame([ 1 => $abMinus, 0 => $c, ], $result); diff --git a/phpstan.neon b/phpstan.neon index 9eb2dd04d3d..aabcebba385 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -663,3 +663,8 @@ parameters: - '#Class method ".+\(\)" is never used#' - '#Parameters should use "(.*?)" types as the only types passed to this method#' + + # regex re-validation + - + message: '#Call to static method Webmozart\\Assert\\Assert\:\:allString\(\) with array will always evaluate to true#' + path: rules/Transform/ValueObject/ParentClassToTraits.php diff --git a/rules-tests/Transform/Rector/Assign/PropertyFetchToMethodCallRector/config/configured_rule.php b/rules-tests/Transform/Rector/Assign/PropertyFetchToMethodCallRector/config/configured_rule.php index a303c316462..a04e75a5d5c 100644 --- a/rules-tests/Transform/Rector/Assign/PropertyFetchToMethodCallRector/config/configured_rule.php +++ b/rules-tests/Transform/Rector/Assign/PropertyFetchToMethodCallRector/config/configured_rule.php @@ -11,7 +11,6 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig ->ruleWithConfiguration(PropertyFetchToMethodCallRector::class, [ - new PropertyFetchToMethodCall(Translator::class, 'locale', 'getLocale', 'setLocale'), new PropertyFetchToMethodCall(Generator::class, 'word', 'word'), new PropertyFetchToMethodCall( diff --git a/rules/CodeQuality/Rector/PropertyFetch/ExplicitMethodCallOverMagicGetSetRector.php b/rules/CodeQuality/Rector/PropertyFetch/ExplicitMethodCallOverMagicGetSetRector.php index 2225aed709b..c80f002bad2 100644 --- a/rules/CodeQuality/Rector/PropertyFetch/ExplicitMethodCallOverMagicGetSetRector.php +++ b/rules/CodeQuality/Rector/PropertyFetch/ExplicitMethodCallOverMagicGetSetRector.php @@ -159,6 +159,7 @@ private function refactorPropertyFetch(PropertyFetch $propertyFetch, Scope $scop if (! $callerType->hasMethod($possibleGetterMethodName)->yes()) { continue; } + $methodReflection = $callerType->getMethod($possibleGetterMethodName, $scope); $variant = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants()); diff --git a/rules/Naming/ValueObject/PropertyRename.php b/rules/Naming/ValueObject/PropertyRename.php index a8464bbf362..ea699312f88 100644 --- a/rules/Naming/ValueObject/PropertyRename.php +++ b/rules/Naming/ValueObject/PropertyRename.php @@ -7,6 +7,7 @@ use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\PropertyProperty; +use Rector\Core\Validation\RectorAssert; use Rector\Naming\Contract\RenamePropertyValueObjectInterface; final class PropertyRename implements RenamePropertyValueObjectInterface @@ -19,6 +20,9 @@ public function __construct( private readonly string $classLikeName, private readonly PropertyProperty $propertyProperty ) { + // name must be valid + RectorAssert::propertyName($currentName); + RectorAssert::propertyName($expectedName); } public function getProperty(): Property diff --git a/rules/Renaming/ValueObject/RenameProperty.php b/rules/Renaming/ValueObject/RenameProperty.php index df8e3fd3ef5..3a31a1d091f 100644 --- a/rules/Renaming/ValueObject/RenameProperty.php +++ b/rules/Renaming/ValueObject/RenameProperty.php @@ -15,6 +15,8 @@ public function __construct( private readonly string $newProperty ) { RectorAssert::className($type); + RectorAssert::propertyName($oldProperty); + RectorAssert::propertyName($newProperty); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/ArgumentFuncCallToMethodCall.php b/rules/Transform/ValueObject/ArgumentFuncCallToMethodCall.php index 1f67ad280a7..3707cb8f0ec 100644 --- a/rules/Transform/ValueObject/ArgumentFuncCallToMethodCall.php +++ b/rules/Transform/ValueObject/ArgumentFuncCallToMethodCall.php @@ -16,6 +16,7 @@ public function __construct( private readonly ?string $methodIfNoArgs = null ) { RectorAssert::className($class); + RectorAssert::functionName($function); } public function getFunction(): string diff --git a/rules/Transform/ValueObject/ArrayFuncCallToMethodCall.php b/rules/Transform/ValueObject/ArrayFuncCallToMethodCall.php index f51e5d5a31a..f1b6ad6b697 100644 --- a/rules/Transform/ValueObject/ArrayFuncCallToMethodCall.php +++ b/rules/Transform/ValueObject/ArrayFuncCallToMethodCall.php @@ -22,6 +22,7 @@ public function __construct( private readonly string $nonArrayMethod ) { RectorAssert::className($class); + RectorAssert::functionName($function); } public function getFunction(): string diff --git a/rules/Transform/ValueObject/DimFetchAssignToMethodCall.php b/rules/Transform/ValueObject/DimFetchAssignToMethodCall.php index 4654c61ff27..55a8de4a901 100644 --- a/rules/Transform/ValueObject/DimFetchAssignToMethodCall.php +++ b/rules/Transform/ValueObject/DimFetchAssignToMethodCall.php @@ -5,6 +5,7 @@ namespace Rector\Transform\ValueObject; use PHPStan\Type\ObjectType; +use Rector\Core\Validation\RectorAssert; final class DimFetchAssignToMethodCall { @@ -13,6 +14,7 @@ public function __construct( private readonly string $itemClass, private readonly string $addMethod ) { + RectorAssert::methodName($addMethod); } public function getListObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/FuncCallToMethodCall.php b/rules/Transform/ValueObject/FuncCallToMethodCall.php index 6f1016eb266..e5c38639b8a 100644 --- a/rules/Transform/ValueObject/FuncCallToMethodCall.php +++ b/rules/Transform/ValueObject/FuncCallToMethodCall.php @@ -5,6 +5,7 @@ namespace Rector\Transform\ValueObject; use PHPStan\Type\ObjectType; +use Rector\Core\Validation\RectorAssert; final class FuncCallToMethodCall { @@ -13,6 +14,10 @@ public function __construct( private readonly string $newClassName, private readonly string $newMethodName ) { + RectorAssert::functionName($oldFuncName); + + RectorAssert::className($newClassName); + RectorAssert::methodName($newMethodName); } public function getOldFuncName(): string diff --git a/rules/Transform/ValueObject/FuncCallToStaticCall.php b/rules/Transform/ValueObject/FuncCallToStaticCall.php index fc7569f5b7a..950aac75159 100644 --- a/rules/Transform/ValueObject/FuncCallToStaticCall.php +++ b/rules/Transform/ValueObject/FuncCallToStaticCall.php @@ -4,6 +4,8 @@ namespace Rector\Transform\ValueObject; +use Rector\Core\Validation\RectorAssert; + final class FuncCallToStaticCall { public function __construct( @@ -11,6 +13,10 @@ public function __construct( private readonly string $newClassName, private readonly string $newMethodName ) { + RectorAssert::functionName($oldFuncName); + + RectorAssert::className($newClassName); + RectorAssert::methodName($newMethodName); } public function getOldFuncName(): string diff --git a/rules/Transform/ValueObject/GetAndSetToMethodCall.php b/rules/Transform/ValueObject/GetAndSetToMethodCall.php index ab5c4254df5..0fb87e74f41 100644 --- a/rules/Transform/ValueObject/GetAndSetToMethodCall.php +++ b/rules/Transform/ValueObject/GetAndSetToMethodCall.php @@ -5,6 +5,7 @@ namespace Rector\Transform\ValueObject; use PHPStan\Type\ObjectType; +use Rector\Core\Validation\RectorAssert; final class GetAndSetToMethodCall { @@ -16,6 +17,8 @@ public function __construct( private readonly string $getMethod, private readonly string $setMethod ) { + RectorAssert::methodName($getMethod); + RectorAssert::methodName($setMethod); } public function getGetMethod(): string diff --git a/rules/Transform/ValueObject/MethodCallToAnotherMethodCallWithArguments.php b/rules/Transform/ValueObject/MethodCallToAnotherMethodCallWithArguments.php index 5be2fba5df8..a017a9d4b59 100644 --- a/rules/Transform/ValueObject/MethodCallToAnotherMethodCallWithArguments.php +++ b/rules/Transform/ValueObject/MethodCallToAnotherMethodCallWithArguments.php @@ -19,6 +19,8 @@ public function __construct( private readonly array $newArguments ) { RectorAssert::className($type); + RectorAssert::methodName($oldMethod); + RectorAssert::methodName($newMethod); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/MethodCallToMethodCall.php b/rules/Transform/ValueObject/MethodCallToMethodCall.php index 776b8e9b993..6d06128d70d 100644 --- a/rules/Transform/ValueObject/MethodCallToMethodCall.php +++ b/rules/Transform/ValueObject/MethodCallToMethodCall.php @@ -19,7 +19,10 @@ public function __construct( private readonly string $newMethod, ) { RectorAssert::className($oldType); + RectorAssert::methodName($oldMethod); + RectorAssert::className($newType); + RectorAssert::methodName($newMethod); } public function getOldType(): string diff --git a/rules/Transform/ValueObject/MethodCallToPropertyFetch.php b/rules/Transform/ValueObject/MethodCallToPropertyFetch.php index 0ae4ff526ec..ed6746daf32 100644 --- a/rules/Transform/ValueObject/MethodCallToPropertyFetch.php +++ b/rules/Transform/ValueObject/MethodCallToPropertyFetch.php @@ -15,6 +15,8 @@ public function __construct( private readonly string $newProperty, ) { RectorAssert::className($oldType); + RectorAssert::methodName($oldMethod); + RectorAssert::propertyName($newProperty); } public function getOldObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/MethodCallToStaticCall.php b/rules/Transform/ValueObject/MethodCallToStaticCall.php index 2f93141fc1b..271d365975d 100644 --- a/rules/Transform/ValueObject/MethodCallToStaticCall.php +++ b/rules/Transform/ValueObject/MethodCallToStaticCall.php @@ -5,6 +5,7 @@ namespace Rector\Transform\ValueObject; use PHPStan\Type\ObjectType; +use Rector\Core\Validation\RectorAssert; final class MethodCallToStaticCall { @@ -14,6 +15,11 @@ public function __construct( private readonly string $newClass, private readonly string $newMethod ) { + RectorAssert::className($oldClass); + RectorAssert::className($oldMethod); + + RectorAssert::className($newClass); + RectorAssert::className($newMethod); } public function getOldObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/NewArgToMethodCall.php b/rules/Transform/ValueObject/NewArgToMethodCall.php index 0438ee3ba3a..888531bdacf 100644 --- a/rules/Transform/ValueObject/NewArgToMethodCall.php +++ b/rules/Transform/ValueObject/NewArgToMethodCall.php @@ -9,15 +9,13 @@ final class NewArgToMethodCall { - /** - * @param mixed $value - */ public function __construct( private readonly string $type, - private $value, + private readonly mixed $value, private readonly string $methodCall ) { RectorAssert::className($type); + RectorAssert::className($methodCall); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/NewToMethodCall.php b/rules/Transform/ValueObject/NewToMethodCall.php index 543dc062f65..8e923edb8bd 100644 --- a/rules/Transform/ValueObject/NewToMethodCall.php +++ b/rules/Transform/ValueObject/NewToMethodCall.php @@ -5,6 +5,7 @@ namespace Rector\Transform\ValueObject; use PHPStan\Type\ObjectType; +use Rector\Core\Validation\RectorAssert; final class NewToMethodCall { @@ -13,6 +14,9 @@ public function __construct( private readonly string $serviceType, private readonly string $serviceMethod ) { + RectorAssert::className($newType); + RectorAssert::className($serviceType); + RectorAssert::methodName($serviceMethod); } public function getNewObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/NewToStaticCall.php b/rules/Transform/ValueObject/NewToStaticCall.php index ee1ee29f74b..3cd30494944 100644 --- a/rules/Transform/ValueObject/NewToStaticCall.php +++ b/rules/Transform/ValueObject/NewToStaticCall.php @@ -15,7 +15,9 @@ public function __construct( private readonly string $staticCallMethod ) { RectorAssert::className($type); + RectorAssert::className($staticCallClass); + RectorAssert::methodName($staticCallMethod); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/ParentClassToTraits.php b/rules/Transform/ValueObject/ParentClassToTraits.php index 8eee37c0982..5561b398a23 100644 --- a/rules/Transform/ValueObject/ParentClassToTraits.php +++ b/rules/Transform/ValueObject/ParentClassToTraits.php @@ -4,6 +4,9 @@ namespace Rector\Transform\ValueObject; +use Rector\Core\Validation\RectorAssert; +use Webmozart\Assert\Assert; + final class ParentClassToTraits { /** @@ -13,6 +16,8 @@ public function __construct( private readonly string $parentType, private readonly array $traitNames ) { + RectorAssert::className($parentType); + Assert::allString($traitNames); } public function getParentType(): string diff --git a/rules/Transform/ValueObject/PropertyAndClassMethodName.php b/rules/Transform/ValueObject/PropertyAndClassMethodName.php index 382aa07fe40..329a6b733f8 100644 --- a/rules/Transform/ValueObject/PropertyAndClassMethodName.php +++ b/rules/Transform/ValueObject/PropertyAndClassMethodName.php @@ -4,12 +4,16 @@ namespace Rector\Transform\ValueObject; +use Rector\Core\Validation\RectorAssert; + final class PropertyAndClassMethodName { public function __construct( private readonly string $propertyName, private readonly string $classMethodName ) { + RectorAssert::propertyName($propertyName); + RectorAssert::methodName($classMethodName); } public function getPropertyName(): string diff --git a/rules/Transform/ValueObject/PropertyAssignToMethodCall.php b/rules/Transform/ValueObject/PropertyAssignToMethodCall.php index 50729f8c198..d5c3c0b76db 100644 --- a/rules/Transform/ValueObject/PropertyAssignToMethodCall.php +++ b/rules/Transform/ValueObject/PropertyAssignToMethodCall.php @@ -15,6 +15,8 @@ public function __construct( private readonly string $newMethodName ) { RectorAssert::className($class); + RectorAssert::propertyName($oldPropertyName); + RectorAssert::methodName($newMethodName); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/PropertyFetchToMethodCall.php b/rules/Transform/ValueObject/PropertyFetchToMethodCall.php index 7c47d73671c..fbe409c600c 100644 --- a/rules/Transform/ValueObject/PropertyFetchToMethodCall.php +++ b/rules/Transform/ValueObject/PropertyFetchToMethodCall.php @@ -20,6 +20,12 @@ public function __construct( private readonly array $newGetArguments = [] ) { RectorAssert::className($oldType); + RectorAssert::propertyName($oldProperty); + + RectorAssert::methodName($newGetMethod); + if (is_string($newSetMethod)) { + RectorAssert::methodName($newSetMethod); + } } public function getOldObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/ReplaceParentCallByPropertyCall.php b/rules/Transform/ValueObject/ReplaceParentCallByPropertyCall.php index 010e3bf1041..78f23826247 100644 --- a/rules/Transform/ValueObject/ReplaceParentCallByPropertyCall.php +++ b/rules/Transform/ValueObject/ReplaceParentCallByPropertyCall.php @@ -15,6 +15,8 @@ public function __construct( private readonly string $property ) { RectorAssert::className($class); + RectorAssert::methodName($method); + RectorAssert::propertyName($property); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/ServiceGetterToConstructorInjection.php b/rules/Transform/ValueObject/ServiceGetterToConstructorInjection.php index a483982b12b..d97f08ff408 100644 --- a/rules/Transform/ValueObject/ServiceGetterToConstructorInjection.php +++ b/rules/Transform/ValueObject/ServiceGetterToConstructorInjection.php @@ -15,6 +15,8 @@ public function __construct( private readonly string $serviceType ) { RectorAssert::className($oldType); + RectorAssert::methodName($oldMethod); + RectorAssert::className($serviceType); } diff --git a/rules/Transform/ValueObject/StaticCallRecipe.php b/rules/Transform/ValueObject/StaticCallRecipe.php index 57551ed50c3..e483b8f8d2a 100644 --- a/rules/Transform/ValueObject/StaticCallRecipe.php +++ b/rules/Transform/ValueObject/StaticCallRecipe.php @@ -4,12 +4,16 @@ namespace Rector\Transform\ValueObject; +use Rector\Core\Validation\RectorAssert; + final class StaticCallRecipe { public function __construct( private readonly string $className, private readonly string $methodName, ) { + RectorAssert::className($className); + RectorAssert::methodName($methodName); } public function getClassName(): string diff --git a/rules/Transform/ValueObject/StaticCallToFuncCall.php b/rules/Transform/ValueObject/StaticCallToFuncCall.php index 04ba57f87a2..f5e96f6963c 100644 --- a/rules/Transform/ValueObject/StaticCallToFuncCall.php +++ b/rules/Transform/ValueObject/StaticCallToFuncCall.php @@ -15,6 +15,9 @@ public function __construct( private readonly string $function ) { RectorAssert::className($class); + RectorAssert::methodName($method); + + RectorAssert::functionName($function); } public function getObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/StaticCallToMethodCall.php b/rules/Transform/ValueObject/StaticCallToMethodCall.php index 34aca80f8a6..e4102e28a70 100644 --- a/rules/Transform/ValueObject/StaticCallToMethodCall.php +++ b/rules/Transform/ValueObject/StaticCallToMethodCall.php @@ -8,6 +8,7 @@ use PhpParser\Node\Identifier; use PhpParser\Node\Name; use PHPStan\Type\ObjectType; +use Rector\Core\Validation\RectorAssert; final class StaticCallToMethodCall { @@ -17,6 +18,18 @@ public function __construct( private readonly string $classType, private readonly string $methodName ) { + RectorAssert::className($staticClass); + + // special char to match all method names + if ($staticMethod !== '*') { + RectorAssert::methodName($staticMethod); + } + + RectorAssert::className($classType); + + if ($methodName !== '*') { + RectorAssert::methodName($methodName); + } } public function getClassObjectType(): ObjectType diff --git a/rules/Transform/ValueObject/StaticCallToNew.php b/rules/Transform/ValueObject/StaticCallToNew.php index f6cb6d884ef..e07fd50a19c 100644 --- a/rules/Transform/ValueObject/StaticCallToNew.php +++ b/rules/Transform/ValueObject/StaticCallToNew.php @@ -13,6 +13,7 @@ public function __construct( private readonly string $method ) { RectorAssert::className($class); + RectorAssert::methodName($method); } public function getClass(): string diff --git a/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php b/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php index 853387517ed..379f656be36 100644 --- a/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php +++ b/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php @@ -15,6 +15,8 @@ public function __construct( private readonly string $unsedMethodCall ) { RectorAssert::className($type); + RectorAssert::methodName($issetMethodCall); + RectorAssert::methodName($unsedMethodCall); } public function getObjectType(): ObjectType diff --git a/src/Validation/RectorAssert.php b/src/Validation/RectorAssert.php index 2a85a10cb4a..93d99bfd27f 100644 --- a/src/Validation/RectorAssert.php +++ b/src/Validation/RectorAssert.php @@ -19,16 +19,60 @@ final class RectorAssert */ private const CLASS_NAME_REGEX = '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*$#'; + /** + * @see https://www.php.net/manual/en/language.variables.basics.php + * @see https://regex101.com/r/hFw17T/1 + * + * @var string + */ + private const PROPERTY_NAME_REGEX = '#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$#'; + + /** + * @see https://regex101.com/r/uh5B0S/1 + * @see https://www.php.net/manual/en/functions.user-defined.php + * + * @var string + */ + private const METHOD_NAME_REGEX = '#^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$#'; + + /** + * @see https://regex101.com/r/uh5B0S/1 + * @see https://www.php.net/manual/en/functions.user-defined.php + * + * @var string + */ + private const FUNCTION_NAME_REGEX = '#([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]))?([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)$#'; + /** * Assert value is valid class name */ - public static function className(string $className): void + public static function className(string $name): void + { + self::elementName($name, self::CLASS_NAME_REGEX, 'class'); + } + + public static function propertyName(string $name): void + { + self::elementName($name, self::PROPERTY_NAME_REGEX, 'property'); + } + + public static function methodName(string $name): void + { + self::elementName($name, self::METHOD_NAME_REGEX, 'method'); + } + + public static function functionName(string $name): void + { + self::elementName($name, self::FUNCTION_NAME_REGEX, 'function'); + } + + public static function elementName(string $name, string $regex, string $elementType): void { - if (StringUtils::isMatch($className, self::CLASS_NAME_REGEX)) { + if (StringUtils::isMatch($name, $regex)) { return; } - $errorMessage = $className . ' is not a valid class name'; + $errorMessage = sprintf('"%s" is not a valid %s name', $name, $elementType); throw new InvalidArgumentException($errorMessage); } }