2019-10-13 05:59:52 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2021-02-20 23:21:19 +00:00
namespace Rector\Arguments\Rector\ClassMethod ;
2018-05-01 17:31:41 +00:00
use PhpParser\BuilderHelpers ;
use PhpParser\Node ;
2018-10-21 19:43:47 +00:00
use PhpParser\Node\Arg ;
2018-05-01 17:31:41 +00:00
use PhpParser\Node\Expr\MethodCall ;
use PhpParser\Node\Expr\StaticCall ;
2018-10-21 19:43:47 +00:00
use PhpParser\Node\Expr\Variable ;
2019-03-08 20:56:34 +00:00
use PhpParser\Node\Identifier ;
2019-12-04 21:06:09 +00:00
use PhpParser\Node\Name ;
2019-03-08 20:56:34 +00:00
use PhpParser\Node\Name\FullyQualified ;
2018-10-21 19:43:47 +00:00
use PhpParser\Node\Param ;
2019-09-06 10:30:58 +00:00
use PhpParser\Node\Stmt\Class_ ;
2018-05-01 17:31:41 +00:00
use PhpParser\Node\Stmt\ClassMethod ;
2021-02-27 02:13:22 +00:00
use PHPStan\Type\ObjectType ;
2021-02-20 23:21:19 +00:00
use Rector\Arguments\NodeAnalyzer\ArgumentAddingScope ;
use Rector\Arguments\ValueObject\ArgumentAdder ;
2020-07-29 23:39:41 +00:00
use Rector\Core\Contract\Rector\ConfigurableRectorInterface ;
2020-08-25 21:25:00 +00:00
use Rector\Core\Exception\ShouldNotHappenException ;
2020-02-06 21:48:18 +00:00
use Rector\Core\Rector\AbstractRector ;
2019-09-04 12:10:29 +00:00
use Rector\NodeTypeResolver\Node\AttributeKey ;
2020-11-16 17:50:38 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample ;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition ;
2021-08-27 09:14:46 +00:00
use RectorPrefix20210827\Webmozart\Assert\Assert ;
2019-09-03 09:11:45 +00:00
/**
2021-03-12 22:20:25 +00:00
* @ see \Rector\Tests\Arguments\Rector\ClassMethod\ArgumentAdderRector\ArgumentAdderRectorTest
2019-09-03 09:11:45 +00:00
*/
2021-05-10 22:23:08 +00:00
final class ArgumentAdderRector extends \Rector\Core\Rector\AbstractRector implements \Rector\Core\Contract\Rector\ConfigurableRectorInterface
2018-05-01 17:31:41 +00:00
{
2021-01-24 11:23:50 +00:00
/**
* @ var string
*/
public const ADDED_ARGUMENTS = 'added_arguments' ;
2020-07-29 23:39:41 +00:00
/**
2021-01-17 15:43:47 +00:00
* @ var ArgumentAdder []
2020-08-25 21:25:00 +00:00
*/
2021-01-17 15:43:47 +00:00
private $addedArguments = [];
2018-05-01 17:31:41 +00:00
/**
2021-05-10 23:39:21 +00:00
* @ var \Rector\Arguments\NodeAnalyzer\ArgumentAddingScope
2020-08-25 21:25:00 +00:00
*/
2021-01-17 15:43:47 +00:00
private $argumentAddingScope ;
2021-05-10 22:23:08 +00:00
public function __construct ( \Rector\Arguments\NodeAnalyzer\ArgumentAddingScope $argumentAddingScope )
2021-01-17 15:43:47 +00:00
{
$this -> argumentAddingScope = $argumentAddingScope ;
}
2021-05-10 22:23:08 +00:00
public function getRuleDefinition () : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
2018-05-01 17:31:41 +00:00
{
2021-05-10 22:23:08 +00:00
$exampleConfiguration = [ self :: ADDED_ARGUMENTS => [ new \Rector\Arguments\ValueObject\ArgumentAdder ( 'SomeExampleClass' , 'someMethod' , 0 , 'someArgument' , \true , 'SomeType' )]];
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition ( 'This Rector adds new default arguments in calls of defined methods and class types.' , [ new \Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample ( <<< 'CODE_SAMPLE'
2018-10-21 19:43:47 +00:00
$someObject = new SomeExampleClass ;
2018-05-04 12:52:17 +00:00
$someObject -> someMethod ();
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
, <<< 'CODE_SAMPLE'
2018-10-21 19:43:47 +00:00
$someObject = new SomeExampleClass ;
2018-05-04 12:52:17 +00:00
$someObject -> someMethod ( true );
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-10 22:23:08 +00:00
, $exampleConfiguration ), new \Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample ( <<< 'CODE_SAMPLE'
2018-10-21 19:43:47 +00:00
class MyCustomClass extends SomeExampleClass
2018-05-04 13:01:35 +00:00
{
public function someMethod ()
{
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
, <<< 'CODE_SAMPLE'
2018-10-21 19:43:47 +00:00
class MyCustomClass extends SomeExampleClass
2018-05-04 13:01:35 +00:00
{
public function someMethod ( $value = true )
{
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
, $exampleConfiguration )]);
2018-05-01 17:31:41 +00:00
}
2018-08-14 22:12:41 +00:00
/**
2021-02-27 00:06:15 +00:00
* @ return array < class - string < Node >>
2018-08-14 22:12:41 +00:00
*/
2021-05-09 20:15:43 +00:00
public function getNodeTypes () : array
2018-05-01 17:31:41 +00:00
{
2021-05-10 22:23:08 +00:00
return [ \PhpParser\Node\Expr\MethodCall :: class , \PhpParser\Node\Expr\StaticCall :: class , \PhpParser\Node\Stmt\ClassMethod :: class ];
2018-05-01 17:31:41 +00:00
}
/**
* @ param MethodCall | StaticCall | ClassMethod $node
2021-07-05 15:06:41 +00:00
* @ return \PhpParser\Node\Expr\MethodCall | \PhpParser\Node\Expr\StaticCall | \PhpParser\Node\Stmt\ClassMethod
2018-05-01 17:31:41 +00:00
*/
2021-07-05 15:06:41 +00:00
public function refactor ( \PhpParser\Node $node )
2018-05-01 17:31:41 +00:00
{
2020-08-25 21:25:00 +00:00
foreach ( $this -> addedArguments as $addedArgument ) {
2021-05-09 20:15:43 +00:00
if ( ! $this -> isObjectTypeMatch ( $node , $addedArgument -> getObjectType ())) {
2018-10-21 19:43:47 +00:00
continue ;
}
2021-05-09 20:15:43 +00:00
if ( ! $this -> isName ( $node -> name , $addedArgument -> getMethod ())) {
2020-08-25 21:25:00 +00:00
continue ;
2018-05-01 17:31:41 +00:00
}
2020-08-25 21:25:00 +00:00
$this -> processPositionWithDefaultValues ( $node , $addedArgument );
2018-05-01 17:31:41 +00:00
}
2018-10-21 19:43:47 +00:00
return $node ;
2018-05-01 17:31:41 +00:00
}
2020-08-22 20:02:50 +00:00
/**
2021-01-24 11:23:50 +00:00
* @ param array < string , ArgumentAdder [] > $configuration
2020-08-22 20:02:50 +00:00
*/
2021-05-09 20:15:43 +00:00
public function configure ( array $configuration ) : void
2020-07-29 23:39:41 +00:00
{
2021-01-24 11:23:50 +00:00
$addedArguments = $configuration [ self :: ADDED_ARGUMENTS ] ? ? [];
2021-08-27 09:14:46 +00:00
\RectorPrefix20210827\Webmozart\Assert\Assert :: allIsInstanceOf ( $addedArguments , \Rector\Arguments\ValueObject\ArgumentAdder :: class );
2020-08-25 21:25:00 +00:00
$this -> addedArguments = $addedArguments ;
2020-07-29 23:39:41 +00:00
}
2019-10-30 09:49:07 +00:00
/**
2021-08-23 00:20:32 +00:00
* @ param \PhpParser\Node\Expr\MethodCall | \PhpParser\Node\Expr\StaticCall | \PhpParser\Node\Stmt\ClassMethod $node
2019-10-30 09:49:07 +00:00
*/
2021-06-29 14:24:45 +00:00
private function isObjectTypeMatch ( $node , \PHPStan\Type\ObjectType $objectType ) : bool
2019-10-30 09:49:07 +00:00
{
2021-05-10 22:23:08 +00:00
if ( $node instanceof \PhpParser\Node\Expr\MethodCall ) {
2021-02-27 02:13:22 +00:00
return $this -> isObjectType ( $node -> var , $objectType );
2019-10-30 09:49:07 +00:00
}
2021-05-10 22:23:08 +00:00
if ( $node instanceof \PhpParser\Node\Expr\StaticCall ) {
2021-02-27 02:13:22 +00:00
return $this -> isObjectType ( $node -> class , $objectType );
2019-10-30 09:49:07 +00:00
}
// ClassMethod
2020-07-19 18:58:54 +00:00
/** @var Class_|null $classLike */
2021-05-10 22:23:08 +00:00
$classLike = $node -> getAttribute ( \Rector\NodeTypeResolver\Node\AttributeKey :: CLASS_NODE );
2019-10-30 09:49:07 +00:00
// anonymous class
2021-05-10 22:23:08 +00:00
if ( ! $classLike instanceof \PhpParser\Node\Stmt\Class_ ) {
2021-05-09 20:15:43 +00:00
return \false ;
2019-10-30 09:49:07 +00:00
}
2021-02-27 02:13:22 +00:00
return $this -> isObjectType ( $classLike , $objectType );
2019-10-30 09:49:07 +00:00
}
2018-05-01 17:31:41 +00:00
/**
2021-08-23 00:20:32 +00:00
* @ param \PhpParser\Node\Stmt\ClassMethod | \PhpParser\Node\Expr\MethodCall | \PhpParser\Node\Expr\StaticCall $node
2018-05-01 17:31:41 +00:00
*/
2021-05-30 10:12:56 +00:00
private function processPositionWithDefaultValues ( $node , \Rector\Arguments\ValueObject\ArgumentAdder $argumentAdder ) : void
2018-05-01 17:31:41 +00:00
{
2020-09-12 21:19:08 +00:00
if ( $this -> shouldSkipParameter ( $node , $argumentAdder )) {
2020-08-25 21:25:00 +00:00
return ;
}
2020-09-12 21:19:08 +00:00
$defaultValue = $argumentAdder -> getArgumentDefaultValue ();
$argumentType = $argumentAdder -> getArgumentType ();
$position = $argumentAdder -> getPosition ();
2021-05-10 22:23:08 +00:00
if ( $node instanceof \PhpParser\Node\Stmt\ClassMethod ) {
2020-10-09 20:00:45 +00:00
$this -> addClassMethodParam ( $node , $argumentAdder , $defaultValue , $argumentType , $position );
2021-05-10 22:23:08 +00:00
} elseif ( $node instanceof \PhpParser\Node\Expr\StaticCall ) {
2020-10-09 20:00:45 +00:00
$this -> processStaticCall ( $node , $position , $argumentAdder );
2020-08-25 21:25:00 +00:00
} else {
2021-05-10 22:23:08 +00:00
$arg = new \PhpParser\Node\Arg ( \PhpParser\BuilderHelpers :: normalizeValue ( $defaultValue ));
2020-10-09 20:00:45 +00:00
if ( isset ( $node -> args [ $position ])) {
return ;
}
2020-08-25 21:25:00 +00:00
$node -> args [ $position ] = $arg ;
2018-05-01 17:31:41 +00:00
}
}
2019-03-08 23:40:33 +00:00
/**
2021-08-23 00:20:32 +00:00
* @ param \PhpParser\Node\Stmt\ClassMethod | \PhpParser\Node\Expr\MethodCall | \PhpParser\Node\Expr\StaticCall $node
2019-03-08 23:40:33 +00:00
*/
2021-06-29 13:37:16 +00:00
private function shouldSkipParameter ( $node , \Rector\Arguments\ValueObject\ArgumentAdder $argumentAdder ) : bool
2019-03-08 23:40:33 +00:00
{
2020-09-12 21:19:08 +00:00
$position = $argumentAdder -> getPosition ();
$argumentName = $argumentAdder -> getArgumentName ();
2021-01-28 19:52:11 +00:00
if ( $argumentName === null ) {
2021-05-09 20:15:43 +00:00
return \true ;
2021-01-28 19:52:11 +00:00
}
2021-05-10 22:23:08 +00:00
if ( $node instanceof \PhpParser\Node\Stmt\ClassMethod ) {
2019-03-08 23:40:33 +00:00
// already added?
2021-05-09 20:15:43 +00:00
if ( ! isset ( $node -> params [ $position ])) {
return \false ;
2020-12-19 15:24:53 +00:00
}
return $this -> isName ( $node -> params [ $position ], $argumentName );
2019-03-08 23:40:33 +00:00
}
// already added?
2021-05-09 20:15:43 +00:00
if ( ! isset ( $node -> args [ $position ])) {
2021-02-21 09:32:45 +00:00
// is correct scope?
2021-05-09 20:15:43 +00:00
return ! $this -> argumentAddingScope -> isInCorrectScope ( $node , $argumentAdder );
2019-12-04 21:06:09 +00:00
}
2021-05-09 20:15:43 +00:00
if ( ! $this -> isName ( $node -> args [ $position ], $argumentName )) {
2021-02-21 09:32:45 +00:00
// is correct scope?
2021-05-09 20:15:43 +00:00
return ! $this -> argumentAddingScope -> isInCorrectScope ( $node , $argumentAdder );
2021-02-21 09:32:45 +00:00
}
2021-05-09 20:15:43 +00:00
return \true ;
2019-03-08 23:40:33 +00:00
}
2020-07-27 06:56:25 +00:00
/**
* @ param mixed $defaultValue
*/
2021-05-10 22:23:08 +00:00
private function addClassMethodParam ( \PhpParser\Node\Stmt\ClassMethod $classMethod , \Rector\Arguments\ValueObject\ArgumentAdder $argumentAdder , $defaultValue , ? string $type , int $position ) : void
2021-05-09 20:15:43 +00:00
{
2020-10-09 20:00:45 +00:00
$argumentName = $argumentAdder -> getArgumentName ();
if ( $argumentName === null ) {
2021-05-10 22:23:08 +00:00
throw new \Rector\Core\Exception\ShouldNotHappenException ();
2020-10-09 20:00:45 +00:00
}
2021-05-10 22:23:08 +00:00
$param = new \PhpParser\Node\Param ( new \PhpParser\Node\Expr\Variable ( $argumentName ), \PhpParser\BuilderHelpers :: normalizeValue ( $defaultValue ));
2020-02-01 16:04:38 +00:00
if ( $type ) {
2021-05-10 22:23:08 +00:00
$param -> type = \ctype_upper ( $type [ 0 ]) ? new \PhpParser\Node\Name\FullyQualified ( $type ) : new \PhpParser\Node\Identifier ( $type );
2020-02-01 16:04:38 +00:00
}
$classMethod -> params [ $position ] = $param ;
}
2021-05-10 22:23:08 +00:00
private function processStaticCall ( \PhpParser\Node\Expr\StaticCall $staticCall , int $position , \Rector\Arguments\ValueObject\ArgumentAdder $argumentAdder ) : void
2020-02-01 16:04:38 +00:00
{
2020-10-09 20:00:45 +00:00
$argumentName = $argumentAdder -> getArgumentName ();
if ( $argumentName === null ) {
2021-05-10 22:23:08 +00:00
throw new \Rector\Core\Exception\ShouldNotHappenException ();
2020-10-09 20:00:45 +00:00
}
2021-05-10 22:23:08 +00:00
if ( ! $staticCall -> class instanceof \PhpParser\Node\Name ) {
2020-02-01 16:04:38 +00:00
return ;
}
2021-05-09 20:15:43 +00:00
if ( ! $this -> isName ( $staticCall -> class , 'parent' )) {
2020-02-01 16:04:38 +00:00
return ;
}
2021-05-10 22:23:08 +00:00
$staticCall -> args [ $position ] = new \PhpParser\Node\Arg ( new \PhpParser\Node\Expr\Variable ( $argumentName ));
2020-02-01 16:04:38 +00:00
}
2018-05-01 17:31:41 +00:00
}