/**
  * Returns an array of tokens this test wants to listen for.
  *
  * @return array
  */
 public function register()
 {
     if ($this->phpVersion === null) {
         $this->phpVersion = Config::getConfigData('php_version');
         if ($this->phpVersion === null) {
             $this->phpVersion = PHP_VERSION_ID;
         }
     }
     if ($this->phpVersion < 70000) {
         $this->aspTags = (bool) ini_get('asp_tags');
     }
     return array(T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_INLINE_HTML);
 }
Example #2
0
 /**
  * Get a list paths where standards are installed.
  *
  * @return array
  */
 public static function getInstalledStandardPaths()
 {
     $installedPaths = array(Common::realPath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Standards'));
     $configPaths = Config::getConfigData('installed_paths');
     if ($configPaths !== null) {
         $installedPaths = array_merge($installedPaths, explode(',', $configPaths));
     }
     $resolvedInstalledPaths = array();
     foreach ($installedPaths as $installedPath) {
         if (substr($installedPath, 0, 1) === '.') {
             $installedPath = Common::realPath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . $installedPath);
         }
         $resolvedInstalledPaths[] = $installedPath;
     }
     return $resolvedInstalledPaths;
 }
Example #3
0
 /**
  * Load configuration data.
  */
 public function __construct()
 {
     $path = Config::getExecutablePath('notifysend');
     if ($path !== null) {
         $this->path = $path;
     }
     $timeout = Config::getConfigData('notifysend_timeout');
     if ($timeout !== null) {
         $this->timeout = (int) $timeout;
     }
     $showOk = Config::getConfigData('notifysend_showok');
     if ($showOk !== null) {
         $this->showOk = (bool) $showOk;
     }
     $this->version = str_replace('notify-send ', '', exec($this->path . ' --version'));
 }
