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

Source for file FunctionCommentSniff.php

Documentation is available at FunctionCommentSniff.php

  1. <?php
  2. /**
  3.  * Parses and verifies the doc comments for functions.
  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\Standards\PEAR\Sniffs\Commenting\FunctionCommentSniff as PEARFunctionCommentSniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Config;
  15. use PHP_CodeSniffer\Util\Common;
  16.  
  17. class FunctionCommentSniff extends PEARFunctionCommentSniff
  18. {
  19.  
  20.     /**
  21.      * The current PHP version.
  22.      *
  23.      * @var integer 
  24.      */
  25.     private $phpVersion = null;
  26.  
  27.  
  28.     /**
  29.      * Process the return comment of this function comment.
  30.      *
  31.      * @param \PHP_CodeSniffer\Files\File $phpcsFile    The file being scanned.
  32.      * @param int                         $stackPtr     The position of the current token
  33.      *                                                   in the stack passed in $tokens.
  34.      * @param int                         $commentStart The position in the stack where the comment started.
  35.      *
  36.      * @return void 
  37.      */
  38.     protected function processReturn(File $phpcsFile, $stackPtr, $commentStart)
  39.     {
  40.         $tokens = $phpcsFile->getTokens();
  41.  
  42.         // Skip constructor and destructor.
  43.         $methodName      = $phpcsFile->getDeclarationName($stackPtr);
  44.         $isSpecialMethod = ($methodName === '__construct' || $methodName === '__destruct');
  45.  
  46.         $return = null;
  47.         foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
  48.             if ($tokens[$tag]['content'] === '@return') {
  49.                 if ($return !== null) {
  50.                     $error = 'Only 1 @return tag is allowed in a function comment';
  51.                     $phpcsFile->addError($error, $tag, 'DuplicateReturn');
  52.                     return;
  53.                 }
  54.  
  55.                 $return = $tag;
  56.             }
  57.         }
  58.  
  59.         if ($isSpecialMethod === true) {
  60.             return;
  61.         }
  62.  
  63.         if ($return !== null) {
  64.             $content = $tokens[($return + 2)]['content'];
  65.             if (empty($content) === true || $tokens[($return + 2)]['code'] !== T_DOC_COMMENT_STRING) {
  66.                 $error = 'Return type missing for @return tag in function comment';
  67.                 $phpcsFile->addError($error, $return, 'MissingReturnType');
  68.             } else {
  69.                 // Support both a return type and a description.
  70.                 $split = preg_match('`^((?:\|?(?:array\([^\)]*\)|[\\\\a-z0-9\[\]]+))*)( .*)?`i', $content, $returnParts);
  71.                 if (isset($returnParts[1]) === false) {
  72.                     return;
  73.                 }
  74.  
  75.                 $returnType = $returnParts[1];
  76.  
  77.                 // Check return type (can be multiple, separated by '|').
  78.                 $typeNames      = explode('|', $returnType);
  79.                 $suggestedNames = array();
  80.                 foreach ($typeNames as $i => $typeName) {
  81.                     $suggestedName = Common::suggestType($typeName);
  82.                     if (in_array($suggestedName, $suggestedNames) === false) {
  83.                         $suggestedNames[] = $suggestedName;
  84.                     }
  85.                 }
  86.  
  87.                 $suggestedType = implode('|', $suggestedNames);
  88.                 if ($returnType !== $suggestedType) {
  89.                     $error = 'Expected "%s" but found "%s" for function return type';
  90.                     $data  = array(
  91.                               $suggestedType,
  92.                               $returnType,
  93.                              );
  94.                     $fix   = $phpcsFile->addFixableError($error, $return, 'InvalidReturn', $data);
  95.                     if ($fix === true) {
  96.                         $replacement = $suggestedType;
  97.                         if (empty($returnParts[2]) === false) {
  98.                             $replacement .= $returnParts[2];
  99.                         }
  100.  
  101.                         $phpcsFile->fixer->replaceToken(($return + 2), $replacement);
  102.                         unset($replacement);
  103.                     }
  104.                 }
  105.  
  106.                 // If the return type is void, make sure there is
  107.                 // no return statement in the function.
  108.                 if ($returnType === 'void') {
  109.                     if (isset($tokens[$stackPtr]['scope_closer']) === true) {
  110.                         $endToken = $tokens[$stackPtr]['scope_closer'];
  111.                         for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++) {
  112.                             if ($tokens[$returnToken]['code'] === T_CLOSURE
  113.                                 || $tokens[$returnToken]['code'] === T_ANON_CLASS
  114.                             ) {
  115.                                 $returnToken = $tokens[$returnToken]['scope_closer'];
  116.                                 continue;
  117.                             }
  118.  
  119.                             if ($tokens[$returnToken]['code'] === T_RETURN
  120.                                 || $tokens[$returnToken]['code'] === T_YIELD
  121.                                 || $tokens[$returnToken]['code'] === T_YIELD_FROM
  122.                             ) {
  123.                                 break;
  124.                             }
  125.                         }
  126.  
  127.                         if ($returnToken !== $endToken) {
  128.                             // If the function is not returning anything, just
  129.                             // exiting, then there is no problem.
  130.                             $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
  131.                             if ($tokens[$semicolon]['code'] !== T_SEMICOLON) {
  132.                                 $error = 'Function return type is void, but function contains return statement';
  133.                                 $phpcsFile->addError($error, $return, 'InvalidReturnVoid');
  134.                             }
  135.                         }
  136.                     }//end if
  137.                 } else if ($returnType !== 'mixed' && in_array('void', $typeNames, true) === false) {
  138.                     // If return type is not void, there needs to be a return statement
  139.                     // somewhere in the function that returns something.
  140.                     if (isset($tokens[$stackPtr]['scope_closer']) === true) {
  141.                         $endToken = $tokens[$stackPtr]['scope_closer'];
  142.                         for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++) {
  143.                             if ($tokens[$returnToken]['code'] === T_CLOSURE
  144.                                 || $tokens[$returnToken]['code'] === T_ANON_CLASS
  145.                             ) {
  146.                                 $returnToken = $tokens[$returnToken]['scope_closer'];
  147.                                 continue;
  148.                             }
  149.  
  150.                             if ($tokens[$returnToken]['code'] === T_RETURN
  151.                                 || $tokens[$returnToken]['code'] === T_YIELD
  152.                                 || $tokens[$returnToken]['code'] === T_YIELD_FROM
  153.                             ) {
  154.                                 break;
  155.                             }
  156.                         }
  157.  
  158.                         if ($returnToken === $endToken) {
  159.                             $error = 'Function return type is not void, but function has no return statement';
  160.                             $phpcsFile->addError($error, $return, 'InvalidNoReturn');
  161.                         } else {
  162.                             $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
  163.                             if ($tokens[$semicolon]['code'] === T_SEMICOLON) {
  164.                                 $error = 'Function return type is not void, but function is returning void here';
  165.                                 $phpcsFile->addError($error, $returnToken, 'InvalidReturnNotVoid');
  166.                             }
  167.                         }
  168.                     }//end if
  169.                 }//end if
  170.             }//end if
  171.         } else {
  172.             $error = 'Missing @return tag in function comment';
  173.             $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn');
  174.         }//end if
  175.  
  176.     }//end processReturn()
  177.  
  178.  
  179.     /**
  180.      * Process any throw tags that this function comment has.
  181.      *
  182.      * @param \PHP_CodeSniffer\Files\File $phpcsFile    The file being scanned.
  183.      * @param int                         $stackPtr     The position of the current token
  184.      *                                                   in the stack passed in $tokens.
  185.      * @param int                         $commentStart The position in the stack where the comment started.
  186.      *
  187.      * @return void 
  188.      */
  189.     protected function processThrows(File $phpcsFile, $stackPtr, $commentStart)
  190.     {
  191.         $tokens = $phpcsFile->getTokens();
  192.  
  193.         $throws = array();
  194.         foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag) {
  195.             if ($tokens[$tag]['content'] !== '@throws') {
  196.                 continue;
  197.             }
  198.  
  199.             $exception = null;
  200.             $comment   = null;
  201.             if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) {
  202.                 $matches = array();
  203.                 preg_match('/([^\s]+)(?:\s+(.*))?/', $tokens[($tag + 2)]['content'], $matches);
  204.                 $exception = $matches[1];
  205.                 if (isset($matches[2]) === true && trim($matches[2]) !== '') {
  206.                     $comment = $matches[2];
  207.                 }
  208.             }
  209.  
  210.             if ($exception === null) {
  211.                 $error = 'Exception type and comment missing for @throws tag in function comment';
  212.                 $phpcsFile->addError($error, $tag, 'InvalidThrows');
  213.             } else if ($comment === null) {
  214.                 $error = 'Comment missing for @throws tag in function comment';
  215.                 $phpcsFile->addError($error, $tag, 'EmptyThrows');
  216.             } else {
  217.                 // Any strings until the next tag belong to this comment.
  218.                 if (isset($tokens[$commentStart]['comment_tags'][($pos + 1)]) === true) {
  219.                     $end = $tokens[$commentStart]['comment_tags'][($pos + 1)];
  220.                 } else {
  221.                     $end = $tokens[$commentStart]['comment_closer'];
  222.                 }
  223.  
  224.                 for ($i = ($tag + 3); $i < $end; $i++) {
  225.                     if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) {
  226.                         $comment .= ' '.$tokens[$i]['content'];
  227.                     }
  228.                 }
  229.  
  230.                 // Starts with a capital letter and ends with a fullstop.
  231.                 $firstChar = $comment{0};
  232.                 if (strtoupper($firstChar) !== $firstChar) {
  233.                     $error = '@throws tag comment must start with a capital letter';
  234.                     $phpcsFile->addError($error, ($tag + 2), 'ThrowsNotCapital');
  235.                 }
  236.  
  237.                 $lastChar = substr($comment, -1);
  238.                 if ($lastChar !== '.') {
  239.                     $error = '@throws tag comment must end with a full stop';
  240.                     $phpcsFile->addError($error, ($tag + 2), 'ThrowsNoFullStop');
  241.                 }
  242.             }//end if
  243.         }//end foreach
  244.  
  245.     }//end processThrows()
  246.  
  247.  
  248.     /**
  249.      * Process the function parameter comments.
  250.      *
  251.      * @param \PHP_CodeSniffer\Files\File $phpcsFile    The file being scanned.
  252.      * @param int                         $stackPtr     The position of the current token
  253.      *                                                   in the stack passed in $tokens.
  254.      * @param int                         $commentStart The position in the stack where the comment started.
  255.      *
  256.      * @return void 
  257.      */
  258.     protected function processParams(File $phpcsFile, $stackPtr, $commentStart)
  259.     {
  260.         if ($this->phpVersion === null) {
  261.             $this->phpVersion = Config::getConfigData('php_version');
  262.             if ($this->phpVersion === null) {
  263.                 $this->phpVersion = PHP_VERSION_ID;
  264.             }
  265.         }
  266.  
  267.         $tokens = $phpcsFile->getTokens();
  268.  
  269.         $params  = array();
  270.         $maxType = 0;
  271.         $maxVar  = 0;
  272.         foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag) {
  273.             if ($tokens[$tag]['content'] !== '@param') {
  274.                 continue;
  275.             }
  276.  
  277.             $type         = '';
  278.             $typeSpace    = 0;
  279.             $var          = '';
  280.             $varSpace     = 0;
  281.             $comment      = '';
  282.             $commentLines = array();
  283.             if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) {
  284.                 $matches = array();
  285.                 preg_match('/([^$&.]+)(?:((?:\.\.\.)?(?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches);
  286.  
  287.                 if (empty($matches) === false) {
  288.                     $typeLen   = strlen($matches[1]);
  289.                     $type      = trim($matches[1]);
  290.                     $typeSpace = ($typeLen - strlen($type));
  291.                     $typeLen   = strlen($type);
  292.                     if ($typeLen > $maxType) {
  293.                         $maxType = $typeLen;
  294.                     }
  295.                 }
  296.  
  297.                 if (isset($matches[2]) === true) {
  298.                     $var    = $matches[2];
  299.                     $varLen = strlen($var);
  300.                     if ($varLen > $maxVar) {
  301.                         $maxVar = $varLen;
  302.                     }
  303.  
  304.                     if (isset($matches[4]) === true) {
  305.                         $varSpace       = strlen($matches[3]);
  306.                         $comment        = $matches[4];
  307.                         $commentLines[] = array(
  308.                                            'comment' => $comment,
  309.                                            'token'   => ($tag + 2),
  310.                                            'indent'  => $varSpace,
  311.                                           );
  312.  
  313.                         // Any strings until the next tag belong to this comment.
  314.                         if (isset($tokens[$commentStart]['comment_tags'][($pos + 1)]) === true) {
  315.                             $end = $tokens[$commentStart]['comment_tags'][($pos + 1)];
  316.                         } else {
  317.                             $end = $tokens[$commentStart]['comment_closer'];
  318.                         }
  319.  
  320.                         for ($i = ($tag + 3); $i < $end; $i++) {
  321.                             if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) {
  322.                                 $indent = 0;
  323.                                 if ($tokens[($i - 1)]['code'] === T_DOC_COMMENT_WHITESPACE) {
  324.                                     $indent = strlen($tokens[($i - 1)]['content']);
  325.                                 }
  326.  
  327.                                 $comment       .= ' '.$tokens[$i]['content'];
  328.                                 $commentLines[] = array(
  329.                                                    'comment' => $tokens[$i]['content'],
  330.                                                    'token'   => $i,
  331.                                                    'indent'  => $indent,
  332.                                                   );
  333.                             }
  334.                         }
  335.                     } else {
  336.                         $error = 'Missing parameter comment';
  337.                         $phpcsFile->addError($error, $tag, 'MissingParamComment');
  338.                         $commentLines[] = array('comment' => '');
  339.                     }//end if
  340.                 } else {
  341.                     $error = 'Missing parameter name';
  342.                     $phpcsFile->addError($error, $tag, 'MissingParamName');
  343.                 }//end if
  344.             } else {
  345.                 $error = 'Missing parameter type';
  346.                 $phpcsFile->addError($error, $tag, 'MissingParamType');
  347.             }//end if
  348.  
  349.             $params[] = array(
  350.                          'tag'          => $tag,
  351.                          'type'         => $type,
  352.                          'var'          => $var,
  353.                          'comment'      => $comment,
  354.                          'commentLines' => $commentLines,
  355.                          'type_space'   => $typeSpace,
  356.                          'var_space'    => $varSpace,
  357.                         );
  358.         }//end foreach
  359.  
  360.         $realParams  = $phpcsFile->getMethodParameters($stackPtr);
  361.         $foundParams = array();
  362.  
  363.         // We want to use ... for all variable length arguments, so added
  364.         // this prefix to the variable name so comparisons are easier.
  365.         foreach ($realParams as $pos => $param) {
  366.             if ($param['variable_length'] === true) {
  367.                 $realParams[$pos]['name'] = '...'.$realParams[$pos]['name'];
  368.             }
  369.         }
  370.  
  371.         foreach ($params as $pos => $param) {
  372.             // If the type is empty, the whole line is empty.
  373.             if ($param['type'] === '') {
  374.                 continue;
  375.             }
  376.  
  377.             // Check the param type value.
  378.             $typeNames          = explode('|', $param['type']);
  379.             $suggestedTypeNames = array();
  380.  
  381.             foreach ($typeNames as $typeName) {
  382.                 $suggestedName        = Common::suggestType($typeName);
  383.                 $suggestedTypeNames[] = $suggestedName;
  384.  
  385.                 if (count($typeNames) > 1) {
  386.                     continue;
  387.                 }
  388.  
  389.                 // Check type hint for array and custom type.
  390.                 $suggestedTypeHint = '';
  391.                 if (strpos($suggestedName, 'array') !== false || substr($suggestedName, -2) === '[]') {
  392.                     $suggestedTypeHint = 'array';
  393.                 } else if (strpos($suggestedName, 'callable') !== false) {
  394.                     $suggestedTypeHint = 'callable';
  395.                 } else if (strpos($suggestedName, 'callback') !== false) {
  396.                     $suggestedTypeHint = 'callable';
  397.                 } else if (in_array($suggestedName, Common::$allowedTypes) === false) {
  398.                     $suggestedTypeHint = $suggestedName;
  399.                 }
  400.  
  401.                 if ($this->phpVersion >= 70000) {
  402.                     if ($suggestedName === 'string') {
  403.                         $suggestedTypeHint = 'string';
  404.                     } else if ($suggestedName === 'int' || $suggestedName === 'integer') {
  405.                         $suggestedTypeHint = 'int';
  406.                     } else if ($suggestedName === 'float') {
  407.                         $suggestedTypeHint = 'float';
  408.                     } else if ($suggestedName === 'bool' || $suggestedName === 'boolean') {
  409.                         $suggestedTypeHint = 'bool';
  410.                     }
  411.                 }
  412.  
  413.                 if ($suggestedTypeHint !== '' && isset($realParams[$pos]) === true) {
  414.                     $typeHint = $realParams[$pos]['type_hint'];
  415.                     if ($typeHint === '') {
  416.                         $error = 'Type hint "%s" missing for %s';
  417.                         $data  = array(
  418.                                   $suggestedTypeHint,
  419.                                   $param['var'],
  420.                                  );
  421.  
  422.                         $errorCode = 'TypeHintMissing';
  423.                         if ($suggestedTypeHint === 'string'
  424.                             || $suggestedTypeHint === 'int'
  425.                             || $suggestedTypeHint === 'float'
  426.                             || $suggestedTypeHint === 'bool'
  427.                         ) {
  428.                             $errorCode = 'Scalar'.$errorCode;
  429.                         }
  430.  
  431.                         $phpcsFile->addError($error, $stackPtr, $errorCode, $data);
  432.                     } else if ($typeHint !== substr($suggestedTypeHint, (strlen($typeHint) * -1))) {
  433.                         $error = 'Expected type hint "%s"; found "%s" for %s';
  434.                         $data  = array(
  435.                                   $suggestedTypeHint,
  436.                                   $typeHint,
  437.                                   $param['var'],
  438.                                  );
  439.                         $phpcsFile->addError($error, $stackPtr, 'IncorrectTypeHint', $data);
  440.                     }//end if
  441.                 } else if ($suggestedTypeHint === '' && isset($realParams[$pos]) === true) {
  442.                     $typeHint = $realParams[$pos]['type_hint'];
  443.                     if ($typeHint !== '') {
  444.                         $error = 'Unknown type hint "%s" found for %s';
  445.                         $data  = array(
  446.                                   $typeHint,
  447.                                   $param['var'],
  448.                                  );
  449.                         $phpcsFile->addError($error, $stackPtr, 'InvalidTypeHint', $data);
  450.                     }
  451.                 }//end if
  452.             }//end foreach
  453.  
  454.             $suggestedType = implode($suggestedTypeNames, '|');
  455.             if ($param['type'] !== $suggestedType) {
  456.                 $error = 'Expected "%s" but found "%s" for parameter type';
  457.                 $data  = array(
  458.                           $suggestedType,
  459.                           $param['type'],
  460.                          );
  461.  
  462.                 $fix = $phpcsFile->addFixableError($error, $param['tag'], 'IncorrectParamVarName', $data);
  463.                 if ($fix === true) {
  464.                     $phpcsFile->fixer->beginChangeset();
  465.  
  466.                     $content  = $suggestedType;
  467.                     $content .= str_repeat(' ', $param['type_space']);
  468.                     $content .= $param['var'];
  469.                     $content .= str_repeat(' ', $param['var_space']);
  470.                     if (isset($param['commentLines'][0]) === true) {
  471.                         $content .= $param['commentLines'][0]['comment'];
  472.                     }
  473.  
  474.                     $phpcsFile->fixer->replaceToken(($param['tag'] + 2), $content);
  475.  
  476.                     // Fix up the indent of additional comment lines.
  477.                     foreach ($param['commentLines'] as $lineNum => $line) {
  478.                         if ($lineNum === 0
  479.                             || $param['commentLines'][$lineNum]['indent'] === 0
  480.                         ) {
  481.                             continue;
  482.                         }
  483.  
  484.                         $diff      = (strlen($param['type']) - strlen($suggestedType));
  485.                         $newIndent = ($param['commentLines'][$lineNum]['indent'] - $diff);
  486.                         $phpcsFile->fixer->replaceToken(
  487.                             ($param['commentLines'][$lineNum]['token'] - 1),
  488.                             str_repeat(' ', $newIndent)
  489.                         );
  490.                     }
  491.  
  492.                     $phpcsFile->fixer->endChangeset();
  493.                 }//end if
  494.             }//end if
  495.  
  496.             if ($param['var'] === '') {
  497.                 continue;
  498.             }
  499.  
  500.             $foundParams[] = $param['var'];
  501.  
  502.             // Check number of spaces after the type.
  503.             $this->checkSpacingAfterParamType($phpcsFile, $param, $maxType);
  504.  
  505.             // Make sure the param name is correct.
  506.             if (isset($realParams[$pos]) === true) {
  507.                 $realName = $realParams[$pos]['name'];
  508.                 if ($realName !== $param['var']) {
  509.                     $code = 'ParamNameNoMatch';
  510.                     $data = array(
  511.                              $param['var'],
  512.                              $realName,
  513.                             );
  514.  
  515.                     $error = 'Doc comment for parameter %s does not match ';
  516.                     if (strtolower($param['var']) === strtolower($realName)) {
  517.                         $error .= 'case of ';
  518.                         $code   = 'ParamNameNoCaseMatch';
  519.                     }
  520.  
  521.                     $error .= 'actual variable name %s';
  522.  
  523.                     $phpcsFile->addError($error, $param['tag'], $code, $data);
  524.                 }
  525.             } else if (substr($param['var'], -4) !== ',...') {
  526.                 // We must have an extra parameter comment.
  527.                 $error = 'Superfluous parameter comment';
  528.                 $phpcsFile->addError($error, $param['tag'], 'ExtraParamComment');
  529.             }//end if
  530.  
  531.             if ($param['comment'] === '') {
  532.                 continue;
  533.             }
  534.  
  535.             // Check number of spaces after the var name.
  536.             $this->checkSpacingAfterParamName($phpcsFile, $param, $maxVar);
  537.  
  538.             // Param comments must start with a capital letter and end with the full stop.
  539.             if (preg_match('/^(\p{Ll}|\P{L})/u', $param['comment']) === 1) {
  540.                 $error = 'Parameter comment must start with a capital letter';
  541.                 $phpcsFile->addError($error, $param['tag'], 'ParamCommentNotCapital');
  542.             }
  543.  
  544.             $lastChar = substr($param['comment'], -1);
  545.             if ($lastChar !== '.') {
  546.                 $error = 'Parameter comment must end with a full stop';
  547.                 $phpcsFile->addError($error, $param['tag'], 'ParamCommentFullStop');
  548.             }
  549.         }//end foreach
  550.  
  551.         $realNames = array();
  552.         foreach ($realParams as $realParam) {
  553.             $realNames[] = $realParam['name'];
  554.         }
  555.  
  556.         // Report missing comments.
  557.         $diff = array_diff($realNames, $foundParams);
  558.         foreach ($diff as $neededParam) {
  559.             $error = 'Doc comment for parameter "%s" missing';
  560.             $data  = array($neededParam);
  561.             $phpcsFile->addError($error, $commentStart, 'MissingParamTag', $data);
  562.         }
  563.  
  564.     }//end processParams()
  565.  
  566.  
  567.     /**
  568.      * Check the spacing after the type of a parameter.
  569.      *
  570.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  571.      * @param array                       $param     The parameter to be checked.
  572.      * @param int                         $maxType   The maxlength of the longest parameter type.
  573.      * @param int                         $spacing   The number of spaces to add after the type.
  574.      *
  575.      * @return void 
  576.      */
  577.     protected function checkSpacingAfterParamType(File $phpcsFile, $param, $maxType, $spacing=1)
  578.     {
  579.         // Check number of spaces after the type.
  580.         $spaces = ($maxType - strlen($param['type']) + $spacing);
  581.         if ($param['type_space'] !== $spaces) {
  582.             $error = 'Expected %s spaces after parameter type; %s found';
  583.             $data  = array(
  584.                       $spaces,
  585.                       $param['type_space'],
  586.                      );
  587.  
  588.             $fix = $phpcsFile->addFixableError($error, $param['tag'], 'SpacingAfterParamType', $data);
  589.             if ($fix === true) {
  590.                 $phpcsFile->fixer->beginChangeset();
  591.  
  592.                 $content  = $param['type'];
  593.                 $content .= str_repeat(' ', $spaces);
  594.                 $content .= $param['var'];
  595.                 $content .= str_repeat(' ', $param['var_space']);
  596.                 $content .= $param['commentLines'][0]['comment'];
  597.                 $phpcsFile->fixer->replaceToken(($param['tag'] + 2), $content);
  598.  
  599.                 // Fix up the indent of additional comment lines.
  600.                 foreach ($param['commentLines'] as $lineNum => $line) {
  601.                     if ($lineNum === 0
  602.                         || $param['commentLines'][$lineNum]['indent'] === 0
  603.                     ) {
  604.                         continue;
  605.                     }
  606.  
  607.                     $diff      = ($param['type_space'] - $spaces);
  608.                     $newIndent = ($param['commentLines'][$lineNum]['indent'] - $diff);
  609.                     $phpcsFile->fixer->replaceToken(
  610.                         ($param['commentLines'][$lineNum]['token'] - 1),
  611.                         str_repeat(' ', $newIndent)
  612.                     );
  613.                 }
  614.  
  615.                 $phpcsFile->fixer->endChangeset();
  616.             }//end if
  617.         }//end if
  618.  
  619.     }//end checkSpacingAfterParamType()
  620.  
  621.  
  622.     /**
  623.      * Check the spacing after the name of a parameter.
  624.      *
  625.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  626.      * @param array                       $param     The parameter to be checked.
  627.      * @param int                         $maxVar    The maxlength of the longest parameter name.
  628.      * @param int                         $spacing   The number of spaces to add after the type.
  629.      *
  630.      * @return void 
  631.      */
  632.     protected function checkSpacingAfterParamName(File $phpcsFile, $param, $maxVar, $spacing=1)
  633.     {
  634.         // Check number of spaces after the var name.
  635.         $spaces = ($maxVar - strlen($param['var']) + $spacing);
  636.         if ($param['var_space'] !== $spaces) {
  637.             $error = 'Expected %s spaces after parameter name; %s found';
  638.             $data  = array(
  639.                       $spaces,
  640.                       $param['var_space'],
  641.                      );
  642.  
  643.             $fix = $phpcsFile->addFixableError($error, $param['tag'], 'SpacingAfterParamName', $data);
  644.             if ($fix === true) {
  645.                 $phpcsFile->fixer->beginChangeset();
  646.  
  647.                 $content  = $param['type'];
  648.                 $content .= str_repeat(' ', $param['type_space']);
  649.                 $content .= $param['var'];
  650.                 $content .= str_repeat(' ', $spaces);
  651.                 $content .= $param['commentLines'][0]['comment'];
  652.                 $phpcsFile->fixer->replaceToken(($param['tag'] + 2), $content);
  653.  
  654.                 // Fix up the indent of additional comment lines.
  655.                 foreach ($param['commentLines'] as $lineNum => $line) {
  656.                     if ($lineNum === 0
  657.                         || $param['commentLines'][$lineNum]['indent'] === 0
  658.                     ) {
  659.                         continue;
  660.                     }
  661.  
  662.                     $diff      = ($param['var_space'] - $spaces);
  663.                     $newIndent = ($param['commentLines'][$lineNum]['indent'] - $diff);
  664.                     if ($newIndent <= 0) {
  665.                         continue;
  666.                     }
  667.  
  668.                     $phpcsFile->fixer->replaceToken(
  669.                         ($param['commentLines'][$lineNum]['token'] - 1),
  670.                         str_repeat(' ', $newIndent)
  671.                     );
  672.                 }
  673.  
  674.                 $phpcsFile->fixer->endChangeset();
  675.             }//end if
  676.         }//end if
  677.  
  678.     }//end checkSpacingAfterParamName()
  679.  
  680.  
  681. }//end class

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