/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $this->currentfile = $phpcsfile; // We are only interested if this is the first open tag. if ($stackptr !== 0) { if ($phpcsfile->findprevious(T_OPEN_TAG, $stackptr - 1) !== false) { return; } } $tokens = $phpcsfile->gettokens(); // Find the next non whitespace token. $commentstart = $phpcsfile->findnext(T_WHITESPACE, $stackptr + 1, null, true); // Look for $Id$ and boilerplate if ($tokens[$commentstart]['code'] != T_COMMENT) { $phpcsfile->adderror('File must begin with License boilerplate', $stackptr + 1); return; } else { if (preg_match('|\\$Id|i', $tokens[$commentstart]['content'])) { $phpcsfile->addwarning("\$Id\$ tag is no longer required, please remove.", $stackptr + 1); return; } } // now look for boilerplate, must be immediately after the first line $boilerplate = '// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>.'; $nexttoken = $phpcsfile->findnext(T_WHITESPACE, $stackptr + 1, null, true); $boilerplate_lines = preg_split('/[\\n\\r]+/', $boilerplate); if (rtrim($tokens[$nexttoken]['content']) != $boilerplate_lines[0]) { $phpcsfile->adderror('You must include the Moodle boilerplate at the top of the file', $nexttoken); return; } $boilerplate_index = 0; foreach ($boilerplate_lines as $line) { $nexttoken = $phpcsfile->findnext(T_COMMENT, $nexttoken); if (rtrim($tokens[$nexttoken]['content']) != $boilerplate_lines[$boilerplate_index]) { $phpcsfile->adderror('Badly formatted boilerplate. Please copy-paste exactly', $nexttoken); return; } $nexttoken++; $boilerplate_index++; } $filedoctoken = $phpcsfile->findnext(T_WHITESPACE, $nexttoken + 1, null, true); if ($tokens[$filedoctoken]['code'] === T_CLOSE_TAG) { // We are only interested if this is the first open tag. return; } else { if ($tokens[$filedoctoken]['code'] === T_COMMENT) { $phpcsfile->adderror('You must use "/**" style comments for a file comment', $filedoctoken + 1); return; } else { if ($filedoctoken === false || $tokens[$filedoctoken]['code'] !== T_DOC_COMMENT) { $phpcsfile->adderror('Missing file doc comment', $filedoctoken + 1); return; } else { // Extract the header comment docblock. $commentend = $phpcsfile->findnext(T_DOC_COMMENT, $filedoctoken + 1, null, true) - 1; // Check if there is only 1 doc comment between the open tag and class token. $nexttoken = array(T_ABSTRACT, T_CLASS, T_FUNCTION, T_DOC_COMMENT); $commentnext = $phpcsfile->findnext($nexttoken, $commentend + 1); if ($commentnext !== false && $tokens[$commentnext]['code'] !== T_DOC_COMMENT) { // Found a class token right after comment doc block. $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $commentend + 1, $commentnext, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $newlinetoken + 1, $commentnext, false, $phpcsfile->eolChar); if ($newlinetoken === false) { // No blank line between the class token and the doc block. // The doc block is most likely a class comment. $phpcsfile->adderror('Missing file doc comment', $stackptr + 1); return; } } } $comment = $phpcsfile->gettokensAsString($filedoctoken, $commentend - $filedoctoken + 1); // Parse the header comment docblock. try { $this->commentparser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsfile); $this->commentparser->parse(); } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { $line = $e->getlinewithinComment() + $filedoctoken; $phpcsfile->adderror($e->getMessage(), $line); return; } $comment = $this->commentparser->getComment(); if (is_null($comment) === true) { $error = 'File doc comment is empty'; $phpcsfile->adderror($error, $filedoctoken); return; } // No extra newline before short description. $short = $comment->getShortComment(); $newlinecount = 0; $newlinespan = strspn($short, $phpcsfile->eolChar); if ($short !== '' && $newlinespan > 0) { $line = $newlinespan > 1 ? 'newlines' : 'newline'; $error = "Extra {$line} found before file comment short description"; $phpcsfile->adderror($error, $filedoctoken + 1); } $newlinecount = substr_count($short, $phpcsfile->eolChar) + 1; // Exactly one blank line between short and long description. $long = $comment->getlongcomment(); if (empty($long) === false) { $between = $comment->getWhiteSpacebetween(); $newlinebetween = substr_count($between, $phpcsfile->eolChar); if ($newlinebetween !== 2) { $error = 'There should be exactly one blank line between descriptions in file comment'; $phpcsfile->addwarning($error, $filedoctoken + $newlinecount + 1); } $newlinecount += $newlinebetween; } // Exactly one blank line before tags. $tags = $this->commentparser->gettagOrders(); if (count($tags) > 1) { $newlinespan = $comment->getNewlineAfter(); if ($newlinespan !== 2) { $error = 'There must be exactly one blank line before the tags in file comment'; if ($long !== '') { $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1; } $phpcsfile->addwarning($error, $filedoctoken + $newlinecount); $short = rtrim($short, $phpcsfile->eolChar . ' '); } } // Check the PHP Version. /* if (strstr(strtolower($long), 'php version') === false) { $error = 'PHP version not specified'; $phpcsfile->addwarning($error, $commentend); } */ // Check each tag. $this->processtags($filedoctoken, $commentend); } } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { // Modify array of required tags $this->tags['package']['required'] = false; $this->tags['copyright']['required'] = false; $this->tags['author']['required'] = false; $this->currentfile = $phpcsfile; $tokens = $phpcsfile->gettokens(); $type = strtolower($tokens[$stackptr]['content']); $find = array(T_ABSTRACT, T_WHITESPACE, T_FINAL); // Extract the class comment docblock. $commentend = $phpcsfile->findprevious($find, $stackptr - 1, null, true); if ($commentend !== false && $tokens[$commentend]['code'] === T_COMMENT) { $phpcsfile->adderror("You must use \"/**\" style comments for a {$type} comment", $stackptr); return; } else { if ($commentend === false || $tokens[$commentend]['code'] !== T_DOC_COMMENT) { $phpcsfile->adderror("Missing {$type} doc comment", $stackptr); return; } } $commentstart = $phpcsfile->findprevious(T_DOC_COMMENT, $commentend - 1, null, true) + 1; $commentnext = $phpcsfile->findprevious(T_WHITESPACE, $commentend + 1, $stackptr, false, $phpcsfile->eolChar); // Distinguish file and class comment. $prevclasstoken = $phpcsfile->findprevious(T_CLASS, $stackptr - 1); if ($prevclasstoken === false) { // This is the first class token in this file, need extra checks. $prevnoncomment = $phpcsfile->findprevious(T_DOC_COMMENT, $commentstart - 1, null, true); if ($prevnoncomment !== false) { $prevcomment = $phpcsfile->findprevious(T_DOC_COMMENT, $prevnoncomment - 1); if ($prevcomment === false) { // There is only 1 doc comment between open tag and class token. $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $commentend + 1, $stackptr, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $newlinetoken + 1, $stackptr, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { // Blank line between the class and the doc block. // The doc block is most likely a file comment. $phpcsfile->adderror("Missing {$type} doc comment", $stackptr + 1); return; } } } } } $comment = $phpcsfile->gettokensAsString($commentstart, $commentend - $commentstart + 1); // Parse the class comment.docblock. try { $this->commentparser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsfile); $this->commentparser->parse(); } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { $line = $e->getlinewithinComment() + $commentstart; $phpcsfile->adderror($e->getMessage(), $line); return; } $comment = $this->commentparser->getComment(); if (is_null($comment) === true) { $error = ucfirst($type) . ' doc comment is empty'; $phpcsfile->adderror($error, $commentstart); return; } // No extra newline before short description. $short = $comment->getShortComment(); $newlinecount = 0; $newlinespan = strspn($short, $phpcsfile->eolChar); if ($short !== '' && $newlinespan > 0) { $line = $newlinespan > 1 ? 'newlines' : 'newline'; $error = "Extra {$line} found before {$type} comment short description"; $phpcsfile->adderror($error, $commentstart + 1); } $newlinecount = substr_count($short, $phpcsfile->eolChar) + 1; // Exactly one blank line between short and long description. $long = $comment->getlongcomment(); if (empty($long) === false) { $between = $comment->getWhiteSpacebetween(); $newlinebetween = substr_count($between, $phpcsfile->eolChar); if ($newlinebetween !== 2) { $error = "There must be exactly one blank line between descriptions in {$type} comments"; $phpcsfile->adderror($error, $commentstart + $newlinecount + 1); } $newlinecount += $newlinebetween; } // Exactly one blank line before tags. $tags = $this->commentparser->gettagOrders(); if (count($tags) > 1) { $newlinespan = $comment->getNewlineAfter(); if ($newlinespan !== 2) { $error = "There must be exactly one blank line before the tags in {$type} comments"; if ($long !== '') { $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1; } $phpcsfile->addwarning($error, $commentstart + $newlinecount); $short = rtrim($short, $phpcsfile->eolChar . ' '); } } // Check each tag. $this->processtags($commentstart, $commentend); }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-statements without body. if (isset($token['scope_opener']) === false) { return; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; $emptybody = true; for (; $next <= $end; ++$next) { if (in_array($tokens[$next]['code'], PHP_CodeSniffer_tokens::$emptyTokens) === false) { $emptybody = false; break; } } if ($emptybody === true) { // Get token identifier. $name = $phpcsfile->gettokensAsString($stackptr, 1); $error = sprintf('Empty %s statement detected', strtoupper($name)); if ($this->_tokens[$token['code']] === true) { $phpcsfile->adderror($error, $stackptr); } else { $phpcsfile->addwarning($error, $stackptr); } } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsfile The file being scanned. * @param int $stackptr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $find = array(T_COMMENT, T_DOC_COMMENT, T_CLASS, T_FUNCTION, T_OPEN_TAG); $commentend = $phpcsfile->findprevious($find, $stackptr - 1); if ($commentend === false) { return; } $this->currentfile = $phpcsfile; $tokens = $phpcsfile->gettokens(); // If the token that we found was a class or a function, then this // function has no doc comment. $code = $tokens[$commentend]['code']; if ($code === T_COMMENT) { $error = 'You must use "/**" style comments for a function comment'; $phpcsfile->adderror($error, $stackptr); return; } else { if ($code !== T_DOC_COMMENT) { $phpcsfile->adderror('Missing function doc comment', $stackptr); return; } } // If there is any code between the function keyword and the doc block // then the doc block is not for us. $ignore = PHP_CodeSniffer_tokens::$scopeModifiers; $ignore[] = T_STATIC; $ignore[] = T_WHITESPACE; $ignore[] = T_ABSTRACT; $ignore[] = T_FINAL; $prevtoken = $phpcsfile->findprevious($ignore, $stackptr - 1, null, true); if ($prevtoken !== $commentend) { $phpcsfile->adderror('Missing function doc comment', $stackptr); return; } $this->_functiontoken = $stackptr; foreach ($tokens[$stackptr]['conditions'] as $condptr => $condition) { if ($condition === T_CLASS || $condition === T_INTERFACE) { $this->_classtoken = $condptr; break; } } // If the first T_OPEN_TAG is right before the comment, it is probably // a file comment. $commentstart = $phpcsfile->findprevious(T_DOC_COMMENT, $commentend - 1, null, true) + 1; $prevtoken = $phpcsfile->findprevious(T_WHITESPACE, $commentstart - 1, null, true); if ($tokens[$prevtoken]['code'] === T_OPEN_TAG) { // Is this the first open tag? if ($stackptr === 0 || $phpcsfile->findprevious(T_OPEN_TAG, $prevtoken - 1) === false) { $phpcsfile->adderror('Missing function doc comment', $stackptr); return; } } $comment = $phpcsfile->gettokensAsString($commentstart, $commentend - $commentstart + 1); $this->_methodname = $phpcsfile->getDeclarationname($stackptr); try { $this->commentparser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($comment, $phpcsfile); $this->commentparser->parse(); } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { $line = $e->getlinewithinComment() + $commentstart; $phpcsfile->adderror($e->getMessage(), $line); return; } $comment = $this->commentparser->getComment(); if (is_null($comment) === true) { $error = 'Function doc comment is empty'; $phpcsfile->adderror($error, $commentstart); return; } $this->processparams($commentstart); $this->processreturn($commentstart, $commentend); $this->processthrows($commentstart); // No extra newline before short description. $short = $comment->getShortComment(); $newlinecount = 0; $newlinespan = strspn($short, $phpcsfile->eolChar); if ($short !== '' && $newlinespan > 0) { $line = $newlinespan > 1 ? 'newlines' : 'newline'; $error = "Extra {$line} found before function comment short description"; $phpcsfile->adderror($error, $commentstart + 1); } $newlinecount = substr_count($short, $phpcsfile->eolChar) + 1; // Exactly one blank line between short and long description. $long = $comment->getlongcomment(); if (empty($long) === false) { $between = $comment->getWhiteSpacebetween(); $newlinebetween = substr_count($between, $phpcsfile->eolChar); if ($newlinebetween !== 2) { $error = 'There must be exactly one blank line between descriptions in function comment'; $phpcsfile->adderror($error, $commentstart + $newlinecount + 1); } $newlinecount += $newlinebetween; } // Exactly one blank line before tags. $params = $this->commentparser->gettagOrders(); if (count($params) > 1) { $newlinespan = $comment->getNewlineAfter(); if ($newlinespan !== 2) { $error = 'There must be exactly one blank line before the tags in function comment'; if ($long !== '') { $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1; } $phpcsfile->addwarning($error, $commentstart + $newlinecount); $short = rtrim($short, $phpcsfile->eolChar . ' '); } } }