Example #4
0
 /**
  * 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(File $phpcsFile, $stackPtr)
 {
     $debug = Config::getConfigData('scope_indent_debug');
     if ($debug !== null) {
         $this->debug = (bool) $debug;
     }
     if ($this->tabWidth === null) {
         if (isset($phpcsFile->config->tabWidth) === false || $phpcsFile->config->tabWidth === 0) {
             // We have no idea how wide tabs are, so assume 4 spaces for fixing.
             // It shouldn't really matter because indent checks elsewhere in the
             // standard should fix things up.
             $this->tabWidth = 4;
         } else {
             $this->tabWidth = $phpcsFile->config->tabWidth;
         }
     }
     $currentIndent = 0;
     $lastOpenTag = $stackPtr;
     $lastCloseTag = null;
     $openScopes = array();
     $adjustments = array();
     $setIndents = array();
     $tokens = $phpcsFile->getTokens();
     $first = $phpcsFile->findFirstOnLine(T_INLINE_HTML, $stackPtr);
     $trimmed = ltrim($tokens[$first]['content']);
     if ($trimmed === '') {
         $currentIndent = $tokens[$stackPtr]['column'] - 1;
     } else {
         $currentIndent = strlen($tokens[$first]['content']) - strlen($trimmed);
     }
     if ($this->debug === true) {
         $line = $tokens[$stackPtr]['line'];
         echo "Start with token {$stackPtr} on line {$line} with indent {$currentIndent}" . PHP_EOL;
     }
     if (empty($this->ignoreIndentation) === true) {
         $this->ignoreIndentation = array(T_INLINE_HTML => true);
         foreach ($this->ignoreIndentationTokens as $token) {
             if (is_int($token) === false) {
                 if (defined($token) === false) {
                     continue;
                 }
                 $token = constant($token);
             }
             $this->ignoreIndentation[$token] = true;
         }
     }
     //end if
     $this->exact = (bool) $this->exact;
     $this->tabIndent = (bool) $this->tabIndent;
     for ($i = $stackPtr + 1; $i < $phpcsFile->numTokens; $i++) {
         if ($i === false) {
             // Something has gone very wrong; maybe a parse error.
             break;
         }
         $checkToken = null;
         $checkIndent = null;
         $exact = (bool) $this->exact;
         if ($exact === true && isset($tokens[$i]['nested_parenthesis']) === true) {
             // Don't check indents exactly between parenthesis as they
             // tend to have custom rules, such as with multi-line function calls
             // and control structure conditions.
             $exact = false;
         }
         // Detect line changes and figure out where the indent is.
         if ($tokens[$i]['column'] === 1) {
             $trimmed = ltrim($tokens[$i]['content']);
             if ($trimmed === '') {
                 if (isset($tokens[$i + 1]) === true && $tokens[$i]['line'] === $tokens[$i + 1]['line']) {
                     $checkToken = $i + 1;
                     $tokenIndent = $tokens[$i + 1]['column'] - 1;
                 }
             } else {
                 $checkToken = $i;
                 $tokenIndent = strlen($tokens[$i]['content']) - strlen($trimmed);
             }
         }
         // Closing parenthesis should just be indented to at least
         // the same level as where they were opened (but can be more).
         if ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$checkToken]['parenthesis_opener']) === true || $tokens[$i]['code'] === T_CLOSE_PARENTHESIS && isset($tokens[$i]['parenthesis_opener']) === true && isset($tokens[$i]['parenthesis_owner']) === true && $tokens[$tokens[$i]['parenthesis_owner']]['code'] === T_ARRAY) {
             if ($checkToken !== null) {
                 $parenCloser = $checkToken;
             } else {
                 $parenCloser = $i;
             }
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Closing parenthesis found on line {$line}" . PHP_EOL;
             }
             $parenOpener = $tokens[$parenCloser]['parenthesis_opener'];
             if ($tokens[$parenCloser]['line'] !== $tokens[$parenOpener]['line']) {
                 $parens = 0;
                 if (isset($tokens[$parenCloser]['nested_parenthesis']) === true && empty($tokens[$parenCloser]['nested_parenthesis']) === false) {
                     end($tokens[$parenCloser]['nested_parenthesis']);
                     $parens = key($tokens[$parenCloser]['nested_parenthesis']);
                     if ($this->debug === true) {
                         $line = $tokens[$parens]['line'];
                         echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
                     }
                 }
                 $condition = 0;
                 if (isset($tokens[$parenCloser]['conditions']) === true && empty($tokens[$parenCloser]['conditions']) === false) {
                     end($tokens[$parenCloser]['conditions']);
                     $condition = key($tokens[$parenCloser]['conditions']);
                     if ($this->debug === true) {
                         $line = $tokens[$condition]['line'];
                         $type = $tokens[$condition]['type'];
                         echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
                     }
                 }
                 if ($parens > $condition) {
                     if ($this->debug === true) {
                         echo "\t* using parenthesis *" . PHP_EOL;
                     }
                     $parenOpener = $parens;
                     $condition = 0;
                 } else {
                     if ($condition > 0) {
                         if ($this->debug === true) {
                             echo "\t* using condition *" . PHP_EOL;
                         }
                         $parenOpener = $condition;
                         $parens = 0;
                     }
                 }
                 $exact = false;
                 if ($condition > 0 && $lastOpenTag > $condition) {
                     if ($this->debug === true) {
                         echo "\t* open tag is inside condition; using open tag *" . PHP_EOL;
                     }
                     $checkIndent = $tokens[$lastOpenTag]['column'] - 1;
                     if (isset($adjustments[$condition]) === true) {
                         $checkIndent += $adjustments[$condition];
                     }
                     $currentIndent = $checkIndent;
                     if ($this->debug === true) {
                         $type = $tokens[$lastOpenTag]['type'];
                         echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$lastOpenTag} ({$type})" . PHP_EOL;
                     }
                 } else {
                     if ($condition > 0 && isset($tokens[$condition]['scope_opener']) === true && isset($setIndents[$tokens[$condition]['scope_opener']]) === true) {
                         $checkIndent = $setIndents[$tokens[$condition]['scope_opener']];
                         if (isset($adjustments[$condition]) === true) {
                             $checkIndent += $adjustments[$condition];
                         }
                         $currentIndent = $checkIndent;
                         if ($this->debug === true) {
                             $type = $tokens[$condition]['type'];
                             echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$condition} ({$type})" . PHP_EOL;
                         }
                     } else {
                         $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $parenOpener, true);
                         $checkIndent = $tokens[$first]['column'] - 1;
                         if (isset($adjustments[$first]) === true) {
                             $checkIndent += $adjustments[$first];
                         }
                         if ($this->debug === true) {
                             $line = $tokens[$first]['line'];
                             $type = $tokens[$first]['type'];
                             echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
                         }
                         if ($first === $tokens[$parenCloser]['parenthesis_opener']) {
                             // This is unlikely to be the start of the statement, so look
                             // back further to find it.
                             $first--;
                         }
                         $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                         if ($prev !== $first) {
                             // This is not the start of the statement.
                             if ($this->debug === true) {
                                 $line = $tokens[$prev]['line'];
                                 $type = $tokens[$prev]['type'];
                                 echo "\t* previous is {$type} on line {$line} *" . PHP_EOL;
                             }
                             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                             $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                             if ($this->debug === true) {
                                 $line = $tokens[$first]['line'];
                                 $type = $tokens[$first]['type'];
                                 echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
                             }
                         }
                         if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
                             if ($this->debug === true) {
                                 echo "\t* first token is a scope closer *" . PHP_EOL;
                             }
                             if (isset($tokens[$first]['scope_condition']) === true) {
                                 $scopeCloser = $first;
                                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true);
                                 $currentIndent = $tokens[$first]['column'] - 1;
                                 if (isset($adjustments[$first]) === true) {
                                     $currentIndent += $adjustments[$first];
                                 }
                                 // Make sure it is divisible by our expected indent.
                                 if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) {
                                     $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
                                 }
                                 $setIndents[$first] = $currentIndent;
                                 if ($this->debug === true) {
                                     $type = $tokens[$first]['type'];
                                     echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
                                 }
                             }
                             //end if
                         } else {
                             // Don't force current indent to divisible because there could be custom
                             // rules in place between parenthesis, such as with arrays.
                             $currentIndent = $tokens[$first]['column'] - 1;
                             if (isset($adjustments[$first]) === true) {
                                 $currentIndent += $adjustments[$first];
                             }
                             $setIndents[$first] = $currentIndent;
                             if ($this->debug === true) {
                                 $type = $tokens[$first]['type'];
                                 echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
                             }
                         }
                         //end if
                     }
                 }
                 //end if
             } else {
                 if ($this->debug === true) {
                     echo "\t * ignoring single-line definition *" . PHP_EOL;
                 }
             }
             //end if
         }
         //end if
         // Closing short array bracket should just be indented to at least
         // the same level as where it was opened (but can be more).
         if ($tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY || $checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_SHORT_ARRAY) {
             if ($checkToken !== null) {
                 $arrayCloser = $checkToken;
             } else {
                 $arrayCloser = $i;
             }
             if ($this->debug === true) {
                 $line = $tokens[$arrayCloser]['line'];
                 echo "Closing short array bracket found on line {$line}" . PHP_EOL;
             }
             $arrayOpener = $tokens[$arrayCloser]['bracket_opener'];
             if ($tokens[$arrayCloser]['line'] !== $tokens[$arrayOpener]['line']) {
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
                 $checkIndent = $tokens[$first]['column'] - 1;
                 if (isset($adjustments[$first]) === true) {
                     $checkIndent += $adjustments[$first];
                 }
                 $exact = false;
                 if ($this->debug === true) {
                     $line = $tokens[$first]['line'];
                     $type = $tokens[$first]['type'];
                     echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
                 }
                 if ($first === $tokens[$arrayCloser]['bracket_opener']) {
                     // This is unlikely to be the start of the statement, so look
                     // back further to find it.
                     $first--;
                 }
                 $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                 if ($prev !== $first) {
                     // This is not the start of the statement.
                     if ($this->debug === true) {
                         $line = $tokens[$prev]['line'];
                         $type = $tokens[$prev]['type'];
                         echo "\t* previous is {$type} on line {$line} *" . PHP_EOL;
                     }
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                     $prev = $phpcsFile->findStartOfStatement($first, T_COMMA);
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                     if ($this->debug === true) {
                         $line = $tokens[$first]['line'];
                         $type = $tokens[$first]['type'];
                         echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
                     }
                 }
                 if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
                     // The first token is a scope closer and would have already
                     // been processed and set the indent level correctly, so
                     // don't adjust it again.
                     if ($this->debug === true) {
                         echo "\t* first token is a scope closer; ignoring closing short array bracket *" . PHP_EOL;
                     }
                     if (isset($setIndents[$first]) === true) {
                         $currentIndent = $setIndents[$first];
                         if ($this->debug === true) {
                             echo "\t=> indent reset to {$currentIndent}" . PHP_EOL;
                         }
                     }
                 } else {
                     // Don't force current indent to be divisible because there could be custom
                     // rules in place for arrays.
                     $currentIndent = $tokens[$first]['column'] - 1;
                     if (isset($adjustments[$first]) === true) {
                         $currentIndent += $adjustments[$first];
                     }
                     $setIndents[$first] = $currentIndent;
                     if ($this->debug === true) {
                         $type = $tokens[$first]['type'];
                         echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
                     }
                 }
                 //end if
             } else {
                 if ($this->debug === true) {
                     echo "\t * ignoring single-line definition *" . PHP_EOL;
                 }
             }
             //end if
         }
         //end if
         // Adjust lines within scopes while auto-fixing.
         if ($checkToken !== null && $exact === false && (empty($tokens[$checkToken]['conditions']) === false || isset($tokens[$checkToken]['scope_opener']) === true && $tokens[$checkToken]['scope_opener'] === $checkToken)) {
             if (empty($tokens[$checkToken]['conditions']) === false) {
                 end($tokens[$checkToken]['conditions']);
                 $condition = key($tokens[$checkToken]['conditions']);
             } else {
                 $condition = $tokens[$checkToken]['scope_condition'];
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $condition, true);
             if (isset($adjustments[$first]) === true && ($adjustments[$first] < 0 && $tokenIndent > $currentIndent || $adjustments[$first] > 0 && $tokenIndent < $currentIndent)) {
                 $padding = $tokenIndent + $adjustments[$first];
                 if ($padding > 0) {
                     if ($this->tabIndent === true) {
                         $numTabs = floor($padding / $this->tabWidth);
                         $numSpaces = $padding - $numTabs * $this->tabWidth;
                         $padding = str_repeat("\t", $numTabs) . str_repeat(' ', $numSpaces);
                     } else {
                         $padding = str_repeat(' ', $padding);
                     }
                 } else {
                     $padding = '';
                 }
                 if ($checkToken === $i) {
                     $phpcsFile->fixer->replaceToken($checkToken, $padding . $trimmed);
                 } else {
                     // Easier to just replace the entire indent.
                     $phpcsFile->fixer->replaceToken($checkToken - 1, $padding);
                 }
                 if ($this->debug === true) {
                     $length = strlen($padding);
                     $line = $tokens[$checkToken]['line'];
                     $type = $tokens[$checkToken]['type'];
                     echo "Indent adjusted to {$length} for {$type} on line {$line}" . PHP_EOL;
                 }
                 $adjustments[$checkToken] = $adjustments[$first];
                 if ($this->debug === true) {
                     $line = $tokens[$checkToken]['line'];
                     $type = $tokens[$checkToken]['type'];
                     echo "\t=> Add adjustment of " . $adjustments[$checkToken] . " for token {$checkToken} ({$type}) on line {$line}" . PHP_EOL;
                 }
             }
             //end if
         }
         //end if
         // Scope closers reset the required indent to the same level as the opening condition.
         if ($checkToken !== null && isset($openScopes[$checkToken]) === true || isset($tokens[$checkToken]['scope_condition']) === true && isset($tokens[$checkToken]['scope_closer']) === true && $tokens[$checkToken]['scope_closer'] === $checkToken && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line'] || ($checkToken === null && isset($openScopes[$i]) === true || isset($tokens[$i]['scope_condition']) === true && isset($tokens[$i]['scope_closer']) === true && $tokens[$i]['scope_closer'] === $i && $tokens[$i]['line'] !== $tokens[$tokens[$i]['scope_opener']]['line'])) {
             if ($this->debug === true) {
                 if ($checkToken === null) {
                     $type = $tokens[$tokens[$i]['scope_condition']]['type'];
                     $line = $tokens[$i]['line'];
                 } else {
                     $type = $tokens[$tokens[$checkToken]['scope_condition']]['type'];
                     $line = $tokens[$checkToken]['line'];
                 }
                 echo "Close scope ({$type}) on line {$line}" . PHP_EOL;
             }
             $scopeCloser = $checkToken;
             if ($scopeCloser === null) {
                 $scopeCloser = $i;
             } else {
                 array_pop($openScopes);
             }
             if (isset($tokens[$scopeCloser]['scope_condition']) === true) {
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['scope_condition'], true);
                 $currentIndent = $tokens[$first]['column'] - 1;
                 if (isset($adjustments[$first]) === true) {
                     $currentIndent += $adjustments[$first];
                 }
                 // Make sure it is divisible by our expected indent.
                 if ($tokens[$tokens[$scopeCloser]['scope_condition']]['code'] !== T_CLOSURE) {
                     $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
                 }
                 $setIndents[$scopeCloser] = $currentIndent;
                 if ($this->debug === true) {
                     $type = $tokens[$scopeCloser]['type'];
                     echo "\t=> indent set to {$currentIndent} by token {$scopeCloser} ({$type})" . PHP_EOL;
                 }
                 // We only check the indent of scope closers if they are
                 // curly braces because other constructs tend to have different rules.
                 if ($tokens[$scopeCloser]['code'] === T_CLOSE_CURLY_BRACKET) {
                     $exact = true;
                 } else {
                     $checkToken = null;
                 }
             }
             //end if
         }
         //end if
         // Handle scope for JS object notation.
         if ($phpcsFile->tokenizerType === 'JS' && ($checkToken !== null && $tokens[$checkToken]['code'] === T_CLOSE_OBJECT && $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['bracket_opener']]['line'] || $checkToken === null && $tokens[$i]['code'] === T_CLOSE_OBJECT && $tokens[$i]['line'] !== $tokens[$tokens[$i]['bracket_opener']]['line'])) {
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Close JS object on line {$line}" . PHP_EOL;
             }
             $scopeCloser = $checkToken;
             if ($scopeCloser === null) {
                 $scopeCloser = $i;
             } else {
                 array_pop($openScopes);
             }
             $parens = 0;
             if (isset($tokens[$scopeCloser]['nested_parenthesis']) === true && empty($tokens[$scopeCloser]['nested_parenthesis']) === false) {
                 end($tokens[$scopeCloser]['nested_parenthesis']);
                 $parens = key($tokens[$scopeCloser]['nested_parenthesis']);
                 if ($this->debug === true) {
                     $line = $tokens[$parens]['line'];
                     echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
                 }
             }
             $condition = 0;
             if (isset($tokens[$scopeCloser]['conditions']) === true && empty($tokens[$scopeCloser]['conditions']) === false) {
                 end($tokens[$scopeCloser]['conditions']);
                 $condition = key($tokens[$scopeCloser]['conditions']);
                 if ($this->debug === true) {
                     $line = $tokens[$condition]['line'];
                     $type = $tokens[$condition]['type'];
                     echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
                 }
             }
             if ($parens > $condition) {
                 if ($this->debug === true) {
                     echo "\t* using parenthesis *" . PHP_EOL;
                 }
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $parens, true);
                 $condition = 0;
             } else {
                 if ($condition > 0) {
                     if ($this->debug === true) {
                         echo "\t* using condition *" . PHP_EOL;
                     }
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $condition, true);
                     $parens = 0;
                 } else {
                     if ($this->debug === true) {
                         $line = $tokens[$tokens[$scopeCloser]['bracket_opener']]['line'];
                         echo "\t* token is not in parenthesis or condition; using opener on line {$line} *" . PHP_EOL;
                     }
                     $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $tokens[$scopeCloser]['bracket_opener'], true);
                 }
             }
             //end if
             $currentIndent = $tokens[$first]['column'] - 1;
             if (isset($adjustments[$first]) === true) {
                 $currentIndent += $adjustments[$first];
             }
             if ($parens > 0 || $condition > 0) {
                 $checkIndent = $tokens[$first]['column'] - 1;
                 if (isset($adjustments[$first]) === true) {
                     $checkIndent += $adjustments[$first];
                 }
                 if ($condition > 0) {
                     $checkIndent += $this->indent;
                     $currentIndent += $this->indent;
                     $exact = true;
                 }
             } else {
                 $checkIndent = $currentIndent;
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
             $setIndents[$first] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$first]['type'];
                 echo "\t=> checking indent of {$checkIndent}; main indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
             }
         }
         //end if
         if ($checkToken !== null && isset(Tokens::$scopeOpeners[$tokens[$checkToken]['code']]) === true && in_array($tokens[$checkToken]['code'], $this->nonIndentingScopes) === false && isset($tokens[$checkToken]['scope_opener']) === true) {
             $exact = true;
             $lastOpener = null;
             if (empty($openScopes) === false) {
                 end($openScopes);
                 $lastOpener = current($openScopes);
             }
             // A scope opener that shares a closer with another token (like multiple
             // CASEs using the same BREAK) needs to reduce the indent level so its
             // indent is checked correctly. It will then increase the indent again
             // (as all openers do) after being checked.
             if ($lastOpener !== null && isset($tokens[$lastOpener]['scope_closer']) === true && $tokens[$lastOpener]['level'] === $tokens[$checkToken]['level'] && $tokens[$lastOpener]['scope_closer'] === $tokens[$checkToken]['scope_closer']) {
                 $currentIndent -= $this->indent;
                 $setIndents[$lastOpener] = $currentIndent;
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     $type = $tokens[$lastOpener]['type'];
                     echo "Shared closer found on line {$line}" . PHP_EOL;
                     echo "\t=> indent set to {$currentIndent} by token {$lastOpener} ({$type})" . PHP_EOL;
                 }
             }
             if ($tokens[$checkToken]['code'] === T_CLOSURE && $tokenIndent > $currentIndent) {
                 // The opener is indented more than needed, which is fine.
                 // But just check that it is divisible by our expected indent.
                 $checkIndent = (int) (ceil($tokenIndent / $this->indent) * $this->indent);
                 $exact = false;
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     echo "Closure found on line {$line}" . PHP_EOL;
                     echo "\t=> checking indent of {$checkIndent}; main indent remains at {$currentIndent}" . PHP_EOL;
                 }
             }
         }
         //end if
         // Method prefix indentation has to be exact or else if will break
         // the rest of the function declaration, and potentially future ones.
         if ($checkToken !== null && isset(Tokens::$methodPrefixes[$tokens[$checkToken]['code']]) === true && $tokens[$checkToken + 1]['code'] !== T_DOUBLE_COLON) {
             $exact = true;
         }
         // JS property indentation has to be exact or else if will break
         // things like function and object indentation.
         if ($checkToken !== null && $tokens[$checkToken]['code'] === T_PROPERTY) {
             $exact = true;
         }
         // PHP tags needs to be indented to exact column positions
         // so they don't cause problems with indent checks for the code
         // within them, but they don't need to line up with the current indent.
         if ($checkToken !== null && ($tokens[$checkToken]['code'] === T_OPEN_TAG || $tokens[$checkToken]['code'] === T_OPEN_TAG_WITH_ECHO || $tokens[$checkToken]['code'] === T_CLOSE_TAG)) {
             $exact = true;
             $checkIndent = $tokens[$checkToken]['column'] - 1;
             $checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
         }
         // Check the line indent.
         if ($checkIndent === null) {
             $checkIndent = $currentIndent;
         }
         $adjusted = false;
         if ($checkToken !== null && isset($this->ignoreIndentation[$tokens[$checkToken]['code']]) === false && ($tokenIndent !== $checkIndent && $exact === true || $tokenIndent < $checkIndent && $exact === false)) {
             $type = 'IncorrectExact';
             $error = 'Line indented incorrectly; expected ';
             if ($exact === false) {
                 $error .= 'at least ';
                 $type = 'Incorrect';
             }
             if ($this->tabIndent === true) {
                 $error .= '%s tabs, found %s';
                 $data = array(floor($checkIndent / $this->tabWidth), floor($tokenIndent / $this->tabWidth));
             } else {
                 $error .= '%s spaces, found %s';
                 $data = array($checkIndent, $tokenIndent);
             }
             if ($this->debug === true) {
                 $line = $tokens[$checkToken]['line'];
                 $message = vsprintf($error, $data);
                 echo "[Line {$line}] {$message}" . PHP_EOL;
             }
             $fix = $phpcsFile->addFixableError($error, $checkToken, $type, $data);
             if ($fix === true || $this->debug === true) {
                 $padding = '';
                 if ($this->tabIndent === true) {
                     $numTabs = floor($checkIndent / $this->tabWidth);
                     if ($numTabs > 0) {
                         $numSpaces = $checkIndent - $numTabs * $this->tabWidth;
                         $padding = str_repeat("\t", $numTabs) . str_repeat(' ', $numSpaces);
                     }
                 } else {
                     if ($checkIndent > 0) {
                         $padding = str_repeat(' ', $checkIndent);
                     }
                 }
                 if ($checkToken === $i) {
                     $accepted = $phpcsFile->fixer->replaceToken($checkToken, $padding . $trimmed);
                 } else {
                     // Easier to just replace the entire indent.
                     $accepted = $phpcsFile->fixer->replaceToken($checkToken - 1, $padding);
                 }
                 if ($accepted === true) {
                     $adjustments[$checkToken] = $checkIndent - $tokenIndent;
                     if ($this->debug === true) {
                         $line = $tokens[$checkToken]['line'];
                         $type = $tokens[$checkToken]['type'];
                         echo "\t=> Add adjustment of " . $adjustments[$checkToken] . " for token {$checkToken} ({$type}) on line {$line}" . PHP_EOL;
                     }
                 }
             } else {
                 // Assume the change would be applied and continue
                 // checking indents under this assumption. This gives more
                 // technically accurate error messages.
                 $adjustments[$checkToken] = $checkIndent - $tokenIndent;
             }
             //end if
         }
         //end if
         if ($checkToken !== null) {
             $i = $checkToken;
         }
         // Completely skip here/now docs as the indent is a part of the
         // content itself.
         if ($tokens[$i]['code'] === T_START_HEREDOC || $tokens[$i]['code'] === T_START_NOWDOC) {
             $i = $phpcsFile->findNext(array(T_END_HEREDOC, T_END_NOWDOC), $i + 1);
             continue;
         }
         // Completely skip multi-line strings as the indent is a part of the
         // content itself.
         if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING || $tokens[$i]['code'] === T_DOUBLE_QUOTED_STRING) {
             $i = $phpcsFile->findNext($tokens[$i]['code'], $i + 1, null, true);
             $i--;
             continue;
         }
         // Completely skip doc comments as they tend to have complex
         // indentation rules.
         if ($tokens[$i]['code'] === T_DOC_COMMENT_OPEN_TAG) {
             $i = $tokens[$i]['comment_closer'];
             continue;
         }
         // Open tags reset the indent level.
         if ($tokens[$i]['code'] === T_OPEN_TAG || $tokens[$i]['code'] === T_OPEN_TAG_WITH_ECHO) {
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Open PHP tag found on line {$line}" . PHP_EOL;
             }
             if ($checkToken === null) {
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true);
                 $currentIndent = strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']));
             } else {
                 $currentIndent = $tokens[$i]['column'] - 1;
             }
             $lastOpenTag = $i;
             if (isset($adjustments[$i]) === true) {
                 $currentIndent += $adjustments[$i];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$i] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$i]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Close tags reset the indent level, unless they are closing a tag
         // opened on the same line.
         if ($tokens[$i]['code'] === T_CLOSE_TAG) {
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Close PHP tag found on line {$line}" . PHP_EOL;
             }
             if ($tokens[$lastOpenTag]['line'] !== $tokens[$i]['line']) {
                 $currentIndent = $tokens[$i]['column'] - 1;
                 $lastCloseTag = $i;
             } else {
                 if ($lastCloseTag === null) {
                     $currentIndent = 0;
                 } else {
                     $currentIndent = $tokens[$lastCloseTag]['column'] - 1;
                 }
             }
             if (isset($adjustments[$i]) === true) {
                 $currentIndent += $adjustments[$i];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$i] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$i]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Anon classes and functions set the indent based on their own indent level.
         if ($tokens[$i]['code'] === T_CLOSURE || $tokens[$i]['code'] === T_ANON_CLASS) {
             $closer = $tokens[$i]['scope_closer'];
             if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
                 if ($this->debug === true) {
                     $type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
                     $line = $tokens[$i]['line'];
                     echo "* ignoring single-line {$type} on line {$line}" . PHP_EOL;
                 }
                 $i = $closer;
                 continue;
             }
             if ($this->debug === true) {
                 $type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
                 $line = $tokens[$i]['line'];
                 echo "Open {$type} on line {$line}" . PHP_EOL;
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true);
             $currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
             if (isset($adjustments[$first]) === true) {
                 $currentIndent += $adjustments[$first];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (floor($currentIndent / $this->indent) * $this->indent);
             $i = $tokens[$i]['scope_opener'];
             $setIndents[$i] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$i]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Scope openers increase the indent level.
         if (isset($tokens[$i]['scope_condition']) === true && isset($tokens[$i]['scope_opener']) === true && $tokens[$i]['scope_opener'] === $i) {
             $closer = $tokens[$i]['scope_closer'];
             if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     $type = $tokens[$i]['type'];
                     echo "* ignoring single-line {$type} on line {$line}" . PHP_EOL;
                 }
                 $i = $closer;
                 continue;
             }
             $condition = $tokens[$tokens[$i]['scope_condition']]['code'];
             if (isset(Tokens::$scopeOpeners[$condition]) === true && in_array($condition, $this->nonIndentingScopes) === false) {
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     $type = $tokens[$tokens[$i]['scope_condition']]['type'];
                     echo "Open scope ({$type}) on line {$line}" . PHP_EOL;
                 }
                 $currentIndent += $this->indent;
                 $setIndents[$i] = $currentIndent;
                 $openScopes[$tokens[$i]['scope_closer']] = $tokens[$i]['scope_condition'];
                 if ($this->debug === true) {
                     $type = $tokens[$i]['type'];
                     echo "\t=> indent set to {$currentIndent} by token {$i} ({$type})" . PHP_EOL;
                 }
                 continue;
             }
         }
         //end if
         // JS objects set the indent level.
         if ($phpcsFile->tokenizerType === 'JS' && $tokens[$i]['code'] === T_OBJECT) {
             $closer = $tokens[$i]['bracket_closer'];
             if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
                 if ($this->debug === true) {
                     $line = $tokens[$i]['line'];
                     echo "* ignoring single-line JS object on line {$line}" . PHP_EOL;
                 }
                 $i = $closer;
                 continue;
             }
             if ($this->debug === true) {
                 $line = $tokens[$i]['line'];
                 echo "Open JS object on line {$line}" . PHP_EOL;
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $i, true);
             $currentIndent = $tokens[$first]['column'] - 1 + $this->indent;
             if (isset($adjustments[$first]) === true) {
                 $currentIndent += $adjustments[$first];
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$first] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$first]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
             }
             continue;
         }
         //end if
         // Closing an anon class or function.
         if (isset($tokens[$i]['scope_condition']) === true && $tokens[$i]['scope_closer'] === $i && ($tokens[$tokens[$i]['scope_condition']]['code'] === T_CLOSURE || $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS)) {
             if ($this->debug === true) {
                 $type = str_replace('_', ' ', strtolower(substr($tokens[$tokens[$i]['scope_condition']]['type'], 2)));
                 $line = $tokens[$i]['line'];
                 echo "Close {$type} on line {$line}" . PHP_EOL;
             }
             $prev = false;
             $object = 0;
             if ($phpcsFile->tokenizerType === 'JS') {
                 $conditions = $tokens[$i]['conditions'];
                 krsort($conditions, SORT_NUMERIC);
                 foreach ($conditions as $token => $condition) {
                     if ($condition === T_OBJECT) {
                         $object = $token;
                         break;
                     }
                 }
                 if ($this->debug === true && $object !== 0) {
                     $line = $tokens[$object]['line'];
                     echo "\t* token is inside JS object {$object} on line {$line} *" . PHP_EOL;
                 }
             }
             $parens = 0;
             if (isset($tokens[$i]['nested_parenthesis']) === true && empty($tokens[$i]['nested_parenthesis']) === false) {
                 end($tokens[$i]['nested_parenthesis']);
                 $parens = key($tokens[$i]['nested_parenthesis']);
                 if ($this->debug === true) {
                     $line = $tokens[$parens]['line'];
                     echo "\t* token has nested parenthesis {$parens} on line {$line} *" . PHP_EOL;
                 }
             }
             $condition = 0;
             if (isset($tokens[$i]['conditions']) === true && empty($tokens[$i]['conditions']) === false) {
                 end($tokens[$i]['conditions']);
                 $condition = key($tokens[$i]['conditions']);
                 if ($this->debug === true) {
                     $line = $tokens[$condition]['line'];
                     $type = $tokens[$condition]['type'];
                     echo "\t* token is inside condition {$condition} ({$type}) on line {$line} *" . PHP_EOL;
                 }
             }
             if ($parens > $object && $parens > $condition) {
                 if ($this->debug === true) {
                     echo "\t* using parenthesis *" . PHP_EOL;
                 }
                 $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $parens - 1, null, true);
                 $object = 0;
                 $condition = 0;
             } else {
                 if ($object > 0 && $object >= $condition) {
                     if ($this->debug === true) {
                         echo "\t* using object *" . PHP_EOL;
                     }
                     $prev = $object;
                     $parens = 0;
                     $condition = 0;
                 } else {
                     if ($condition > 0) {
                         if ($this->debug === true) {
                             echo "\t* using condition *" . PHP_EOL;
                         }
                         $prev = $condition;
                         $object = 0;
                         $parens = 0;
                     }
                 }
             }
             //end if
             if ($prev === false) {
                 $prev = $phpcsFile->findPrevious(array(T_EQUAL, T_RETURN), $tokens[$i]['scope_condition'] - 1, null, false, null, true);
                 if ($prev === false) {
                     $prev = $i;
                     if ($this->debug === true) {
                         echo "\t* could not find a previous T_EQUAL or T_RETURN token; will use current token *" . PHP_EOL;
                     }
                 }
             }
             if ($this->debug === true) {
                 $line = $tokens[$prev]['line'];
                 $type = $tokens[$prev]['type'];
                 echo "\t* previous token is {$type} on line {$line} *" . PHP_EOL;
             }
             $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
             if ($this->debug === true) {
                 $line = $tokens[$first]['line'];
                 $type = $tokens[$first]['type'];
                 echo "\t* first token on line {$line} is {$first} ({$type}) *" . PHP_EOL;
             }
             $prev = $phpcsFile->findStartOfStatement($first);
             if ($prev !== $first) {
                 // This is not the start of the statement.
                 if ($this->debug === true) {
                     $line = $tokens[$prev]['line'];
                     $type = $tokens[$prev]['type'];
                     echo "\t* amended previous is {$type} on line {$line} *" . PHP_EOL;
                 }
                 $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $prev, true);
                 if ($this->debug === true) {
                     $line = $tokens[$first]['line'];
                     $type = $tokens[$first]['type'];
                     echo "\t* amended first token is {$first} ({$type}) on line {$line} *" . PHP_EOL;
                 }
             }
             $currentIndent = $tokens[$first]['column'] - 1;
             if ($object > 0 || $condition > 0) {
                 $currentIndent += $this->indent;
             }
             if (isset($tokens[$first]['scope_closer']) === true && $tokens[$first]['scope_closer'] === $first) {
                 if ($this->debug === true) {
                     echo "\t* first token is a scope closer *" . PHP_EOL;
                 }
                 if ($condition === 0 || $tokens[$condition]['scope_opener'] < $first) {
                     $currentIndent = $setIndents[$first];
                 } else {
                     if ($this->debug === true) {
                         echo "\t* ignoring scope closer *" . PHP_EOL;
                     }
                 }
             }
             // Make sure it is divisible by our expected indent.
             $currentIndent = (int) (ceil($currentIndent / $this->indent) * $this->indent);
             $setIndents[$first] = $currentIndent;
             if ($this->debug === true) {
                 $type = $tokens[$first]['type'];
                 echo "\t=> indent set to {$currentIndent} by token {$first} ({$type})" . PHP_EOL;
             }
         }
         //end if
     }
     //end for
     // Don't process the rest of the file.
     return $phpcsFile->numTokens;
 }
Example #5
0
 /**
  * Creates a Config object and populates it with command line values.
  *
  * @param array $cliArgs         An array of values gathered from CLI args.
  * @param bool  $dieOnUnknownArg Whether or not to kill the process when an
  *                               unknown command line arg is found.
  *
  * @return void
  */
 public function __construct(array $cliArgs = array(), $dieOnUnknownArg = true)
 {
     if (defined('PHP_CODESNIFFER_IN_TESTS') === true) {
         // Let everything through during testing so that we can
         // make use of PHPUnit command line arguments as well.
         $this->dieOnUnknownArg = false;
     } else {
         $this->dieOnUnknownArg = $dieOnUnknownArg;
     }
     $checkStdin = false;
     if (empty($cliArgs) === true) {
         $cliArgs = $_SERVER['argv'];
         array_shift($cliArgs);
         $checkStdin = true;
     }
     $this->restoreDefaults();
     $this->setCommandLineValues($cliArgs);
     if (isset($this->overriddenDefaults['standards']) === false && Config::getConfigData('default_standard') === null) {
         // They did not supply a standard to use.
         // Look for a default ruleset in the current directory or higher.
         $currentDir = getcwd();
         do {
             $default = $currentDir . DIRECTORY_SEPARATOR . 'phpcs.xml';
             if (is_file($default) === true) {
                 $this->standards = array($default);
             } else {
                 $default = $currentDir . DIRECTORY_SEPARATOR . 'phpcs.xml.dist';
                 if (is_file($default) === true) {
                     $this->standards = array($default);
                 }
             }
             $lastDir = $currentDir;
             $currentDir = dirname($currentDir);
         } while ($currentDir !== '.' && $currentDir !== $lastDir);
     }
     // Check for content on STDIN.
     if ($checkStdin === true) {
         $handle = fopen('php://stdin', 'r');
         if (stream_set_blocking($handle, false) === true) {
             $fileContents = '';
             while (($line = fgets($handle)) !== false) {
                 $fileContents .= $line;
                 usleep(10);
             }
             stream_set_blocking($handle, true);
             fclose($handle);
             if (trim($fileContents) !== '') {
                 $this->stdin = true;
                 $this->stdinContent = $fileContents;
                 $this->overriddenDefaults['stdin'] = true;
                 $this->overriddenDefaults['stdinContent'] = true;
             }
         }
     }
 }
