Skip to content

Commit 971b8d9

Browse files
author
Vincent Langlet
committed
✨ Add check for var doc and spacing
1 parent 7d29acd commit 971b8d9

File tree

4 files changed

+497
-0
lines changed

4 files changed

+497
-0
lines changed
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
<?php
2+
3+
if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) {
4+
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found');
5+
}
6+
7+
/**
8+
* Parses and verifies the variable doc comment.
9+
*/
10+
class Symfony3Custom_Sniffs_Commenting_VariableCommentSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff
11+
{
12+
/**
13+
* Called to process class member vars.
14+
*
15+
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
16+
* @param int $stackPtr The position of the current token
17+
* in the stack passed in $tokens.
18+
*
19+
* @return void
20+
*/
21+
public function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
22+
{
23+
$tokens = $phpcsFile->getTokens();
24+
$ignore = array(
25+
T_PUBLIC,
26+
T_PRIVATE,
27+
T_PROTECTED,
28+
T_VAR,
29+
T_STATIC,
30+
T_WHITESPACE,
31+
);
32+
33+
$commentEnd = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true);
34+
if ($commentEnd === false
35+
|| ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG
36+
&& $tokens[$commentEnd]['code'] !== T_COMMENT)
37+
) {
38+
$phpcsFile->addError('Missing member variable doc comment', $stackPtr, 'Missing');
39+
40+
return;
41+
}
42+
43+
if ($tokens[$commentEnd]['code'] === T_COMMENT) {
44+
$phpcsFile->addError(
45+
'You must use "/**" style comments for a member variable comment',
46+
$stackPtr,
47+
'WrongStyle'
48+
);
49+
50+
return;
51+
}
52+
53+
$commentStart = $tokens[$commentEnd]['comment_opener'];
54+
55+
$foundVar = null;
56+
foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
57+
if ($tokens[$tag]['content'] === '@var') {
58+
if ($foundVar !== null) {
59+
$error = 'Only one @var tag is allowed in a member variable comment';
60+
$phpcsFile->addError($error, $tag, 'DuplicateVar');
61+
} else {
62+
$foundVar = $tag;
63+
}
64+
} elseif ($tokens[$tag]['content'] === '@see') {
65+
// Make sure the tag isn't empty.
66+
$string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd);
67+
if ($string === false || $tokens[$string]['line'] !== $tokens[$tag]['line']) {
68+
$error = 'Content missing for @see tag in member variable comment';
69+
$phpcsFile->addError($error, $tag, 'EmptySees');
70+
}
71+
} else {
72+
$error = '%s tag is not allowed in member variable comment';
73+
$data = array($tokens[$tag]['content']);
74+
$phpcsFile->addWarning($error, $tag, 'TagNotAllowed', $data);
75+
}//end if
76+
}//end foreach
77+
78+
// The @var tag is the only one we require.
79+
if ($foundVar === null) {
80+
$error = 'Missing @var tag in member variable comment';
81+
$phpcsFile->addError($error, $commentEnd, 'MissingVar');
82+
83+
return;
84+
}
85+
86+
$firstTag = $tokens[$commentStart]['comment_tags'][0];
87+
if ($foundVar !== null && $tokens[$firstTag]['content'] !== '@var') {
88+
$error = 'The @var tag must be the first tag in a member variable comment';
89+
$phpcsFile->addError($error, $foundVar, 'VarOrder');
90+
}
91+
92+
// Make sure the tag isn't empty and has the correct padding.
93+
$string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $foundVar, $commentEnd);
94+
if ($string === false || $tokens[$string]['line'] !== $tokens[$foundVar]['line']) {
95+
$error = 'Content missing for @var tag in member variable comment';
96+
$phpcsFile->addError($error, $foundVar, 'EmptyVar');
97+
98+
return;
99+
}
100+
101+
$this->processWhitespace($phpcsFile, $commentStart);
102+
}
103+
104+
/**
105+
* @param PHP_CodeSniffer_File $phpcsFile
106+
* @param int $commentStart
107+
*/
108+
protected function processWhitespace(
109+
PHP_CodeSniffer_File $phpcsFile,
110+
$commentStart
111+
) {
112+
$tokens = $phpcsFile->getTokens();
113+
$before = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true);
114+
115+
$startLine = $tokens[$commentStart]['line'];
116+
$prevLine = $tokens[$before]['line'];
117+
118+
$found = $startLine - $prevLine - 1;
119+
120+
// Skip for class opening
121+
if ($found < 1 && !($found === 0 && $tokens[$before]['type'] === 'T_OPEN_CURLY_BRACKET')) {
122+
if ($found < 0) {
123+
$found = 0;
124+
}
125+
126+
$error = 'Expected 1 blank line before docblock; %s found';
127+
$rule = 'SpacingBeforeDocblock';
128+
129+
$data = array($found);
130+
$fix = $phpcsFile->addFixableError($error, $commentStart, $rule, $data);
131+
132+
if ($fix === true) {
133+
if ($found > 1) {
134+
$phpcsFile->fixer->beginChangeset();
135+
136+
for ($i = ($before + 1); $i < ($commentStart - 1); $i++) {
137+
$phpcsFile->fixer->replaceToken($i, '');
138+
}
139+
140+
$phpcsFile->fixer->endChangeset();
141+
} else {
142+
// Try and maintain indentation.
143+
if ($tokens[($commentStart - 1)]['code'] === T_WHITESPACE) {
144+
$phpcsFile->fixer->addNewlineBefore($commentStart - 1);
145+
} else {
146+
$phpcsFile->fixer->addNewlineBefore($commentStart);
147+
}
148+
}
149+
}
150+
}
151+
}
152+
153+
/**
154+
* Called to process a normal variable.
155+
*
156+
* Not required for this sniff.
157+
*
158+
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found.
159+
* @param int $stackPtr The position where the double quoted
160+
* string was found.
161+
*
162+
* @return void
163+
*/
164+
protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
165+
{
166+
}
167+
168+
/**
169+
* Called to process variables found in double quoted strings.
170+
*
171+
* Not required for this sniff.
172+
*
173+
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found.
174+
* @param int $stackPtr The position where the double quoted
175+
* string was found.
176+
*
177+
* @return void
178+
*/
179+
protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
180+
{
181+
}
182+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
class VariableCommentUnitTest
4+
{
5+
/**
6+
* Short description of the member variable.
7+
*
8+
* Long description of member variable. Can span over multiple
9+
* lines and can have multiple paragraphs.
10+
*
11+
* @var array
12+
* @see otherFunctions()
13+
* @see anotherFunctions()
14+
*/
15+
public $variableName = array();
16+
17+
18+
// Not "/**" style comment.
19+
//
20+
// @var string
21+
private $_incorrectCommentStyle = '';
22+
23+
24+
protected $noComment = '';
25+
26+
27+
/**
28+
*
29+
* Extra newline before short comment.
30+
*
31+
* @var string
32+
*/
33+
public $extraNewlineBeforeShort = '';
34+
35+
36+
/**
37+
* Extra newline between short description.
38+
*
39+
*
40+
*
41+
* Long description.
42+
*
43+
* @var string
44+
*/
45+
private $_extraNewlineBetween = '';
46+
47+
48+
/**
49+
* Extra newline before tags.
50+
*
51+
* Long description,
52+
* with two var tags.
53+
*
54+
*
55+
* @var string
56+
* @var array
57+
*/
58+
protected $extraNewlineBeforeTags = '';
59+
60+
61+
/**
62+
* No newline before tags, var tag missing.
63+
* @see otherFunctions()
64+
*/
65+
protected $noNewlineBeforeTags = '';
66+
67+
68+
/**
69+
* Short comment that spans multiple
70+
* lines and does not end with a full stop
71+
* also var type is missing
72+
*
73+
* @var
74+
*/
75+
public $singleLineFullStopShortComment = '';
76+
77+
78+
/**
79+
* Incorrect tag indentation.
80+
*
81+
* @var string
82+
* @see otherFunctions()
83+
* @see anotherFunctions()
84+
* @see
85+
*/
86+
public $singleLineFullStopShortComment = '';
87+
88+
89+
/**
90+
* Unknown summary tag
91+
*
92+
* @var string
93+
* @summary unknown tag
94+
*/
95+
public $missingSinceTag = '';
96+
97+
98+
/**
99+
* T_VARIABLE check, without scope.
100+
*
101+
* @var string
102+
*/
103+
$variableCheck = '';
104+
105+
/**
106+
* T_VARIABLE check, var in string and in function.
107+
*
108+
* @param integer $var1 First variable.
109+
* @param integer $var2 Second variable.
110+
*
111+
* @return integer
112+
*/
113+
protected function checkVariable($var1, $var2)
114+
{
115+
$var4 = 'A normal variable';
116+
$var5 = PHP_CodeSniffer_Tokens::$operators;
117+
echo "Printing $var1 $var2 and unknown $var3 in a double quoted string\n";
118+
foreach (self::$_array as $index => $content) {
119+
echo $content;
120+
}
121+
122+
return $var1;
123+
124+
}
125+
126+
127+
/**
128+
*
129+
*
130+
*/
131+
$emptyVarDoc = '';
132+
/**
133+
* @var int
134+
*/
135+
private $noNewLine;
136+
}

0 commit comments

Comments
 (0)