Passed
Push — master ( 17dafe...3e29f4 )
by Gytis
02:42 queued 11s
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\TypeComparator;
7
use Gskema\TypeSniff\Core\Type\TypeHelper;
8
use PHP_CodeSniffer\Files\File;
9
use Gskema\TypeSniff\Core\CodeElement\Element\AbstractFqcnPropElement;
10
use Gskema\TypeSniff\Core\CodeElement\Element\ClassPropElement;
11
use Gskema\TypeSniff\Core\CodeElement\Element\CodeElementInterface;
12
use Gskema\TypeSniff\Core\CodeElement\Element\TraitPropElement;
13
use Gskema\TypeSniff\Core\DocBlock\Tag\VarTag;
14
use Gskema\TypeSniff\Core\DocBlock\UndefinedDocBlock;
15
use Gskema\TypeSniff\Core\Type\Common\ArrayType;
16
use Gskema\TypeSniff\Core\Type\Common\UndefinedType;
17
18
class FqcnPropSniff implements CodeElementSniffInterface
19
{
20
    /**
21
     * @inheritDoc
22
     */
23 6
    public function configure(array $config): void
24
    {
25
        // nothing to do
26 6
    }
27
28
    /**
29
     * @inheritDoc
30
     */
31 6
    public function register(): array
32
    {
33
        return [
34 6
            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 3
        $docBlock = $prop->getDocBlock();
46 3
        $defValueType = $prop->getDefaultValueType();
0 ignored issues
show
Bug introduced by
The method getDefaultValueType() does not exist on Gskema\TypeSniff\Core\Co...nt\CodeElementInterface. It seems like you code against a sub-type of Gskema\TypeSniff\Core\Co...nt\CodeElementInterface such as Gskema\TypeSniff\Core\Co...AbstractFqcnPropElement. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
        /** @scrutinizer ignore-call */ 
47
        $defValueType = $prop->getDefaultValueType();
Loading history...
47
48
        /** @var VarTag|null $varTag */
49 3
        $varTag = $docBlock->getTagsByName('var')[0] ?? null;
50 3
        $docType = $varTag ? $varTag->getType() : null;
51 3
        $docTypeLine = $varTag ? $varTag->getLine() : $prop->getLine();
52 3
        $fnTypeLine = $prop->getLine();
53
54 3
        $warnings = [];
55 3
        if ($docBlock instanceof UndefinedDocBlock) {
56 3
            $warnings[$fnTypeLine][] = 'Add PHPDoc for :subject:';
57 1
        } elseif (null === $varTag) {
58 1
            $warnings[$docTypeLine][] = 'Add @var tag for :subject:';
59 1
        } elseif ($docType instanceof UndefinedType) {
60 1
            $warnings[$docTypeLine][] = 'Add type hint to @var tag for :subject:';
61 1
        } elseif (TypeHelper::containsType($docType, ArrayType::class)) {
62 1
            $warnings[$docTypeLine][] = 'Replace array type with typed array type in PHPDoc for :subject:. Use mixed[] for generic arrays. Correct array depth must be specified.';
63 1
        } elseif (is_a($defValueType, ArrayType::class)
64 1
            && !TypeHelper::containsType($docType, TypedArrayType::class)
65
        ) {
66 1
            $warnings[$docTypeLine][] = 'Add PHPDoc with typed array type hint for :subject:. Use mixed[] for generic arrays. Correct array depth must be specified.';
67 1
        } elseif ($fakeType = TypeHelper::getFakeTypedArrayType($docType)) {
68 1
            $warnings[$docTypeLine][] = sprintf(
69 1
                'Use a more specific type in typed array hint "%s" for :subject:. Correct array depth must be specified.',
70 1
                $fakeType->toString()
71
            );
72
        }
73
74 3
        if ($redundantTypes = TypeComparator::getRedundantDocTypes($docType)) {
75 1
            $warnings[$docTypeLine][] = sprintf('Remove redundant :subject: type hints "%s"', TypeHelper::listRawTypes($redundantTypes));
76
        }
77
78 3
        if ($varTag && null !== $varTag->getParamName()) {
79 1
            $warnings[$docTypeLine][] = 'Remove property name $'.$varTag->getParamName().' from @var tag';
80
        }
81
82 3
        if ($docType && $defValueType) {
83
            // $wrongTypes are intentionally ignored, props are dynamic
84 1
            [, $missingDocTypes] = TypeComparator::compare($docType, new UndefinedType(), $defValueType);
85
86 1
            if ($missingDocTypes) {
87 1
                $warnings[$docTypeLine][] = sprintf(
88 1
                    'Missing "%s" %s in :subject: type hint',
89 1
                    TypeHelper::listRawTypes($missingDocTypes),
90 1
                    isset($missingDocTypes[1]) ? 'types' : 'type'
91
                );
92
            }
93
        }
94
95 3
        $subject = 'property $'.$prop->getPropName();
96 3
        foreach ($warnings as $line => $lineWarnings) {
97 3
            foreach ($lineWarnings as $warningTpl) {
98 3
                $warning = str_replace(':subject:', $subject, $warningTpl);
99 3
                $file->addWarningOnLine($warning, $line, 'FqcnPropSniff');
100
            }
101
        }
102 3
    }
103
}
104