Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 31 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
EmptyTagSniff | |
0.00% |
0 / 31 |
|
0.00% |
0 / 3 |
110 | |
0.00% |
0 / 1 |
register | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
process | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
56 | |||
findContext | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | /** |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or |
7 | * (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | * http://www.gnu.org/copyleft/gpl.html |
18 | * |
19 | * @file |
20 | */ |
21 | |
22 | namespace MediaWiki\Sniffs\Commenting; |
23 | |
24 | use PHP_CodeSniffer\Files\File; |
25 | use PHP_CodeSniffer\Sniffs\Sniff; |
26 | use PHP_CodeSniffer\Util\Tokens; |
27 | |
28 | /** |
29 | * Check for tags with nothing after them |
30 | * |
31 | * @author DannyS712 |
32 | */ |
33 | class EmptyTagSniff implements Sniff { |
34 | |
35 | private const DISALLOWED_EMPTY_TAGS = [ |
36 | // There are separate sniffs that cover @param, @return, @throws, and @covers |
37 | '@access' => '@access', |
38 | '@author' => '@author', |
39 | '@dataProvider' => '@dataProvider', |
40 | '@depends' => '@depends', |
41 | '@group' => '@group', |
42 | '@license' => '@license', |
43 | '@link' => '@link', |
44 | '@see' => '@see', |
45 | '@since' => '@since', |
46 | '@suppress' => '@suppress', |
47 | ]; |
48 | |
49 | /** |
50 | * @inheritDoc |
51 | */ |
52 | public function register(): array { |
53 | return [ T_DOC_COMMENT_OPEN_TAG ]; |
54 | } |
55 | |
56 | /** |
57 | * Processes this test, when one of its tokens is encountered. |
58 | * |
59 | * @param File $phpcsFile The file being scanned. |
60 | * @param int $stackPtr The position of the current token in the stack passed in $tokens. |
61 | * |
62 | * @return void |
63 | */ |
64 | public function process( File $phpcsFile, $stackPtr ) { |
65 | $tokens = $phpcsFile->getTokens(); |
66 | // Delay this because we typically (when there are no errors) don't need it |
67 | $where = null; |
68 | |
69 | foreach ( $tokens[$stackPtr]['comment_tags'] as $tag ) { |
70 | $content = $tokens[$tag]['content']; |
71 | |
72 | if ( !isset( self::DISALLOWED_EMPTY_TAGS[$content] ) || |
73 | !isset( $tokens[$tag + 2] ) || |
74 | // The tag is "not empty" only when it's followed by something on the same line |
75 | ( $tokens[$tag + 2]['code'] === T_DOC_COMMENT_STRING && |
76 | $tokens[$tag + 2]['line'] === $tokens[$tag]['line'] ) |
77 | ) { |
78 | continue; |
79 | } |
80 | |
81 | if ( !$where ) { |
82 | $where = $this->findContext( $phpcsFile, $tokens[$stackPtr]['comment_closer'] + 1 ); |
83 | } |
84 | |
85 | $phpcsFile->addError( |
86 | 'Content missing for %s tag in %s comment', |
87 | $tag, |
88 | ucfirst( $where ) . ucfirst( substr( $content, 1 ) ), |
89 | [ $content, $where ] |
90 | ); |
91 | } |
92 | } |
93 | |
94 | /** |
95 | * @param File $phpcsFile |
96 | * @param int $start |
97 | * |
98 | * @return string Either "property" or "function" |
99 | */ |
100 | private function findContext( File $phpcsFile, int $start ): string { |
101 | $tokens = $phpcsFile->getTokens(); |
102 | $skip = array_merge( |
103 | Tokens::$emptyTokens, |
104 | Tokens::$methodPrefixes, |
105 | [ |
106 | // Skip outdated `var` keywords as well |
107 | T_VAR, |
108 | // Skip type hints, e.g. in `public ?Foo\Bar $var` |
109 | T_STRING, |
110 | T_NS_SEPARATOR, |
111 | T_NULLABLE, |
112 | ] |
113 | ); |
114 | $next = $phpcsFile->findNext( $skip, $start, null, true ); |
115 | return $tokens[$next]['code'] === T_VARIABLE ? 'property' : $tokens[$next]['content']; |
116 | } |
117 | |
118 | } |