Test Failed
Push — main ( dbb295...c6e244 )
by mikhail
03:14
created

MissingDocBlockAnalyzer::analyzeTokens()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 6
nop 2
dl 0
loc 24
ccs 12
cts 12
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SavinMikhail\CommentsDensity\MissingDocblock;
6
7
use SavinMikhail\CommentsDensity\DTO\Input\MissingDocblockConfigDTO;
0 ignored issues
show
Bug introduced by
The type SavinMikhail\CommentsDen...issingDocblockConfigDTO was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use function is_array;
9
10
use const T_CLASS;
11
use const T_CONST;
12
use const T_DOC_COMMENT;
13
use const T_ENUM;
14
use const T_FUNCTION;
15
use const T_INTERFACE;
16
use const T_TRAIT;
17
use const T_VARIABLE;
18
19
final class MissingDocBlockAnalyzer
20
{
21
    private bool $exceedThreshold = false;
22
23
    public function __construct(
24
        private readonly Tokenizer $tokenizer,
0 ignored issues
show
Bug introduced by
The type SavinMikhail\CommentsDen...ssingDocblock\Tokenizer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
        private readonly MissingDocblockConfigDTO $missingDocblockConfigDTO,
26
    ) {
27
    }
28
29
    /**
30
     * Analyzes the tokens of a file for docblocks.
31
     *
32
     * @param array $tokens The tokens to analyze.
33 23
     * @return array The analysis results.
34
     */
35 23
    private function analyzeTokens(array $tokens, string $filename): array
36
    {
37
        $lastDocBlock = null;
38
        $missingDocBlocks = [];
39
        $tokenCount = count($tokens);
40
41
        for ($i = 0; $i < $tokenCount; $i++) {
42
            $token = $tokens[$i];
43 23
44
            if (! is_array($token)) {
45 23
                continue;
46 23
            }
47 23
48
            if ($token[0] === T_DOC_COMMENT) {
49 23
                $lastDocBlock = $token[1];
50 23
            } elseif ($this->isDocBlockRequired($token, $tokens, $i)) {
51
                if (empty($lastDocBlock)) {
52 23
                    $missingDocBlocks[] = $this->createMissingDocBlockStat($token, $filename);
53 23
                }
54
                $lastDocBlock = null;
55
            }
56 23
        }
57 9
58 23
        return $missingDocBlocks;
59 14
    }
60 12
61
    private function shouldAnalyzeToken(array $token): bool
62 14
    {
63
        return match ($token[0]) {
64
            T_CLASS => $this->missingDocblockConfigDTO->class,
65
            T_TRAIT => $this->missingDocblockConfigDTO->trait,
66 23
            T_INTERFACE => $this->missingDocblockConfigDTO->interface,
67
            T_ENUM => $this->missingDocblockConfigDTO->enum,
68
            T_FUNCTION => $this->missingDocblockConfigDTO->function,
69 23
            T_CONST => $this->missingDocblockConfigDTO->constant,
70
            T_VARIABLE => $this->missingDocblockConfigDTO->property,
71 23
            default => false,
72 23
        };
73
    }
74
75 23
    private function isDocBlockRequired(array $token, array $tokens, int $index): bool
76
    {
77 15
        if (!$this->shouldAnalyzeToken($token)) {
78 15
            return false;
79
        }
80 5
81
        if ($this->tokenizer->isClass($token)) {
82
               return ! $this->tokenizer->isAnonymousClass($tokens, $index)
83
                && !$this->tokenizer->isClassNameResolution($tokens, $index);
84 23
        }
85
86 7
        if ($this->tokenizer->isFunction($token)) {
87 7
             return  ! $this->tokenizer->isAnonymousFunction($tokens, $index)
88
                && ! $this->tokenizer->isFunctionImport($tokens, $index);
89 2
        }
90
91
        if ($this->tokenizer->isVariable($token)) {
92
            return $this->tokenizer->isPropertyOrConstant($tokens, $index);
93 22
        }
94 15
95 10
        if ($this->tokenizer->isConst($token)) {
96
            return $this->tokenizer->isPropertyOrConstant($tokens, $index);
97
        }
98
99 14
        return true;
100 1
    }
101 1
102
    private function createMissingDocBlockStat(array $token, string $filename): array
103
    {
104
        return [
105 14
            'type' => 'missingDocblock',
106
            'content' => '',
107
            'file' => $filename,
108 12
            'line' => $token[2]
109
        ];
110 12
    }
111 12
112 12
    public function getMissingDocblocks(array $tokens, string $filename): array
113 12
    {
114 12
        return $this->analyzeTokens($tokens, $filename);
115 12
    }
116
117
    public function getColor(): string
118 23
    {
119
        return 'red';
120 23
    }
121
122
    public function getStatColor(float $count, array $thresholds): string
123
    {
124
        if (! isset($thresholds['missingDocBlock'])) {
125
            return 'white';
126
        }
127
        if ($count <= $thresholds['missingDocBlock']) {
128
            return 'green';
129
        }
130
        $this->exceedThreshold = true;
131
        return 'red';
132
    }
133
134
    public function hasExceededThreshold(): bool
135
    {
136
        return $this->exceedThreshold;
137
    }
138
139
    public function getName(): string
140
    {
141
        return 'missingDocblock';
142
    }
143
}
144