PageRenderTime 104ms CodeModel.GetById 40ms app.highlight 12ms RepoModel.GetById 48ms app.codeStats 0ms

/.dev/code-sniffs/XLite/Sniffs/PHP/Commenting/ClassVarCommentSniff.php

https://github.com/istran/core
PHP | 300 lines | 189 code | 36 blank | 75 comment | 22 complexity | 2aed577fb633aba9c52b5597f0157e7d MD5 | raw file
  1<?php
  2/**
  3 * Parses and verifies the doc comments for functions.
  4 *
  5 * PHP version 5
  6 *
  7 * @category  PHP
  8 * @package   PHP_CodeSniffer
  9 * @author    Greg Sherwood <gsherwood@squiz.net>
 10 * @author    Marc McIntyre <mmcintyre@squiz.net>
 11 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
 12 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 13 * @version   CVS: $Id: ee3d08ebdd16c8ebc0275671310b819af7348a28 $
 14 * @link      http://pear.php.net/package/PHP_CodeSniffer
 15 */
 16
 17if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) {
 18    throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found');
 19}
 20
 21/**
 22 * Parses and verifies the doc comments for functions.
 23 *
 24 * Verifies that :
 25 * <ul>
 26 *  <li>A comment exists</li>
 27 *  <li>There is a blank newline after the short description.</li>
 28 *  <li>There is a blank newline between the long and short description.</li>
 29 *  <li>There is a blank newline between the long description and tags.</li>
 30 *  <li>Parameter names represent those in the method.</li>
 31 *  <li>Parameter comments are in the correct order</li>
 32 *  <li>Parameter comments are complete</li>
 33 *  <li>A space is present before the first and after the last parameter</li>
 34 *  <li>A return type exists</li>
 35 *  <li>There must be one blank line between body and headline comments.</li>
 36 *  <li>Any throw tag must have an exception class.</li>
 37 * </ul>
 38 *
 39 * @category  PHP
 40 * @package   PHP_CodeSniffer
 41 * @author    Greg Sherwood <gsherwood@squiz.net>
 42 * @author    Marc McIntyre <mmcintyre@squiz.net>
 43 * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
 44 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 45 * @version   Release: 1.2.0RC1
 46 * @link      http://pear.php.net/package/PHP_CodeSniffer
 47 */
 48class XLite_Sniffs_PHP_Commenting_ClassVarCommentSniff extends XLite_TagsSniff
 49{
 50
 51    /**
 52     * The function comment parser for the current method.
 53     *
 54     * @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser
 55     */
 56    protected $commentParser = null;
 57
 58    /**
 59     * The current PHP_CodeSniffer_File object we are processing.
 60     *
 61     * @var PHP_CodeSniffer_File
 62     */
 63    protected $currentFile = null;
 64
 65	protected $tags = array(
 66    	'var'    => array(
 67        	'required'       => true,
 68            'allow_multiple' => false,
 69            'order_text'     => 'precedes @access',
 70        ),
 71        'access' => array(
 72            'required'       => true,
 73            'allow_multiple' => false,
 74            'order_text'     => 'follows @var',
 75        ),
 76        'see'      => array(
 77            'required'       => false,
 78            'allow_multiple' => false,
 79            'order_text'     => 'follows @since',
 80        ),
 81        'since'      => array(
 82            'required'       => true,
 83            'allow_multiple' => false,
 84            'order_text'     => 'follows @access',
 85        ),
 86        'Column'      => array(
 87            'required'       => false,
 88            'allow_multiple' => false,
 89            'order_text'     => 'follows @since',
 90        ),
 91        'OneToMany'      => array(
 92            'required'       => false,
 93            'allow_multiple' => false,
 94            'order_text'     => 'follows @Column',
 95        ),
 96        'OneToOne'      => array(
 97            'required'       => false,
 98            'allow_multiple' => false,
 99            'order_text'     => 'follows @Column',
100        ),
101        'ManyToMany'      => array(
102            'required'       => false,
103            'allow_multiple' => false,
104            'order_text'     => 'follows @Column',
105        ),
106        'ManyToOne'      => array(
107            'required'       => false,
108            'allow_multiple' => false,
109            'order_text'     => 'follows @Column',
110        ),
111        'Id'      => array(
112            'required'       => false,
113            'allow_multiple' => false,
114            'order_text'     => 'follows @Column',
115        ),
116        'GeneratedValue'      => array(
117            'required'       => false,
118            'allow_multiple' => false,
119            'order_text'     => 'follows @Column',
120        ),
121        'JoinColumn'      => array(
122            'required'       => false,
123            'allow_multiple' => false,
124            'order_text'     => 'follows @Column',
125		),
126        'OrderBy'      => array(
127            'required'       => false,
128            'allow_multiple' => false,
129            'order_text'     => 'follows @Column',
130		),
131	);
132
133    protected $reqCodeRequire = array('REQ.PHP.4.6.3');
134    protected $reqCodePHPVersion = false;
135    protected $reqCodeForbidden = 'REQ.PHP.4.6.3';
136    protected $reqCodeOnlyOne = 'REQ.PHP.4.6.5';
137
138    protected $docBlock = 'variable';
139
140    /**
141     * Returns an array of tokens this test wants to listen for.
142     *
143     * @return array
144     */
145    public function register()
146    {
147        return array(T_VARIABLE);
148
149    }//end register()
150
151
152    /**
153     * Processes this test, when one of its tokens is encountered.
154     *
155     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
156     * @param int                  $stackPtr  The position of the current token
157     *                                        in the stack passed in $tokens.
158     *
159     * @return void
160     */
161    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
162    {
163        $find = array(
164                 T_COMMENT,
165                 T_DOC_COMMENT,
166                 T_CLASS,
167                 T_FUNCTION,
168                 T_OPEN_TAG,
169                );
170
171        $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1));
172
173        if ($commentEnd === false) {
174            return;
175        }
176
177        $this->currentFile = $phpcsFile;
178        $tokens            = $phpcsFile->getTokens();
179
180		if (isset($tokens[$stackPtr]['nested_parenthesis'])) {
181			return;
182		}
183
184		if (!isset($tokens[$stackPtr]['conditions'])) {
185			return;
186		}
187
188		end($tokens[$stackPtr]['conditions']);
189		$ckey = key($tokens[$stackPtr]['conditions']);
190		if (!isset($tokens[$ckey]) || ($tokens[$ckey]['code'] !== T_CLASS && $tokens[$ckey]['code'] !== T_INTERFACE)) {
191			return;
192		}
193
194        // If the token that we found was a class or a function, then this
195        // function has no doc comment.
196        $code = $tokens[$commentEnd]['code'];
197
198        if ($code === T_COMMENT) {
199            $error = 'You must use "/**" style comments for a variable comment';
200            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.6.4') . $error, $stackPtr);
201            return;
202
203        } else if ($code !== T_DOC_COMMENT) {
204			$error = 'Missing variable doc comment';
205            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.6.1') . $error, $stackPtr);
206            return;
207        }
208
209        // If there is any code between the function keyword and the doc block
210        // then the doc block is not for us.
211        $ignore    = PHP_CodeSniffer_Tokens::$scopeModifiers;
212        $ignore[]  = T_STATIC;
213        $ignore[]  = T_WHITESPACE;
214        $ignore[]  = T_ABSTRACT;
215        $ignore[]  = T_FINAL;
216        $prevToken = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true);
217        if ($prevToken !== $commentEnd) {
218            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.6.1') . 'Missing function doc comment', $stackPtr);
219            return;
220        }
221
222        // If the first T_OPEN_TAG is right before the comment, it is probably
223        // a file comment.
224        $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1);
225        $prevToken    = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true);
226        if ($tokens[$prevToken]['code'] === T_OPEN_TAG) {
227            // Is this the first open tag?
228            if ($stackPtr === 0 || $phpcsFile->findPrevious(T_OPEN_TAG, ($prevToken - 1)) === false) {
229                $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.6.1') . 'Missing function doc comment', $stackPtr);
230                return;
231            }
232        }
233
234        $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1));
235
236        try {
237            $this->commentParser = new XLite_FunctionCommentParser($comment, $phpcsFile);
238            $this->commentParser->parse();
239        } catch (PHP_CodeSniffer_CommentParser_ParserException $e) {
240            $line = ($e->getLineWithinComment() + $commentStart);
241            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.1') . $e->getMessage(), $line);
242            return;
243        }
244
245        $comment = $this->commentParser->getComment();
246        if (is_null($comment) === true) {
247            $error = 'Variable doc comment is empty';
248            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.6.2') . $error, $commentStart);
249            return;
250        }
251
252		$this->checkAccess($stackPtr, $commentStart, $commentEnd);
253
254        $this->processTags($commentStart, $commentEnd);
255
256        // No extra newline before short description.
257        $short        = $comment->getShortComment();
258        $newlineCount = 0;
259        $newlineSpan  = strspn($short, $phpcsFile->eolChar);
260        if ($short !== '' && $newlineSpan > 0) {
261            $line  = ($newlineSpan > 1) ? 'newlines' : 'newline';
262            $error = "Extra $line found before variable comment short description";
263            $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.7') . $error, ($commentStart + 1));
264        }
265
266        $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1);
267
268        // Exactly one blank line between short and long description.
269        $long = $comment->getLongComment();
270        if (empty($long) === false) {
271            $between        = $comment->getWhiteSpaceBetween();
272            $newlineBetween = substr_count($between, $phpcsFile->eolChar);
273            if ($newlineBetween !== 2) {
274                $error = 'There must be exactly one blank line between descriptions in variable comment';
275                $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.19') . $error, ($commentStart + $newlineCount + 1));
276            }
277
278            $newlineCount += $newlineBetween;
279        }
280
281        // Exactly one blank line before tags.
282        $params = $this->commentParser->getTagOrders();
283        if (count($params) > 1) {
284            $newlineSpan = $comment->getNewlineAfter();
285            if ($newlineSpan !== 2) {
286                $error = 'There must be exactly one blank line before the tags in function comment';
287                if ($long !== '') {
288                    $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1);
289                }
290
291                $phpcsFile->addError($this->getReqPrefix('REQ.PHP.4.1.18') . $error, ($commentStart + $newlineCount));
292                $short = rtrim($short, $phpcsFile->eolChar.' ');
293            }
294        }
295
296    }//end process()
297
298}//end class
299
300?>