Completed
Pull Request — master (#19)
by
unknown
08:16
created

GeneralDocSniff   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 330
Duplicated Lines 14.24 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 2
dl 47
loc 330
ccs 98
cts 98
cp 1
rs 9.3999
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 6 1
A process() 0 10 1
C checkEmptyLineBeforeComment() 29 51 10
A checkCommentTagsSpacing() 0 17 3
B checkCommentTagSpacing() 0 22 5
A checkCommentTagStringSpacing() 18 18 3
A fixCommentTagStringSpacing() 0 10 1
A fixCommentTagSpacing() 0 4 1
A fixMuchLinesBeforeComment() 0 14 4
A fixNoLineBeforeComment() 0 12 2
A checkCommentTagWhiteSpacing() 0 12 2

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
namespace BestIt\Sniffs\Commenting;
4
5
use PHP_CodeSniffer_File;
6
use PHP_CodeSniffer_Sniff;
7
8
/**
9
 * Class GeneralDocSniff
10
 *
11
 * @package BestIt\Sniffs\Commenting
12
 * @author Nick Lubisch <[email protected]>
13
 */
14
class GeneralDocSniff implements PHP_CodeSniffer_Sniff
15
{
16
    /**
17
     * Code that there is no line before the comment.
18
     *
19
     * @var string
20
     */
21
    const CODE_NO_LINE_BEFORE_COMMENT = 'NoLineBeforeComment';
22
23
    /**
24
     * Message that there is no line before the comment.
25
     *
26
     * @var string
27
     */
28
    const MESSAGE_NO_LINE_BEFORE_COMMENT = 'There is no line before the comment.';
29
30
    /**
31
     * Code that are too much lines before comment.
32
     *
33
     * @var string
34
     */
35
    const CODE_MUCH_LINES_BEFORE_COMMENT = 'MuchLinesBeforeComment';
36
37
    /**
38
     * Message that are too much lines before comment.
39
     *
40
     * @var string
41
     */
42
    const MESSAGE_MUCH_LINES_BEFORE_COMMENT = 'There are more than one lines before the comment.';
43
44
    /**
45
     * Code that are too much spaces between comment tag fragments.
46
     *
47
     * @var string
48
     */
49
    const CODE_WRONG_COMMENT_TAG_SPACING = 'WrongCommentTagSpacing';
50
    
51
    /**
52
     * Message that are too much spaces between comment tag fragments.
53
     *
54
     * @var string
55
     */
56
    const MESSAGE_WRONG_COMMENT_TAG_SPACING = 'There must only be 1 space between comment tag fragments.';
57
58
    /**
59
     * The PHP_CodeSniffer file where the token was found.
60
     *
61
     * @var PHP_CodeSniffer_File CodeSniffer file.
62
     */
63
    private $phpcsFile;
64
65
    /**
66
     * The cs file token stack.
67
     *
68
     * @var array
69
     */
70
    private $tokens;
71
72
    /**
73
     * Pointer of the comment start token.
74
     *
75
     * @var int
76
     */
77
    private $commentStartPtr;
78
79
    /**
80
     * Token of the comment start
81
     *
82
     * @var array
83
     */
84
    private $commentStartToken;
85
86
    /**
87
     * Registers the tokens that this sniff wants to listen for.
88
     *
89
     * @return int[] List of tokens to listen for
90
     */
91 4
    public function register()
92
    {
93
        return [
94 4
            T_DOC_COMMENT_OPEN_TAG
95
        ];
96
    }
97
98
    /**
99
     * Called when one of the token types that this sniff is listening for is found.
100
     *
101
     * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where the token was found.
102
     * @param int $commentStartPtr The position in the PHP_CodeSniffer file's token stack where the token was found.
103
     *
104
     * @return void|int Optionally returns a stack pointer.
105
     */
106 4
    public function process(PHP_CodeSniffer_File $phpcsFile, $commentStartPtr)
107
    {
108 4
        $this->phpcsFile = $phpcsFile;
109 4
        $this->tokens = $phpcsFile->getTokens();
110 4
        $this->commentStartPtr = $commentStartPtr;
111 4
        $this->commentStartToken = $this->tokens[$commentStartPtr];
112
113 4
        $this->checkEmptyLineBeforeComment();
114 4
        $this->checkCommentTagsSpacing();
115 4
    }
116
117
    /**
118
     * Checks if an empty line is before the comment.
119
     *
120
     * @return void
121
     */
122 4
    private function checkEmptyLineBeforeComment()
123
    {
124 4
        $prevNonSpacePtr = $this->phpcsFile->findPrevious(T_WHITESPACE, $this->commentStartPtr - 1, null, true);
125 4
        $prevNonSpaceToken = $this->tokens[$prevNonSpacePtr];
126
127 4
        $hasPrevCurlyBrace = $prevNonSpaceToken['type'] === 'T_OPEN_CURLY_BRACKET';
128
129 4
        $whitespacePtrs = [];
130 4
        for ($i = $prevNonSpacePtr + 1; $i < $this->commentStartPtr; $i++) {
131 4
            $whitespaceToken = $this->tokens[$i];
132
133 4
            if ($whitespaceToken['column'] === 1 && $this->commentStartToken['line'] !== $whitespaceToken['line']) {
134 4
                $whitespacePtrs[] = $i;
135
            }
136
        }
137
138 4
        $expectedLines = $hasPrevCurlyBrace ? 0 : 1;
139
140
        //More than one line before comment
141 4 View Code Duplication
        if (count($whitespacePtrs) > $expectedLines) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
142 1
            $fixMuchLines = $this->phpcsFile->addFixableError(
143 1
                self::MESSAGE_MUCH_LINES_BEFORE_COMMENT,
144 1
                $this->commentStartPtr,
145 1
                self::CODE_MUCH_LINES_BEFORE_COMMENT
146
            );
147
148 1
            if ($fixMuchLines) {
149 1
                $this->fixMuchLinesBeforeComment(
150
                    $whitespacePtrs,
151
                    $hasPrevCurlyBrace
152
                );
153
            }
154
155 1
            return;
156
        }
157
158
        //No line before comment
159 4 View Code Duplication
        if (!$hasPrevCurlyBrace && count($whitespacePtrs) === 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
160 1
            $fixNoLine = $this->phpcsFile->addFixableError(
161 1
                self::MESSAGE_NO_LINE_BEFORE_COMMENT,
162 1
                $this->commentStartPtr,
163 1
                self::CODE_NO_LINE_BEFORE_COMMENT
164
            );
165
166 1
            if ($fixNoLine) {
167 1
                $this->fixNoLineBeforeComment();
168
            }
169
170 1
            return;
171
        }
172 4
    }
173
174
    /**
175
     * Check if there is a comment tag alignment.
176
     *
177
     * @return void
178
     */
179 4
    private function checkCommentTagsSpacing()
180
    {
181 4
        $commentTagPtrs = $this->commentStartToken['comment_tags'];
182
183 4
        if (count($commentTagPtrs) === 0) {
184 3
            return;
185
        }
186
187
        /**
188
         * Array of comment tag pointers.
189
         *
190
         * @var int[] $commentTagPtrs
191
         */
192 4
        foreach ($commentTagPtrs as $commentTagPtr) {
193 4
            $this->checkCommentTagSpacing($commentTagPtr);
194
        }
195 4
    }
196
197
    /**
198
     * Checks a single comment tag alignment.
199
     *
200
     * @param int $commentTagPtr Pointer to comment tag.
201
     *
202
     * @return void
203
     */
204 4
    private function checkCommentTagSpacing($commentTagPtr)
205
    {
206 4
        $lineEndingPtr = $this->phpcsFile->findNext(
207 4
            T_DOC_COMMENT_WHITESPACE,
208
            $commentTagPtr,
209 4
            null,
210 4
            false,
211 4
            $this->phpcsFile->eolChar
212
        );
213
214 4
        for ($tagFragmentPtr = $commentTagPtr; $tagFragmentPtr < $lineEndingPtr; $tagFragmentPtr++) {
215 4
            $tagFragmentToken = $this->tokens[$tagFragmentPtr];
216
217 4
            if ($tagFragmentToken['type'] === 'T_DOC_COMMENT_STRING') {
218 4
                $this->checkCommentTagStringSpacing($tagFragmentPtr);
219
            }
220
221 4
            if ($tagFragmentToken['type'] === 'T_DOC_COMMENT_WHITESPACE' && $tagFragmentToken['length'] > 1) {
222 1
                $this->checkCommentTagWhiteSpacing($tagFragmentPtr);
223
            }
224
        }
225 4
    }
226
227
    /**
228
     * Checks comment tag strings spacing.
229
     *
230
     * @param int $tagStringPtr Pointer to the beginning of a tag
231
     *
232
     * @return void
233
     */
234 4 View Code Duplication
    private function checkCommentTagStringSpacing($tagStringPtr)
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...
235
    {
236 4
        $tagStringToken = $this->tokens[$tagStringPtr];
237
238 4
        $tagStringContent = $tagStringToken['content'];
239
240 4
        if (preg_replace('/\s\s+/', ' ', $tagStringContent) !== $tagStringContent) {
241 1
            $fixStringAlignment = $this->phpcsFile->addFixableError(
242 1
                self::MESSAGE_WRONG_COMMENT_TAG_SPACING,
243
                $tagStringPtr,
244 1
                self::CODE_WRONG_COMMENT_TAG_SPACING
245
            );
246
247 1
            if ($fixStringAlignment) {
248 1
                $this->fixCommentTagStringSpacing($tagStringPtr);
249
            }
250
        }
251 4
    }
252
253
    /**
254
     * Fixes comment tag string spacing.
255
     *
256
     * @param int $tagStringPtr Pointer to the beginning of a tag
257
     *
258
     * @return void
259
     */
260 1
    private function fixCommentTagStringSpacing($tagStringPtr)
261
    {
262 1
        $tagStringToken = $this->tokens[$tagStringPtr];
263 1
        $tagStringContent = $tagStringToken['content'];
264
265 1
        $this->phpcsFile->fixer->replaceToken(
266
            $tagStringPtr,
267 1
            preg_replace('/\s\s+/', ' ', $tagStringContent)
268
        );
269 1
    }
270
271
    /**
272
     * Fixes too long comment tag whitespaces.
273
     *
274
     * @param int $whitespacePtr Pointer to whitespace which is too long.
275
     *
276
     * @return void
277
     */
278 1
    private function fixCommentTagSpacing($whitespacePtr)
279
    {
280 1
        $this->phpcsFile->fixer->replaceToken($whitespacePtr, ' ');
281 1
    }
282
283
    /**
284
     * Fixes lines before comment.
285
     *
286
     * @param int[] $whitespacePtrs Pointers of all whitespaces before comment.
287
     * @param bool $noWhitespace Indicator which controls if there should be minimum one whitespace or not.
288
     *
289
     * @return void
290
     */
291 1
    private function fixMuchLinesBeforeComment(array $whitespacePtrs, $noWhitespace = false)
292
    {
293 1
        $this->phpcsFile->fixer->beginChangeset();
294
295 1
        foreach ($whitespacePtrs as $whitespaceIndex => $whitespacePtr) {
296 1
            if ($whitespaceIndex === 0 && !$noWhitespace) {
297 1
                continue;
298
            }
299
300 1
            $this->phpcsFile->fixer->replaceToken($whitespacePtr, '');
301
        }
302
303 1
        $this->phpcsFile->fixer->endChangeset();
304 1
    }
305
306
    /**
307
     * Fixes no line before comment.
308
     *
309
     * @return void
310
     */
311 1
    private function fixNoLineBeforeComment()
312
    {
313 1
        $this->phpcsFile->fixer->beginChangeset();
314
315 1
        if ($this->commentStartToken['column'] === 1) {
316 1
            $this->phpcsFile->fixer->addNewlineBefore($this->commentStartPtr);
317
        } else {
318 1
            $this->phpcsFile->fixer->addNewlineBefore($this->commentStartPtr - 1);
319
        }
320
321 1
        $this->phpcsFile->fixer->endChangeset();
322 1
    }
323
324
    /**
325
     * Checks given whitespace for proper spacing.
326
     *
327
     * @param int $whitespacePtr Pointer to whitespace to check.
328
     *
329
     * @return void
330
     */
331 1
    private function checkCommentTagWhiteSpacing($whitespacePtr)
332
    {
333 1
        $fixWrongWhitespace = $this->phpcsFile->addFixableError(
334 1
            self::MESSAGE_WRONG_COMMENT_TAG_SPACING,
335
            $whitespacePtr,
336 1
            self::CODE_WRONG_COMMENT_TAG_SPACING
337
        );
338
339 1
        if ($fixWrongWhitespace) {
340 1
            $this->fixCommentTagSpacing($whitespacePtr);
341
        }
342 1
    }
343
}
344