Completed
Pull Request — master (#44)
by Björn
02:58
created

DocHelper::getBlockEndToken()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
ccs 5
cts 5
cp 1
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BestIt\CodeSniffer\Helper;
6
7
use DomainException;
8
use PHP_CodeSniffer\Files\File;
9
use PHP_CodeSniffer\Util\Tokens;
10
use SlevomatCodingStandard\Helpers\TokenHelper;
11
use function sprintf;
12
use const T_DOC_COMMENT_CLOSE_TAG;
13
14
/**
15
 * Class DocHelper
16
 *
17
 * @author Nick Lubisch <[email protected]>
18
 * @package BestIt\CodeSniffer\Helper
19
 */
20
class DocHelper
21
{
22
    /**
23
     * The position of the end token of the doc block.
24
     *
25
     * @var int|null|bool If false then it will be loaded in the getter.
26
     */
27
    private $blockEndPosition = false;
28
29
    /**
30
     * The php cs file.
31
     *
32
     * @var File
33
     */
34
    private $file;
35
36
    /**
37
     * Position to the token which is to be listened.
38
     *
39
     * @var int
40
     */
41
    private $stackPos;
42
43
    /**
44
     * Token stack of the current file.
45
     *
46 121
     * @var array
47
     */
48 121
    private $tokens;
49 121
50 121
    /**
51 121
     * DocHelper constructor.
52
     *
53
     * @param File $file File object of file which is processed.
54
     * @param int $stackPos Position to the token which is processed.
55
     */
56
    public function __construct(File $file, $stackPos)
57
    {
58
        $this->file = $file;
59
        $this->tokens = $file->getTokens();
60 121
        $this->stackPos = $stackPos;
61
    }
62 121
63 121
    /**
64
     * Returns position to the class comment end.
65 121
     *
66 121
     * @return int|null Position to the class comment end.
67
     */
68 4
    public function getBlockEndPosition(): ?int
69 4
    {
70 4
        if ($this->blockEndPosition === false) {
71 4
            $this->blockEndPosition = $this->loadBlockEndPosition();
72
        }
73
74 4
        return $this->blockEndPosition;
75
    }
76
77 117
    /**
78
     * Returns token data of the evaluated class comment end.
79
     *
80
     * @return array Token data of the comment end.
81
     */
82
    public function getBlockEndToken(): array
83
    {
84
        if (!$this->hasDocBlock()) {
85 117
            throw new DomainException(
86
                sprintf('Missing doc block for position %s of file %s.', $this->stackPos, $this->file->getFilename())
87 117
            );
88 117
        }
89
90 117
        return $this->tokens[$this->getBlockEndPosition()];
91 4
    }
92 4
93 4
    /**
94 4
     * Returns pointer to the class comment start.
95
     *
96
     * @return int Pointer to the class comment start.
97 4
     */
98
    public function getBlockStartPosition(): int
99
    {
100 113
        $commentEndToken = $this->getBlockEndToken();
101
102
        return $commentEndToken['comment_opener'];
103
    }
104
105
    /**
106
     * Returns token data of the evaluated class comment start.
107
     *
108 117
     * @return array Token data of the comment start.
109
     */
110 117
    public function getBlockStartToken(): array
111
    {
112 117
        $commentStartPtr = $this->getBlockStartPosition();
113
114
        return $this->tokens[$commentStartPtr];
115
    }
116
117
    /**
118
     * Returns true if there is a doc block.
119
     *
120 117
     * @return bool
121
     */
122 117
    public function hasDocBlock(): bool
123
    {
124 117
        return $this->getBlockEndPosition() !== null;
125
    }
126
127
    /**
128
     * Returns true if this doc block is a multi line comment.
129
     *
130
     * @return bool
131
     */
132 121
    public function isMultiLine(): bool
133
    {
134 121
        $openingToken = $this->getBlockStartToken();
135 121
        $closingToken = $this->getBlockEndToken();
136 121
137
        return $openingToken['line'] < $closingToken['line'];
138
    }
139 121
140 121
    /**
141 121
     * Returns the position of the token for the doc block end.
142 121
     *
143 121
     * @return int|null
144
     */
145
    private function loadBlockEndPosition(): ?int
146
    {
147
        $endPos = $this->file->findPrevious(
148
            [T_DOC_COMMENT_CLOSE_TAG],
149
            $this->stackPos - 1,
150
            // Search till the next method, property, etc ...
151
            TokenHelper::findPreviousExcluding(
152 121
                $this->file,
153
                TokenHelper::$ineffectiveTokenCodes + Tokens::$methodPrefixes,
154 121
                $this->stackPos - 1
155
            )
156
        );
157
158
        return ((int) $endPos) > 0 ? $endPos : null;
159
    }
160
}
161