| Conditions | 62 |
| Paths | > 20000 |
| Total Lines | 287 |
| Code Lines | 172 |
| Lines | 115 |
| Ratio | 40.07 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php |
||
| 61 | public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) |
||
| 62 | { |
||
| 63 | $tokens = $phpcsFile->getTokens(); |
||
| 64 | $commentStart = $stackPtr; |
||
| 65 | $commentEnd = $tokens[$stackPtr]['comment_closer']; |
||
| 66 | |||
| 67 | $empty = array( |
||
| 68 | T_DOC_COMMENT_WHITESPACE, |
||
| 69 | T_DOC_COMMENT_STAR, |
||
| 70 | ); |
||
| 71 | |||
| 72 | $short = $phpcsFile->findNext($empty, ($stackPtr + 1), $commentEnd, true); |
||
| 73 | if ($short === false) { |
||
| 74 | // No content at all. |
||
| 75 | $error = 'Doc comment is empty'; |
||
| 76 | $phpcsFile->addError($error, $stackPtr, 'Empty'); |
||
| 77 | return; |
||
| 78 | } |
||
| 79 | |||
| 80 | // The first line of the comment should just be the /** code. |
||
| 81 | if ($tokens[$short]['line'] === $tokens[$stackPtr]['line']) { |
||
| 82 | $error = 'The open comment tag must be the only content on the line'; |
||
| 83 | $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpen'); |
||
| 84 | if ($fix === true) { |
||
| 85 | $phpcsFile->fixer->beginChangeset(); |
||
| 86 | $phpcsFile->fixer->addNewline($stackPtr); |
||
| 87 | $phpcsFile->fixer->addContentBefore($short, '* '); |
||
| 88 | $phpcsFile->fixer->endChangeset(); |
||
| 89 | } |
||
| 90 | } |
||
| 91 | |||
| 92 | // The last line of the comment should just be the */ code. |
||
| 93 | $prev = $phpcsFile->findPrevious($empty, ($commentEnd - 1), $stackPtr, true); |
||
| 94 | if ($tokens[$prev]['line'] === $tokens[$commentEnd]['line']) { |
||
| 95 | $error = 'The close comment tag must be the only content on the line'; |
||
| 96 | $fix = $phpcsFile->addFixableError($error, $commentEnd, 'ContentBeforeClose'); |
||
| 97 | if ($fix === true) { |
||
| 98 | $phpcsFile->fixer->addNewlineBefore($commentEnd); |
||
| 99 | } |
||
| 100 | } |
||
| 101 | |||
| 102 | // Check for additional blank lines at the end of the comment. |
||
| 103 | if ($tokens[$prev]['line'] < ($tokens[$commentEnd]['line'] - 1)) { |
||
| 104 | $error = 'Additional blank lines found at end of doc comment'; |
||
| 105 | $fix = $phpcsFile->addFixableError($error, $commentEnd, 'SpacingAfter'); |
||
| 106 | if ($fix === true) { |
||
| 107 | $phpcsFile->fixer->beginChangeset(); |
||
| 108 | for ($i = ($prev + 1); $i < $commentEnd; $i++) { |
||
| 109 | if ($tokens[($i + 1)]['line'] === $tokens[$commentEnd]['line']) { |
||
| 110 | break; |
||
| 111 | } |
||
| 112 | |||
| 113 | $phpcsFile->fixer->replaceToken($i, ''); |
||
| 114 | } |
||
| 115 | |||
| 116 | $phpcsFile->fixer->endChangeset(); |
||
| 117 | } |
||
| 118 | } |
||
| 119 | |||
| 120 | // Check for a comment description. |
||
| 121 | if ($tokens[$short]['code'] !== T_DOC_COMMENT_STRING) { |
||
| 122 | $error = 'Missing short description in doc comment'; |
||
| 123 | $phpcsFile->addError($error, $stackPtr, 'MissingShort'); |
||
| 124 | return; |
||
| 125 | } |
||
| 126 | |||
| 127 | // No extra newline before short description. |
||
| 128 | if ($tokens[$short]['line'] !== ($tokens[$stackPtr]['line'] + 1)) { |
||
| 129 | $error = 'Doc comment short description must be on the first line'; |
||
| 130 | $fix = $phpcsFile->addFixableError($error, $short, 'SpacingBeforeShort'); |
||
| 131 | if ($fix === true) { |
||
| 132 | $phpcsFile->fixer->beginChangeset(); |
||
| 133 | for ($i = $stackPtr; $i < $short; $i++) { |
||
| 134 | if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) { |
||
| 135 | continue; |
||
| 136 | } else if ($tokens[$i]['line'] === $tokens[$short]['line']) { |
||
| 137 | break; |
||
| 138 | } |
||
| 139 | |||
| 140 | $phpcsFile->fixer->replaceToken($i, ''); |
||
| 141 | } |
||
| 142 | |||
| 143 | $phpcsFile->fixer->endChangeset(); |
||
| 144 | } |
||
| 145 | } |
||
| 146 | |||
| 147 | // Account for the fact that a short description might cover |
||
| 148 | // multiple lines. |
||
| 149 | $shortContent = $tokens[$short]['content']; |
||
| 150 | $shortEnd = $short; |
||
| 151 | for ($i = ($short + 1); $i < $commentEnd; $i++) { |
||
| 152 | if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) { |
||
| 153 | if ($tokens[$i]['line'] === ($tokens[$shortEnd]['line'] + 1)) { |
||
| 154 | $shortContent .= $tokens[$i]['content']; |
||
| 155 | $shortEnd = $i; |
||
| 156 | } else { |
||
| 157 | break; |
||
| 158 | } |
||
| 159 | } |
||
| 160 | } |
||
| 161 | |||
| 162 | if (preg_match('/^\p{Ll}/u', $shortContent) === 1) { |
||
| 163 | $error = 'Doc comment short description must start with a capital letter'; |
||
| 164 | $phpcsFile->addError($error, $short, 'ShortNotCapital'); |
||
| 165 | } |
||
| 166 | |||
| 167 | $long = $phpcsFile->findNext($empty, ($shortEnd + 1), ($commentEnd - 1), true); |
||
| 168 | if ($long !== false && $tokens[$long]['code'] === T_DOC_COMMENT_STRING) { |
||
| 169 | if ($tokens[$long]['line'] !== ($tokens[$shortEnd]['line'] + 2)) { |
||
| 170 | $error = 'There must be exactly one blank line between descriptions in a doc comment'; |
||
| 171 | $fix = $phpcsFile->addFixableError($error, $long, 'SpacingBetween'); |
||
| 172 | if ($fix === true) { |
||
| 173 | $phpcsFile->fixer->beginChangeset(); |
||
| 174 | for ($i = ($shortEnd + 1); $i < $long; $i++) { |
||
| 175 | if ($tokens[$i]['line'] === $tokens[$shortEnd]['line']) { |
||
| 176 | continue; |
||
| 177 | } else if ($tokens[$i]['line'] === ($tokens[$long]['line'] - 1)) { |
||
| 178 | break; |
||
| 179 | } |
||
| 180 | |||
| 181 | $phpcsFile->fixer->replaceToken($i, ''); |
||
| 182 | } |
||
| 183 | |||
| 184 | $phpcsFile->fixer->endChangeset(); |
||
| 185 | } |
||
| 186 | } |
||
| 187 | |||
| 188 | if (preg_match('/^\p{Ll}/u', $tokens[$long]['content']) === 1) { |
||
| 189 | $error = 'Doc comment long description must start with a capital letter'; |
||
| 190 | $phpcsFile->addError($error, $long, 'LongNotCapital'); |
||
| 191 | } |
||
| 192 | }//end if |
||
| 193 | |||
| 194 | if (empty($tokens[$commentStart]['comment_tags']) === true) { |
||
| 195 | // No tags in the comment. |
||
| 196 | return; |
||
| 197 | } |
||
| 198 | |||
| 199 | $firstTag = $tokens[$commentStart]['comment_tags'][0]; |
||
| 200 | $prev = $phpcsFile->findPrevious($empty, ($firstTag - 1), $stackPtr, true); |
||
| 201 | if ($tokens[$firstTag]['line'] !== ($tokens[$prev]['line'] + 2)) { |
||
| 202 | $error = 'There must be exactly one blank line before the tags in a doc comment'; |
||
| 203 | $fix = $phpcsFile->addFixableError($error, $firstTag, 'SpacingBeforeTags'); |
||
| 204 | if ($fix === true) { |
||
| 205 | $phpcsFile->fixer->beginChangeset(); |
||
| 206 | for ($i = ($prev + 1); $i < $firstTag; $i++) { |
||
| 207 | if ($tokens[$i]['line'] === $tokens[$firstTag]['line']) { |
||
| 208 | break; |
||
| 209 | } |
||
| 210 | |||
| 211 | $phpcsFile->fixer->replaceToken($i, ''); |
||
| 212 | } |
||
| 213 | |||
| 214 | $indent = str_repeat(' ', $tokens[$stackPtr]['column']); |
||
| 215 | $phpcsFile->fixer->addContent($prev, $phpcsFile->eolChar.$indent.'*'.$phpcsFile->eolChar); |
||
| 216 | $phpcsFile->fixer->endChangeset(); |
||
| 217 | } |
||
| 218 | } |
||
| 219 | |||
| 220 | // Break out the tags into groups and check alignment within each. |
||
| 221 | // A tag group is one where there are no blank lines between tags. |
||
| 222 | // The param tag group is special as it requires all @param tags to be inside. |
||
| 223 | $tagGroups = array(); |
||
| 224 | $groupid = 0; |
||
| 225 | $paramGroupid = null; |
||
| 226 | foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag) { |
||
| 227 | if ($pos > 0) { |
||
| 228 | $prev = $phpcsFile->findPrevious( |
||
| 229 | T_DOC_COMMENT_STRING, |
||
| 230 | ($tag - 1), |
||
| 231 | $tokens[$commentStart]['comment_tags'][($pos - 1)] |
||
| 232 | ); |
||
| 233 | |||
| 234 | if ($prev === false) { |
||
| 235 | $prev = $tokens[$commentStart]['comment_tags'][($pos - 1)]; |
||
| 236 | } |
||
| 237 | |||
| 238 | if ($tokens[$prev]['line'] !== ($tokens[$tag]['line'] - 1)) { |
||
| 239 | $groupid++; |
||
| 240 | } |
||
| 241 | } |
||
| 242 | |||
| 243 | if ($tokens[$tag]['content'] === '@param') { |
||
| 244 | if (($paramGroupid === null |
||
| 245 | && empty($tagGroups[$groupid]) === false) |
||
| 246 | || ($paramGroupid !== null |
||
| 247 | && $paramGroupid !== $groupid) |
||
| 248 | ) { |
||
| 249 | $error = 'Parameter tags must be grouped together in a doc comment'; |
||
| 250 | $phpcsFile->addError($error, $tag, 'ParamGroup'); |
||
| 251 | } |
||
| 252 | |||
| 253 | if ($paramGroupid === null) { |
||
| 254 | $paramGroupid = $groupid; |
||
| 255 | } |
||
| 256 | } else if ($groupid === $paramGroupid) { |
||
| 257 | $error = 'Tag cannot be grouped with parameter tags in a doc comment'; |
||
| 258 | $phpcsFile->addError($error, $tag, 'NonParamGroup'); |
||
| 259 | }//end if |
||
| 260 | |||
| 261 | $tagGroups[$groupid][] = $tag; |
||
| 262 | }//end foreach |
||
| 263 | |||
| 264 | foreach ($tagGroups as $group) { |
||
| 265 | $maxLength = 0; |
||
| 266 | $paddings = array(); |
||
| 267 | foreach ($group as $pos => $tag) { |
||
| 268 | $tagLength = strlen($tokens[$tag]['content']); |
||
| 269 | if ($tagLength > $maxLength) { |
||
| 270 | $maxLength = $tagLength; |
||
| 271 | } |
||
| 272 | |||
| 273 | // Check for a value. No value means no padding needed. |
||
| 274 | $string = $phpcsFile->findNext(T_DOC_COMMENT_STRING, $tag, $commentEnd); |
||
| 275 | if ($string !== false && $tokens[$string]['line'] === $tokens[$tag]['line']) { |
||
| 276 | $paddings[$tag] = strlen($tokens[($tag + 1)]['content']); |
||
| 277 | } |
||
| 278 | } |
||
| 279 | |||
| 280 | // Check that there was single blank line after the tag block |
||
| 281 | // but account for a multi-line tag comments. |
||
| 282 | $lastTag = $group[$pos]; |
||
| 283 | $next = $phpcsFile->findNext(T_DOC_COMMENT_TAG, ($lastTag + 3), $commentEnd); |
||
| 284 | if ($next !== false) { |
||
| 285 | $prev = $phpcsFile->findPrevious(array(T_DOC_COMMENT_TAG, T_DOC_COMMENT_STRING), ($next - 1), $commentStart); |
||
| 286 | if ($tokens[$next]['line'] !== ($tokens[$prev]['line'] + 2)) { |
||
| 287 | $error = 'There must be a single blank line after a tag group'; |
||
| 288 | $fix = $phpcsFile->addFixableError($error, $lastTag, 'SpacingAfterTagGroup'); |
||
| 289 | if ($fix === true) { |
||
| 290 | $phpcsFile->fixer->beginChangeset(); |
||
| 291 | for ($i = ($prev + 1); $i < $next; $i++) { |
||
| 292 | if ($tokens[$i]['line'] === $tokens[$next]['line']) { |
||
| 293 | break; |
||
| 294 | } |
||
| 295 | |||
| 296 | $phpcsFile->fixer->replaceToken($i, ''); |
||
| 297 | } |
||
| 298 | |||
| 299 | $indent = str_repeat(' ', $tokens[$stackPtr]['column']); |
||
| 300 | $phpcsFile->fixer->addContent($prev, $phpcsFile->eolChar.$indent.'*'.$phpcsFile->eolChar); |
||
| 301 | $phpcsFile->fixer->endChangeset(); |
||
| 302 | } |
||
| 303 | } |
||
| 304 | }//end if |
||
| 305 | |||
| 306 | // Now check paddings. |
||
| 307 | foreach ($paddings as $tag => $padding) { |
||
| 308 | $required = ($maxLength - strlen($tokens[$tag]['content']) + 1); |
||
| 309 | |||
| 310 | if ($padding !== $required) { |
||
| 311 | $error = 'Tag value indented incorrectly; expected %s spaces but found %s'; |
||
| 312 | $data = array( |
||
| 313 | $required, |
||
| 314 | $padding, |
||
| 315 | ); |
||
| 316 | |||
| 317 | $fix = $phpcsFile->addFixableError($error, ($tag + 1), 'TagValueIndent', $data); |
||
| 318 | if ($fix === true) { |
||
| 319 | $phpcsFile->fixer->replaceToken(($tag + 1), str_repeat(' ', $required)); |
||
| 320 | } |
||
| 321 | } |
||
| 322 | } |
||
| 323 | }//end foreach |
||
| 324 | |||
| 325 | // If there is a param group, it needs to be first. |
||
| 326 | if ($paramGroupid !== null && $paramGroupid !== 0) { |
||
| 327 | $error = 'Parameter tags must be defined first in a doc comment'; |
||
| 328 | $phpcsFile->addError($error, $tagGroups[$paramGroupid][0], 'ParamNotFirst'); |
||
| 329 | } |
||
| 330 | |||
| 331 | $foundTags = array(); |
||
| 332 | foreach ($tokens[$stackPtr]['comment_tags'] as $pos => $tag) { |
||
| 333 | $tagName = $tokens[$tag]['content']; |
||
| 334 | if (isset($foundTags[$tagName]) === true) { |
||
| 335 | $lastTag = $tokens[$stackPtr]['comment_tags'][($pos - 1)]; |
||
| 336 | if ($tokens[$lastTag]['content'] !== $tagName) { |
||
| 337 | $error = 'Tags must be grouped together in a doc comment'; |
||
| 338 | $phpcsFile->addError($error, $tag, 'TagsNotGrouped'); |
||
| 339 | } |
||
| 340 | |||
| 341 | continue; |
||
| 342 | } |
||
| 343 | |||
| 344 | $foundTags[$tagName] = true; |
||
| 345 | } |
||
| 346 | |||
| 347 | }//end process() |
||
| 348 | |||
| 351 |