Skip to content

Commit

Permalink
[Php84] Add ExplicitNullableParamTypeRector (#5724)
Browse files Browse the repository at this point in the history
* [Php84] Add ExplicitNullableParamTypeRector

* more fixture

Signed-off-by: Abdul Malik Ikhsan <samsonasik@gmail.com>

* fix phpstan

* rename fixture

* renaming fixture

* renaming fixture

* fix @see

* fix

* final touch: regenerate docs

* final touch: more test

* final touch: more test

---------

Signed-off-by: Abdul Malik Ikhsan <samsonasik@gmail.com>
  • Loading branch information
samsonasik committed Mar 15, 2024
1 parent 23e3da2 commit ff32c0c
Show file tree
Hide file tree
Showing 19 changed files with 296 additions and 3 deletions.
19 changes: 18 additions & 1 deletion build/target-repository/docs/rector_rules_overview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 364 Rules Overview
# 365 Rules Overview

<br>

Expand Down Expand Up @@ -46,6 +46,8 @@

- [Php83](#php83) (3)

- [Php84](#php84) (1)

- [Privatization](#privatization) (5)

- [Removing](#removing) (5)
Expand Down Expand Up @@ -5328,6 +5330,21 @@ Combine separated host and port on `ldap_connect()` args

<br>

## Php84

### ExplicitNullableParamTypeRector

Make implicit nullable param to explicit

- class: [`Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector`](../rules/Php84/Rector/Param/ExplicitNullableParamTypeRector.php)

```diff
-function foo(string $param = null) {}
+function foo(?string $param = null) {}
```

<br>

## Privatization

### FinalizeClassesWithoutChildrenRector
Expand Down
11 changes: 11 additions & 0 deletions config/set/level/up-to-php84.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;
use Rector\Set\ValueObject\SetList;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->sets([SetList::PHP_84, LevelSetList::UP_TO_PHP_83]);
};
12 changes: 12 additions & 0 deletions config/set/php84.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rules([
ExplicitNullableParamTypeRector::class,
]);
};
4 changes: 2 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ parameters:
- '#Callable callable\(PHPStan\\Type\\Type\)\: PHPStan\\Type\\Type invoked with 2 parameters, 1 required#'

# known value
- '#Method Rector\\Php\\PhpVersionProvider\:\:provide\(\) should return 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|100000 but returns int#'
- '#Method Rector\\Php\\PhpVersionProvider\:\:provide\(\) should return 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|80400\|100000 but returns int#'

# stubs-rector directory exists on target-repository
-
Expand Down Expand Up @@ -279,7 +279,7 @@ parameters:
- '#Method "renamePropertyPromotion\(\)" returns bool type, so the name should start with is/has/was#'

-
message: '#Parameter \#1 \$phpVersion of method Rector\\Config\\RectorConfig\:\:phpVersion\(\) expects 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|100000, (.*?) given#'
message: '#Parameter \#1 \$phpVersion of method Rector\\Config\\RectorConfig\:\:phpVersion\(\) expects 50200\|50300\|50400\|50500\|50600\|70000\|70100\|70200\|70300\|70400\|80000\|80100\|80200\|80300\|80400\|100000, (.*?) given#'
path: rules-tests

-
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector;

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class ExplicitNullableParamTypeRectorTest extends AbstractRectorTestCase
{
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class WithParamTypeNullDefault
{
public function run(string $a = null)
{
}
}

?>
-----
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class WithParamTypeNullDefault
{
public function run(?string $a = null)
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class SkipAlreadyNullable
{
public function run(?string $a = null)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class SkipDefaultTrue
{
public function run(bool $a = true)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class SkipNoDefault
{
public function run(bool $a)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class SkipNoType
{
public function run($a = null)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class SkipNullParam
{
public function run(null $a = null)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class UnionTypeNullDefault
{
public function run(int|string $a = null)
{
}
}

?>
-----
<?php

namespace Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\Fixture;

class UnionTypeNullDefault
{
public function run(int|string|null $a = null)
{
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php84\Rector\Param\ExplicitNullableParamTypeRector;
use Rector\ValueObject\PhpVersion;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rule(ExplicitNullableParamTypeRector::class);

$rectorConfig->phpVersion(PhpVersion::PHP_84);
};
87 changes: 87 additions & 0 deletions rules/Php84/Rector/Param/ExplicitNullableParamTypeRector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

declare(strict_types=1);

namespace Rector\Php84\Rector\Param;

use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Param;
use PHPStan\Type\NullType;
use PHPStan\Type\TypeCombinator;
use Rector\PhpParser\Node\Value\ValueResolver;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\Rector\AbstractRector;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\Php84\Rector\Param\ExplicitNullableParamTypeRector\ExplicitNullableParamTypeRectorTest
*/
final class ExplicitNullableParamTypeRector extends AbstractRector implements MinPhpVersionInterface
{
public function __construct(
private readonly ValueResolver $valueResolver,
private readonly StaticTypeMapper $staticTypeMapper
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Make implicit nullable param to explicit', [
new CodeSample(
<<<'CODE_SAMPLE'
function foo(string $param = null) {}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
function foo(?string $param = null) {}
CODE_SAMPLE
,
),
]);
}

public function getNodeTypes(): array
{
return [Param::class];
}

/**
* @param Param $node
*/
public function refactor(Node $node): ?Param
{
if (! $node->type instanceof Node) {
return null;
}

if (! $node->default instanceof ConstFetch || ! $this->valueResolver->isNull($node->default)) {
return null;
}

$nodeType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($node->type);
if ($nodeType instanceof NullType) {
return null;
}

$removedNullNodeType = TypeCombinator::removeNull($nodeType);

if (! $nodeType->equals($removedNullNodeType)) {
return null;
}

$newNodeType = TypeCombinator::addNull($nodeType);
$node->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($newNodeType, TypeKind::PARAM);

return $node;
}

public function provideMinPhpVersion(): int
{
return PhpVersionFeature::DEPRECATE_IMPLICIT_NULLABLE_PARAM_TYPE;
}
}
3 changes: 3 additions & 0 deletions src/Configuration/RectorConfigBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ public function withPhpSets(
bool $php55 = false,
bool $php54 = false,
bool $php53 = false,
bool $php84 = false, // place on later as BC break when used in php 7.x without named arg
): self {
$pickedArguments = array_filter(func_get_args());
if (count($pickedArguments) > 1) {
Expand Down Expand Up @@ -429,6 +430,8 @@ public function withPhpSets(
$this->sets[] = LevelSetList::UP_TO_PHP_82;
} elseif ($php83) {
$this->sets[] = LevelSetList::UP_TO_PHP_83;
} elseif ($php84) {
$this->sets[] = LevelSetList::UP_TO_PHP_84;
}

return $this;
Expand Down
6 changes: 6 additions & 0 deletions src/Set/ValueObject/LevelSetList.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
*/
final class LevelSetList implements SetListInterface
{
/**
* @var string
*/
public const UP_TO_PHP_84 = __DIR__ . '/../../../config/set/level/up-to-php84.php';


/**
* @var string
*/
Expand Down
5 changes: 5 additions & 0 deletions src/Set/ValueObject/SetList.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ final class SetList implements SetListInterface
*/
public const PHP_83 = __DIR__ . '/../../../config/set/php83.php';

/**
* @var string
*/
public const PHP_84 = __DIR__ . '/../../../config/set/php84.php';

/**
* @var string
*/
Expand Down
5 changes: 5 additions & 0 deletions src/ValueObject/PhpVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ final class PhpVersion
*/
public const PHP_83 = 80300;

/**
* @var int
*/
public const PHP_84 = 80400;

/**
* @var int
*/
Expand Down
6 changes: 6 additions & 0 deletions src/ValueObject/PhpVersionFeature.php
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,12 @@ final class PhpVersionFeature
*/
public const TYPED_CLASS_CONSTANTS = PhpVersion::PHP_83;

/**
* @see https://wiki.php.net/rfc/deprecate-implicitly-nullable-types
* @var int
*/
public const DEPRECATE_IMPLICIT_NULLABLE_PARAM_TYPE = PhpVersion::PHP_84;

/**
* @see https://www.php.net/manual/en/migration83.deprecated.php#migration83.deprecated.ldap
* @var int
Expand Down

0 comments on commit ff32c0c

Please sign in to comment.