EmptyLinesDocSniff::searchEmptyLines()   B
last analyzed

Complexity

Conditions 6
Paths 4

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 39
rs 8.6737
c 0
b 0
f 0
cc 6
nc 4
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BestIt\Sniffs\Commenting;
6
7
use BestIt\CodeSniffer\Helper\LineHelper;
8
use BestIt\Sniffs\AbstractSniff;
9
use PHP_CodeSniffer\Files\File;
10
11
/**
12
 * Class EmptyLinesDocSniff.
13
 *
14
 * @author Mika Bertels <[email protected]>
15
 * @package BestIt\Sniffs\Commenting
16
 */
17
class EmptyLinesDocSniff extends AbstractSniff
18
{
19
    /**
20
     * There MUST be no redundant lines in your doc block.
21
     *
22
     * @var string
23
     */
24
    public const CODE_EMPTY_LINES_FOUND = 'EmptyLinesFound';
25
26
    /**
27
     * Error message when empty line is detected.
28
     *
29
     * @var string
30
     */
31
    private const ERROR_EMPTY_LINES_FOUND = 'There are too many empty lines in your doc-block!';
32
33
    /**
34
     * Process token within scope.
35
     *
36
     * @return void
37
     */
38
    protected function processToken(): void
39
    {
40
        $this->searchEmptyLines($this->file, $this->stackPos);
41
    }
42
43
    /**
44
     * Registers the tokens that this sniff wants to listen for.
45
     *
46
     * An example return value for a sniff that wants to listen for whitespace
47
     * and any comments would be:
48
     *
49
     * <code>
50
     *    return array(
51
     *            T_WHITESPACE,
52
     *            T_DOC_COMMENT,
53
     *            T_COMMENT,
54
     *           );
55
     * </code>
56
     *
57
     * @see Tokens.php
58
     *
59
     * @return int[]
60
     */
61
    public function register(): array
62
    {
63
        return [T_DOC_COMMENT_OPEN_TAG];
64
    }
65
66
    /**
67
     * Remove unnecessary lines from doc block.
68
     *
69
     * @param File $phpcsFile
70
     * @param array $nextToken
71
     * @param array $currentToken
72
     *
73
     * @return void
74
     */
75
    private function removeUnnecessaryLines(File $phpcsFile, array $nextToken, array $currentToken): void
76
    {
77
        $movement = 2;
78
79
        if ($nextToken['code'] === T_DOC_COMMENT_CLOSE_TAG) {
80
            $movement = 1;
81
        }
82
83
        $phpcsFile->fixer->beginChangeset();
84
85
        (new LineHelper($this->file))->removeLines(
86
            $currentToken['line'] + $movement,
87
            $nextToken['line'] - 1
88
        );
89
90
        $phpcsFile->fixer->endChangeset();
91
    }
92
93
    /**
94
     * Process method for tokens within scope and also outside scope.
95
     *
96
     * @param File $phpcsFile The sniffed file.
97
     * @param int $searchPosition
98
     *
99
     * @return void
100
     */
101
    private function searchEmptyLines(File $phpcsFile, int $searchPosition): void
102
    {
103
        $endOfDoc = $phpcsFile->findEndOfStatement($searchPosition);
104
105
        do {
106
            $currentToken = $phpcsFile->getTokens()[$searchPosition];
107
            $nextTokenPosition = (int) $phpcsFile->findNext(
108
                [T_DOC_COMMENT_WHITESPACE, T_DOC_COMMENT_STAR],
109
                $searchPosition + 1,
110
                $endOfDoc,
111
                true
112
            );
113
114
            if ($hasToken = ($nextTokenPosition > 0)) {
115
                $nextToken = $phpcsFile->getTokens()[$nextTokenPosition];
116
                $hasTooManyLines = ($nextToken['line'] - $currentToken['line']) > 2;
117
118
                if ($hasTooManyLines) {
119
                    $isFixing = $phpcsFile->addFixableError(
120
                        self::ERROR_EMPTY_LINES_FOUND,
121
                        $nextTokenPosition,
122
                        static::CODE_EMPTY_LINES_FOUND
123
                    );
124
125
                    if ($isFixing) {
126
                        $this->removeUnnecessaryLines($phpcsFile, $nextToken, $currentToken);
127
                    }
128
                }
129
130
                $phpcsFile->recordMetric(
131
                    $searchPosition,
132
                    'DocBlock has too many lines',
133
                    $hasTooManyLines ? 'yes' : 'no'
134
                );
135
136
                $searchPosition = $nextTokenPosition;
137
            }
138
        } while ($hasToken);
139
    }
140
}
141