Skip to content

Commit 5f9ae1c

Browse files
authored
Implement TrueTruthyFalseFalseyTypeSpecifierContextMutator (#36)
1 parent 5d7c0ca commit 5f9ae1c

File tree

5 files changed

+197
-3
lines changed

5 files changed

+197
-3
lines changed

resources/infection.json5

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
},
1313
"mutators": {
1414
"@default": false,
15+
"PHPStan\\Infection\\IsSuperTypeOfCalleeAndArgumentMutator": true,
1516
"PHPStan\\Infection\\LooseBooleanMutator": true,
1617
"PHPStan\\Infection\\TrinaryLogicMutator": true,
17-
"PHPStan\\Infection\\IsSuperTypeOfCalleeAndArgumentMutator": true
18+
"PHPStan\\Infection\\TrueTruthyFalseFalseyTypeSpecifierContextMutator": true
1819
},
1920
"bootstrap": "build-infection/vendor/autoload.php"
2021
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Infection;
4+
5+
use Infection\Mutator\Definition;
6+
use Infection\Mutator\Mutator;
7+
use Infection\Mutator\MutatorCategory;
8+
use LogicException;
9+
use PhpParser\Node;
10+
use function count;
11+
use function in_array;
12+
13+
/**
14+
* @implements Mutator<Node\Expr\MethodCall>
15+
*/
16+
final class TrueTruthyFalseFalseyTypeSpecifierContextMutator implements Mutator
17+
{
18+
19+
public static function getDefinition(): Definition
20+
{
21+
return new Definition(
22+
<<<'TXT'
23+
Replaces boolean TypeSpecifierContext->true() with TypeSpecifierContext->truthy().
24+
TXT
25+
,
26+
MutatorCategory::ORTHOGONAL_REPLACEMENT,
27+
null,
28+
<<<'DIFF'
29+
- $context->false()
30+
+ $context->falsey()
31+
DIFF,
32+
);
33+
}
34+
35+
public function getName(): string
36+
{
37+
return self::class;
38+
}
39+
40+
public function canMutate(Node $node): bool
41+
{
42+
if (!$node instanceof Node\Expr\MethodCall) {
43+
return false;
44+
}
45+
46+
if (!$node->name instanceof Node\Identifier) {
47+
return false;
48+
}
49+
50+
if (!in_array($node->name->name, ['true', 'truthy', 'false', 'falsey'], true)) {
51+
return false;
52+
}
53+
54+
if (count($node->getArgs()) !== 0) {
55+
return false;
56+
}
57+
58+
return true;
59+
}
60+
61+
public function mutate(Node $node): iterable
62+
{
63+
if (!$node->name instanceof Node\Identifier) {
64+
throw new LogicException();
65+
}
66+
67+
switch ($node->name->name) {
68+
case 'true':
69+
yield new Node\Expr\MethodCall($node->var, 'truthy');
70+
break;
71+
case 'truthy':
72+
yield new Node\Expr\MethodCall($node->var, 'true');
73+
break;
74+
case 'false':
75+
yield new Node\Expr\MethodCall($node->var, 'falsey');
76+
break;
77+
case 'falsey':
78+
yield new Node\Expr\MethodCall($node->var, 'false');
79+
break;
80+
default:
81+
throw new LogicException();
82+
}
83+
}
84+
85+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Infection;
4+
5+
use Infection\Testing\BaseMutatorTestCase;
6+
use PHPUnit\Framework\Attributes\CoversClass;
7+
use PHPUnit\Framework\Attributes\DataProvider;
8+
9+
#[CoversClass(TrueTruthyFalseFalseyTypeSpecifierContextMutator::class)]
10+
final class TrueTruthyFalseFalseyTypeSpecifierContextMutatorTest extends BaseMutatorTestCase
11+
{
12+
13+
/**
14+
* @param string|string[] $expected
15+
*/
16+
#[DataProvider('mutationsProvider')]
17+
public function testMutator(string $input, $expected = []): void
18+
{
19+
$this->assertMutatesInput($input, $expected);
20+
}
21+
22+
/**
23+
* @return iterable<string, array{0: string, 1?: string}>
24+
*/
25+
public static function mutationsProvider(): iterable
26+
{
27+
yield 'It mutates true()' => [
28+
<<<'PHP'
29+
<?php
30+
$context = TypeSpecifierContext::createNull();
31+
$context->true();
32+
PHP
33+
,
34+
<<<'PHP'
35+
<?php
36+
37+
$context = TypeSpecifierContext::createNull();
38+
$context->truthy();
39+
PHP
40+
,
41+
];
42+
43+
yield 'It mutates truthy()' => [
44+
<<<'PHP'
45+
<?php
46+
$context = TypeSpecifierContext::createNull();
47+
$context->truthy();
48+
PHP
49+
,
50+
<<<'PHP'
51+
<?php
52+
53+
$context = TypeSpecifierContext::createNull();
54+
$context->true();
55+
PHP
56+
,
57+
];
58+
59+
yield 'It mutates false()' => [
60+
<<<'PHP'
61+
<?php
62+
$context = TypeSpecifierContext::createNull();
63+
$context->false();
64+
PHP
65+
,
66+
<<<'PHP'
67+
<?php
68+
69+
$context = TypeSpecifierContext::createNull();
70+
$context->falsey();
71+
PHP
72+
,
73+
];
74+
75+
yield 'It mutates falsey()' => [
76+
<<<'PHP'
77+
<?php
78+
$context = TypeSpecifierContext::createNull();
79+
$context->falsey();
80+
PHP
81+
,
82+
<<<'PHP'
83+
<?php
84+
85+
$context = TypeSpecifierContext::createNull();
86+
$context->false();
87+
PHP
88+
,
89+
];
90+
91+
yield 'It skips null()' => [
92+
<<<'PHP'
93+
<?php
94+
$context = TypeSpecifierContext::createNull();
95+
$context->null();
96+
PHP
97+
,
98+
];
99+
}
100+
101+
protected function getTestedMutatorClassName(): string
102+
{
103+
return TrueTruthyFalseFalseyTypeSpecifierContextMutator::class;
104+
}
105+
106+
}

tests/phpt/infection-config-default.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ echo shell_exec($bin);
1919
},
2020
"mutators": {
2121
"@default": false,
22+
"PHPStan\\Infection\\IsSuperTypeOfCalleeAndArgumentMutator": true,
2223
"PHPStan\\Infection\\LooseBooleanMutator": true,
2324
"PHPStan\\Infection\\TrinaryLogicMutator": true,
24-
"PHPStan\\Infection\\IsSuperTypeOfCalleeAndArgumentMutator": true
25+
"PHPStan\\Infection\\TrueTruthyFalseFalseyTypeSpecifierContextMutator": true
2526
},
2627
"bootstrap": "build-infection\/vendor\/autoload.php"
2728
}

tests/phpt/infection-config.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ echo shell_exec($bin." --source-directory='more/files/' --timeout=180 --mutator-
2020
},
2121
"mutators": {
2222
"@default": false,
23+
"PHPStan\\Infection\\IsSuperTypeOfCalleeAndArgumentMutator": true,
2324
"PHPStan\\Infection\\LooseBooleanMutator": true,
2425
"PHPStan\\Infection\\TrinaryLogicMutator": true,
25-
"PHPStan\\Infection\\IsSuperTypeOfCalleeAndArgumentMutator": true,
26+
"PHPStan\\Infection\\TrueTruthyFalseFalseyTypeSpecifierContextMutator": true,
2627
"My\\Class": true
2728
},
2829
"bootstrap": "build-infection\/vendor\/autoload.php"

0 commit comments

Comments
 (0)