Initial Commit
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_BlockCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_BlockCommentSniff.
|
||||
*
|
||||
* Verifies that block comments are used appropriately.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_BlockCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(
|
||||
T_COMMENT,
|
||||
T_DOC_COMMENT,
|
||||
);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @param PHP_CodeSniffer_File $phpcsFile The current 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();
|
||||
|
||||
// If its an inline comment return.
|
||||
if (substr($tokens[$stackPtr]['content'], 0, 2) !== '/*') {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a function/class/interface doc block comment, skip it.
|
||||
// We are only interested in inline doc block comments.
|
||||
if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT) {
|
||||
$nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
|
||||
$ignore = array(
|
||||
T_CLASS,
|
||||
T_INTERFACE,
|
||||
T_FUNCTION,
|
||||
T_PUBLIC,
|
||||
T_PRIVATE,
|
||||
T_FINAL,
|
||||
T_PROTECTED,
|
||||
T_STATIC,
|
||||
T_ABSTRACT,
|
||||
T_CONST,
|
||||
);
|
||||
if (in_array($tokens[$nextToken]['code'], $ignore) === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
|
||||
if ($tokens[$prevToken]['code'] === T_OPEN_TAG) {
|
||||
return;
|
||||
}
|
||||
}//end if
|
||||
|
||||
$commentLines = array($stackPtr);
|
||||
$nextComment = $stackPtr;
|
||||
$lastLine = $tokens[$stackPtr]['line'];
|
||||
|
||||
// Construct the comment into an array.
|
||||
while (($nextComment = $phpcsFile->findNext($tokens[$stackPtr]['code'], ($nextComment + 1), null, false)) !== false) {
|
||||
if (($tokens[$nextComment]['line'] - 1) !== $lastLine) {
|
||||
// Not part of the block.
|
||||
break;
|
||||
}
|
||||
|
||||
$lastLine = $tokens[$nextComment]['line'];
|
||||
$commentLines[] = $nextComment;
|
||||
}
|
||||
|
||||
if (count($commentLines) <= 2) {
|
||||
// Small comment. Can't be right.
|
||||
if (count($commentLines) === 1) {
|
||||
$error = 'Single line block comment not allowed; use inline ("// text") comment instead';
|
||||
$phpcsFile->addError($error, $stackPtr, 'SingleLine');
|
||||
return;
|
||||
}
|
||||
|
||||
if (trim($tokens[$commentLines[1]]['content']) === '*/') {
|
||||
if (trim($tokens[$stackPtr]['content']) === '/*') {
|
||||
$error = 'Empty block comment not allowed';
|
||||
$phpcsFile->addError($error, $stackPtr, 'Empty');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$content = trim($tokens[$stackPtr]['content']);
|
||||
if ($content !== '/*' && $content !== '/**') {
|
||||
$error = 'Block comment text must start on a new line';
|
||||
$phpcsFile->addError($error, $stackPtr, 'NoNewLine');
|
||||
return;
|
||||
}
|
||||
|
||||
$starColumn = ($tokens[$stackPtr]['column'] + 3);
|
||||
|
||||
// Make sure first line isn't blank.
|
||||
if (trim($tokens[$commentLines[1]]['content']) === '') {
|
||||
$error = 'Empty line not allowed at start of comment';
|
||||
$phpcsFile->addError($error, $commentLines[1], 'HasEmptyLine');
|
||||
} else {
|
||||
// Check indentation of first line.
|
||||
$content = $tokens[$commentLines[1]]['content'];
|
||||
$commentText = ltrim($content);
|
||||
$leadingSpace = (strlen($content) - strlen($commentText));
|
||||
if ($leadingSpace !== $starColumn) {
|
||||
$expected = $starColumn;
|
||||
$expected .= ($starColumn === 1) ? ' space' : ' spaces';
|
||||
$data = array(
|
||||
$expected,
|
||||
$leadingSpace,
|
||||
);
|
||||
|
||||
$error = 'First line of comment not aligned correctly; expected %s but found %s';
|
||||
$phpcsFile->addError($error, $commentLines[1], 'FirstLineIndent', $data);
|
||||
}
|
||||
|
||||
if (preg_match('|[A-Z]|', $commentText[0]) === 0) {
|
||||
$error = 'Block comments must start with a capital letter';
|
||||
$phpcsFile->addError($error, $commentLines[1], 'NoCaptial');
|
||||
}
|
||||
}
|
||||
|
||||
// Check that each line of the comment is indented past the star.
|
||||
foreach ($commentLines as $line) {
|
||||
$leadingSpace = (strlen($tokens[$line]['content']) - strlen(ltrim($tokens[$line]['content'])));
|
||||
// First and last lines (comment opener and closer) are handled seperately.
|
||||
if ($line === $commentLines[(count($commentLines) - 1)] || $line === $commentLines[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// First comment line was handled above.
|
||||
if ($line === $commentLines[1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's empty, continue.
|
||||
if (trim($tokens[$line]['content']) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($leadingSpace < $starColumn) {
|
||||
$expected = $starColumn;
|
||||
$expected .= ($starColumn === 1) ? ' space' : ' spaces';
|
||||
$data = array(
|
||||
$expected,
|
||||
$leadingSpace,
|
||||
);
|
||||
|
||||
$error = 'Comment line indented incorrectly; expected at least %s but found %s';
|
||||
$phpcsFile->addError($error, $line, 'LineIndent', $data);
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
// Finally, test the last line is correct.
|
||||
$lastIndex = (count($commentLines) - 1);
|
||||
$content = trim($tokens[$commentLines[$lastIndex]]['content']);
|
||||
if ($content !== '*/' && $content !== '**/') {
|
||||
$error = 'Comment closer must be on a new line';
|
||||
$phpcsFile->addError($error, $commentLines[$lastIndex]);
|
||||
} else {
|
||||
$content = $tokens[$commentLines[$lastIndex]]['content'];
|
||||
$commentText = ltrim($content);
|
||||
$leadingSpace = (strlen($content) - strlen($commentText));
|
||||
if ($leadingSpace !== ($tokens[$stackPtr]['column'] - 1)) {
|
||||
$expected = ($tokens[$stackPtr]['column'] - 1);
|
||||
$expected .= ($expected === 1) ? ' space' : ' spaces';
|
||||
$data = array(
|
||||
$expected,
|
||||
$leadingSpace,
|
||||
);
|
||||
|
||||
$error = 'Last line of comment aligned incorrectly; expected %s but found %s';
|
||||
$phpcsFile->addError($error, $commentLines[$lastIndex], 'LastLineIndent', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Check that the lines before and after this comment are blank.
|
||||
$contentBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
|
||||
if ($tokens[$contentBefore]['code'] === T_OPEN_CURLY_BRACKET) {
|
||||
if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) < 1) {
|
||||
$error = 'Empty line not required before block comment';
|
||||
$phpcsFile->addError($error, $stackPtr, 'HasEmptyLineBefore');
|
||||
}
|
||||
} else {
|
||||
if (($tokens[$stackPtr]['line'] - $tokens[$contentBefore]['line']) < 2) {
|
||||
$error = 'Empty line required before block comment';
|
||||
$phpcsFile->addError($error, $stackPtr, 'NoEmptyLineBefore');
|
||||
}
|
||||
}
|
||||
|
||||
$commentCloser = $commentLines[$lastIndex];
|
||||
$contentAfter = $phpcsFile->findNext(T_WHITESPACE, ($commentCloser + 1), null, true);
|
||||
if (($tokens[$contentAfter]['line'] - $tokens[$commentCloser]['line']) < 2) {
|
||||
$error = 'Empty line required after block comment';
|
||||
$phpcsFile->addError($error, $commentCloser, 'NoEmptyLineAfter');
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
/**
|
||||
* Parses and verifies the class doc comment.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) {
|
||||
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and verifies the class doc comment.
|
||||
*
|
||||
* Verifies that :
|
||||
* <ul>
|
||||
* <li>A class doc comment exists.</li>
|
||||
* <li>There is exactly one blank line before the class comment.</li>
|
||||
* <li>Short description ends with a full stop.</li>
|
||||
* <li>There is a blank line after the short description.</li>
|
||||
* <li>Each paragraph of the long description ends with a full stop.</li>
|
||||
* <li>There is a blank line between the description and the tags.</li>
|
||||
* <li>Check the format of the since tag (x.x.x).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_ClassCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_CLASS);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
$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 class comment', $stackPtr, 'WrongStyle');
|
||||
return;
|
||||
} else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) {
|
||||
$phpcsFile->addError('Missing class doc comment', $stackPtr, 'Missing');
|
||||
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 class doc comment', ($stackPtr + 1), 'Missing');
|
||||
return;
|
||||
}
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
// Exactly one blank line before the class comment.
|
||||
$prevTokenEnd = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true);
|
||||
if ($prevTokenEnd !== false) {
|
||||
$blankLineBefore = 0;
|
||||
for ($i = ($prevTokenEnd + 1); $i < $commentStart; $i++) {
|
||||
if ($tokens[$i]['code'] === T_WHITESPACE && $tokens[$i]['content'] === $phpcsFile->eolChar) {
|
||||
$blankLineBefore++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($blankLineBefore !== 2) {
|
||||
$error = 'There must be exactly one blank line before the class comment';
|
||||
$phpcsFile->addError($error, ($commentStart - 1), 'SpacingBefore');
|
||||
}
|
||||
}
|
||||
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
$commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));
|
||||
|
||||
// Parse the class comment docblock.
|
||||
try {
|
||||
$this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($commentString, $phpcsFile);
|
||||
$this->commentParser->parse();
|
||||
} catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
|
||||
$line = ($e->getLineWithinComment() + $commentStart);
|
||||
$phpcsFile->addError($e->getMessage(), $line, 'FailedParse');
|
||||
return;
|
||||
}
|
||||
|
||||
$comment = $this->commentParser->getComment();
|
||||
if (is_null($comment) === true) {
|
||||
$error = 'Class doc comment is empty';
|
||||
$phpcsFile->addError($error, $commentStart, 'Empty');
|
||||
return;
|
||||
}
|
||||
|
||||
// The first line of the comment should just be the /** code.
|
||||
$eolPos = strpos($commentString, $phpcsFile->eolChar);
|
||||
$firstLine = substr($commentString, 0, $eolPos);
|
||||
if ($firstLine !== '/**') {
|
||||
$error = 'The open comment tag must be the only content on the line';
|
||||
$phpcsFile->addError($error, $commentStart, 'SpacingAfterOpen');
|
||||
}
|
||||
|
||||
// Check for a comment description.
|
||||
$short = rtrim($comment->getShortComment(), $phpcsFile->eolChar);
|
||||
if (trim($short) === '') {
|
||||
$error = 'Missing short description in class doc comment';
|
||||
$phpcsFile->addError($error, $commentStart, 'MissingShort');
|
||||
return;
|
||||
}
|
||||
|
||||
// No extra newline before short description.
|
||||
$newlineCount = 0;
|
||||
$newlineSpan = strspn($short, $phpcsFile->eolChar);
|
||||
if ($short !== '' && $newlineSpan > 0) {
|
||||
$error = 'Extra newline(s) found before class comment short description';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort');
|
||||
}
|
||||
|
||||
$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 class comment';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween');
|
||||
}
|
||||
|
||||
$newlineCount += $newlineBetween;
|
||||
|
||||
$testLong = trim($long);
|
||||
if (preg_match('|[A-Z]|', $testLong[0]) === 0) {
|
||||
$error = 'Class comment long description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCaptial');
|
||||
}
|
||||
}
|
||||
|
||||
// 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 class comment';
|
||||
if ($long !== '') {
|
||||
$newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1);
|
||||
}
|
||||
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags');
|
||||
$short = rtrim($short, $phpcsFile->eolChar.' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Short description must be single line and end with a full stop.
|
||||
$testShort = trim($short);
|
||||
$lastChar = $testShort[(strlen($testShort) - 1)];
|
||||
if (substr_count($testShort, $phpcsFile->eolChar) !== 0) {
|
||||
$error = 'Class comment short description must be on a single line';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine');
|
||||
}
|
||||
|
||||
if (preg_match('|[A-Z]|', $testShort[0]) === 0) {
|
||||
$error = 'Class comment short description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital');
|
||||
}
|
||||
|
||||
if ($lastChar !== '.') {
|
||||
$error = 'Class comment short description must end with a full stop';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop');
|
||||
}
|
||||
|
||||
// No tags are allowed in the class comment.
|
||||
$tags = $this->commentParser->getTags();
|
||||
foreach ($tags as $errorTag) {
|
||||
$error = '@%s tag is not allowed in class comment';
|
||||
$data = array($errorTag['tag']);
|
||||
$phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data);
|
||||
}
|
||||
|
||||
// The last content should be a newline and the content before
|
||||
// that should not be blank. If there is more blank space
|
||||
// then they have additional blank lines at the end of the comment.
|
||||
$words = $this->commentParser->getWords();
|
||||
$lastPos = (count($words) - 1);
|
||||
if (trim($words[($lastPos - 1)]) !== ''
|
||||
|| strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false
|
||||
|| trim($words[($lastPos - 2)]) === ''
|
||||
) {
|
||||
$error = 'Additional blank lines found at end of class comment';
|
||||
$this->currentFile->addError($error, $commentEnd, 'SpacingAfter');
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
?>
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff.
|
||||
*
|
||||
* Checks the //end ... comments on classes, interfaces and functions.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_ClosingDeclarationCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(
|
||||
T_FUNCTION,
|
||||
T_CLASS,
|
||||
T_INTERFACE,
|
||||
);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
if ($tokens[$stackPtr]['code'] === T_FUNCTION) {
|
||||
|
||||
$methodProps = $phpcsFile->getMethodProperties($stackPtr);
|
||||
|
||||
// Abstract methods do not require a closing comment.
|
||||
if ($methodProps['is_abstract'] === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Closures do not require a closing comment.
|
||||
if ($methodProps['is_closure'] === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this function is in an interface then we don't require
|
||||
// a closing comment.
|
||||
if ($phpcsFile->hasCondition($stackPtr, T_INTERFACE) === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($tokens[$stackPtr]['scope_closer']) === false) {
|
||||
$error = 'Possible parse error: non-abstract method defined as abstract';
|
||||
$phpcsFile->addWarning($error, $stackPtr, 'Abstract');
|
||||
return;
|
||||
}
|
||||
|
||||
$decName = $phpcsFile->getDeclarationName($stackPtr);
|
||||
$comment = '//end '.$decName.'()';
|
||||
} else if ($tokens[$stackPtr]['code'] === T_CLASS) {
|
||||
$comment = '//end class';
|
||||
} else {
|
||||
$comment = '//end interface';
|
||||
}//end if
|
||||
|
||||
if (isset($tokens[$stackPtr]['scope_closer']) === false) {
|
||||
$error = 'Possible parse error: %s missing opening or closing brace';
|
||||
$data = array($tokens[$stackPtr]['content']);
|
||||
$phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data);
|
||||
return;
|
||||
}
|
||||
|
||||
$closingBracket = $tokens[$stackPtr]['scope_closer'];
|
||||
|
||||
if ($closingBracket === null) {
|
||||
// Possible inline structure. Other tests will handle it.
|
||||
return;
|
||||
}
|
||||
|
||||
$error = 'Expected '.$comment;
|
||||
if (isset($tokens[($closingBracket + 1)]) === false || $tokens[($closingBracket + 1)]['code'] !== T_COMMENT) {
|
||||
$phpcsFile->addError($error, $closingBracket, 'Missing');
|
||||
return;
|
||||
}
|
||||
|
||||
if (rtrim($tokens[($closingBracket + 1)]['content']) !== $comment) {
|
||||
$phpcsFile->addError($error, $closingBracket, 'Incorrect');
|
||||
return;
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_EmptyCatchCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_DocCommentAlignmentSniff.
|
||||
*
|
||||
* Tests that the stars in a doc comment align correctly.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_DocCommentAlignmentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_DOC_COMMENT);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
// We are only interested in function/class/interface doc block comments.
|
||||
$nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
|
||||
$ignore = array(
|
||||
T_CLASS,
|
||||
T_INTERFACE,
|
||||
T_FUNCTION,
|
||||
T_PUBLIC,
|
||||
T_PRIVATE,
|
||||
T_PROTECTED,
|
||||
T_STATIC,
|
||||
T_ABSTRACT,
|
||||
);
|
||||
|
||||
if (in_array($tokens[$nextToken]['code'], $ignore) === false) {
|
||||
// Could be a file comment.
|
||||
$prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
|
||||
if ($tokens[$prevToken]['code'] !== T_OPEN_TAG) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We only want to get the first comment in a block. If there is
|
||||
// a comment on the line before this one, return.
|
||||
$docComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($stackPtr - 1));
|
||||
if ($docComment !== false) {
|
||||
if ($tokens[$docComment]['line'] === ($tokens[$stackPtr]['line'] - 1)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$comments = array($stackPtr);
|
||||
$currentComment = $stackPtr;
|
||||
$lastComment = $stackPtr;
|
||||
while (($currentComment = $phpcsFile->findNext(T_DOC_COMMENT, ($currentComment + 1))) !== false) {
|
||||
if ($tokens[$lastComment]['line'] === ($tokens[$currentComment]['line'] - 1)) {
|
||||
$comments[] = $currentComment;
|
||||
$lastComment = $currentComment;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The $comments array now contains pointers to each token in the
|
||||
// comment block.
|
||||
$requiredColumn = strpos($tokens[$stackPtr]['content'], '*');
|
||||
$requiredColumn += $tokens[$stackPtr]['column'];
|
||||
|
||||
foreach ($comments as $commentPointer) {
|
||||
// Check the spacing after each asterisk.
|
||||
$content = $tokens[$commentPointer]['content'];
|
||||
$firstChar = substr($content, 0, 1);
|
||||
$lastChar = substr($content, -1);
|
||||
if ($firstChar !== '/' && $lastChar !== '/') {
|
||||
$matches = array();
|
||||
preg_match('|^(\s+)?\*(\s+)?@|', $content, $matches);
|
||||
if (empty($matches) === false) {
|
||||
if (isset($matches[2]) === false) {
|
||||
$error = 'Expected 1 space between asterisk and tag; 0 found';
|
||||
$phpcsFile->addError($error, $commentPointer, 'NoSpaceBeforeTag');
|
||||
} else {
|
||||
$length = strlen($matches[2]);
|
||||
if ($length !== 1) {
|
||||
$error = 'Expected 1 space between asterisk and tag; %s found';
|
||||
$data = array($length);
|
||||
$phpcsFile->addError($error, $commentPointer, 'SpaceBeforeTag', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
// Check the alignment of each asterisk.
|
||||
$currentColumn = strpos($content, '*');
|
||||
$currentColumn += $tokens[$commentPointer]['column'];
|
||||
|
||||
if ($currentColumn === $requiredColumn) {
|
||||
// Star is aligned correctly.
|
||||
continue;
|
||||
}
|
||||
|
||||
$error = 'Expected %s space(s) before asterisk; %s found';
|
||||
$data = array(
|
||||
($requiredColumn - 1),
|
||||
($currentColumn - 1),
|
||||
);
|
||||
$phpcsFile->addError($error, $commentPointer, 'SpaceBeforeAsterisk', $data);
|
||||
}//end foreach
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_EmptyCatchCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_EmptyCatchCommentSniff.
|
||||
*
|
||||
* Checks for empty Catch clause. Catch clause must at least have comment
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_EmptyCatchCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_CATCH);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document.
|
||||
* @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();
|
||||
|
||||
$scopeStart = $tokens[$stackPtr]['scope_opener'];
|
||||
$firstContent = $phpcsFile->findNext(T_WHITESPACE, ($scopeStart + 1), $tokens[$stackPtr]['scope_closer'], true);
|
||||
|
||||
if ($firstContent === false) {
|
||||
$error = 'Empty CATCH statement must have a comment to explain why the exception is not handled';
|
||||
$phpcsFile->addError($error, $scopeStart, 'Missing');
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,609 @@
|
||||
<?php
|
||||
/**
|
||||
* Parses and verifies the file doc comment.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) {
|
||||
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and verifies the file doc comment.
|
||||
*
|
||||
* Verifies that :
|
||||
* <ul>
|
||||
* <li>A file doc comment exists.</li>
|
||||
* <li>There is no blank line between the open tag and the file comment.</li>
|
||||
* <li>Short description ends with a full stop.</li>
|
||||
* <li>There is a blank line after the short description.</li>
|
||||
* <li>Each paragraph of the long description ends with a full stop.</li>
|
||||
* <li>There is a blank line between the description and the tags.</li>
|
||||
* <li>Check the order, indentation and content of each tag.</li>
|
||||
* <li>There is exactly one blank line after the file comment.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
class Squiz_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* A list of tokenizers this sniff supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $supportedTokenizers = array(
|
||||
'PHP',
|
||||
'JS',
|
||||
);
|
||||
|
||||
/**
|
||||
* The header comment parser for the current file.
|
||||
*
|
||||
* @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser
|
||||
*/
|
||||
protected $commentParser = null;
|
||||
|
||||
/**
|
||||
* The current PHP_CodeSniffer_File object we are processing.
|
||||
*
|
||||
* @var PHP_CodeSniffer_File
|
||||
*/
|
||||
protected $currentFile = null;
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_OPEN_TAG);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
$errorToken = ($stackPtr + 1);
|
||||
if (isset($tokens[$errorToken]) === false) {
|
||||
$errorToken--;
|
||||
}
|
||||
|
||||
// Find the next non whitespace token.
|
||||
$commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
|
||||
|
||||
if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) {
|
||||
// We are only interested if this is the first open tag.
|
||||
return;
|
||||
} else if ($tokens[$commentStart]['code'] === T_COMMENT) {
|
||||
$phpcsFile->addError('You must use "/**" style comments for a file comment', $errorToken, 'WrongStyle');
|
||||
return;
|
||||
} else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT) {
|
||||
$phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the header comment docblock.
|
||||
$commentEnd = ($phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 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_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', $errorToken, 'Missing');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No blank line between the open tag and the file comment.
|
||||
$blankLineBefore = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, false, $phpcsFile->eolChar);
|
||||
if ($blankLineBefore !== false && $blankLineBefore < $commentStart) {
|
||||
$error = 'Extra newline found after the open tag';
|
||||
$phpcsFile->addError($error, $stackPtr, 'SpacingAfterOpen');
|
||||
}
|
||||
|
||||
// Exactly one blank line after the file comment.
|
||||
$nextTokenStart = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), null, true);
|
||||
if ($nextTokenStart !== false) {
|
||||
$blankLineAfter = 0;
|
||||
for ($i = ($commentEnd + 1); $i < $nextTokenStart; $i++) {
|
||||
if ($tokens[$i]['code'] === T_WHITESPACE && $tokens[$i]['content'] === $phpcsFile->eolChar) {
|
||||
$blankLineAfter++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($blankLineAfter !== 2) {
|
||||
$error = 'There must be exactly one blank line after the file comment';
|
||||
$phpcsFile->addError($error, ($commentEnd + 1), 'SpacingAfterComment');
|
||||
}
|
||||
}
|
||||
|
||||
$commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));
|
||||
|
||||
// Parse the header comment docblock.
|
||||
try {
|
||||
$this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($commentString, $phpcsFile);
|
||||
$this->commentParser->parse();
|
||||
} catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
|
||||
$line = ($e->getLineWithinComment() + $commentStart);
|
||||
$phpcsFile->addError($e->getMessage(), $line, 'Exception');
|
||||
return;
|
||||
}
|
||||
|
||||
$comment = $this->commentParser->getComment();
|
||||
if (is_null($comment) === true) {
|
||||
$error = 'File doc comment is empty';
|
||||
$phpcsFile->addError($error, $commentStart, 'Empty');
|
||||
return;
|
||||
}
|
||||
|
||||
// The first line of the comment should just be the /** code.
|
||||
$eolPos = strpos($commentString, $phpcsFile->eolChar);
|
||||
$firstLine = substr($commentString, 0, $eolPos);
|
||||
if ($firstLine !== '/**') {
|
||||
$error = 'The open comment tag must be the only content on the line';
|
||||
$phpcsFile->addError($error, $commentStart, 'ContentAfterOpen');
|
||||
}
|
||||
|
||||
// No extra newline before short description.
|
||||
$short = $comment->getShortComment();
|
||||
$newlineCount = 0;
|
||||
$newlineSpan = strspn($short, $phpcsFile->eolChar);
|
||||
if ($short !== '' && $newlineSpan > 0) {
|
||||
$error = 'Extra newline(s) found before file comment short description';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort');
|
||||
}
|
||||
|
||||
$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 file comment';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween');
|
||||
}
|
||||
|
||||
$newlineCount += $newlineBetween;
|
||||
|
||||
$testLong = trim($long);
|
||||
if (preg_match('|[A-Z]|', $testLong[0]) === 0) {
|
||||
$error = 'File comment long description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCaptial');
|
||||
}
|
||||
}//end if
|
||||
|
||||
// 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->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags');
|
||||
$short = rtrim($short, $phpcsFile->eolChar.' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Short description must be single line and end with a full stop.
|
||||
$testShort = trim($short);
|
||||
$lastChar = $testShort[(strlen($testShort) - 1)];
|
||||
if (substr_count($testShort, $phpcsFile->eolChar) !== 0) {
|
||||
$error = 'File comment short description must be on a single line';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine');
|
||||
}
|
||||
|
||||
if (preg_match('|[A-Z]|', $testShort[0]) === 0) {
|
||||
$error = 'File comment short description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital');
|
||||
}
|
||||
|
||||
if ($lastChar !== '.') {
|
||||
$error = 'File comment short description must end with a full stop';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop');
|
||||
}
|
||||
|
||||
// Check for unknown/deprecated tags.
|
||||
$unknownTags = $this->commentParser->getUnknown();
|
||||
foreach ($unknownTags as $errorTag) {
|
||||
// Unknown tags are not parsed, do not process further.
|
||||
$error = '@%s tag is not allowed in file comment';
|
||||
$data = array($errorTag['tag']);
|
||||
$phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data);
|
||||
}
|
||||
|
||||
// Check each tag.
|
||||
$this->processTags($commentStart, $commentEnd);
|
||||
|
||||
// The last content should be a newline and the content before
|
||||
// that should not be blank. If there is more blank space
|
||||
// then they have additional blank lines at the end of the comment.
|
||||
$words = $this->commentParser->getWords();
|
||||
$lastPos = (count($words) - 1);
|
||||
if (trim($words[($lastPos - 1)]) !== ''
|
||||
|| strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false
|
||||
|| trim($words[($lastPos - 2)]) === ''
|
||||
) {
|
||||
$error = 'Additional blank lines found at end of file comment';
|
||||
$this->currentFile->addError($error, $commentEnd, 'SpacingAfter');
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
/**
|
||||
* Processes each required or optional tag.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
* @param int $commentEnd The position in the stack where the comment ended.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processTags($commentStart, $commentEnd)
|
||||
{
|
||||
// Required tags in correct order.
|
||||
$tags = array(
|
||||
'package' => 'precedes @subpackage',
|
||||
'subpackage' => 'follows @package',
|
||||
'author' => 'follows @subpackage',
|
||||
'copyright' => 'follows @author',
|
||||
'license' => 'follows @copyright',
|
||||
);
|
||||
|
||||
$foundTags = $this->commentParser->getTagOrders();
|
||||
$errorPos = 0;
|
||||
$orderIndex = 0;
|
||||
$longestTag = 0;
|
||||
$indentation = array();
|
||||
foreach ($tags as $tag => $orderText) {
|
||||
|
||||
// Required tag missing.
|
||||
if (in_array($tag, $foundTags) === false) {
|
||||
$error = 'Missing @%s tag in file comment';
|
||||
$data = array($tag);
|
||||
$this->currentFile->addError($error, $commentEnd, 'MissingTag', $data);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the line number for current tag.
|
||||
$tagName = ucfirst($tag);
|
||||
if ($tagName === 'Author' || $tagName === 'Copyright') {
|
||||
// These tags are different because they return an array.
|
||||
$tagName .= 's';
|
||||
}
|
||||
|
||||
// Work out the line number for this tag.
|
||||
$getMethod = 'get'.$tagName;
|
||||
$tagElement = $this->commentParser->$getMethod();
|
||||
if (is_null($tagElement) === true || empty($tagElement) === true) {
|
||||
continue;
|
||||
} else if (is_array($tagElement) === true && empty($tagElement) === false) {
|
||||
$tagElement = $tagElement[0];
|
||||
}
|
||||
|
||||
$errorPos = ($commentStart + $tagElement->getLine());
|
||||
|
||||
// Make sure there is no duplicate tag.
|
||||
$foundIndexes = array_keys($foundTags, $tag);
|
||||
if (count($foundIndexes) > 1) {
|
||||
$error = 'Only 1 @%s tag is allowed in file comment';
|
||||
$data = array($tag);
|
||||
$this->currentFile->addError($error, $errorPos, 'DuplicateTag', $data);
|
||||
}
|
||||
|
||||
// Check tag order.
|
||||
if ($foundIndexes[0] > $orderIndex) {
|
||||
$orderIndex = $foundIndexes[0];
|
||||
} else {
|
||||
$error = 'The @%s tag is in the wrong order; the tag %s';
|
||||
$data = array(
|
||||
$tag,
|
||||
$orderText,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'TagOrder', $data);
|
||||
}
|
||||
|
||||
// Store the indentation of each tag.
|
||||
$len = strlen($tag);
|
||||
if ($len > $longestTag) {
|
||||
$longestTag = $len;
|
||||
}
|
||||
|
||||
$indentation[] = array(
|
||||
'tag' => $tag,
|
||||
'errorPos' => $errorPos,
|
||||
'space' => $this->getIndentation($tag, $tagElement),
|
||||
);
|
||||
|
||||
$method = 'process'.$tagName;
|
||||
if (method_exists($this, $method) === true) {
|
||||
// Process each tag if a method is defined.
|
||||
call_user_func(array($this, $method), $errorPos);
|
||||
} else {
|
||||
$tagElement->process($this->currentFile, $commentStart, 'file');
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
// Check tag indentation.
|
||||
foreach ($indentation as $indentInfo) {
|
||||
$tagName = ucfirst($indentInfo['tag']);
|
||||
if ($tagName === 'Author') {
|
||||
$tagName .= 's';
|
||||
}
|
||||
|
||||
if ($indentInfo['space'] !== 0 && $indentInfo['space'] !== ($longestTag + 1)) {
|
||||
$expected = ($longestTag - strlen($indentInfo['tag']) + 1);
|
||||
$space = ($indentInfo['space'] - strlen($indentInfo['tag']));
|
||||
$error = '@%s tag comment indented incorrectly; expected %s spaces but found %s';
|
||||
$data = array(
|
||||
$indentInfo['tag'],
|
||||
$expected,
|
||||
$space,
|
||||
);
|
||||
$this->currentFile->addError($error, $indentInfo['errorPos'], 'TagIndent', $data);
|
||||
}
|
||||
}
|
||||
|
||||
}//end processTags()
|
||||
|
||||
|
||||
/**
|
||||
* Get the indentation information of each tag.
|
||||
*
|
||||
* @param string $tagName The name of the doc comment element.
|
||||
* @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment element.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function getIndentation($tagName, $tagElement)
|
||||
{
|
||||
if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) {
|
||||
if ($tagElement->getContent() !== '') {
|
||||
return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' '));
|
||||
}
|
||||
} else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) {
|
||||
if ($tagElement->getValue() !== '') {
|
||||
return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' '));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}//end getIndentation()
|
||||
|
||||
|
||||
/**
|
||||
* The package name must be camel-cased.
|
||||
*
|
||||
* @param int $errorPos The line number where the error occurs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processPackage($errorPos)
|
||||
{
|
||||
$package = $this->commentParser->getPackage();
|
||||
if ($package !== null) {
|
||||
$content = $package->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Content missing for @package tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingPackage');
|
||||
} else if (PHP_CodeSniffer::isUnderscoreName($content) !== true) {
|
||||
// Package name must be properly camel-cased.
|
||||
$nameBits = explode('_', str_replace(' ', '', $content));
|
||||
$firstBit = array_shift($nameBits);
|
||||
$newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_';
|
||||
foreach ($nameBits as $bit) {
|
||||
$newName .= strtoupper($bit{0}).substr($bit, 1).'_';
|
||||
}
|
||||
|
||||
$error = 'Package name "%s" is not valid; consider "%s" instead';
|
||||
$data = array(
|
||||
$content,
|
||||
trim($newName, '_'),
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectPackage', $data);
|
||||
} else if (strpos($content, 'Squiz') === 0) {
|
||||
// Package name must not start with Squiz.
|
||||
$newName = substr($content, 5);
|
||||
$error = 'Package name "%s" is not valid; consider "%s" instead';
|
||||
$data = array(
|
||||
$content,
|
||||
$newName,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'SquizPackage', $data);
|
||||
}
|
||||
}
|
||||
|
||||
}//end processPackage()
|
||||
|
||||
|
||||
/**
|
||||
* The subpackage name must be camel-cased.
|
||||
*
|
||||
* @param int $errorPos The line number where the error occurs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processSubpackage($errorPos)
|
||||
{
|
||||
$subpackage = $this->commentParser->getSubpackage();
|
||||
if ($subpackage !== null) {
|
||||
$content = $subpackage->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Content missing for @subpackage tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingSubpackage');
|
||||
} else if (PHP_CodeSniffer::isUnderscoreName($content) !== true) {
|
||||
// Subpackage name must be properly camel-cased.
|
||||
$nameBits = explode('_', $content);
|
||||
$firstBit = array_shift($nameBits);
|
||||
$newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_';
|
||||
foreach ($nameBits as $bit) {
|
||||
$newName .= strtoupper($bit{0}).substr($bit, 1).'_';
|
||||
}
|
||||
|
||||
$error = 'Subpackage name "%s" is not valid; consider "%s" instead';
|
||||
$data = array(
|
||||
$content,
|
||||
trim($newName, '_'),
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectSubpackage', $data);
|
||||
}
|
||||
}
|
||||
|
||||
}//end processSubpackage()
|
||||
|
||||
|
||||
/**
|
||||
* Author tag must be 'Squiz Pty Ltd <mysource4@squiz.net>'.
|
||||
*
|
||||
* @param int $errorPos The line number where the error occurs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processAuthors($errorPos)
|
||||
{
|
||||
$authors = $this->commentParser->getAuthors();
|
||||
if (empty($authors) === false) {
|
||||
$author = $authors[0];
|
||||
$content = $author->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Content missing for @author tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingAuthor');
|
||||
} else if ($content !== 'Squiz Pty Ltd <products@squiz.net>') {
|
||||
$error = 'Expected "Squiz Pty Ltd <products@squiz.net>" for author tag';
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectAuthor');
|
||||
}
|
||||
}
|
||||
|
||||
}//end processAuthors()
|
||||
|
||||
|
||||
/**
|
||||
* Copyright tag must be in the form '2006-YYYY Squiz Pty Ltd (ABN 77 084 670 600)'.
|
||||
*
|
||||
* @param int $errorPos The line number where the error occurs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processCopyrights($errorPos)
|
||||
{
|
||||
$copyrights = $this->commentParser->getCopyrights();
|
||||
$copyright = $copyrights[0];
|
||||
|
||||
if ($copyright !== null) {
|
||||
$content = $copyright->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Content missing for @copyright tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingCopyright');
|
||||
|
||||
} else if (preg_match('/^([0-9]{4})(-[0-9]{4})? (Squiz Pty Ltd \(ACN 084 670 600\))$/', $content) === 0) {
|
||||
$error = 'Expected "xxxx-xxxx Squiz Pty Ltd (ACN 084 670 600)" for copyright declaration';
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectCopyright');
|
||||
}
|
||||
}
|
||||
|
||||
}//end processCopyrights()
|
||||
|
||||
|
||||
/**
|
||||
* License tag must be 'http://matrix.squiz.net/licence Squiz.Net Open Source Licence'.
|
||||
*
|
||||
* @param int $errorPos The line number where the error occurs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processLicense($errorPos)
|
||||
{
|
||||
$license = $this->commentParser->getLicense();
|
||||
if ($license !== null) {
|
||||
$url = $license->getValue();
|
||||
$content = $license->getComment();
|
||||
if (empty($url) === true && empty($content) === true) {
|
||||
$error = 'Content missing for @license tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingLicense');
|
||||
} else {
|
||||
// Check for license URL.
|
||||
if (empty($url) === true) {
|
||||
$error = 'License URL missing for @license tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingLinceseURL');
|
||||
} else if ($url !== 'http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt') {
|
||||
$error = 'Expected "http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt" for license URL';
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectLicenseURL');
|
||||
}
|
||||
|
||||
// Check for license name.
|
||||
if (empty($content) === true) {
|
||||
$error = 'License name missing for @license tag in file comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingLinceseName');
|
||||
} else if ($content !== 'GPLv2') {
|
||||
$error = 'Expected "GPLv2" for license name';
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectLicenseName');
|
||||
}
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
}//end processLicense()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,806 @@
|
||||
<?php
|
||||
/**
|
||||
* Parses and verifies the doc comments for functions.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) {
|
||||
$error = 'Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found';
|
||||
throw new PHP_CodeSniffer_Exception($error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and verifies the doc comments for functions.
|
||||
*
|
||||
* Verifies that :
|
||||
* <ul>
|
||||
* <li>A comment exists</li>
|
||||
* <li>There is a blank newline after the short description</li>
|
||||
* <li>There is a blank newline between the long and short description</li>
|
||||
* <li>There is a blank newline between the long description and tags</li>
|
||||
* <li>Parameter names represent those in the method</li>
|
||||
* <li>Parameter comments are in the correct order</li>
|
||||
* <li>Parameter comments are complete</li>
|
||||
* <li>A type hint is provided for array and custom class</li>
|
||||
* <li>Type hint matches the actual variable/class type</li>
|
||||
* <li>A blank line is present before the first and after the last parameter</li>
|
||||
* <li>A return type exists</li>
|
||||
* <li>Any throw tag must have a comment</li>
|
||||
* <li>The tag order and indentation are correct</li>
|
||||
* </ul>
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_FunctionCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* The name of the method that we are currently processing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_methodName = '';
|
||||
|
||||
/**
|
||||
* The position in the stack where the fucntion token was found.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_functionToken = null;
|
||||
|
||||
/**
|
||||
* The position in the stack where the class token was found.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_classToken = null;
|
||||
|
||||
/**
|
||||
* The index of the current tag we are processing.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $_tagIndex = 0;
|
||||
|
||||
/**
|
||||
* The function comment parser for the current method.
|
||||
*
|
||||
* @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser
|
||||
*/
|
||||
protected $commentParser = null;
|
||||
|
||||
/**
|
||||
* The current PHP_CodeSniffer_File object we are processing.
|
||||
*
|
||||
* @var PHP_CodeSniffer_File
|
||||
*/
|
||||
protected $currentFile = null;
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_FUNCTION);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
|
||||
$find = array(
|
||||
T_COMMENT,
|
||||
T_DOC_COMMENT,
|
||||
T_CLASS,
|
||||
T_FUNCTION,
|
||||
T_OPEN_TAG,
|
||||
);
|
||||
|
||||
$commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1));
|
||||
|
||||
if ($commentEnd === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// The function might actually be missing a comment, and this last comment
|
||||
// found is just commenting a bit of code on a line. So if it is not the
|
||||
// only thing on the line, assume we found nothing.
|
||||
$prevContent = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, $commentEnd);
|
||||
if ($tokens[$commentEnd]['line'] === $tokens[$commentEnd]['line']) {
|
||||
$error = 'Missing function doc comment';
|
||||
$phpcsFile->addError($error, $stackPtr, 'Missing');
|
||||
} else {
|
||||
$error = 'You must use "/**" style comments for a function comment';
|
||||
$phpcsFile->addError($error, $stackPtr, 'WrongStyle');
|
||||
}
|
||||
return;
|
||||
} else if ($code !== T_DOC_COMMENT) {
|
||||
$error = 'Missing function doc comment';
|
||||
$phpcsFile->addError($error, $stackPtr, 'Missing');
|
||||
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, 'Missing');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_functionToken = $stackPtr;
|
||||
|
||||
$this->_classToken = null;
|
||||
foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) {
|
||||
if ($condition === T_CLASS || $condition === T_INTERFACE) {
|
||||
$this->_classToken = $condPtr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the first doc comment.
|
||||
$commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1);
|
||||
$commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));
|
||||
$this->_methodName = $phpcsFile->getDeclarationName($stackPtr);
|
||||
|
||||
try {
|
||||
$this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($commentString, $phpcsFile);
|
||||
$this->commentParser->parse();
|
||||
} catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
|
||||
$line = ($e->getLineWithinComment() + $commentStart);
|
||||
$phpcsFile->addError($e->getMessage(), $line, 'FailedParse');
|
||||
return;
|
||||
}
|
||||
|
||||
$comment = $this->commentParser->getComment();
|
||||
if (is_null($comment) === true) {
|
||||
$error = 'Function doc comment is empty';
|
||||
$phpcsFile->addError($error, $commentStart, 'Empty');
|
||||
return;
|
||||
}
|
||||
|
||||
// The first line of the comment should just be the /** code.
|
||||
$eolPos = strpos($commentString, $phpcsFile->eolChar);
|
||||
$firstLine = substr($commentString, 0, $eolPos);
|
||||
if ($firstLine !== '/**') {
|
||||
$error = 'The open comment tag must be the only content on the line';
|
||||
$phpcsFile->addError($error, $commentStart, 'ContentAfterOpen');
|
||||
}
|
||||
|
||||
$this->processParams($commentStart, $commentEnd);
|
||||
$this->processSees($commentStart);
|
||||
$this->processReturn($commentStart, $commentEnd);
|
||||
$this->processThrows($commentStart);
|
||||
|
||||
// Check for a comment description.
|
||||
$short = $comment->getShortComment();
|
||||
if (trim($short) === '') {
|
||||
$error = 'Missing short description in function doc comment';
|
||||
$phpcsFile->addError($error, $commentStart, 'MissingShort');
|
||||
return;
|
||||
}
|
||||
|
||||
// No extra newline before short description.
|
||||
$newlineCount = 0;
|
||||
$newlineSpan = strspn($short, $phpcsFile->eolChar);
|
||||
if ($short !== '' && $newlineSpan > 0) {
|
||||
$error = 'Extra newline(s) found before function comment short description';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort');
|
||||
}
|
||||
|
||||
$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), 'SpacingBetween');
|
||||
}
|
||||
|
||||
$newlineCount += $newlineBetween;
|
||||
|
||||
$testLong = trim($long);
|
||||
if (preg_match('|[A-Z]|', $testLong[0]) === 0) {
|
||||
$error = 'Function comment long description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital');
|
||||
}
|
||||
}//end if
|
||||
|
||||
// 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->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags');
|
||||
$short = rtrim($short, $phpcsFile->eolChar.' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Short description must be single line and end with a full stop.
|
||||
$testShort = trim($short);
|
||||
$lastChar = $testShort[(strlen($testShort) - 1)];
|
||||
if (substr_count($testShort, $phpcsFile->eolChar) !== 0) {
|
||||
$error = 'Function comment short description must be on a single line';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine');
|
||||
}
|
||||
|
||||
if (preg_match('|[A-Z]|', $testShort[0]) === 0) {
|
||||
$error = 'Function comment short description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital');
|
||||
}
|
||||
|
||||
if ($lastChar !== '.') {
|
||||
$error = 'Function comment short description must end with a full stop';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop');
|
||||
}
|
||||
|
||||
// Check for unknown/deprecated tags.
|
||||
$this->processUnknownTags($commentStart, $commentEnd);
|
||||
|
||||
// The last content should be a newline and the content before
|
||||
// that should not be blank. If there is more blank space
|
||||
// then they have additional blank lines at the end of the comment.
|
||||
$words = $this->commentParser->getWords();
|
||||
$lastPos = (count($words) - 1);
|
||||
if (trim($words[($lastPos - 1)]) !== ''
|
||||
|| strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false
|
||||
|| trim($words[($lastPos - 2)]) === ''
|
||||
) {
|
||||
$error = 'Additional blank lines found at end of function comment';
|
||||
$this->currentFile->addError($error, $commentEnd, 'SpacingAfter');
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
/**
|
||||
* Process the see tags.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processSees($commentStart)
|
||||
{
|
||||
$sees = $this->commentParser->getSees();
|
||||
if (empty($sees) === false) {
|
||||
$tagOrder = $this->commentParser->getTagOrders();
|
||||
$index = array_keys($this->commentParser->getTagOrders(), 'see');
|
||||
foreach ($sees as $i => $see) {
|
||||
$errorPos = ($commentStart + $see->getLine());
|
||||
$since = array_keys($tagOrder, 'since');
|
||||
if (count($since) === 1 && $this->_tagIndex !== 0) {
|
||||
$this->_tagIndex++;
|
||||
if ($index[$i] !== $this->_tagIndex) {
|
||||
$error = 'The @see tag is in the wrong order; the tag precedes @return';
|
||||
$this->currentFile->addError($error, $errorPos, 'SeeOrder');
|
||||
}
|
||||
}
|
||||
|
||||
$content = $see->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Content missing for @see tag in function comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'EmptySee');
|
||||
continue;
|
||||
}
|
||||
|
||||
$spacing = substr_count($see->getWhitespaceBeforeContent(), ' ');
|
||||
if ($spacing !== 4) {
|
||||
$error = '@see tag indented incorrectly; expected 4 spaces but found %s';
|
||||
$data = array($spacing);
|
||||
$this->currentFile->addError($error, $errorPos, 'SeeIndent', $data);
|
||||
}
|
||||
}//end foreach
|
||||
}//end if
|
||||
|
||||
}//end processSees()
|
||||
|
||||
|
||||
/**
|
||||
* Process the return comment of this function comment.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
* @param int $commentEnd The position in the stack where the comment ended.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processReturn($commentStart, $commentEnd)
|
||||
{
|
||||
// Skip constructor and destructor.
|
||||
$className = '';
|
||||
if ($this->_classToken !== null) {
|
||||
$className = $this->currentFile->getDeclarationName($this->_classToken);
|
||||
$className = strtolower(ltrim($className, '_'));
|
||||
}
|
||||
|
||||
$methodName = strtolower(ltrim($this->_methodName, '_'));
|
||||
$isSpecialMethod = ($this->_methodName === '__construct' || $this->_methodName === '__destruct');
|
||||
$return = $this->commentParser->getReturn();
|
||||
|
||||
if ($isSpecialMethod === false && $methodName !== $className) {
|
||||
if ($return !== null) {
|
||||
$tagOrder = $this->commentParser->getTagOrders();
|
||||
$index = array_keys($tagOrder, 'return');
|
||||
$errorPos = ($commentStart + $return->getLine());
|
||||
$content = trim($return->getRawContent());
|
||||
|
||||
if (count($index) > 1) {
|
||||
$error = 'Only 1 @return tag is allowed in function comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'DuplicateReturn');
|
||||
return;
|
||||
}
|
||||
|
||||
$since = array_keys($tagOrder, 'since');
|
||||
if (count($since) === 1 && $this->_tagIndex !== 0) {
|
||||
$this->_tagIndex++;
|
||||
if ($index[0] !== $this->_tagIndex) {
|
||||
$error = 'The @return tag is in the wrong order; the tag follows @see (if used)';
|
||||
$this->currentFile->addError($error, $errorPos, 'ReturnOrder');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($content) === true) {
|
||||
$error = 'Return type missing for @return tag in function comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingReturnType');
|
||||
} else {
|
||||
// Check return type (can be multiple, separated by '|').
|
||||
$typeNames = explode('|', $content);
|
||||
$suggestedNames = array();
|
||||
foreach ($typeNames as $i => $typeName) {
|
||||
$suggestedName = PHP_CodeSniffer::suggestType($typeName);
|
||||
if (in_array($suggestedName, $suggestedNames) === false) {
|
||||
$suggestedNames[] = $suggestedName;
|
||||
}
|
||||
}
|
||||
|
||||
$suggestedType = implode('|', $suggestedNames);
|
||||
if ($content !== $suggestedType) {
|
||||
$error = 'Function return type "%s" is invalid';
|
||||
$data = array($content);
|
||||
$this->currentFile->addError($error, $errorPos, 'InvalidReturn', $data);
|
||||
}
|
||||
|
||||
$tokens = $this->currentFile->getTokens();
|
||||
|
||||
// If the return type is void, make sure there is
|
||||
// no return statement in the function.
|
||||
if ($content === 'void') {
|
||||
if (isset($tokens[$this->_functionToken]['scope_closer']) === true) {
|
||||
$endToken = $tokens[$this->_functionToken]['scope_closer'];
|
||||
$returnToken = $this->currentFile->findNext(T_RETURN, $this->_functionToken, $endToken);
|
||||
if ($returnToken !== false) {
|
||||
// If the function is not returning anything, just
|
||||
// exiting, then there is no problem.
|
||||
$semicolon = $this->currentFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
|
||||
if ($tokens[$semicolon]['code'] !== T_SEMICOLON) {
|
||||
$error = 'Function return type is void, but function contains return statement';
|
||||
$this->currentFile->addError($error, $errorPos, 'InvalidReturnVoid');
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ($content !== 'mixed') {
|
||||
// If return type is not void, there needs to be a
|
||||
// returns statement somewhere in the function that
|
||||
// returns something.
|
||||
if (isset($tokens[$this->_functionToken]['scope_closer']) === true) {
|
||||
$endToken = $tokens[$this->_functionToken]['scope_closer'];
|
||||
$returnToken = $this->currentFile->findNext(T_RETURN, $this->_functionToken, $endToken);
|
||||
if ($returnToken === false) {
|
||||
$error = 'Function return type is not void, but function has no return statement';
|
||||
$this->currentFile->addError($error, $errorPos, 'InvalidNoReturn');
|
||||
} else {
|
||||
$semicolon = $this->currentFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
|
||||
if ($tokens[$semicolon]['code'] === T_SEMICOLON) {
|
||||
$error = 'Function return type is not void, but function is returning void here';
|
||||
$this->currentFile->addError($error, $returnToken, 'InvalidReturnNotVoid');
|
||||
}
|
||||
}
|
||||
}
|
||||
}//end if
|
||||
|
||||
$spacing = substr_count($return->getWhitespaceBeforeValue(), ' ');
|
||||
if ($spacing !== 1) {
|
||||
$error = '@return tag indented incorrectly; expected 1 space but found %s';
|
||||
$data = array($spacing);
|
||||
$this->currentFile->addError($error, $errorPos, 'ReturnIndent', $data);
|
||||
}
|
||||
}//end if
|
||||
} else {
|
||||
$error = 'Missing @return tag in function comment';
|
||||
$this->currentFile->addError($error, $commentEnd, 'MissingReturn');
|
||||
}//end if
|
||||
|
||||
} else {
|
||||
// No return tag for constructor and destructor.
|
||||
if ($return !== null) {
|
||||
$errorPos = ($commentStart + $return->getLine());
|
||||
$error = '@return tag is not required for constructor and destructor';
|
||||
$this->currentFile->addError($error, $errorPos, 'ReturnNotRequired');
|
||||
}
|
||||
}//end if
|
||||
|
||||
}//end processReturn()
|
||||
|
||||
|
||||
/**
|
||||
* Process any throw tags that this function comment has.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processThrows($commentStart)
|
||||
{
|
||||
if (count($this->commentParser->getThrows()) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tagOrder = $this->commentParser->getTagOrders();
|
||||
$index = array_keys($this->commentParser->getTagOrders(), 'throws');
|
||||
|
||||
foreach ($this->commentParser->getThrows() as $i => $throw) {
|
||||
$exception = $throw->getValue();
|
||||
$content = trim($throw->getComment());
|
||||
$errorPos = ($commentStart + $throw->getLine());
|
||||
if (empty($exception) === true) {
|
||||
$error = 'Exception type and comment missing for @throws tag in function comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'InvalidThrows');
|
||||
} else if (empty($content) === true) {
|
||||
$error = 'Comment missing for @throws tag in function comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'EmptyThrows');
|
||||
} else {
|
||||
// Starts with a capital letter and ends with a fullstop.
|
||||
$firstChar = $content{0};
|
||||
if (strtoupper($firstChar) !== $firstChar) {
|
||||
$error = '@throws tag comment must start with a capital letter';
|
||||
$this->currentFile->addError($error, $errorPos, 'ThrowsNotCapital');
|
||||
}
|
||||
|
||||
$lastChar = $content[(strlen($content) - 1)];
|
||||
if ($lastChar !== '.') {
|
||||
$error = '@throws tag comment must end with a full stop';
|
||||
$this->currentFile->addError($error, $errorPos, 'ThrowsNoFullStop');
|
||||
}
|
||||
}
|
||||
|
||||
$since = array_keys($tagOrder, 'since');
|
||||
if (count($since) === 1 && $this->_tagIndex !== 0) {
|
||||
$this->_tagIndex++;
|
||||
if ($index[$i] !== $this->_tagIndex) {
|
||||
$error = 'The @throws tag is in the wrong order; the tag follows @return';
|
||||
$this->currentFile->addError($error, $errorPos, 'ThrowsOrder');
|
||||
}
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
}//end processThrows()
|
||||
|
||||
|
||||
/**
|
||||
* Process the function parameter comments.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where
|
||||
* the comment started.
|
||||
* @param int $commentEnd The position in the stack where
|
||||
* the comment ended.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processParams($commentStart, $commentEnd)
|
||||
{
|
||||
$realParams = $this->currentFile->getMethodParameters($this->_functionToken);
|
||||
$params = $this->commentParser->getParams();
|
||||
$foundParams = array();
|
||||
|
||||
if (empty($params) === false) {
|
||||
|
||||
if (substr_count($params[(count($params) - 1)]->getWhitespaceAfter(), $this->currentFile->eolChar) !== 2) {
|
||||
$error = 'Last parameter comment requires a blank newline after it';
|
||||
$errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart);
|
||||
$this->currentFile->addError($error, $errorPos, 'SpacingAfterParams');
|
||||
}
|
||||
|
||||
// Parameters must appear immediately after the comment.
|
||||
if ($params[0]->getOrder() !== 2) {
|
||||
$error = 'Parameters must appear immediately after the comment';
|
||||
$errorPos = ($params[0]->getLine() + $commentStart);
|
||||
$this->currentFile->addError($error, $errorPos, 'SpacingBeforeParams');
|
||||
}
|
||||
|
||||
$previousParam = null;
|
||||
$spaceBeforeVar = 10000;
|
||||
$spaceBeforeComment = 10000;
|
||||
$longestType = 0;
|
||||
$longestVar = 0;
|
||||
|
||||
foreach ($params as $param) {
|
||||
|
||||
$paramComment = trim($param->getComment());
|
||||
$errorPos = ($param->getLine() + $commentStart);
|
||||
|
||||
// Make sure that there is only one space before the var type.
|
||||
if ($param->getWhitespaceBeforeType() !== ' ') {
|
||||
$error = 'Expected 1 space before variable type';
|
||||
$this->currentFile->addError($error, $errorPos, 'SpacingBeforeParamType');
|
||||
}
|
||||
|
||||
$spaceCount = substr_count($param->getWhitespaceBeforeVarName(), ' ');
|
||||
if ($spaceCount < $spaceBeforeVar) {
|
||||
$spaceBeforeVar = $spaceCount;
|
||||
$longestType = $errorPos;
|
||||
}
|
||||
|
||||
$spaceCount = substr_count($param->getWhitespaceBeforeComment(), ' ');
|
||||
|
||||
if ($spaceCount < $spaceBeforeComment && $paramComment !== '') {
|
||||
$spaceBeforeComment = $spaceCount;
|
||||
$longestVar = $errorPos;
|
||||
}
|
||||
|
||||
// Make sure they are in the correct order, and have the correct name.
|
||||
$pos = $param->getPosition();
|
||||
$paramName = ($param->getVarName() !== '') ? $param->getVarName() : '[ UNKNOWN ]';
|
||||
|
||||
if ($previousParam !== null) {
|
||||
$previousName = ($previousParam->getVarName() !== '') ? $previousParam->getVarName() : 'UNKNOWN';
|
||||
|
||||
// Check to see if the parameters align properly.
|
||||
if ($param->alignsVariableWith($previousParam) === false) {
|
||||
$error = 'The variable names for parameters %s (%s) and %s (%s) do not align';
|
||||
$data = array(
|
||||
$previousName,
|
||||
($pos - 1),
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'ParameterNamesNotAligned', $data);
|
||||
}
|
||||
|
||||
if ($param->alignsCommentWith($previousParam) === false) {
|
||||
$error = 'The comments for parameters %s (%s) and %s (%s) do not align';
|
||||
$data = array(
|
||||
$previousName,
|
||||
($pos - 1),
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'ParameterCommentsNotAligned', $data);
|
||||
}
|
||||
}
|
||||
|
||||
// Variable must be one of the supported standard type.
|
||||
$typeNames = explode('|', $param->getType());
|
||||
foreach ($typeNames as $typeName) {
|
||||
$suggestedName = PHP_CodeSniffer::suggestType($typeName);
|
||||
if ($typeName !== $suggestedName) {
|
||||
$error = 'Expected "%s"; found "%s" for %s at position %s';
|
||||
$data = array(
|
||||
$suggestedName,
|
||||
$typeName,
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectParamVarName', $data);
|
||||
} else if (count($typeNames) === 1) {
|
||||
// Check type hint for array and custom type.
|
||||
$suggestedTypeHint = '';
|
||||
if (strpos($suggestedName, 'array') !== false) {
|
||||
$suggestedTypeHint = 'array';
|
||||
} else if (in_array($typeName, PHP_CodeSniffer::$allowedTypes) === false) {
|
||||
$suggestedTypeHint = $suggestedName;
|
||||
}
|
||||
|
||||
if ($suggestedTypeHint !== '' && isset($realParams[($pos - 1)]) === true) {
|
||||
$typeHint = $realParams[($pos - 1)]['type_hint'];
|
||||
if ($typeHint === '') {
|
||||
$error = 'Type hint "%s" missing for %s at position %s';
|
||||
$data = array(
|
||||
$suggestedTypeHint,
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, ($commentEnd + 2), 'TypeHintMissing', $data);
|
||||
} else if ($typeHint !== $suggestedTypeHint) {
|
||||
$error = 'Expected type hint "%s"; found "%s" for %s at position %s';
|
||||
$data = array(
|
||||
$suggestedTypeHint,
|
||||
$typeHint,
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, ($commentEnd + 2), 'IncorrectTypeHint', $data);
|
||||
}
|
||||
} else if ($suggestedTypeHint === '' && isset($realParams[($pos - 1)]) === true) {
|
||||
$typeHint = $realParams[($pos - 1)]['type_hint'];
|
||||
if ($typeHint !== '') {
|
||||
$error = 'Unknown type hint "%s" found for %s at position %s';
|
||||
$data = array(
|
||||
$typeHint,
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, ($commentEnd + 2), 'InvalidTypeHint', $data);
|
||||
}
|
||||
}
|
||||
}//end if
|
||||
}//end foreach
|
||||
|
||||
// Make sure the names of the parameter comment matches the
|
||||
// actual parameter.
|
||||
if (isset($realParams[($pos - 1)]) === true) {
|
||||
$realName = $realParams[($pos - 1)]['name'];
|
||||
$foundParams[] = $realName;
|
||||
|
||||
// Append ampersand to name if passing by reference.
|
||||
if ($realParams[($pos - 1)]['pass_by_reference'] === true) {
|
||||
$realName = '&'.$realName;
|
||||
}
|
||||
|
||||
if ($realName !== $paramName) {
|
||||
$code = 'ParamNameNoMatch';
|
||||
$data = array(
|
||||
$paramName,
|
||||
$realName,
|
||||
$pos,
|
||||
);
|
||||
|
||||
$error = 'Doc comment for var %s does not match ';
|
||||
if (strtolower($paramName) === strtolower($realName)) {
|
||||
$error .= 'case of ';
|
||||
$code = 'ParamNameNoCaseMatch';
|
||||
}
|
||||
|
||||
$error .= 'actual variable name %s at position %s';
|
||||
|
||||
$this->currentFile->addError($error, $errorPos, $code, $data);
|
||||
}
|
||||
} else {
|
||||
// We must have an extra parameter comment.
|
||||
$error = 'Superfluous doc comment at position '.$pos;
|
||||
$this->currentFile->addError($error, $errorPos, 'ExtraParamComment');
|
||||
}
|
||||
|
||||
if ($param->getVarName() === '') {
|
||||
$error = 'Missing parameter name at position '.$pos;
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingParamName');
|
||||
}
|
||||
|
||||
if ($param->getType() === '') {
|
||||
$error = 'Missing type at position '.$pos;
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingParamType');
|
||||
}
|
||||
|
||||
if ($paramComment === '') {
|
||||
$error = 'Missing comment for param "%s" at position %s';
|
||||
$data = array(
|
||||
$paramName,
|
||||
$pos,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingParamComment', $data);
|
||||
} else {
|
||||
// Param comments must start with a capital letter and
|
||||
// end with the full stop.
|
||||
$firstChar = $paramComment{0};
|
||||
if (preg_match('|[A-Z]|', $firstChar) === 0) {
|
||||
$error = 'Param comment must start with a capital letter';
|
||||
$this->currentFile->addError($error, $errorPos, 'ParamCommentNotCapital');
|
||||
}
|
||||
|
||||
$lastChar = $paramComment[(strlen($paramComment) - 1)];
|
||||
if ($lastChar !== '.') {
|
||||
$error = 'Param comment must end with a full stop';
|
||||
$this->currentFile->addError($error, $errorPos, 'ParamCommentFullStop');
|
||||
}
|
||||
}
|
||||
|
||||
$previousParam = $param;
|
||||
|
||||
}//end foreach
|
||||
|
||||
if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) {
|
||||
$error = 'Expected 1 space after the longest type';
|
||||
$this->currentFile->addError($error, $longestType, 'SpacingAfterLongType');
|
||||
}
|
||||
|
||||
if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) {
|
||||
$error = 'Expected 1 space after the longest variable name';
|
||||
$this->currentFile->addError($error, $longestVar, 'SpacingAfterLongName');
|
||||
}
|
||||
|
||||
}//end if
|
||||
|
||||
$realNames = array();
|
||||
foreach ($realParams as $realParam) {
|
||||
$realNames[] = $realParam['name'];
|
||||
}
|
||||
|
||||
// Report missing comments.
|
||||
$diff = array_diff($realNames, $foundParams);
|
||||
foreach ($diff as $neededParam) {
|
||||
if (count($params) !== 0) {
|
||||
$errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart);
|
||||
} else {
|
||||
$errorPos = $commentStart;
|
||||
}
|
||||
|
||||
$error = 'Doc comment for "%s" missing';
|
||||
$data = array($neededParam);
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingParamTag', $data);
|
||||
}
|
||||
|
||||
}//end processParams()
|
||||
|
||||
|
||||
/**
|
||||
* Process a list of unknown tags.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
* @param int $commentEnd The position in the stack where the comment ended.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processUnknownTags($commentStart, $commentEnd)
|
||||
{
|
||||
$unknownTags = $this->commentParser->getUnknown();
|
||||
foreach ($unknownTags as $errorTag) {
|
||||
$error = '@%s tag is not allowed in function comment';
|
||||
$data = array($errorTag['tag']);
|
||||
$this->currentFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data);
|
||||
}
|
||||
|
||||
}//end processUnknownTags
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
/**
|
||||
* Verifies that a @throws tag exists for a function that throws exceptions.
|
||||
* Verifies the number of @throws tags and the number of throw tokens matches.
|
||||
* Verifies the exception type.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) {
|
||||
$error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found';
|
||||
throw new PHP_CodeSniffer_Exception($error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that a @throws tag exists for a function that throws exceptions.
|
||||
* Verifies the number of @throws tags and the number of throw tokens matches.
|
||||
* Verifies the exception type.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(array(T_FUNCTION), array(T_THROW));
|
||||
|
||||
}//end __construct()
|
||||
|
||||
|
||||
/**
|
||||
* Processes the function tokens within the class.
|
||||
*
|
||||
* @param PHP_CodeSniffer_File $phpcsFile The file where this token was found.
|
||||
* @param int $stackPtr The position where the token was found.
|
||||
* @param int $currScope The current scope opener token.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope)
|
||||
{
|
||||
// Is this the first throw token within the current function scope?
|
||||
// If so, we have to validate other throw tokens within the same scope.
|
||||
$previousThrow = $phpcsFile->findPrevious(T_THROW, ($stackPtr - 1), $currScope);
|
||||
if ($previousThrow !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
|
||||
$find = array(
|
||||
T_COMMENT,
|
||||
T_DOC_COMMENT,
|
||||
T_CLASS,
|
||||
T_FUNCTION,
|
||||
T_OPEN_TAG,
|
||||
);
|
||||
|
||||
$commentEnd = $phpcsFile->findPrevious($find, ($currScope - 1));
|
||||
|
||||
if ($commentEnd === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT) {
|
||||
// Function doesn't have a comment. Let someone else warn about that.
|
||||
return;
|
||||
}
|
||||
|
||||
$commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1);
|
||||
$comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));
|
||||
|
||||
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, 'FailedParse');
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the position where the current function scope ends.
|
||||
$currScopeEnd = 0;
|
||||
if (isset($tokens[$currScope]['scope_closer']) === true) {
|
||||
$currScopeEnd = $tokens[$currScope]['scope_closer'];
|
||||
}
|
||||
|
||||
// Find all the exception type token within the current scope.
|
||||
$throwTokens = array();
|
||||
$currPos = $stackPtr;
|
||||
if ($currScopeEnd !== 0) {
|
||||
while ($currPos < $currScopeEnd && $currPos !== false) {
|
||||
|
||||
/*
|
||||
If we can't find a NEW, we are probably throwing
|
||||
a variable, so we ignore it, but they still need to
|
||||
provide at least one @throws tag, even through we
|
||||
don't know the exception class.
|
||||
*/
|
||||
|
||||
$nextToken = $phpcsFile->findNext(T_WHITESPACE, ($currPos + 1), null, true);
|
||||
if ($tokens[$nextToken]['code'] === T_NEW) {
|
||||
$currException = $phpcsFile->findNext(
|
||||
array(
|
||||
T_NS_SEPARATOR,
|
||||
T_STRING,
|
||||
),
|
||||
$currPos,
|
||||
$currScopeEnd,
|
||||
false,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ($currException !== false) {
|
||||
$endException = $phpcsFile->findNext(
|
||||
array(
|
||||
T_NS_SEPARATOR,
|
||||
T_STRING,
|
||||
),
|
||||
($currException + 1),
|
||||
$currScopeEnd,
|
||||
true,
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ($endException === false) {
|
||||
$throwTokens[] = $tokens[$currException]['content'];
|
||||
} else {
|
||||
$throwTokens[] = $phpcsFile->getTokensAsString($currException, ($endException - $currException));
|
||||
}
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
$currPos = $phpcsFile->findNext(T_THROW, ($currPos + 1), $currScopeEnd);
|
||||
}//end while
|
||||
}//end if
|
||||
|
||||
// Only need one @throws tag for each type of exception thrown.
|
||||
$throwTokens = array_unique($throwTokens);
|
||||
sort($throwTokens);
|
||||
|
||||
$throws = $this->commentParser->getThrows();
|
||||
if (empty($throws) === true) {
|
||||
$error = 'Missing @throws tag in function comment';
|
||||
$phpcsFile->addError($error, $commentEnd, 'Missing');
|
||||
} else if (empty($throwTokens) === true) {
|
||||
// If token count is zero, it means that only variables are being
|
||||
// thrown, so we need at least one @throws tag (checked above).
|
||||
// Nothing more to do.
|
||||
return;
|
||||
} else {
|
||||
$throwTags = array();
|
||||
$lineNumber = array();
|
||||
foreach ($throws as $throw) {
|
||||
$throwTags[] = $throw->getValue();
|
||||
$lineNumber[$throw->getValue()] = $throw->getLine();
|
||||
}
|
||||
|
||||
$throwTags = array_unique($throwTags);
|
||||
sort($throwTags);
|
||||
|
||||
// Make sure @throws tag count matches throw token count.
|
||||
$tokenCount = count($throwTokens);
|
||||
$tagCount = count($throwTags);
|
||||
if ($tokenCount !== $tagCount) {
|
||||
$error = 'Expected %s @throws tag(s) in function comment; %s found';
|
||||
$data = array(
|
||||
$tokenCount,
|
||||
$tagCount,
|
||||
);
|
||||
$phpcsFile->addError($error, $commentEnd, 'WrongNumber', $data);
|
||||
return;
|
||||
} else {
|
||||
// Exception type in @throws tag must be thrown in the function.
|
||||
foreach ($throwTags as $i => $throwTag) {
|
||||
$errorPos = ($commentStart + $lineNumber[$throwTag]);
|
||||
if (empty($throwTag) === false && $throwTag !== $throwTokens[$i]) {
|
||||
$error = 'Expected "%s" but found "%s" for @throws tag exception';
|
||||
$data = array(
|
||||
$throwTokens[$i],
|
||||
$throwTag,
|
||||
);
|
||||
$phpcsFile->addError($error, $errorPos, 'WrongType', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//end if
|
||||
|
||||
}//end processTokenWithinScope()
|
||||
|
||||
|
||||
}//end class
|
||||
?>
|
||||
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_InlineCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_InlineCommentSniff.
|
||||
*
|
||||
* Checks that there is adequate spacing between comments.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* A list of tokenizers this sniff supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $supportedTokenizers = array(
|
||||
'PHP',
|
||||
'JS',
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(
|
||||
T_COMMENT,
|
||||
T_DOC_COMMENT,
|
||||
);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
// If this is a function/class/interface doc block comment, skip it.
|
||||
// We are only interested in inline doc block comments, which are
|
||||
// not allowed.
|
||||
if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT) {
|
||||
$nextToken = $phpcsFile->findNext(
|
||||
PHP_CodeSniffer_Tokens::$emptyTokens,
|
||||
($stackPtr + 1),
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
$ignore = array(
|
||||
T_CLASS,
|
||||
T_INTERFACE,
|
||||
T_FUNCTION,
|
||||
T_PUBLIC,
|
||||
T_PRIVATE,
|
||||
T_PROTECTED,
|
||||
T_FINAL,
|
||||
T_STATIC,
|
||||
T_ABSTRACT,
|
||||
T_CONST,
|
||||
T_OBJECT,
|
||||
T_PROPERTY,
|
||||
);
|
||||
|
||||
if (in_array($tokens[$nextToken]['code'], $ignore) === true) {
|
||||
return;
|
||||
} else {
|
||||
if ($phpcsFile->tokenizerType === 'JS') {
|
||||
// We allow block comments if a function is being assigned
|
||||
// to a variable.
|
||||
$ignore = PHP_CodeSniffer_Tokens::$emptyTokens;
|
||||
$ignore[] = T_EQUAL;
|
||||
$ignore[] = T_STRING;
|
||||
$ignore[] = T_OBJECT_OPERATOR;
|
||||
$nextToken = $phpcsFile->findNext($ignore, ($nextToken + 1), null, true);
|
||||
if ($tokens[$nextToken]['code'] === T_FUNCTION) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$prevToken = $phpcsFile->findPrevious(
|
||||
PHP_CodeSniffer_Tokens::$emptyTokens,
|
||||
($stackPtr - 1),
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ($tokens[$prevToken]['code'] === T_OPEN_TAG) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only error once per comment.
|
||||
if (substr($tokens[$stackPtr]['content'], 0, 3) === '/**') {
|
||||
$error = 'Inline doc block comments are not allowed; use "/* Comment */" or "// Comment" instead';
|
||||
$phpcsFile->addError($error, $stackPtr, 'DocBlock');
|
||||
}
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
if ($tokens[$stackPtr]['content']{0} === '#') {
|
||||
$error = 'Perl-style comments are not allowed; use "// Comment" instead';
|
||||
$phpcsFile->addError($error, $stackPtr, 'WrongStyle');
|
||||
}
|
||||
|
||||
// We don't want end of block comments. If the last comment is a closing
|
||||
// curly brace.
|
||||
$previousContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
|
||||
if ($tokens[$previousContent]['line'] === $tokens[$stackPtr]['line']) {
|
||||
if ($tokens[$previousContent]['code'] === T_CLOSE_CURLY_BRACKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case for JS files.
|
||||
if ($tokens[$previousContent]['code'] === T_COMMA
|
||||
|| $tokens[$previousContent]['code'] === T_SEMICOLON
|
||||
) {
|
||||
$lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($previousContent - 1), null, true);
|
||||
if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$comment = rtrim($tokens[$stackPtr]['content']);
|
||||
|
||||
// Only want inline comments.
|
||||
if (substr($comment, 0, 2) !== '//') {
|
||||
return;
|
||||
}
|
||||
|
||||
$spaceCount = 0;
|
||||
for ($i = 2; $i < strlen($comment); $i++) {
|
||||
if ($comment[$i] !== ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
$spaceCount++;
|
||||
}
|
||||
|
||||
if ($spaceCount === 0) {
|
||||
$error = 'No space before comment text; expected "// %s" but found "%s"';
|
||||
$data = array(
|
||||
substr($comment, 2),
|
||||
$comment,
|
||||
);
|
||||
$phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore', $data);
|
||||
}
|
||||
|
||||
if ($spaceCount > 1) {
|
||||
$error = '%s spaces found before inline comment; expected "// %s" but found "%s"';
|
||||
$data = array(
|
||||
$spaceCount,
|
||||
substr($comment, (2 + $spaceCount)),
|
||||
$comment,
|
||||
);
|
||||
$phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data);
|
||||
}
|
||||
|
||||
|
||||
// The below section determines if a comment block is correctly capitalised,
|
||||
// and ends in a full-stop. It will find the last comment in a block, and
|
||||
// work its way up.
|
||||
$nextComment = $phpcsFile->findNext(array(T_COMMENT), ($stackPtr + 1), null, false);
|
||||
|
||||
if (($nextComment !== false) && (($tokens[$nextComment]['line']) === ($tokens[$stackPtr]['line'] + 1))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$topComment = $stackPtr;
|
||||
$lastComment = $stackPtr;
|
||||
while (($topComment = $phpcsFile->findPrevious(array(T_COMMENT), ($lastComment - 1), null, false)) !== false) {
|
||||
if ($tokens[$topComment]['line'] !== ($tokens[$lastComment]['line'] - 1)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$lastComment = $topComment;
|
||||
}
|
||||
|
||||
$topComment = $lastComment;
|
||||
$commentText = '';
|
||||
|
||||
for ($i = $topComment; $i <= $stackPtr; $i++) {
|
||||
if ($tokens[$i]['code'] === T_COMMENT) {
|
||||
$commentText .= trim(substr($tokens[$i]['content'], 2));
|
||||
}
|
||||
}
|
||||
|
||||
if ($commentText === '') {
|
||||
$error = 'Blank comments are not allowed';
|
||||
$phpcsFile->addError($error, $stackPtr, 'Empty');
|
||||
return;
|
||||
}
|
||||
|
||||
if (preg_match('|[A-Z]|', $commentText[0]) === 0) {
|
||||
$error = 'Inline comments must start with a capital letter';
|
||||
$phpcsFile->addError($error, $topComment, 'NotCapital');
|
||||
}
|
||||
|
||||
$commentCloser = $commentText[(strlen($commentText) - 1)];
|
||||
$acceptedClosers = array(
|
||||
'full-stops' => '.',
|
||||
'exclamation marks' => '!',
|
||||
'or question marks' => '?',
|
||||
);
|
||||
|
||||
if (in_array($commentCloser, $acceptedClosers) === false) {
|
||||
$error = 'Inline comments must end in %s';
|
||||
$ender = '';
|
||||
foreach ($acceptedClosers as $closerName => $symbol) {
|
||||
$ender .= ' '.$closerName.',';
|
||||
}
|
||||
|
||||
$ender = rtrim($ender, ',');
|
||||
$data = array($ender);
|
||||
$phpcsFile->addError($error, $stackPtr, 'InvalidEndChar', $data);
|
||||
}
|
||||
|
||||
// Finally, the line below the last comment cannot be empty.
|
||||
$start = false;
|
||||
for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) {
|
||||
if ($tokens[$i]['line'] === ($tokens[$stackPtr]['line'] + 1)) {
|
||||
if ($tokens[$i]['code'] !== T_WHITESPACE) {
|
||||
return;
|
||||
}
|
||||
} else if ($tokens[$i]['line'] > ($tokens[$stackPtr]['line'] + 1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$error = 'There must be no blank line following an inline comment';
|
||||
$phpcsFile->addError($error, $stackPtr, 'SpacingAfter');
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_ControlStructures_LongConditionClosingCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_ControlStructures_LongConditionClosingCommentSniff.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_LongConditionClosingCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* A list of tokenizers this sniff supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $supportedTokenizers = array(
|
||||
'PHP',
|
||||
'JS',
|
||||
);
|
||||
|
||||
/**
|
||||
* The openers that we are interested in.
|
||||
*
|
||||
* @var array(int)
|
||||
*/
|
||||
private static $_openers = array(
|
||||
T_SWITCH,
|
||||
T_IF,
|
||||
T_FOR,
|
||||
T_FOREACH,
|
||||
T_WHILE,
|
||||
T_TRY,
|
||||
T_CASE,
|
||||
);
|
||||
|
||||
/**
|
||||
* The length that a code block must be before
|
||||
* requiring a closing comment.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $lineLimit = 20;
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_CLOSE_CURLY_BRACKET);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
if (isset($tokens[$stackPtr]['scope_condition']) === false) {
|
||||
// No scope condition. It is a function closer.
|
||||
return;
|
||||
}
|
||||
|
||||
$startCondition = $tokens[$tokens[$stackPtr]['scope_condition']];
|
||||
$startBrace = $tokens[$tokens[$stackPtr]['scope_opener']];
|
||||
$endBrace = $tokens[$stackPtr];
|
||||
|
||||
// We are only interested in some code blocks.
|
||||
if (in_array($startCondition['code'], self::$_openers) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($startCondition['code'] === T_IF) {
|
||||
// If this is actually and ELSE IF, skip it as the brace
|
||||
// will be checked by the original IF.
|
||||
$else = $phpcsFile->findPrevious(T_WHITESPACE, ($tokens[$stackPtr]['scope_condition'] - 1), null, true);
|
||||
if ($tokens[$else]['code'] === T_ELSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// IF statements that have an ELSE block need to use
|
||||
// "end if" rather than "end else" or "end elseif".
|
||||
do {
|
||||
$nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
|
||||
if ($tokens[$nextToken]['code'] === T_ELSE || $tokens[$nextToken]['code'] === T_ELSEIF) {
|
||||
// Check for ELSE IF (2 tokens) as opposed to ELSEIF (1 token).
|
||||
if ($tokens[$nextToken]['code'] === T_ELSE
|
||||
&& isset($tokens[$nextToken]['scope_closer']) === false
|
||||
) {
|
||||
$nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextToken + 1), null, true);
|
||||
if ($tokens[$nextToken]['code'] !== T_IF
|
||||
|| isset($tokens[$nextToken]['scope_closer']) === false
|
||||
) {
|
||||
// Not an ELSE IF or is an inline ELSE IF.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The end brace becomes the ELSE's end brace.
|
||||
$stackPtr = $tokens[$nextToken]['scope_closer'];
|
||||
$endBrace = $tokens[$stackPtr];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (isset($tokens[$nextToken]['scope_closer']) === true);
|
||||
}//end if
|
||||
|
||||
if ($startCondition['code'] === T_TRY) {
|
||||
// TRY statements need to check until the end of all CATCH statements.
|
||||
do {
|
||||
$nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
|
||||
if ($tokens[$nextToken]['code'] === T_CATCH) {
|
||||
// The end brace becomes the CATCH's end brace.
|
||||
$stackPtr = $tokens[$nextToken]['scope_closer'];
|
||||
$endBrace = $tokens[$stackPtr];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (isset($tokens[$nextToken]['scope_closer']) === true);
|
||||
}
|
||||
|
||||
$lineDifference = ($endBrace['line'] - $startBrace['line']);
|
||||
|
||||
$expected = '//end '.$startCondition['content'];
|
||||
$comment = $phpcsFile->findNext(array(T_COMMENT), $stackPtr, null, false);
|
||||
|
||||
if (($comment === false) || ($tokens[$comment]['line'] !== $endBrace['line'])) {
|
||||
if ($lineDifference >= $this->lineLimit) {
|
||||
$error = 'End comment for long condition not found; expected "%s"';
|
||||
$data = array($expected);
|
||||
$phpcsFile->addError($error, $stackPtr, 'Missing', $data);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (($comment - $stackPtr) !== 1) {
|
||||
$error = 'Space found before closing comment; expected "%s"';
|
||||
$data = array($expected);
|
||||
$phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data);
|
||||
}
|
||||
|
||||
if (trim($tokens[$comment]['content']) !== $expected) {
|
||||
$found = trim($tokens[$comment]['content']);
|
||||
$error = 'Incorrect closing comment; expected "%s" but found "%s"';
|
||||
$data = array(
|
||||
$expected,
|
||||
$found,
|
||||
);
|
||||
$phpcsFile->addError($error, $stackPtr, 'Invalid', $data);
|
||||
return;
|
||||
}
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_PostStatementCommentSniff.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
/**
|
||||
* Squiz_Sniffs_Commenting_PostStatementCommentSniff.
|
||||
*
|
||||
* Checks to ensure that there are no comments after statements.
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
class Squiz_Sniffs_Commenting_PostStatementCommentSniff implements PHP_CodeSniffer_Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* A list of tokenizers this sniff supports.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $supportedTokenizers = array(
|
||||
'PHP',
|
||||
'JS',
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(T_COMMENT);
|
||||
|
||||
}//end register()
|
||||
|
||||
|
||||
/**
|
||||
* Processes this sniff, 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();
|
||||
|
||||
if (substr($tokens[$stackPtr]['content'], 0, 2) !== '//') {
|
||||
return;
|
||||
}
|
||||
|
||||
$commentLine = $tokens[$stackPtr]['line'];
|
||||
$lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
|
||||
|
||||
if ($tokens[$lastContent]['line'] !== $commentLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case for JS files.
|
||||
if ($tokens[$lastContent]['code'] === T_COMMA
|
||||
|| $tokens[$lastContent]['code'] === T_SEMICOLON
|
||||
) {
|
||||
$lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($lastContent - 1), null, true);
|
||||
if ($tokens[$lastContent]['code'] === T_CLOSE_CURLY_BRACKET) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$error = 'Comments may not appear after statements.';
|
||||
$phpcsFile->addError($error, $stackPtr, 'Found');
|
||||
|
||||
}//end process()
|
||||
|
||||
|
||||
}//end class
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,347 @@
|
||||
<?php
|
||||
/**
|
||||
* Parses and verifies the variable doc comment.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
if (class_exists('PHP_CodeSniffer_Standards_AbstractVariableSniff', true) === false) {
|
||||
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found');
|
||||
}
|
||||
|
||||
if (class_exists('PHP_CodeSniffer_CommentParser_MemberCommentParser', true) === false) {
|
||||
throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_MemberCommentParser not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and verifies the variable doc comment.
|
||||
*
|
||||
* Verifies that :
|
||||
* <ul>
|
||||
* <li>A variable doc comment exists.</li>
|
||||
* <li>Short description ends with a full stop.</li>
|
||||
* <li>There is a blank line after the short description.</li>
|
||||
* <li>There is a blank line between the description and the tags.</li>
|
||||
* <li>Check the order, indentation and content of each tag.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @category PHP
|
||||
* @package PHP_CodeSniffer
|
||||
* @author Greg Sherwood <gsherwood@squiz.net>
|
||||
* @author Marc McIntyre <mmcintyre@squiz.net>
|
||||
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
|
||||
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
|
||||
* @version Release: 1.3.3
|
||||
* @link http://pear.php.net/package/PHP_CodeSniffer
|
||||
*/
|
||||
|
||||
class Squiz_Sniffs_Commenting_VariableCommentSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff
|
||||
{
|
||||
|
||||
/**
|
||||
* The header comment parser for the current file.
|
||||
*
|
||||
* @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser
|
||||
*/
|
||||
protected $commentParser = null;
|
||||
|
||||
|
||||
/**
|
||||
* Called to process class member vars.
|
||||
*
|
||||
* @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 processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
|
||||
{
|
||||
$this->currentFile = $phpcsFile;
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
$commentToken = array(
|
||||
T_COMMENT,
|
||||
T_DOC_COMMENT,
|
||||
);
|
||||
|
||||
// Extract the var comment docblock.
|
||||
$commentEnd = $phpcsFile->findPrevious($commentToken, ($stackPtr - 3));
|
||||
if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) {
|
||||
$phpcsFile->addError('You must use "/**" style comments for a variable comment', $stackPtr, 'WrongStyle');
|
||||
return;
|
||||
} else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) {
|
||||
$phpcsFile->addError('Missing variable doc comment', $stackPtr, 'Missing');
|
||||
return;
|
||||
} else {
|
||||
// Make sure the comment we have found belongs to us.
|
||||
$commentFor = $phpcsFile->findNext(array(T_VARIABLE, T_CLASS, T_INTERFACE), ($commentEnd + 1));
|
||||
if ($commentFor !== $stackPtr) {
|
||||
$phpcsFile->addError('Missing variable doc comment', $stackPtr, 'Missing');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1);
|
||||
$commentString = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));
|
||||
|
||||
// Parse the header comment docblock.
|
||||
try {
|
||||
$this->commentParser = new PHP_CodeSniffer_CommentParser_MemberCommentParser($commentString, $phpcsFile);
|
||||
$this->commentParser->parse();
|
||||
} catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
|
||||
$line = ($e->getLineWithinComment() + $commentStart);
|
||||
$phpcsFile->addError($e->getMessage(), $line, 'ErrorParsing');
|
||||
return;
|
||||
}
|
||||
|
||||
$comment = $this->commentParser->getComment();
|
||||
if (is_null($comment) === true) {
|
||||
$error = 'Variable doc comment is empty';
|
||||
$phpcsFile->addError($error, $commentStart, 'Empty');
|
||||
return;
|
||||
}
|
||||
|
||||
// The first line of the comment should just be the /** code.
|
||||
$eolPos = strpos($commentString, $phpcsFile->eolChar);
|
||||
$firstLine = substr($commentString, 0, $eolPos);
|
||||
if ($firstLine !== '/**') {
|
||||
$error = 'The open comment tag must be the only content on the line';
|
||||
$phpcsFile->addError($error, $commentStart, 'ContentAfterOpen');
|
||||
}
|
||||
|
||||
// Check for a comment description.
|
||||
$short = $comment->getShortComment();
|
||||
$long = '';
|
||||
if (trim($short) === '') {
|
||||
$error = 'Missing short description in variable doc comment';
|
||||
$phpcsFile->addError($error, $commentStart, 'MissingShort');
|
||||
$newlineCount = 1;
|
||||
} else {
|
||||
// No extra newline before short description.
|
||||
$newlineCount = 0;
|
||||
$newlineSpan = strspn($short, $phpcsFile->eolChar);
|
||||
if ($short !== '' && $newlineSpan > 0) {
|
||||
$error = 'Extra newline(s) found before variable comment short description';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'SpacingBeforeShort');
|
||||
}
|
||||
|
||||
$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 variable comment';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount + 1), 'SpacingBetween');
|
||||
}
|
||||
|
||||
$newlineCount += $newlineBetween;
|
||||
|
||||
$testLong = trim($long);
|
||||
if (preg_match('|[A-Z]|', $testLong[0]) === 0) {
|
||||
$error = 'Variable comment long description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount), 'LongNotCapital');
|
||||
}
|
||||
}//end if
|
||||
|
||||
// Short description must be single line and end with a full stop.
|
||||
$testShort = trim($short);
|
||||
$lastChar = $testShort[(strlen($testShort) - 1)];
|
||||
if (substr_count($testShort, $phpcsFile->eolChar) !== 0) {
|
||||
$error = 'Variable comment short description must be on a single line';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortSingleLine');
|
||||
}
|
||||
|
||||
if (preg_match('|[A-Z]|', $testShort[0]) === 0) {
|
||||
$error = 'Variable comment short description must start with a capital letter';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortNotCapital');
|
||||
}
|
||||
|
||||
if ($lastChar !== '.') {
|
||||
$error = 'Variable comment short description must end with a full stop';
|
||||
$phpcsFile->addError($error, ($commentStart + 1), 'ShortFullStop');
|
||||
}
|
||||
}//end if
|
||||
|
||||
// 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 variable comment';
|
||||
if ($long !== '') {
|
||||
$newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1);
|
||||
}
|
||||
|
||||
$phpcsFile->addError($error, ($commentStart + $newlineCount), 'SpacingBeforeTags');
|
||||
$short = rtrim($short, $phpcsFile->eolChar.' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Check for unknown/deprecated tags.
|
||||
$unknownTags = $this->commentParser->getUnknown();
|
||||
foreach ($unknownTags as $errorTag) {
|
||||
// Unknown tags are not parsed, do not process further.
|
||||
$error = '@%s tag is not allowed in variable comment';
|
||||
$data = array($errorTag['tag']);
|
||||
$phpcsFile->addWarning($error, ($commentStart + $errorTag['line']), 'TagNotAllowed', $data);
|
||||
}
|
||||
|
||||
// Check each tag.
|
||||
$this->processVar($commentStart, $commentEnd);
|
||||
$this->processSees($commentStart);
|
||||
|
||||
// The last content should be a newline and the content before
|
||||
// that should not be blank. If there is more blank space
|
||||
// then they have additional blank lines at the end of the comment.
|
||||
$words = $this->commentParser->getWords();
|
||||
$lastPos = (count($words) - 1);
|
||||
if (trim($words[($lastPos - 1)]) !== ''
|
||||
|| strpos($words[($lastPos - 1)], $this->currentFile->eolChar) === false
|
||||
|| trim($words[($lastPos - 2)]) === ''
|
||||
) {
|
||||
$error = 'Additional blank lines found at end of variable comment';
|
||||
$this->currentFile->addError($error, $commentEnd, 'SpacingAfter');
|
||||
}
|
||||
|
||||
}//end processMemberVar()
|
||||
|
||||
|
||||
/**
|
||||
* Process the var tag.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
* @param int $commentEnd The position in the stack where the comment ended.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processVar($commentStart, $commentEnd)
|
||||
{
|
||||
$var = $this->commentParser->getVar();
|
||||
|
||||
if ($var !== null) {
|
||||
$errorPos = ($commentStart + $var->getLine());
|
||||
$index = array_keys($this->commentParser->getTagOrders(), 'var');
|
||||
|
||||
if (count($index) > 1) {
|
||||
$error = 'Only 1 @var tag is allowed in variable comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'DuplicateVar');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($index[0] !== 1) {
|
||||
$error = 'The @var tag must be the first tag in a variable comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'VarOrder');
|
||||
}
|
||||
|
||||
$content = $var->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Var type missing for @var tag in variable comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'MissingVarType');
|
||||
return;
|
||||
} else {
|
||||
$suggestedType = PHP_CodeSniffer::suggestType($content);
|
||||
if ($content !== $suggestedType) {
|
||||
$error = 'Expected "%s"; found "%s" for @var tag in variable comment';
|
||||
$data = array(
|
||||
$suggestedType,
|
||||
$content,
|
||||
);
|
||||
$this->currentFile->addError($error, $errorPos, 'IncorrectVarType', $data);
|
||||
}
|
||||
}
|
||||
|
||||
$spacing = substr_count($var->getWhitespaceBeforeContent(), ' ');
|
||||
if ($spacing !== 1) {
|
||||
$error = '@var tag indented incorrectly; expected 1 space but found %s';
|
||||
$data = array($spacing);
|
||||
$this->currentFile->addError($error, $errorPos, 'VarIndent', $data);
|
||||
}
|
||||
} else {
|
||||
$error = 'Missing @var tag in variable comment';
|
||||
$this->currentFile->addError($error, $commentEnd, 'MissingVar');
|
||||
}//end if
|
||||
|
||||
}//end processVar()
|
||||
|
||||
|
||||
/**
|
||||
* Process the see tags.
|
||||
*
|
||||
* @param int $commentStart The position in the stack where the comment started.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processSees($commentStart)
|
||||
{
|
||||
$sees = $this->commentParser->getSees();
|
||||
if (empty($sees) === false) {
|
||||
foreach ($sees as $see) {
|
||||
$errorPos = ($commentStart + $see->getLine());
|
||||
$content = $see->getContent();
|
||||
if (empty($content) === true) {
|
||||
$error = 'Content missing for @see tag in variable comment';
|
||||
$this->currentFile->addError($error, $errorPos, 'EmptySees');
|
||||
continue;
|
||||
}
|
||||
|
||||
$spacing = substr_count($see->getWhitespaceBeforeContent(), ' ');
|
||||
if ($spacing !== 1) {
|
||||
$error = '@see tag indented incorrectly; expected 1 spaces but found %s';
|
||||
$data = array($spacing);
|
||||
$this->currentFile->addError($error, $errorPos, 'SeesIndent', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}//end processSees()
|
||||
|
||||
|
||||
/**
|
||||
* Called to process a normal variable.
|
||||
*
|
||||
* Not required for this sniff.
|
||||
*
|
||||
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found.
|
||||
* @param int $stackPtr The position where the double quoted
|
||||
* string was found.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
|
||||
{
|
||||
return;
|
||||
|
||||
}//end processVariable()
|
||||
|
||||
|
||||
/**
|
||||
* Called to process variables found in duoble quoted strings.
|
||||
*
|
||||
* Not required for this sniff.
|
||||
*
|
||||
* @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this token was found.
|
||||
* @param int $stackPtr The position where the double quoted
|
||||
* string was found.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
|
||||
{
|
||||
return;
|
||||
|
||||
}//end processVariableInString()
|
||||
|
||||
|
||||
}//end class
|
||||
?>
|
||||
Reference in New Issue
Block a user