Example #6
0
 /**
  * Process the function parameter comments.
  *
  * @param PHP_CodeSniffer_File $phpcsFile    The file being scanned.
  * @param int                  $stackPtr     The position of the current token
  *                                           in the stack passed in $tokens.
  * @param int                  $commentStart The position in the stack where the comment started.
  *
  * @return void
  */
 protected function processParams(File $phpcsFile, $stackPtr, $commentStart)
 {
     if ($this->phpVersion === null) {
         $this->phpVersion = Config::getConfigData('php_version');
         if ($this->phpVersion === null) {
             $this->phpVersion = PHP_VERSION_ID;
         }
     }
     $tokens = $phpcsFile->getTokens();
     $params = array();
     $maxType = 0;
     $maxVar = 0;
     foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag) {
         if ($tokens[$tag]['content'] !== '@param') {
             continue;
         }
         $type = '';
         $typeSpace = 0;
         $var = '';
         $varSpace = 0;
         $comment = '';
         $commentLines = array();
         if ($tokens[$tag + 2]['code'] === T_DOC_COMMENT_STRING) {
             $matches = array();
             preg_match('/([^$&.]+)(?:((?:\\.\\.\\.)?(?:\\$|&)[^\\s]+)(?:(\\s+)(.*))?)?/', $tokens[$tag + 2]['content'], $matches);
             if (empty($matches) === false) {
                 $typeLen = strlen($matches[1]);
                 $type = trim($matches[1]);
                 $typeSpace = $typeLen - strlen($type);
                 $typeLen = strlen($type);
                 if ($typeLen > $maxType) {
                     $maxType = $typeLen;
                 }
             }
             if (isset($matches[2]) === true) {
                 $var = $matches[2];
                 $varLen = strlen($var);
                 if ($varLen > $maxVar) {
                     $maxVar = $varLen;
                 }
                 if (isset($matches[4]) === true) {
                     $varSpace = strlen($matches[3]);
                     $comment = $matches[4];
                     $commentLines[] = array('comment' => $comment, 'token' => $tag + 2, 'indent' => $varSpace);
                     // Any strings until the next tag belong to this comment.
                     if (isset($tokens[$commentStart]['comment_tags'][$pos + 1]) === true) {
                         $end = $tokens[$commentStart]['comment_tags'][$pos + 1];
                     } else {
                         $end = $tokens[$commentStart]['comment_closer'];
                     }
                     for ($i = $tag + 3; $i < $end; $i++) {
                         if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) {
                             $indent = 0;
                             if ($tokens[$i - 1]['code'] === T_DOC_COMMENT_WHITESPACE) {
                                 $indent = strlen($tokens[$i - 1]['content']);
                             }
                             $comment .= ' ' . $tokens[$i]['content'];
                             $commentLines[] = array('comment' => $tokens[$i]['content'], 'token' => $i, 'indent' => $indent);
                         }
                     }
                 } else {
                     $error = 'Missing parameter comment';
                     $phpcsFile->addError($error, $tag, 'MissingParamComment');
                     $commentLines[] = array('comment' => '');
                 }
                 //end if
             } else {
                 $error = 'Missing parameter name';
                 $phpcsFile->addError($error, $tag, 'MissingParamName');
             }
             //end if
         } else {
             $error = 'Missing parameter type';
             $phpcsFile->addError($error, $tag, 'MissingParamType');
         }
         //end if
         $params[] = array('tag' => $tag, 'type' => $type, 'var' => $var, 'comment' => $comment, 'commentLines' => $commentLines, 'type_space' => $typeSpace, 'var_space' => $varSpace);
     }
     //end foreach
     $realParams = $phpcsFile->getMethodParameters($stackPtr);
     $foundParams = array();
     // We want to use ... for all variable length arguments, so added
     // this prefix to the variable name so comparisons are easier.
     foreach ($realParams as $pos => $param) {
         if ($param['variable_length'] === true) {
             $realParams[$pos]['name'] = '...' . $realParams[$pos]['name'];
         }
     }
     foreach ($params as $pos => $param) {
         // If the type is empty, the whole line is empty.
         if ($param['type'] === '') {
             continue;
         }
         // Check the param type value.
         $typeNames = explode('|', $param['type']);
         foreach ($typeNames as $typeName) {
             $suggestedName = Common::suggestType($typeName);
             if ($typeName !== $suggestedName) {
                 $error = 'Expected "%s" but found "%s" for parameter type';
                 $data = array($suggestedName, $typeName);
                 $fix = $phpcsFile->addFixableError($error, $param['tag'], 'IncorrectParamVarName', $data);
                 if ($fix === true) {
                     $content = $suggestedName;
                     $content .= str_repeat(' ', $param['type_space']);
                     $content .= $param['var'];
                     $content .= str_repeat(' ', $param['var_space']);
                     if (isset($param['commentLines'][0]) === true) {
                         $content .= $param['commentLines'][0]['comment'];
                     }
                     $phpcsFile->fixer->replaceToken($param['tag'] + 2, $content);
                 }
             } else {
                 if (count($typeNames) === 1) {
                     // Check type hint for array and custom type.
                     $suggestedTypeHint = '';
                     if (strpos($suggestedName, 'array') !== false || substr($suggestedName, -2) === '[]') {
                         $suggestedTypeHint = 'array';
                     } else {
                         if (strpos($suggestedName, 'callable') !== false) {
                             $suggestedTypeHint = 'callable';
                         } else {
                             if (strpos($suggestedName, 'callback') !== false) {
                                 $suggestedTypeHint = 'callable';
                             } else {
                                 if (in_array($typeName, Common::$allowedTypes) === false) {
                                     $suggestedTypeHint = $suggestedName;
                                 } else {
                                     if ($this->phpVersion >= 70000) {
                                         if ($typeName === 'string') {
                                             $suggestedTypeHint = 'string';
                                         } else {
                                             if ($typeName === 'int' || $typeName === 'integer') {
                                                 $suggestedTypeHint = 'int';
                                             } else {
                                                 if ($typeName === 'float') {
                                                     $suggestedTypeHint = 'float';
                                                 } else {
                                                     if ($typeName === 'bool' || $typeName === 'boolean') {
                                                         $suggestedTypeHint = 'bool';
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                     if ($suggestedTypeHint !== '' && isset($realParams[$pos]) === true) {
                         $typeHint = $realParams[$pos]['type_hint'];
                         if ($typeHint === '') {
                             $error = 'Type hint "%s" missing for %s';
                             $data = array($suggestedTypeHint, $param['var']);
                             $errorCode = 'TypeHintMissing';
                             if ($suggestedTypeHint === 'string' || $suggestedTypeHint === 'int' || $suggestedTypeHint === 'float' || $suggestedTypeHint === 'bool') {
                                 $errorCode = 'Scalar' . $errorCode;
                             }
                             $phpcsFile->addError($error, $stackPtr, $errorCode, $data);
                         } else {
                             if ($typeHint !== substr($suggestedTypeHint, strlen($typeHint) * -1)) {
                                 $error = 'Expected type hint "%s"; found "%s" for %s';
                                 $data = array($suggestedTypeHint, $typeHint, $param['var']);
                                 $phpcsFile->addError($error, $stackPtr, 'IncorrectTypeHint', $data);
                             }
                         }
                         //end if
                     } else {
                         if ($suggestedTypeHint === '' && isset($realParams[$pos]) === true) {
                             $typeHint = $realParams[$pos]['type_hint'];
                             if ($typeHint !== '') {
                                 $error = 'Unknown type hint "%s" found for %s';
                                 $data = array($typeHint, $param['var']);
                                 $phpcsFile->addError($error, $stackPtr, 'InvalidTypeHint', $data);
                             }
                         }
                     }
                     //end if
                 }
             }
             //end if
         }
         //end foreach
         if ($param['var'] === '') {
             continue;
         }
         $foundParams[] = $param['var'];
         // Check number of spaces after the type.
         $spaces = $maxType - strlen($param['type']) + 1;
         if ($param['type_space'] !== $spaces) {
             $error = 'Expected %s spaces after parameter type; %s found';
             $data = array($spaces, $param['type_space']);
             $fix = $phpcsFile->addFixableError($error, $param['tag'], 'SpacingAfterParamType', $data);
             if ($fix === true) {
                 $phpcsFile->fixer->beginChangeset();
                 $content = $param['type'];
                 $content .= str_repeat(' ', $spaces);
                 $content .= $param['var'];
                 $content .= str_repeat(' ', $param['var_space']);
                 $content .= $param['commentLines'][0]['comment'];
                 $phpcsFile->fixer->replaceToken($param['tag'] + 2, $content);
                 // Fix up the indent of additional comment lines.
                 foreach ($param['commentLines'] as $lineNum => $line) {
                     if ($lineNum === 0 || $param['commentLines'][$lineNum]['indent'] === 0) {
                         continue;
                     }
                     $newIndent = $param['commentLines'][$lineNum]['indent'] + $spaces - $param['type_space'];
                     $phpcsFile->fixer->replaceToken($param['commentLines'][$lineNum]['token'] - 1, str_repeat(' ', $newIndent));
                 }
                 $phpcsFile->fixer->endChangeset();
             }
             //end if
         }
         //end if
         // Make sure the param name is correct.
         if (isset($realParams[$pos]) === true) {
             $realName = $realParams[$pos]['name'];
             if ($realName !== $param['var']) {
                 $code = 'ParamNameNoMatch';
                 $data = array($param['var'], $realName);
                 $error = 'Doc comment for parameter %s does not match ';
                 if (strtolower($param['var']) === strtolower($realName)) {
                     $error .= 'case of ';
                     $code = 'ParamNameNoCaseMatch';
                 }
                 $error .= 'actual variable name %s';
                 $phpcsFile->addError($error, $param['tag'], $code, $data);
             }
         } else {
             if (substr($param['var'], -4) !== ',...') {
                 // We must have an extra parameter comment.
                 $error = 'Superfluous parameter comment';
                 $phpcsFile->addError($error, $param['tag'], 'ExtraParamComment');
             }
         }
         //end if
         if ($param['comment'] === '') {
             continue;
         }
         // Check number of spaces after the var name.
         $spaces = $maxVar - strlen($param['var']) + 1;
         if ($param['var_space'] !== $spaces) {
             $error = 'Expected %s spaces after parameter name; %s found';
             $data = array($spaces, $param['var_space']);
             $fix = $phpcsFile->addFixableError($error, $param['tag'], 'SpacingAfterParamName', $data);
             if ($fix === true) {
                 $phpcsFile->fixer->beginChangeset();
                 $content = $param['type'];
                 $content .= str_repeat(' ', $param['type_space']);
                 $content .= $param['var'];
                 $content .= str_repeat(' ', $spaces);
                 $content .= $param['commentLines'][0]['comment'];
                 $phpcsFile->fixer->replaceToken($param['tag'] + 2, $content);
                 // Fix up the indent of additional comment lines.
                 foreach ($param['commentLines'] as $lineNum => $line) {
                     if ($lineNum === 0 || $param['commentLines'][$lineNum]['indent'] === 0) {
                         continue;
                     }
                     $newIndent = $param['commentLines'][$lineNum]['indent'] + $spaces - $param['var_space'];
                     $phpcsFile->fixer->replaceToken($param['commentLines'][$lineNum]['token'] - 1, str_repeat(' ', $newIndent));
                 }
                 $phpcsFile->fixer->endChangeset();
             }
             //end if
         }
         //end if
         // Param comments must start with a capital letter and end with the full stop.
         if (preg_match('/^(\\p{Ll}|\\P{L})/u', $param['comment']) === 1) {
             $error = 'Parameter comment must start with a capital letter';
             $phpcsFile->addError($error, $param['tag'], 'ParamCommentNotCapital');
         }
         $lastChar = substr($param['comment'], -1);
         if ($lastChar !== '.') {
             $error = 'Parameter comment must end with a full stop';
             $phpcsFile->addError($error, $param['tag'], 'ParamCommentFullStop');
         }
     }
     //end foreach
     $realNames = array();
     foreach ($realParams as $realParam) {
         $realNames[] = $realParam['name'];
     }
     // Report missing comments.
     $diff = array_diff($realNames, $foundParams);
     foreach ($diff as $neededParam) {
         $error = 'Doc comment for parameter "%s" missing';
         $data = array($neededParam);
         $phpcsFile->addError($error, $commentStart, 'MissingParamTag', $data);
     }
 }
Example #7
0
 /**
  * Performs the run.
  *
  * @return int The number of errors and warnings found.
  */
 private function run()
 {
     // The class that manages all reporters for the run.
     $this->reporter = new Reporter($this->config);
     // Include bootstrap files.
     foreach ($this->config->bootstrap as $bootstrap) {
         include $bootstrap;
     }
     if ($this->config->stdin === true) {
         $fileContents = $this->config->stdinContent;
         if ($fileContents === null) {
             $handle = fopen('php://stdin', 'r');
             stream_set_blocking($handle, true);
             $fileContents = stream_get_contents($handle);
             fclose($handle);
         }
         $todo = new FileList($this->config, $this->ruleset);
         $dummy = new DummyFile($fileContents, $this->ruleset, $this->config);
         $todo->addFile($dummy->path, $dummy);
         $numFiles = 1;
     } else {
         if (empty($this->config->files) === true) {
             echo 'ERROR: You must supply at least one file or directory to process.' . PHP_EOL . PHP_EOL;
             $this->config->printUsage();
             exit(0);
         }
         if (PHP_CODESNIFFER_VERBOSITY > 0) {
             echo 'Creating file list... ';
         }
         $todo = new FileList($this->config, $this->ruleset);
         $numFiles = count($todo);
         if (PHP_CODESNIFFER_VERBOSITY > 0) {
             echo "DONE ({$numFiles} files in queue)" . PHP_EOL;
         }
         if ($this->config->cache === true) {
             if (PHP_CODESNIFFER_VERBOSITY > 0) {
                 echo 'Loading cache... ';
             }
             Cache::load($this->ruleset, $this->config);
             if (PHP_CODESNIFFER_VERBOSITY > 0) {
                 $size = Cache::getSize();
                 echo "DONE ({$size} files in cache)" . PHP_EOL;
             }
         }
     }
     //end if
     // Turn all sniff errors into exceptions.
     set_error_handler(array($this, 'handleErrors'));
     // If verbosity is too high, turn off parallelism so the
     // debug output is clean.
     if (PHP_CODESNIFFER_VERBOSITY > 1) {
         $this->config->parallel = 1;
     }
     // If the PCNTL extension isn't installed, we can't fork.
     if (function_exists('pcntl_fork') === false) {
         $this->config->parallel = 1;
     }
     $lastDir = '';
     if ($this->config->parallel === 1) {
         // Running normally.
         $numProcessed = 0;
         foreach ($todo as $path => $file) {
             $currDir = dirname($path);
             if ($lastDir !== $currDir) {
                 if (PHP_CODESNIFFER_VERBOSITY > 0) {
                     echo 'Changing into directory ' . Common::stripBasepath($currDir, $this->config->basepath) . PHP_EOL;
                 }
                 $lastDir = $currDir;
             }
             $this->processFile($file);
             $numProcessed++;
             $this->printProgress($file, $numFiles, $numProcessed);
         }
     } else {
         // Batching and forking.
         $childProcs = array();
         $numFiles = count($todo);
         $numPerBatch = ceil($numFiles / $this->config->parallel);
         for ($batch = 0; $batch < $this->config->parallel; $batch++) {
             $startAt = $batch * $numPerBatch;
             if ($startAt >= $numFiles) {
                 break;
             }
             $endAt = $startAt + $numPerBatch;
             if ($endAt > $numFiles) {
                 $endAt = $numFiles;
             }
             $childOutFilename = tempnam(sys_get_temp_dir(), 'phpcs-child');
             $pid = pcntl_fork();
             if ($pid === -1) {
                 throw new RuntimeException('Failed to create child process');
             } else {
                 if ($pid !== 0) {
                     $childProcs[] = array('pid' => $pid, 'out' => $childOutFilename);
                 } else {
                     // Move forward to the start of the batch.
                     $todo->rewind();
                     for ($i = 0; $i < $startAt; $i++) {
                         $todo->next();
                     }
                     // Reset the reporter to make sure only figures from this
                     // file batch are recorded.
                     $this->reporter->totalFiles = 0;
                     $this->reporter->totalErrors = 0;
                     $this->reporter->totalWarnings = 0;
                     $this->reporter->totalFixable = 0;
                     // Process the files.
                     $pathsProcessed = array();
                     ob_start();
                     for ($i = $startAt; $i < $endAt; $i++) {
                         $path = $todo->key();
                         $file = $todo->current();
                         $currDir = dirname($path);
                         if ($lastDir !== $currDir) {
                             if (PHP_CODESNIFFER_VERBOSITY > 0) {
                                 echo 'Changing into directory ' . Common::stripBasepath($currDir, $this->config->basepath) . PHP_EOL;
                             }
                             $lastDir = $currDir;
                         }
                         $this->processFile($file);
                         $pathsProcessed[] = $path;
                         $todo->next();
                     }
                     $debugOutput = ob_get_contents();
                     ob_end_clean();
                     // Write information about the run to the filesystem
                     // so it can be picked up by the main process.
                     $childOutput = array('totalFiles' => $this->reporter->totalFiles, 'totalErrors' => $this->reporter->totalErrors, 'totalWarnings' => $this->reporter->totalWarnings, 'totalFixable' => $this->reporter->totalFixable, 'totalFixed' => $this->reporter->totalFixed);
                     $output = '<' . '?php' . "\n" . ' $childOutput = ';
                     $output .= var_export($childOutput, true);
                     $output .= ";\n\$debugOutput = ";
                     $output .= var_export($debugOutput, true);
                     if ($this->config->cache === true) {
                         $childCache = array();
                         foreach ($pathsProcessed as $path) {
                             $childCache[$path] = Cache::get($path);
                         }
                         $output .= ";\n\$childCache = ";
                         $output .= var_export($childCache, true);
                     }
                     $output .= ";\n?" . '>';
                     file_put_contents($childOutFilename, $output);
                     exit($pid);
                 }
             }
             //end if
         }
         //end for
         $this->processChildProcs($childProcs);
     }
     //end if
     restore_error_handler();
     if (PHP_CODESNIFFER_VERBOSITY === 0 && $this->config->interactive === false && $this->config->showProgress === true) {
         echo PHP_EOL . PHP_EOL;
     }
     if ($this->config->cache === true) {
         Cache::save();
     }
     $ignoreWarnings = Config::getConfigData('ignore_warnings_on_exit');
     $ignoreErrors = Config::getConfigData('ignore_errors_on_exit');
     $return = $this->reporter->totalErrors + $this->reporter->totalWarnings;
     if ($ignoreErrors !== null) {
         $ignoreErrors = (bool) $ignoreErrors;
         if ($ignoreErrors === true) {
             $return -= $this->reporter->totalErrors;
         }
     }
     if ($ignoreWarnings !== null) {
         $ignoreWarnings = (bool) $ignoreWarnings;
         if ($ignoreWarnings === true) {
             $return -= $this->reporter->totalWarnings;
         }
     }
     return $return;
 }