ImportsReplacement::__construct()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 11
rs 10
c 0
b 0
f 0
cc 4
nc 3
nop 2
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\PhpGenerics\Generator\Visitor;
4
5
use PhpParser\Node;
6
use PhpParser\Node\Name;
7
use PhpParser\Node\Stmt\Namespace_;
8
use PhpParser\Node\Stmt\Use_;
9
use PhpParser\Node\Stmt\UseUse;
10
use PhpParser\NodeTraverser;
11
use PhpParser\NodeVisitorAbstract;
12
use Stratadox\PhpGenerics\Annotation\Generic;
13
use Stratadox\PhpGenerics\Generator\Type\TypeArguments;
14
use function in_array;
15
use function strpos;
16
17
final class ImportsReplacement extends NodeVisitorAbstract
18
{
19
    /** @var string[] */
20
    private $newImports;
21
22
    public function __construct(
23
        string $genericBaseClass,
24
        TypeArguments $typeArguments
25
    ) {
26
        $this->newImports = [$genericBaseClass];
27
        foreach ($typeArguments as $argument) {
28
            if (
29
                $argument->requiresImport() &&
30
                !in_array($argument->fullName(), $this->newImports)
31
            ) {
32
                $this->newImports[] = $argument->fullName();
33
            }
34
        }
35
    }
36
37
    public function leaveNode(Node $node)
38
    {
39
        if ($node instanceof Namespace_) {
40
            foreach ($this->newImports as $import) {
41
                $this->addImportTo($node, $import);
42
            }
43
        } elseif ($node instanceof Use_) {
44
            if ($this->shouldRemoveImport($node->uses[0]->name->toString())) {
45
                return NodeTraverser::REMOVE_NODE;
46
            }
47
        }
48
        return null;
49
    }
50
51
    private function addImportTo(Node $namespace, string $import): void
52
    {
53
        $position = 0;
54
        foreach ($namespace->stmts as $stmt) {
0 ignored issues
show
Bug introduced by
Accessing stmts on the interface PhpParser\Node suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
55
            if ($stmt instanceof Use_ && $stmt->uses[0]->name->toString() < $import) {
56
                $position++;
57
            }
58
        }
59
        $namespace->stmts = array_merge(
60
            array_slice($namespace->stmts, 0, $position),
61
            [new Use_([new UseUse(new Name($import))])],
62
            array_slice($namespace->stmts, $position)
63
        );
64
    }
65
66
    private function shouldRemoveImport(string $use): bool
67
    {
68
        return strpos($use, 'Stratadox\\PhpGenerics\\Generic\\') === 0
69
            || $use === Generic::class;
70
    }
71
}
72