Completed
Pull Request — master (#19)
by
unknown
07:50
created

DocSummaryHelper   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 270
Duplicated Lines 14.81 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 3
dl 40
loc 270
ccs 105
cts 105
cp 1
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getCommentSummaryPointer() 0 19 2
A getCommentSummaryToken() 0 4 1
B checkCommentSummary() 0 25 2
A checkSummaryCapitalLetter() 18 18 3
A checkSummaryLineLength() 0 12 2
A checkSummaryIsFirstLine() 0 14 3
A fixNoLineAfterSummary() 14 14 1
A fixSummaryNotFirst() 0 12 1
A fixSummaryUcFirst() 8 8 1
B checkLineAfterSummary() 0 32 4

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace BestIt\CodeSniffer\Helper;
6
7
use BestIt\CodeSniffer\File;
8
use BestIt\Sniffs\Commenting\AbstractDocSniff;
9
10
/**
11
 * Class DocSummaryHelper
12
 *
13
 * @package BestIt\Helper
14
 * @author Nick Lubisch <[email protected]>
15
 */
16
class DocSummaryHelper
17
{
18
    /**
19
     * The php cs file.
20
     *
21
     * @var File
22
     */
23
    private $file;
24
25
    /**
26
     * The doc comment helper.
27
     *
28
     * @var DocHelper
29
     */
30
    private $docHelper;
31
32
    /**
33
     * Token stack of the current file.
34
     *
35
     * @var array
36
     */
37
    private $tokens;
38
39
    /**
40
     * DocSummaryHelper constructor.
41
     *
42
     * @param File $file The php cs file
43
     * @param DocHelper $docHelper The doc comment helper
44
     */
45 121
    public function __construct(File $file, DocHelper $docHelper)
46
    {
47 121
        $this->file = $file;
48 121
        $this->tokens = $file->getTokens();
49 121
        $this->docHelper = $docHelper;
50 121
    }
51
52
    /**
53
     * Returns pointer to the comment summary.
54
     *
55
     * @return int Pointer to the token or -1
56
     */
57 113
    public function getCommentSummaryPointer(): int
58
    {
59 113
        $commentStartPtr = $this->docHelper->getCommentStartPointer();
60 113
        $commentEndPtr = $this->docHelper->getCommentEndPointer();
61
62 113
        $summaryPtr = $this->file->findNext(
63
            [
64 113
                T_DOC_COMMENT_WHITESPACE,
65 113
                T_DOC_COMMENT_STAR
66
            ],
67 113
            $commentStartPtr + 1,
68 113
            $commentEndPtr,
69 113
            true
70
        );
71
72 113
        $summaryToken = $this->tokens[$summaryPtr];
73
74 113
        return $summaryToken['code'] === T_DOC_COMMENT_STRING ? $summaryPtr : -1;
75
    }
76
77
    /**
78
     * Returns comment summary token.
79
     *
80
     * @return array Summary token array
81
     */
82 109
    public function getCommentSummaryToken(): array
83
    {
84 109
        return $this->tokens[$this->getCommentSummaryPointer()];
85
    }
86
87
    /**
88
     * Check class comment summary.
89
     *
90
     * @return void
91
     */
92 113
    public function checkCommentSummary(): void
93
    {
94 113
        $commentEndPtr = $this->docHelper->getCommentEndPointer();
95 113
        $commentStartPtr = $this->docHelper->getCommentStartPointer();
96 113
        $commentStartToken = $this->docHelper->getCommentStartToken();
97
98 113
        $summaryPtr = $this->getCommentSummaryPointer();
99
100 113
        if ($summaryPtr === -1) {
101 4
            $this->file->addError(
102 4
                AbstractDocSniff::MESSAGE_NO_SUMMARY,
103 4
                $commentStartPtr,
104 4
                AbstractDocSniff::CODE_NO_SUMMARY
105
            );
106
107 4
            return;
108
        }
109
110 109
        $summaryToken = $this->tokens[$summaryPtr];
111
112 109
        $this->checkSummaryIsFirstLine($commentStartToken, $summaryToken, $summaryPtr);
113 109
        $this->checkSummaryCapitalLetter($summaryToken, $summaryPtr);
114 109
        $this->checkSummaryLineLength($summaryToken, $summaryPtr);
115 109
        $this->checkLineAfterSummary($summaryPtr, $commentEndPtr);
116 109
    }
117
118
    /**
119
     * Checks that the first character of the summary is upper case.
120
     *
121
     * @param array $summaryToken Token of the summary
122
     * @param int $summaryPtr Pointer to the summary
123
     *
124
     * @return void
125
     */
126 109 View Code Duplication
    private function checkSummaryCapitalLetter(array $summaryToken, int $summaryPtr): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
127
    {
128 109
        $summaryText = $summaryToken['content'];
129
130 109
        if (ucfirst($summaryText) === $summaryText) {
131 105
            return;
132
        }
133
134 8
        $fixUcFirst = $this->file->addFixableError(
135 8
            AbstractDocSniff::MESSAGE_SUMMARY_UC_FIRST,
136 8
            $summaryPtr,
137 8
            AbstractDocSniff::CODE_SUMMARY_UC_FIRST
138
        );
139
140 8
        if ($fixUcFirst) {
141 4
            $this->fixSummaryUcFirst($summaryToken, $summaryPtr);
142
        }
143 8
    }
144
145
    /**
146
     * Checks if the line length of the summary is maximum 120 chars.
147
     *
148
     * @param array $summaryToken Token array of the summary
149
     * @param int $summaryPtr Pointer of the summary
150
     *
151
     * @return void
152
     */
153 109
    private function checkSummaryLineLength(array $summaryToken, int $summaryPtr): void
154
    {
155 109
        $summaryLineLength = $summaryToken['column'] + $summaryToken['length'];
156
157 109
        if ($summaryLineLength > AbstractDocSniff::MAX_LINE_LENGTH) {
158 4
            $this->file->addError(
159 4
                AbstractDocSniff::MESSAGE_SUMMARY_TOO_LONG,
160 4
                $summaryPtr,
161 4
                AbstractDocSniff::CODE_SUMMARY_TOO_LONG
162
            );
163
        }
164 109
    }
165
166
    /**
167
     * Checks if the summary is the first line of the comment.
168
     *
169
     * @param array $commentStartToken Token array of the comment start
170
     * @param array $summaryToken Token of the summary
171
     * @param int $summaryPtr Pointer to the summary
172
     *
173
     * @return void
174
     */
175 109
    private function checkSummaryIsFirstLine(array $commentStartToken, array $summaryToken, int $summaryPtr): void
176
    {
177 109
        if ($summaryToken['line'] !== $commentStartToken['line'] + 1) {
178 8
            $fixSummaryNotFirst = $this->file->addFixableError(
179 8
                AbstractDocSniff::MESSAGE_SUMMARY_NOT_FIRST,
180 8
                $summaryPtr,
181 8
                AbstractDocSniff::CODE_SUMMARY_NOT_FIRST
182
            );
183
184 8
            if ($fixSummaryNotFirst) {
185 4
                $this->fixSummaryNotFirst();
186
            }
187
        }
188 109
    }
189
190
    /**
191
     * Checks the line after the summary.
192
     *
193
     * @param int $summaryPtr Pointer to the summary
194
     * @param int $commentEndPtr Pointer to the end of the doc comment
195
     *
196
     * @return void
197
     */
198 109
    private function checkLineAfterSummary(int $summaryPtr, int $commentEndPtr): void
199
    {
200 109
        $summaryToken = $this->getCommentSummaryToken();
201
202 109
        $nextRelevantPtr = $this->file->findNext(
203
            [
204 109
                T_DOC_COMMENT_WHITESPACE,
205 109
                T_DOC_COMMENT_STAR
206
            ],
207 109
            $summaryPtr + 1,
208 109
            $commentEndPtr,
209 109
            true
210
        );
211
212 109
        if ($nextRelevantPtr === -1) {
213 1
            return;
214
        }
215
216 108
        $nextRelevantToken = $this->tokens[$nextRelevantPtr];
217
218 108
        if (($nextRelevantToken['line'] - $summaryToken['line']) === 1) {
219 8
            $fixLineAfterSummary = $this->file->addFixableError(
220 8
                AbstractDocSniff::MESSAGE_NO_LINE_AFTER_SUMMARY,
221 8
                $summaryPtr,
222 8
                AbstractDocSniff::CODE_NO_LINE_AFTER_SUMMARY
223
            );
224
225 8
            if ($fixLineAfterSummary) {
226 4
                $this->fixNoLineAfterSummary();
227
            }
228
        }
229 108
    }
230
231
    /**
232
     * Fixes no line after summary.
233
     *
234
     * @return void
235
     */
236 4 View Code Duplication
    private function fixNoLineAfterSummary(): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
237
    {
238 4
        $summaryPtr = $this->getCommentSummaryPointer();
239 4
        $summaryToken = $this->getCommentSummaryToken();
240
241 4
        $this->file->getFixer()->beginChangeset();
242
243 4
        $this->file->getFixer()->addContent(
244 4
            $summaryPtr,
245 4
            $this->file->getEolChar() . str_repeat('    ', $summaryToken['level']) . ' *'
246
        );
247
248 4
        $this->file->getFixer()->endChangeset();
249 4
    }
250
251
    /**
252
     * Fixes summary not first statement.
253
     *
254
     * @return void
255
     */
256 4
    private function fixSummaryNotFirst(): void
257
    {
258 4
        $commentStartToken = $this->docHelper->getCommentStartToken();
259 4
        $summaryStartToken = $this->getCommentSummaryToken();
260
261 4
        $startLine = $commentStartToken['line'] + 1;
262 4
        $endLine = $summaryStartToken['line'] - 1;
263
264 4
        $this->file->getFixer()->beginChangeset();
265 4
        $this->file->getFixer()->removeLines($startLine, $endLine);
266 4
        $this->file->getFixer()->endChangeset();
267 4
    }
268
269
    /**
270
     * Fixes the first letter of the summary to be uppercase.
271
     *
272
     * @param array $summaryToken Token array of the summary
273
     * @param int $summaryPtr Pointer to the summary
274
     *
275
     * @return void
276
     */
277 4 View Code Duplication
    private function fixSummaryUcFirst(array $summaryToken, int $summaryPtr): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
278
    {
279 4
        $this->file->getFixer()->beginChangeset();
280
281 4
        $this->file->getFixer()->replaceToken($summaryPtr, ucfirst($summaryToken['content']));
282
283 4
        $this->file->getFixer()->endChangeset();
284 4
    }
285
}
286