Completed
Push — master ( 57ffc6...e4cea5 )
by Gytis
02:04
created

FqcnPropSniff::containsType()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 2
nc 3
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Gskema\TypeSniff\Sniffs\CodeElement;
4
5
use Gskema\TypeSniff\Core\Type\DocBlock\TypedArrayType;
6
use Gskema\TypeSniff\Core\Type\TypeInterface;
7
use PHP_CodeSniffer\Files\File;
8
use Gskema\TypeSniff\Core\CodeElement\Element\AbstractFqcnPropElement;
9
use Gskema\TypeSniff\Core\CodeElement\Element\ClassPropElement;
10
use Gskema\TypeSniff\Core\CodeElement\Element\CodeElementInterface;
11
use Gskema\TypeSniff\Core\CodeElement\Element\TraitPropElement;
12
use Gskema\TypeSniff\Core\DocBlock\Tag\VarTag;
13
use Gskema\TypeSniff\Core\DocBlock\UndefinedDocBlock;
14
use Gskema\TypeSniff\Core\Type\Common\ArrayType;
15
use Gskema\TypeSniff\Core\Type\Common\UndefinedType;
16
use Gskema\TypeSniff\Core\Type\DocBlock\CompoundType;
17
18
class FqcnPropSniff implements CodeElementSniffInterface
19
{
20
    /**
21
     * @inheritDoc
22
     */
23 4
    public function configure(array $config): void
24
    {
25
        // nothing to do
26 4
    }
27
28
    /**
29
     * @inheritDoc
30
     */
31 4
    public function register(): array
32
    {
33
        return [
34 4
            ClassPropElement::class,
35
            TraitPropElement::class,
36
        ];
37
    }
38
39
    /**
40
     * @inheritDoc
41
     * @param AbstractFqcnPropElement $prop
42
     */
43 3
    public function process(File $file, CodeElementInterface $prop): void
44
    {
45
        // @TODO Infer type from initial value?
46 3
        $docBlock = $prop->getDocBlock();
47
48
        /** @var VarTag|null $varTag */
49 3
        $varTag = $docBlock->getTagsByName('var')[0] ?? null;
50 3
        $docType = $varTag ? $varTag->getType() : null;
51
52 3
        $subject = 'property $'.$prop->getPropName();
53
54 3
        if ($docBlock instanceof UndefinedDocBlock) {
55 3
            $file->addWarningOnLine(
56 3
                'Add PHPDoc for '.$subject,
57 3
                $prop->getLine(),
58 3
                'FqcnPropSniff'
59
            );
60 1
        } elseif (null === $varTag) {
61 1
            $file->addWarningOnLine(
62 1
                'Add @var tag for '.$subject,
63 1
                $prop->getLine(),
64 1
                'FqcnPropSniff'
65
            );
66 1
        } elseif ($docType instanceof UndefinedType) {
67 1
            $file->addWarningOnLine(
68 1
                'Add type hint to @var tag for '.$subject,
69 1
                $prop->getLine(),
70 1
                'FqcnPropSniff'
71
            );
72 1
        } elseif ($this->containsType($docType, ArrayType::class)) {
73 1
            $file->addWarningOnLine(
74 1
                'Replace array type with typed array type in PHPDoc for '.$subject.'. Use mixed[] for generic arrays.',
75 1
                $prop->getLine(),
76 1
                'FqcnPropSniff'
77
            );
78 1
        } elseif (is_a($prop->getDefaultValueType(), ArrayType::class)
79 1
            && !$this->containsType($docType, TypedArrayType::class)
80
        ) {
81 1
            $file->addWarningOnLine(
82 1
                'Add PHPDoc with typed array type hint for '.$subject.'. Use mixed[] for generic arrays.',
83 1
                $prop->getLine(),
84 1
                'FqcnPropSniff'
85
            );
86
        }
87
88 3
        if ($varTag && null !== $varTag->getParamName()) {
89 1
            $file->addWarningOnLine(
90 1
                'Remove property name $'.$varTag->getParamName().' from @var tag',
91 1
                $prop->getLine(),
92 1
                'FqcnPropSniff'
93
            );
94
        }
95 3
    }
96
97 1
    protected function containsType(?TypeInterface $type, string $typeClassName): bool
98
    {
99 1
        return is_a($type, $typeClassName)
100 1
            || ($type instanceof CompoundType && $type->containsType($typeClassName));
101
    }
102
}
103