PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file FunctionCommentThrowTagSniff.php

Documentation is available at FunctionCommentThrowTagSniff.php

  1. <?php
  2. /**
  3.  * Verifies that a @throws tag exists for each exception type a function throws.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Commenting;
  11.  
  12. use PHP_CodeSniffer\Sniffs\AbstractScopeSniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class FunctionCommentThrowTagSniff extends AbstractScopeSniff
  17. {
  18.  
  19.  
  20.     /**
  21.      * Constructs a Squiz_Sniffs_Commenting_FunctionCommentThrowTagSniff.
  22.      */
  23.     public function __construct()
  24.     {
  25.         parent::__construct(array(T_FUNCTION)array(T_THROW));
  26.  
  27.     }//end __construct()
  28.  
  29.  
  30.     /**
  31.      * Processes the function tokens within the class.
  32.      *
  33.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
  34.      * @param int                         $stackPtr  The position where the token was found.
  35.      * @param int                         $currScope The current scope opener token.
  36.      *
  37.      * @return void 
  38.      */
  39.     protected function processTokenWithinScope(File $phpcsFile$stackPtr$currScope)
  40.     {
  41.         // Is this the first throw token within the current function scope?
  42.         // If so, we have to validate other throw tokens within the same scope.
  43.         $previousThrow $phpcsFile->findPrevious(T_THROW($stackPtr - 1)$currScope);
  44.         if ($previousThrow !== false{
  45.             return;
  46.         }
  47.  
  48.         $tokens $phpcsFile->getTokens();
  49.  
  50.         $find   = Tokens::$methodPrefixes;
  51.         $find[= T_WHITESPACE;
  52.  
  53.         $commentEnd $phpcsFile->findPrevious($find($currScope - 1)nulltrue);
  54.         if ($tokens[$commentEnd]['code'=== T_COMMENT{
  55.             // Function is using the wrong type of comment.
  56.             return;
  57.         }
  58.  
  59.         if ($tokens[$commentEnd]['code'!== T_DOC_COMMENT_CLOSE_TAG
  60.             && $tokens[$commentEnd]['code'!== T_COMMENT
  61.         {
  62.             // Function doesn't have a doc comment.
  63.             return;
  64.         }
  65.  
  66.         $currScopeEnd $tokens[$currScope]['scope_closer'];
  67.  
  68.         // Find all the exception type token within the current scope.
  69.         $thrownExceptions = array();
  70.         $currPos          $stackPtr;
  71.         $foundThrows      = false;
  72.         while ($currPos $currScopeEnd && $currPos !== false{
  73.             if ($phpcsFile->hasCondition($currPosT_CLOSURE=== false{
  74.                 $foundThrows = true;
  75.  
  76.                 /*
  77.                     If we can't find a NEW, we are probably throwing
  78.                     a variable.
  79.  
  80.                     If we're throwing the same variable as the exception container
  81.                     from the nearest 'catch' block, we take that exception, as it is
  82.                     likely to be a re-throw.
  83.  
  84.                     If we can't find a matching catch block, or the variable name
  85.                     is different, it's probably a different variable, so we ignore it,
  86.                     but they still need to provide at least one @throws tag, even through we
  87.                     don't know the exception class.
  88.                 */
  89.  
  90.                 $nextToken $phpcsFile->findNext(T_WHITESPACE($currPos + 1)nulltrue);
  91.                 if ($tokens[$nextToken]['code'=== T_NEW{
  92.                     $currException $phpcsFile->findNext(
  93.                         array(
  94.                          T_NS_SEPARATOR,
  95.                          T_STRING,
  96.                         ),
  97.                         $currPos,
  98.                         $currScopeEnd,
  99.                         false,
  100.                         null,
  101.                         true
  102.                     );
  103.  
  104.                     if ($currException !== false{
  105.                         $endException $phpcsFile->findNext(
  106.                             array(
  107.                              T_NS_SEPARATOR,
  108.                              T_STRING,
  109.                             ),
  110.                             ($currException + 1),
  111.                             $currScopeEnd,
  112.                             true,
  113.                             null,
  114.                             true
  115.                         );
  116.  
  117.                         if ($endException === false{
  118.                             $thrownExceptions[$tokens[$currException]['content'];
  119.                         else {
  120.                             $thrownExceptions[$phpcsFile->getTokensAsString($currException($endException $currException));
  121.                         }
  122.                     }//end if
  123.                 else if ($tokens[$nextToken]['code'=== T_VARIABLE{
  124.                     // Find the nearest catch block in this scope and, if the caught var
  125.                     // matches our rethrown var, use the exception types being caught as
  126.                     // exception types that are being thrown as well.
  127.                     $catch $phpcsFile->findPrevious(
  128.                         T_CATCH,
  129.                         $currPos,
  130.                         $tokens[$currScope]['scope_opener'],
  131.                         false,
  132.                         null,
  133.                         false
  134.                     );
  135.  
  136.                     if ($catch !== false{
  137.                         $thrownVar $phpcsFile->findPrevious(
  138.                             T_VARIABLE,
  139.                             ($tokens[$catch]['parenthesis_closer'- 1),
  140.                             $tokens[$catch]['parenthesis_opener']
  141.                         );
  142.  
  143.                         if ($tokens[$thrownVar]['content'=== $tokens[$nextToken]['content']{
  144.                             $exceptions explode('|'$phpcsFile->getTokensAsString(($tokens[$catch]['parenthesis_opener'+ 1)($thrownVar $tokens[$catch]['parenthesis_opener'- 1)));
  145.                             foreach ($exceptions as $exception{
  146.                                 $thrownExceptions[trim($exception);
  147.                             }
  148.                         }
  149.                     }
  150.                 }//end if
  151.             }//end if
  152.  
  153.             $currPos $phpcsFile->findNext(T_THROW($currPos + 1)$currScopeEnd);
  154.         }//end while
  155.  
  156.         if ($foundThrows === false{
  157.             return;
  158.         }
  159.  
  160.         // Only need one @throws tag for each type of exception thrown.
  161.         $thrownExceptions array_unique($thrownExceptions);
  162.  
  163.         $throwTags    = array();
  164.         $commentStart $tokens[$commentEnd]['comment_opener'];
  165.         foreach ($tokens[$commentStart]['comment_tags'as $tag{
  166.             if ($tokens[$tag]['content'!== '@throws'{
  167.                 continue;
  168.             }
  169.  
  170.             if ($tokens[($tag + 2)]['code'=== T_DOC_COMMENT_STRING{
  171.                 $exception $tokens[($tag + 2)]['content'];
  172.                 $space     strpos($exception' ');
  173.                 if ($space !== false{
  174.                     $exception substr($exception0$space);
  175.                 }
  176.  
  177.                 $throwTags[$exception= true;
  178.             }
  179.         }
  180.  
  181.         if (empty($throwTags=== true{
  182.             $error 'Missing @throws tag in function comment';
  183.             $phpcsFile->addError($error$commentEnd'Missing');
  184.             return;
  185.         else if (empty($thrownExceptions=== true{
  186.             // If token count is zero, it means that only variables are being
  187.             // thrown, so we need at least one @throws tag (checked above).
  188.             // Nothing more to do.
  189.             return;
  190.         }
  191.  
  192.         // Make sure @throws tag count matches thrown count.
  193.         $thrownCount count($thrownExceptions);
  194.         $tagCount    count($throwTags);
  195.         if ($thrownCount !== $tagCount{
  196.             $error 'Expected %s @throws tag(s) in function comment; %s found';
  197.             $data  = array(
  198.                       $thrownCount,
  199.                       $tagCount,
  200.                      );
  201.             $phpcsFile->addError($error$commentEnd'WrongNumber'$data);
  202.             return;
  203.         }
  204.  
  205.         foreach ($thrownExceptions as $throw{
  206.             if (isset($throwTags[$throw]=== false{
  207.                 $error 'Missing @throws tag for "%s" exception';
  208.                 $data  = array($throw);
  209.                 $phpcsFile->addError($error$commentEnd'Missing'$data);
  210.             }
  211.         }
  212.  
  213.     }//end processTokenWithinScope()
  214.  
  215.  
  216.     /**
  217.      * Processes a token that is found within the scope that this test is
  218.      * listening to.
  219.      *
  220.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
  221.      * @param int                         $stackPtr  The position in the stack where this
  222.      *                                                token was found.
  223.      *
  224.      * @return void 
  225.      */
  226.     protected function processTokenOutsideScope(File $phpcsFile$stackPtr)
  227.     {
  228.  
  229.     }//end processTokenOutsideScope()
  230.  
  231.  
  232. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:31 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.