Completed
Push — master ( 14c836...906b18 )
by Björn
06:09 queued 03:52
created

DocHelper   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 141
ccs 43
cts 43
cp 1
rs 10
c 0
b 0
f 0
wmc 11
lcom 1
cbo 3
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 function sprintf;
11
use const T_DOC_COMMENT_CLOSE_TAG;
12
13
/**
14
 * Class DocHelper
15
 *
16
 * @author Nick Lubisch <[email protected]>
17
 * @package BestIt\CodeSniffer\Helper
18
 */
19
class DocHelper
20
{
21
    /**
22
     * The position of the end token of the doc block.
23
     *
24
     * @var int|null|bool If false then it will be loaded in the getter.
25
     */
26
    private $blockEndPosition = false;
27
28
    /**
29
     * The php cs file.
30
     *
31
     * @var File
32
     */
33
    private File $file;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
34
35
    /**
36
     * Position to the token which is to be listened.
37
     *
38
     * @var int
39
     */
40
    private int $stackPos;
41
42
    /**
43
     * Token stack of the current file.
44
     *
45
     * @var array
46 121
     */
47
    private array $tokens;
48 121
49 121
    /**
50 121
     * DocHelper constructor.
51 121
     *
52
     * @param File $file File object of file which is processed.
53
     * @param int $stackPos Position to the token which is processed.
54
     */
55
    public function __construct(File $file, int $stackPos)
56
    {
57
        $this->file = $file;
58
        $this->tokens = $file->getTokens();
59
        $this->stackPos = $stackPos;
60 121
    }
61
62 121
    /**
63 121
     * Returns position to the class comment end.
64
     *
65 121
     * @return int|null Position to the class comment end.
66 121
     */
67
    public function getBlockEndPosition(): ?int
68 4
    {
69 4
        if ($this->blockEndPosition === false) {
70 4
            $this->blockEndPosition = $this->loadBlockEndPosition();
71 4
        }
72
73
        return $this->blockEndPosition;
74 4
    }
75
76
    /**
77 117
     * Returns token data of the evaluated class comment end.
78
     *
79
     * @return array Token data of the comment end.
80
     */
81
    public function getBlockEndToken(): array
82
    {
83
        if (!$this->hasDocBlock()) {
84
            throw new DomainException(
85 117
                sprintf('Missing doc block for position %s of file %s.', $this->stackPos, $this->file->getFilename())
86
            );
87 117
        }
88 117
89
        return $this->tokens[$this->getBlockEndPosition()];
90 117
    }
91 4
92 4
    /**
93 4
     * Returns pointer to the class comment start.
94 4
     *
95
     * @return int Pointer to the class comment start.
96
     */
97 4
    public function getBlockStartPosition(): int
98
    {
99
        $commentEndToken = $this->getBlockEndToken();
100 113
101
        return $commentEndToken['comment_opener'];
102
    }
103
104
    /**
105
     * Returns token data of the evaluated class comment start.
106
     *
107
     * @return array Token data of the comment start.
108 117
     */
109
    public function getBlockStartToken(): array
110 117
    {
111
        $commentStartPtr = $this->getBlockStartPosition();
112 117
113
        return $this->tokens[$commentStartPtr];
114
    }
115
116
    /**
117
     * Returns true if there is a doc block.
118
     *
119
     * @return bool
120 117
     */
121
    public function hasDocBlock(): bool
122 117
    {
123
        return $this->getBlockEndPosition() !== null;
124 117
    }
125
126
    /**
127
     * Returns true if this doc block is a multi line comment.
128
     *
129
     * @return bool
130
     */
131
    public function isMultiLine(): bool
132 121
    {
133
        $openingToken = $this->getBlockStartToken();
134 121
        $closingToken = $this->getBlockEndToken();
135 121
136 121
        return $openingToken['line'] < $closingToken['line'];
137
    }
138
139 121
    /**
140 121
     * Returns the position of the token for the doc block end.
141 121
     *
142 121
     * @return int|null
143 121
     */
144
    private function loadBlockEndPosition(): ?int
145
    {
146
        $endPos = $this->file->findPrevious(
147
            [T_DOC_COMMENT_CLOSE_TAG],
148
            $this->stackPos - 1,
149
            // Search till the next method, property, etc ...
150
            TokenHelper::findPreviousExcluding(
151
                $this->file,
152 121
                TokenHelper::$ineffectiveTokenCodes + Tokens::$methodPrefixes,
153
                $this->stackPos - 1
154 121
            )
155
        );
156
157
        return $endPos !== false ? $endPos : null;
158
    }
159
}
160