Skip to content

Commit f207412

Browse files
committed
Refactor: added NullableParameterFixer
1 parent c3364e6 commit f207412

File tree

10 files changed

+501
-0
lines changed

10 files changed

+501
-0
lines changed

src/Ast/DefaultValue.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ public function toString(): string
3535
}
3636

3737

38+
public function isNull(): bool
39+
{
40+
$literalValue = trim($this->literal->getLiteral());
41+
return strtolower($literalValue) === 'null';
42+
}
43+
44+
3845
public static function parseForFunctionParameter(NodeParser $parser): self
3946
{
4047
$nodeIndentation = $parser->consumeNodeIndentation();

src/Ast/NamedType.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ public function toString(): string
4848
}
4949

5050

51+
public function isNullable(): bool
52+
{
53+
return $this->nullableSign === '?';
54+
}
55+
56+
57+
public function setNullable(bool $nullable): void
58+
{
59+
$this->nullableSign = $nullable ? '?' : '';
60+
}
61+
62+
5163
public static function parse(NodeParser $parser): self
5264
{
5365
$nodeIndentation = $parser->consumeNodeIndentation();

src/Ast/Parameter.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ public function hasPromotedProperty(): bool
6262
}
6363

6464

65+
public function getType(): ?Type
66+
{
67+
return $this->type;
68+
}
69+
70+
71+
public function getDefaultValue(): ?DefaultValue
72+
{
73+
return $this->defaultValue;
74+
}
75+
76+
6577
public function toString()
6678
{
6779
$s = $this->indentation;

src/Ast/Type.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ public function toString(): string
4040
}
4141

4242

43+
/**
44+
* @return NamedType[]
45+
*/
46+
public function getNamedTypes(): array
47+
{
48+
return $this->types;
49+
}
50+
51+
4352
public static function parse(NodeParser $parser): self
4453
{
4554
$nodeIndentation = $parser->consumeNodeIndentation();
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CzProject\PhpSimpleAst\Refactor;
6+
7+
use CzProject\PhpSimpleAst\Reflection;
8+
9+
10+
class NullableParameterFixer
11+
{
12+
/**
13+
* @param Reflection\ClassReflection[] $classes
14+
*/
15+
public static function processClasses(array $classes): void
16+
{
17+
foreach ($classes as $class) {
18+
self::processClass($class);
19+
}
20+
}
21+
22+
23+
public static function processClass(Reflection\ClassReflection $classReflection): void
24+
{
25+
foreach ($classReflection->getMethods() as $methodReflection) {
26+
$parameters = $methodReflection->getParameters();
27+
28+
foreach ($parameters as $parameter) {
29+
$type = $parameter->getType();
30+
$defaultValue = $parameter->getDefaultValue();
31+
32+
if ($type !== NULL &&
33+
$defaultValue !== NULL &&
34+
$defaultValue->isNull() &&
35+
!$parameter->isNullable()) {
36+
$parameter->setNullable(true);
37+
}
38+
}
39+
}
40+
}
41+
}

src/Reflection/ParameterReflection.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,48 @@ public function isPassedByReference(): bool
4545
{
4646
return $this->parameter->isPassedByReference();
4747
}
48+
49+
50+
public function getType(): ?Ast\Type
51+
{
52+
return $this->parameter->getType();
53+
}
54+
55+
56+
public function getDefaultValue(): ?Ast\DefaultValue
57+
{
58+
return $this->parameter->getDefaultValue();
59+
}
60+
61+
62+
public function isNullable(): bool
63+
{
64+
$type = $this->parameter->getType();
65+
if ($type === NULL) {
66+
return false;
67+
}
68+
69+
$namedTypes = $type->getNamedTypes();
70+
foreach ($namedTypes as $namedType) {
71+
if ($namedType->isNullable()) {
72+
return true;
73+
}
74+
}
75+
76+
return false;
77+
}
78+
79+
80+
public function setNullable(bool $nullable): void
81+
{
82+
$type = $this->parameter->getType();
83+
if ($type === NULL) {
84+
return;
85+
}
86+
87+
$namedTypes = $type->getNamedTypes();
88+
foreach ($namedTypes as $namedType) {
89+
$namedType->setNullable($nullable);
90+
}
91+
}
4892
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use CzProject\PhpSimpleAst;
6+
use Tester\Assert;
7+
8+
require __DIR__ . '/../../bootstrap.php';
9+
10+
11+
test('nullable parameter fixer', function () {
12+
$reflection = PhpSimpleAst\Reflection\FilesReflection::scanFile(Fixtures::path('Refactoring/NullableParameterFixer.php'));
13+
$classReflection = $reflection->getClass(\Foo\TestClass::class);
14+
15+
PhpSimpleAst\Refactor\NullableParameterFixer::processClass($classReflection);
16+
17+
$method = $classReflection->getMethod('methodWithNullableParams');
18+
$parameters = $method->getParameters();
19+
20+
// param1: string $param1 = null should become nullable
21+
Assert::true($parameters['param1']->isNullable());
22+
23+
// param2: int $param2 = 42 should NOT become nullable (default is not null)
24+
Assert::false($parameters['param2']->isNullable());
25+
26+
// param3: array $param3 = null should become nullable
27+
Assert::true($parameters['param3']->isNullable());
28+
29+
// param4: $param4 = null should NOT be affected (no type declaration)
30+
Assert::false($parameters['param4']->isNullable());
31+
32+
// Test method without defaults - should not be affected
33+
$method2 = $classReflection->getMethod('methodWithoutDefaults');
34+
$parameters2 = $method2->getParameters();
35+
Assert::false($parameters2['param1']->isNullable());
36+
Assert::false($parameters2['param2']->isNullable());
37+
38+
// Test method with already nullable types - should remain unchanged
39+
$method3 = $classReflection->getMethod('methodWithNullableTypes');
40+
$parameters3 = $method3->getParameters();
41+
Assert::true($parameters3['param1']->isNullable());
42+
Assert::true($parameters3['param2']->isNullable());
43+
44+
Assert::same(
45+
Fixtures::load('Refactoring/NullableParameterFixer.result'),
46+
$reflection->getFiles()[0]->toString()
47+
);
48+
});

0 commit comments

Comments
 (0)