6 declare(strict_types=1);
9 use PHP_CodeSniffer\Files\File;
24 private function getShortDescriptionEndPosition(File $phpcsFile,
int $shortPtr, $commentEndPtr) :
int 26 $tokens = $phpcsFile->getTokens();
27 $shortPtrEnd = $shortPtr;
28 for (
$i = ($shortPtr + 1);
$i < $commentEndPtr;
$i++) {
29 if (
$tokens[
$i][
'code'] === T_DOC_COMMENT_STRING) {
47 private function validateMultiLinesInShortDescription(
52 $tokens = $phpcsFile->getTokens();
53 $shortPtrEnd = $this->getShortDescriptionEndPosition(
58 $shortPtrEndContent =
$tokens[$shortPtrEnd][
'content'];
59 if (preg_match(
'/^[a-z]/', $shortPtrEndContent)
60 && $shortPtrEnd != $shortPtr
61 && !preg_match(
'/\bSee\b/', $shortPtrEndContent)
63 &&
$tokens[$shortPtrEnd][
'code'] !== T_DOC_COMMENT_TAG
65 $error =
'Short description should not be in multi lines';
66 $phpcsFile->addFixableError($error, $shortPtrEnd+1,
'MethodAnnotation');
78 private function validateSpacingBetweenShortAndLongDescriptions(
82 array $emptyTypeTokens
84 $tokens = $phpcsFile->getTokens();
85 $shortPtrEnd = $this->getShortDescriptionEndPosition(
90 $shortPtrEndContent =
$tokens[$shortPtrEnd][
'content'];
91 if (preg_match(
'/^[A-Z]/', $shortPtrEndContent)
92 && !preg_match(
'/\bSee\b/', $shortPtrEndContent)
94 &&
$tokens[$shortPtrEnd][
'code'] !== T_DOC_COMMENT_TAG
96 $error =
'There must be exactly one blank line between lines';
97 $phpcsFile->addFixableError($error, $shortPtrEnd + 1,
'MethodAnnotation');
99 if ($shortPtrEnd != $shortPtr) {
100 $this->validateLongDescriptionFormat($phpcsFile, $shortPtrEnd, $commentEndPtr, $emptyTypeTokens);
102 $this->validateLongDescriptionFormat($phpcsFile, $shortPtr, $commentEndPtr, $emptyTypeTokens);
115 private function validateShortDescriptionFormat(
120 array $emptyTypeTokens
122 $tokens = $phpcsFile->getTokens();
123 if (
$tokens[$shortPtr][
'line'] !==
$tokens[$stackPtr][
'line'] + 1) {
124 $error =
'No blank lines are allowed before short description';
125 $phpcsFile->addFixableError($error, $shortPtr,
'MethodAnnotation');
127 if (strtolower(
$tokens[$shortPtr][
'content']) ===
'{@inheritdoc}') {
128 $error =
'If the @inheritdoc not inline it shouldn’t have braces';
129 $phpcsFile->addFixableError($error, $shortPtr,
'MethodAnnotation');
131 $shortPtrContent =
$tokens[$shortPtr][
'content'];
132 if (preg_match(
'/^\p{Ll}/u', $shortPtrContent) === 1) {
133 $error =
'Short description must start with a capital letter';
134 $phpcsFile->addFixableError($error, $shortPtr,
'MethodAnnotation');
136 $this->validateNoExtraNewLineBeforeShortDescription(
142 $this->validateSpacingBetweenShortAndLongDescriptions(
148 $this->validateMultiLinesInShortDescription(
163 private function validateLongDescriptionFormat(
167 array $emptyTypeTokens
169 $tokens = $phpcsFile->getTokens();
170 $longPtr = $phpcsFile->findNext($emptyTypeTokens, $shortPtrEnd + 1, $commentEndPtr - 1,
true);
171 if (strtolower(
$tokens[$longPtr][
'content']) ===
'{@inheritdoc}') {
172 $error =
'{@inheritdoc} imports only short description, annotation must have long description';
173 $phpcsFile->addFixableError($error, $longPtr,
'MethodAnnotation');
175 if ($longPtr !==
false &&
$tokens[$longPtr][
'code'] === T_DOC_COMMENT_STRING) {
176 if (
$tokens[$longPtr][
'line'] !==
$tokens[$shortPtrEnd][
'line'] + 2) {
177 $error =
'There must be exactly one blank line between descriptions';
178 $phpcsFile->addFixableError($error, $longPtr,
'MethodAnnotation');
180 if (preg_match(
'/^\p{Ll}/u',
$tokens[$longPtr][
'content']) === 1) {
181 $error =
'Long description must start with a capital letter';
182 $phpcsFile->addFixableError($error, $longPtr,
'MethodAnnotation');
196 $tokens = $phpcsFile->getTokens();
197 if (isset(
$tokens[$commentStartPtr][
'comment_tags'][0])) {
198 $firstTagPtr =
$tokens[$commentStartPtr][
'comment_tags'][0];
199 $commentTagPtrContent =
$tokens[$firstTagPtr][
'content'];
200 $prevPtr = $phpcsFile->findPrevious($emptyTypeTokens, $firstTagPtr - 1, $commentStartPtr,
true);
201 if (
$tokens[$firstTagPtr][
'line'] !==
$tokens[$prevPtr][
'line'] + 2
202 && strtolower($commentTagPtrContent) !==
'@inheritdoc' 204 $error =
'There must be exactly one blank line before tags';
205 $phpcsFile->addFixableError($error, $firstTagPtr,
'MethodAnnotation');
218 $tokens = $phpcsFile->getTokens();
221 $paramGroupId =
null;
222 foreach (
$tokens[$commentStartPtr][
'comment_tags'] as $position => $tag) {
224 $prevPtr = $phpcsFile->findPrevious(
225 T_DOC_COMMENT_STRING,
227 $tokens[$commentStartPtr][
'comment_tags'][$position - 1]
229 if ($prevPtr ===
false) {
230 $prevPtr =
$tokens[$commentStartPtr][
'comment_tags'][$position - 1];
238 if (strtolower(
$tokens[$tag][
'content']) ===
'@param') {
239 if ($paramGroupId !==
null 241 $error =
'Parameter tags must be grouped together';
242 $phpcsFile->addFixableError($error, $tag,
'MethodAnnotation');
244 if ($paramGroupId ===
null) {
260 private function validateNoExtraNewLineBeforeShortDescription(
262 int $commentStartPtr,
264 array $emptyTypeTokens
266 $tokens = $phpcsFile->getTokens();
267 $prevPtr = $phpcsFile->findPrevious($emptyTypeTokens, $commentEndPtr - 1, $commentStartPtr,
true);
268 if (
$tokens[$prevPtr][
'line'] < (
$tokens[$commentEndPtr][
'line'] - 1)) {
269 $error =
'Additional blank lines found at end of the annotation block';
270 $phpcsFile->addFixableError($error, $commentEndPtr,
'MethodAnnotation');
285 int $commentStartPtr,
288 array $emptyTypeTokens
290 $tokens = $phpcsFile->getTokens();
291 if (isset(
$tokens[$commentStartPtr][
'comment_tags'][0])
293 $commentTagPtr =
$tokens[$commentStartPtr][
'comment_tags'][0];
294 $commentTagPtrContent =
$tokens[$commentTagPtr][
'content'];
295 if (
$tokens[$shortPtr][
'code'] !== T_DOC_COMMENT_STRING
296 && strtolower($commentTagPtrContent) !==
'@inheritdoc' 298 $error =
'Missing short description';
299 $phpcsFile->addFixableError($error, $commentStartPtr,
'MethodAnnotation');
301 $this->validateShortDescriptionFormat(
310 $this->validateShortDescriptionFormat(