Passed
Pull Request — master (#13)
by
unknown
01:50
created

MethodDocSniff   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 265
Duplicated Lines 21.13 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 60.71%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 32
c 1
b 0
f 0
lcom 0
cbo 2
dl 56
loc 265
ccs 51
cts 84
cp 0.6071
rs 9.6

2 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 4 1
F process() 56 130 31

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
6
namespace BestIt\Sniffs\Commenting;
7
8
use PHP_CodeSniffer_File;
9
use PHP_CodeSniffer_Sniff;
10
11
/**
12
 * This Sniff checks the method phpdoc
13
 *
14
 * It is a modified version of the Generic DocCommentSniff adjusted for the bestit codestyle
15
 *
16
 * @package BestIt\Sniffs\Commenting
17
 *
18
 * @author Nils Hardeweg <[email protected]>
19
 */
20
class MethodDocSniff implements PHP_CodeSniffer_Sniff
21
{
22
    #region constants
23
    /**
24
     * Code for an empty doc block
25
     *
26
     * @var string
27
     */
28
    const CODE_EMPTY = 'Empty';
29
30
    /**
31
     * Message for an empty doc block
32
     *
33
     * @var string
34
     */
35
    const MESSAGE_DOC_EMPTY = 'Doc comment is empty';
36
37
    /**
38
     * Code for a Spacing Error after the Summary
39
     *
40
     * @var string
41
     */
42
    const CODE_SPACING_AFTER = 'SpacingAfter';
43
44
    /**
45
     * Code for missing spacing between descriptions
46
     *
47
     * @var string
48
     */
49
    const CODE_SPACING_BETWEEN = 'SpacingBetween';
50
51
    /**
52
     * Message for missing spacing between descriptions
53
     *
54
     * @var string
55
     */
56
    const MESSAGE_SPACING_BETWEEN = 'There must be exactly one blank line between descriptions in a doc comment';
57
58
    /**
59
     * Code for missing spacing before the tags
60
     *
61
     * @var string
62
     */
63
    const CODE_SPACING_BEFORE_TAGS = 'SpacingBeforeTags';
64
65
    /**
66
     * Message for missing spacing before the tags
67
     *
68
     * @var string
69
     */
70
    const MESSAGE_SPACING_BEFORE_TAGS = 'There must be exactly one blank line before the tags in a doc comment';
71
72
    /**
73
     * Code for missing short description (Summary)
74
     *
75
     * @var string
76
     */
77
    const CODE_MISSING_SHORT = 'MissingShort';
78
79
    /**
80
     * Message for missing short description (Summary)
81
     *
82
     * @var string
83
     */
84
    const MESSAGE_MISSING_SHORT = 'Missing short description in doc comment';
85
86
    /**
87
     * Code for not capitalized short description
88
     *
89
     * @var string
90
     */
91
    const CODE_SHORT_NOT_CAPITAL = 'ShortNotCapital';
92
93
    /**
94
     * Message for not capitalized short description
95
     *
96
     * @var string
97
     */
98
    const MESSAGE_SHORT_NOT_CAPITAL = 'Doc comment short description must start with a capital letter';
99
100
    /**
101
     * Code for not Capitalized long description
102
     *
103
     * @var string
104
     */
105
    const CODE_LONG_NOT_CAPITAL = 'LongNotCapital';
106
107
    /**
108
     * Message for not Capitalized long description
109
     *
110
     * @var string
111
     */
112
    const MESSAGE_LONG_NOT_CAPITAL = 'Doc comment long description must start with a capital letter';
113
114
    /**
115
     * Code for empty lines before the short description
116
     *
117
     * @var string
118
     */
119
    const CODE_SPACING_BEFORE_SHORT = 'SpacingBeforeShort';
120
121
    /**
122
     * Message for empty lines before the short description
123
     *
124
     * @var string
125
     */
126
    const MESSAGE_CODE_SPACING_BEFORE = 'Doc comment short description must be on the first line';
127
    #endregion
128
129
    /**
130
     * A list of tokenizers this sniff supports.
131
     *
132
     * @var array
133
     */
134
    public $supportedTokenizers = ['PHP', 'JS'];
135
136
    /**
137
     * Returns an array of tokens this test wants to listen for.
138
     *
139
     * @return array
140
     */
141 6
    public function register()
142
    {
143 6
        return [T_DOC_COMMENT_OPEN_TAG];
144
    }
145
146
    /**
147
     * Processes this test, when one of its tokens is encountered.
148
     *
149
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
150
     * @param int $stackPtr The position of the current token in the stack passed in $tokens.
151
     *
152
     * @return void
153
     */
154 6
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
155
    {
156 6
        $tokens = $phpcsFile->getTokens();
157 6
        $commentStart = $stackPtr;
158 6
        $commentEnd = $tokens[$stackPtr]['comment_closer'];
159
160 6
        $empty = [T_DOC_COMMENT_WHITESPACE, T_DOC_COMMENT_STAR];
161
162 6
        $short = $phpcsFile->findNext($empty, $stackPtr + 1, $commentEnd, true);
163 6
        if ($short === false) {
164
            // No content at all.
165 1
            $error = self::MESSAGE_DOC_EMPTY;
166 1
            $phpcsFile->addError($error, $stackPtr, self::CODE_EMPTY);
167 1
            return;
168
        }
169
170
        // The last line of the comment should just be the */ code.
171 5
        $prev = $phpcsFile->findPrevious($empty, $commentEnd - 1, $stackPtr, true);
172
173
        // Check for additional blank lines at the end of the comment.
174 5
        if ($tokens[$prev]['line'] < ($tokens[$commentEnd]['line'] - 1)) {
175
            $error = self::MESSAGE_SPACING_AFTER;
176
            $fix = $phpcsFile->addFixableError($error, $commentEnd, self::CODE_SPACING_AFTER);
177
            if ($fix) {
178
                $phpcsFile->fixer->beginChangeset();
179 View Code Duplication
                for ($i = ($prev + 1); $i < $commentEnd; $i++) {
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...
180
                    if ($tokens[$i + 1]['line'] === $tokens[$commentEnd]['line']) {
181
                        break;
182
                    }
183
                    $phpcsFile->fixer->replaceToken($i, '');
184
                }
185
                $phpcsFile->fixer->endChangeset();
186
            }
187
        }
188
189
        // Check for a comment description.
190 5
        if ($tokens[$short]['code'] !== T_DOC_COMMENT_STRING && $tokens[$short]['content'] !== '@inheritdoc') {
191 1
            $error = self::MESSAGE_MISSING_SHORT;
192 1
            $phpcsFile->addError($error, $stackPtr, self::CODE_MISSING_SHORT);
193 1
            return;
194
        }
195
196
        // No extra newline before short description.
197 4 View Code Duplication
        if ($tokens[$short]['line'] !== ($tokens[$stackPtr]['line'] + 1)) {
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...
198 1
            $error = self::MESSAGE_CODE_SPACING_BEFORE;
199 1
            $fix = $phpcsFile->addFixableError($error, $short, self::CODE_SPACING_BEFORE_SHORT);
200 1
            if ($fix === true) {
201
                $phpcsFile->fixer->beginChangeset();
202
                for ($i = $stackPtr; $i < $short; $i++) {
203
                    if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) {
204
                        continue;
205
                    } elseif ($tokens[$i]['line'] === $tokens[$short]['line']) {
206
                        break;
207
                    }
208
                    $phpcsFile->fixer->replaceToken($i, '');
209
                }
210
                $phpcsFile->fixer->endChangeset();
211
            }
212
        }
213
214 4
        $shortContent = $tokens[$short]['content'];
215 4
        $shortEnd = $short;
216
217 4
        if (preg_match('/^\p{Ll}/u', $shortContent) === 1) {
218 1
            $error = self::MESSAGE_SHORT_NOT_CAPITAL;
219 1
            $phpcsFile->addError($error, $short, self::CODE_SHORT_NOT_CAPITAL);
220
        }
221
222 4
        $long = $phpcsFile->findNext($empty, $shortEnd + 1, $commentEnd - 1, true);
223 4
        if ($long !== false && $tokens[$long]['code'] === T_DOC_COMMENT_STRING) {
224 2 View Code Duplication
            if (preg_match('/^\p{Ll}/u', $tokens[$long]['content']) === 1) {
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...
225 1
                $error = self::MESSAGE_LONG_NOT_CAPITAL;
226 1
                $phpcsFile->addError($error, $long, self::CODE_LONG_NOT_CAPITAL);
227
            }
228
        }
229
230 4
        $long = $phpcsFile->findNext($empty, $shortEnd + 1, $commentEnd - 1, true);
231 4
        if ($long !== false && $tokens[$long]['code'] === T_DOC_COMMENT_STRING) {
232 2 View Code Duplication
            if ($tokens[$long]['line'] !== ($tokens[$shortEnd]['line'] + 2)) {
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...
233 1
                $error = self::MESSAGE_SPACING_BETWEEN;
234 1
                $fix   = $phpcsFile->addFixableError($error, $long, self::CODE_SPACING_BETWEEN);
235 1
                if ($fix === true) {
236
                    $phpcsFile->fixer->beginChangeset();
237
                    for ($i = ($shortEnd + 1); $i < $long; $i++) {
238
                        if ($tokens[$i]['line'] === $tokens[$shortEnd]['line']) {
239
                            continue;
240
                        } elseif ($tokens[$i]['line'] === ($tokens[$long]['line'] - 1)) {
241
                            break;
242
                        }
243
244
                        $phpcsFile->fixer->replaceToken($i, '');
245
                    }
246
247
                    $phpcsFile->fixer->endChangeset();
248
                }
249
            }
250
251 2 View Code Duplication
            if (preg_match('/^\p{Ll}/u', $tokens[$long]['content']) === 1) {
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...
252 1
                $error = self::MESSAGE_LONG_NOT_CAPITAL;
253 1
                $phpcsFile->addError($error, $long, self::CODE_LONG_NOT_CAPITAL);
254
            }
255
        }
256
257 4
        if (empty($tokens[$commentStart]['comment_tags']) === true) {
258
            // No tags in the comment.
259 1
            return;
260
        }
261
262 4
        $firstTag = $tokens[$commentStart]['comment_tags'][0];
263 4
        $prev = $phpcsFile->findPrevious($empty, $firstTag - 1, $stackPtr, true);
264 4
        if ($tokens[$firstTag]['line'] !== ($tokens[$prev]['line'] + 2)
265 4
            && $tokens[$short]['content'] !== '@inheritdoc'
266
        ) {
267 1
            $error = self::MESSAGE_SPACING_BEFORE_TAGS;
268 1
            $fix = $phpcsFile->addFixableError($error, $firstTag, self::CODE_SPACING_BEFORE_TAGS);
269 1
            if ($fix === true) {
270
                $phpcsFile->fixer->beginChangeset();
271 View Code Duplication
                for ($i = ($prev + 1); $i < $firstTag; $i++) {
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...
272
                    if ($tokens[$i]['line'] === $tokens[$firstTag]['line']) {
273
                        break;
274
                    }
275
                    $phpcsFile->fixer->replaceToken($i, '');
276
                }
277
278
                $indent = str_repeat(' ', $tokens[$stackPtr]['column']);
279
                $phpcsFile->fixer->addContent($prev, $phpcsFile->eolChar . $indent . '*' . $phpcsFile->eolChar);
280
                $phpcsFile->fixer->endChangeset();
281
            }
282
        }
283 4
    }
284
}
285