Example #1
0
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The current file being processed.
  * @param int                  $stackPtr  The position of the current token in the
  *                                        stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     if (isset($tokens[$stackPtr]['scope_opener']) === false) {
         $error = 'Possible parse error: %s missing opening or closing brace';
         $data = array($tokens[$stackPtr]['content']);
         $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data);
         return;
     }
     // Determine the name of the class or interface. Note that we cannot
     // simply look for the first T_STRING because a class name
     // starting with the number will be multiple tokens.
     $opener = $tokens[$stackPtr]['scope_opener'];
     $nameStart = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, $opener, true);
     $nameEnd = $phpcsFile->findNext(T_WHITESPACE, $nameStart, $opener);
     if ($nameEnd === false) {
         $name = $tokens[$nameStart]['content'];
     } else {
         $name = trim($phpcsFile->getTokensAsString($nameStart, $nameEnd - $nameStart));
     }
     // Check for camel caps format.
     $valid = Common::isCamelCaps($name, true, true, false);
     if ($valid === false) {
         $type = ucfirst($tokens[$stackPtr]['content']);
         $error = '%s name "%s" is not in camel caps format';
         $data = array($type, $name);
         $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data);
         $phpcsFile->recordMetric($stackPtr, 'CamelCase class name', 'no');
     } else {
         $phpcsFile->recordMetric($stackPtr, 'CamelCase class name', 'yes');
     }
 }
Example #2
0
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token
  *                                        in the stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $prevType = $tokens[$stackPtr - 1]['code'];
     if (isset(Tokens::$emptyTokens[$prevType]) === false) {
         return;
     }
     $nonSpace = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 2, null, true);
     if ($tokens[$nonSpace]['code'] === T_SEMICOLON) {
         // Empty statement.
         return;
     }
     $expected = $tokens[$nonSpace]['content'] . ';';
     $found = $phpcsFile->getTokensAsString($nonSpace, $stackPtr - $nonSpace) . ';';
     $error = 'Space found before semicolon; expected "%s" but found "%s"';
     $data = array($expected, $found);
     $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Incorrect', $data);
     if ($fix === true) {
         $phpcsFile->fixer->beginChangeset();
         for ($i = $stackPtr - 1; $i > $nonSpace; $i--) {
             $phpcsFile->fixer->replaceToken($i, '');
         }
         $phpcsFile->fixer->endChangeset();
     }
 }
 /**
  * Processes this sniff, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The current file being checked.
  * @param int                  $stackPtr  The position of the current token in the
  *                                        stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // PHP 5.4 introduced a shorthand array declaration syntax, so we need
     // to ignore the these type of array declarations because this sniff is
     // only dealing with array usage.
     if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) {
         $openBracket = $stackPtr;
     } else {
         if (isset($tokens[$stackPtr]['bracket_opener']) === false) {
             return;
         }
         $openBracket = $tokens[$stackPtr]['bracket_opener'];
     }
     $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, $openBracket - 1, null, true);
     if ($tokens[$prev]['code'] === T_EQUAL) {
         return;
     }
     // Square brackets can not have a space before them.
     $prevType = $tokens[$stackPtr - 1]['code'];
     if (isset(Tokens::$emptyTokens[$prevType]) === true) {
         $nonSpace = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 2, null, true);
         $expected = $tokens[$nonSpace]['content'] . $tokens[$stackPtr]['content'];
         $found = $phpcsFile->getTokensAsString($nonSpace, $stackPtr - $nonSpace) . $tokens[$stackPtr]['content'];
         $error = 'Space found before square bracket; expected "%s" but found "%s"';
         $data = array($expected, $found);
         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceBeforeBracket', $data);
         if ($fix === true) {
             $phpcsFile->fixer->replaceToken($stackPtr - 1, '');
         }
     }
     // Open square brackets can't ever have spaces after them.
     if ($tokens[$stackPtr]['code'] === T_OPEN_SQUARE_BRACKET) {
         $nextType = $tokens[$stackPtr + 1]['code'];
         if (isset(Tokens::$emptyTokens[$nextType]) === true) {
             $nonSpace = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 2, null, true);
             $expected = $tokens[$stackPtr]['content'] . $tokens[$nonSpace]['content'];
             $found = $phpcsFile->getTokensAsString($stackPtr, $nonSpace - $stackPtr + 1);
             $error = 'Space found after square bracket; expected "%s" but found "%s"';
             $data = array($expected, $found);
             $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterBracket', $data);
             if ($fix === true) {
                 $phpcsFile->fixer->replaceToken($stackPtr + 1, '');
             }
         }
     }
 }
Example #4
0
 /**
  * Processes this sniff, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token in
  *                                        the stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $varName = $tokens[$stackPtr]['content'];
     if ($varName !== '$_REQUEST' && $varName !== '$_GET' && $varName !== '$_POST' && $varName !== '$_FILES') {
         return;
     }
     // The only place these super globals can be accessed directly is
     // in the getRequestData() method of the Security class.
     $inClass = false;
     foreach ($tokens[$stackPtr]['conditions'] as $i => $type) {
         if ($tokens[$i]['code'] === T_CLASS) {
             $className = $phpcsFile->findNext(T_STRING, $i);
             $className = $tokens[$className]['content'];
             if (strtolower($className) === 'security') {
                 $inClass = true;
             } else {
                 // We don't have nested classes.
                 break;
             }
         } else {
             if ($inClass === true && $tokens[$i]['code'] === T_FUNCTION) {
                 $funcName = $phpcsFile->findNext(T_STRING, $i);
                 $funcName = $tokens[$funcName]['content'];
                 if (strtolower($funcName) === 'getrequestdata') {
                     // This is valid.
                     return;
                 } else {
                     // We don't have nested functions.
                     break;
                 }
             }
         }
         //end if
     }
     //end foreach
     // If we get to here, the super global was used incorrectly.
     // First find out how it is being used.
     $globalName = strtolower(substr($varName, 2));
     $usedVar = '';
     $openBracket = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true);
     if ($tokens[$openBracket]['code'] === T_OPEN_SQUARE_BRACKET) {
         $closeBracket = $tokens[$openBracket]['bracket_closer'];
         $usedVar = $phpcsFile->getTokensAsString($openBracket + 1, $closeBracket - $openBracket - 1);
     }
     $type = 'SuperglobalAccessed';
     $error = 'The %s super global must not be accessed directly; use Security::getRequestData(';
     $data = array($varName);
     if ($usedVar !== '') {
         $type .= 'WithVar';
         $error .= '%s, \'%s\'';
         $data[] = $usedVar;
         $data[] = $globalName;
     }
     $error .= ') instead';
     $phpcsFile->addError($error, $stackPtr, $type, $data);
 }
Example #5
0
 /**
  * Processes this sniff, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token in
  *                                        the stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // Make sure it is an API function. We know this by the doc comment.
     $commentEnd = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr);
     $commentStart = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $commentEnd - 1);
     $comment = $phpcsFile->getTokensAsString($commentStart, $commentEnd - $commentStart);
     if (strpos($comment, '* @api') === false) {
         return;
     }
     // Find all the vars passed in as we are only interested in comparisons
     // to NULL for these specific variables.
     $foundVars = array();
     $open = $tokens[$stackPtr]['parenthesis_opener'];
     $close = $tokens[$stackPtr]['parenthesis_closer'];
     for ($i = $open + 1; $i < $close; $i++) {
         if ($tokens[$i]['code'] === T_VARIABLE) {
             $foundVars[$tokens[$i]['content']] = true;
         }
     }
     if (empty($foundVars) === true) {
         return;
     }
     $start = $tokens[$stackPtr]['scope_opener'];
     $end = $tokens[$stackPtr]['scope_closer'];
     for ($i = $start + 1; $i < $end; $i++) {
         if ($tokens[$i]['code'] !== T_VARIABLE || isset($foundVars[$tokens[$i]['content']]) === false) {
             continue;
         }
         $operator = $phpcsFile->findNext(T_WHITESPACE, $i + 1, null, true);
         if ($tokens[$operator]['code'] !== T_IS_IDENTICAL && $tokens[$operator]['code'] !== T_IS_NOT_IDENTICAL) {
             continue;
         }
         $nullValue = $phpcsFile->findNext(T_WHITESPACE, $operator + 1, null, true);
         if ($tokens[$nullValue]['code'] !== T_NULL) {
             continue;
         }
         $error = 'Values submitted via Ajax requests should not be compared directly to NULL; use empty() instead';
         $phpcsFile->addWarning($error, $nullValue, 'Found');
     }
     //end for
 }
Example #6
0
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token
  *                                        in the stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $namespace = '';
     $findTokens = array(T_CLASS, T_INTERFACE, T_NAMESPACE, T_CLOSE_TAG);
     $stackPtr = $phpcsFile->findNext($findTokens, $stackPtr + 1);
     while ($stackPtr !== false) {
         if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) {
             // We can stop here. The sniff will continue from the next open
             // tag when PHPCS reaches that token, if there is one.
             return;
         }
         // Keep track of what namespace we are in.
         if ($tokens[$stackPtr]['code'] === T_NAMESPACE) {
             $nsEnd = $phpcsFile->findNext(array(T_NS_SEPARATOR, T_STRING, T_WHITESPACE), $stackPtr + 1, null, true);
             $namespace = trim($phpcsFile->getTokensAsString($stackPtr + 1, $nsEnd - $stackPtr - 1));
             $stackPtr = $nsEnd;
         } else {
             $nameToken = $phpcsFile->findNext(T_STRING, $stackPtr);
             $name = $tokens[$nameToken]['content'];
             if ($namespace !== '') {
                 $name = $namespace . '\\' . $name;
             }
             $compareName = strtolower($name);
             if (isset($this->foundClasses[$compareName]) === true) {
                 $type = strtolower($tokens[$stackPtr]['content']);
                 $file = $this->foundClasses[$compareName]['file'];
                 $line = $this->foundClasses[$compareName]['line'];
                 $error = 'Duplicate %s name "%s" found; first defined in %s on line %s';
                 $data = array($type, $name, $file, $line);
                 $phpcsFile->addWarning($error, $stackPtr, 'Found', $data);
             } else {
                 $this->foundClasses[$compareName] = array('file' => $phpcsFile->getFilename(), 'line' => $tokens[$stackPtr]['line']);
             }
         }
         //end if
         $stackPtr = $phpcsFile->findNext($findTokens, $stackPtr + 1);
     }
     //end while
 }
Example #7
0
 /**
  * Processes the tokens that this sniff is interested in.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found.
  * @param int                  $stackPtr  The position in the stack where
  *                                        the token was found.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     // Some styles look like shorthand but are not actually a set of 4 sizes.
     $style = strtolower($tokens[$stackPtr]['content']);
     if (isset($this->excludeStyles[$style]) === true) {
         return;
     }
     // Get the whole style content.
     $end = $phpcsFile->findNext(T_SEMICOLON, $stackPtr + 1);
     $origContent = $phpcsFile->getTokensAsString($stackPtr + 1, $end - $stackPtr - 1);
     $origContent = trim($origContent, ': ');
     // Account for a !important annotation.
     $content = $origContent;
     if (substr($content, -10) === '!important') {
         $content = substr($content, 0, -10);
         $content = trim($content);
     }
     // Check if this style value is a set of numbers with optional prefixes.
     $content = preg_replace('/\\s+/', ' ', $content);
     $values = array();
     $num = preg_match_all('/([0-9]+)([a-zA-Z]{2}\\s+|%\\s+|\\s+)/', $content . ' ', $values, PREG_SET_ORDER);
     // Only interested in styles that have multiple sizes defined.
     if ($num < 2) {
         return;
     }
     // Rebuild the content we matched to ensure we got everything.
     $matched = '';
     foreach ($values as $value) {
         $matched .= $value[0];
     }
     if ($content !== trim($matched)) {
         return;
     }
     if ($num === 3) {
         $expected = trim($content . ' ' . $values[1][1] . $values[1][2]);
         $error = 'Shorthand syntax not allowed here; use %s instead';
         $data = array($expected);
         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NotAllowed', $data);
         if ($fix === true) {
             $phpcsFile->fixer->beginChangeset();
             if (substr($origContent, -10) === '!important') {
                 $expected .= ' !important';
             }
             $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 2, null, true);
             $phpcsFile->fixer->replaceToken($next, $expected);
             for ($next++; $next < $end; $next++) {
                 $phpcsFile->fixer->replaceToken($next, '');
             }
             $phpcsFile->fixer->endChangeset();
         }
         return;
     }
     //end if
     if ($num === 2) {
         if ($values[0][0] !== $values[1][0]) {
             // Both values are different, so it is already shorthand.
             return;
         }
     } else {
         if ($values[0][0] !== $values[2][0] || $values[1][0] !== $values[3][0]) {
             // Can't shorthand this.
             return;
         }
     }
     if ($values[0][0] === $values[1][0]) {
         // All values are the same.
         $expected = $values[0][0];
     } else {
         $expected = $values[0][0] . ' ' . $values[1][0];
     }
     $expected = preg_replace('/\\s+/', ' ', trim($expected));
     $error = 'Size definitions must use shorthand if available; expected "%s" but found "%s"';
     $data = array($expected, $content);
     $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NotUsed', $data);
     if ($fix === true) {
         $phpcsFile->fixer->beginChangeset();
         if (substr($origContent, -10) === '!important') {
             $expected .= ' !important';
         }
         $next = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 2, null, true);
         $phpcsFile->fixer->replaceToken($next, $expected);
         for ($next++; $next < $end; $next++) {
             $phpcsFile->fixer->replaceToken($next, '');
         }
         $phpcsFile->fixer->endChangeset();
     }
 }
 /**
  * Processes the function tokens within the class.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found.
  * @param int                  $stackPtr  The position where the token was found.
  * @param int                  $currScope The current scope opener token.
  *
  * @return void
  */
 protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope)
 {
     // Is this the first throw token within the current function scope?
     // If so, we have to validate other throw tokens within the same scope.
     $previousThrow = $phpcsFile->findPrevious(T_THROW, $stackPtr - 1, $currScope);
     if ($previousThrow !== false) {
         return;
     }
     $tokens = $phpcsFile->getTokens();
     $find = Tokens::$methodPrefixes;
     $find[] = T_WHITESPACE;
     $commentEnd = $phpcsFile->findPrevious($find, $currScope - 1, null, true);
     if ($tokens[$commentEnd]['code'] === T_COMMENT) {
         // Function is using the wrong type of comment.
         return;
     }
     if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG && $tokens[$commentEnd]['code'] !== T_COMMENT) {
         // Function doesn't have a doc comment.
         return;
     }
     $currScopeEnd = $tokens[$currScope]['scope_closer'];
     // Find all the exception type token within the current scope.
     $throwTokens = array();
     $currPos = $stackPtr;
     $foundThrows = false;
     while ($currPos < $currScopeEnd && $currPos !== false) {
         if ($phpcsFile->hasCondition($currPos, T_CLOSURE) === false) {
             $foundThrows = true;
             /*
                 If we can't find a NEW, we are probably throwing
                 a variable, so we ignore it, but they still need to
                 provide at least one @throws tag, even through we
                 don't know the exception class.
             */
             $nextToken = $phpcsFile->findNext(T_WHITESPACE, $currPos + 1, null, true);
             if ($tokens[$nextToken]['code'] === T_NEW) {
                 $currException = $phpcsFile->findNext(array(T_NS_SEPARATOR, T_STRING), $currPos, $currScopeEnd, false, null, true);
                 if ($currException !== false) {
                     $endException = $phpcsFile->findNext(array(T_NS_SEPARATOR, T_STRING), $currException + 1, $currScopeEnd, true, null, true);
                     if ($endException === false) {
                         $throwTokens[] = $tokens[$currException]['content'];
                     } else {
                         $throwTokens[] = $phpcsFile->getTokensAsString($currException, $endException - $currException);
                     }
                 }
                 //end if
             }
             //end if
         }
         //end if
         $currPos = $phpcsFile->findNext(T_THROW, $currPos + 1, $currScopeEnd);
     }
     //end while
     if ($foundThrows === false) {
         return;
     }
     // Only need one @throws tag for each type of exception thrown.
     $throwTokens = array_unique($throwTokens);
     $throwTags = array();
     $commentStart = $tokens[$commentEnd]['comment_opener'];
     foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
         if ($tokens[$tag]['content'] !== '@throws') {
             continue;
         }
         if ($tokens[$tag + 2]['code'] === T_DOC_COMMENT_STRING) {
             $exception = $tokens[$tag + 2]['content'];
             $space = strpos($exception, ' ');
             if ($space !== false) {
                 $exception = substr($exception, 0, $space);
             }
             $throwTags[$exception] = true;
         }
     }
     if (empty($throwTags) === true) {
         $error = 'Missing @throws tag in function comment';
         $phpcsFile->addError($error, $commentEnd, 'Missing');
         return;
     } else {
         if (empty($throwTokens) === true) {
             // If token count is zero, it means that only variables are being
             // thrown, so we need at least one @throws tag (checked above).
             // Nothing more to do.
             return;
         }
     }
     // Make sure @throws tag count matches throw token count.
     $tokenCount = count($throwTokens);
     $tagCount = count($throwTags);
     if ($tokenCount !== $tagCount) {
         $error = 'Expected %s @throws tag(s) in function comment; %s found';
         $data = array($tokenCount, $tagCount);
         $phpcsFile->addError($error, $commentEnd, 'WrongNumber', $data);
         return;
     }
     foreach ($throwTokens as $throw) {
         if (isset($throwTags[$throw]) === false) {
             $error = 'Missing @throws tag for "%s" exception';
             $data = array($throw);
             $phpcsFile->addError($error, $commentEnd, 'Missing', $data);
         }
     }
 }
Example #9
0
 /**
  * Processes this test, when one of its tokens is encountered.
  *
  * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
  * @param int                  $stackPtr  The position of the current token in the
  *                                        stack passed in $tokens.
  *
  * @return void
  */
 public function process(File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     if (isset($tokens[$stackPtr + 1]) === false) {
         return;
     }
     // Single space after the keyword.
     $found = 1;
     if ($tokens[$stackPtr + 1]['code'] !== T_WHITESPACE) {
         $found = 0;
     } else {
         if ($tokens[$stackPtr + 1]['content'] !== ' ') {
             if (strpos($tokens[$stackPtr + 1]['content'], $phpcsFile->eolChar) !== false) {
                 $found = 'newline';
             } else {
                 $found = strlen($tokens[$stackPtr + 1]['content']);
             }
         }
     }
     if ($found !== 1) {
         $error = 'Expected 1 space after %s keyword; %s found';
         $data = array(strtoupper($tokens[$stackPtr]['content']), $found);
         $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterKeyword', $data);
         if ($fix === true) {
             if ($found === 0) {
                 $phpcsFile->fixer->addContent($stackPtr, ' ');
             } else {
                 $phpcsFile->fixer->replaceToken($stackPtr + 1, ' ');
             }
         }
     }
     // Single space after closing parenthesis.
     if (isset($tokens[$stackPtr]['parenthesis_closer']) === true && isset($tokens[$stackPtr]['scope_opener']) === true) {
         $closer = $tokens[$stackPtr]['parenthesis_closer'];
         $opener = $tokens[$stackPtr]['scope_opener'];
         $content = $phpcsFile->getTokensAsString($closer + 1, $opener - $closer - 1);
         if ($content !== ' ') {
             $error = 'Expected 1 space after closing parenthesis; found %s';
             if (trim($content) === '') {
                 $found = strlen($content);
             } else {
                 $found = '"' . str_replace($phpcsFile->eolChar, '\\n', $content) . '"';
             }
             $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseParenthesis', array($found));
             if ($fix === true) {
                 if ($closer === $opener - 1) {
                     $phpcsFile->fixer->addContent($closer, ' ');
                 } else {
                     $phpcsFile->fixer->beginChangeset();
                     $phpcsFile->fixer->addContent($closer, ' ' . $tokens[$opener]['content']);
                     $phpcsFile->fixer->replaceToken($opener, '');
                     if ($tokens[$opener]['line'] !== $tokens[$closer]['line']) {
                         $next = $phpcsFile->findNext(T_WHITESPACE, $opener + 1, null, true);
                         if ($tokens[$next]['line'] !== $tokens[$opener]['line']) {
                             for ($i = $opener + 1; $i < $next; $i++) {
                                 $phpcsFile->fixer->replaceToken($i, '');
                             }
                         }
                     }
                     $phpcsFile->fixer->endChangeset();
                 }
             }
         }
         //end if
     }
     //end if
     // Single newline after opening brace.
     if (isset($tokens[$stackPtr]['scope_opener']) === true) {
         $opener = $tokens[$stackPtr]['scope_opener'];
         for ($next = $opener + 1; $next < $phpcsFile->numTokens; $next++) {
             $code = $tokens[$next]['code'];
             if ($code === T_WHITESPACE || $code === T_INLINE_HTML && trim($tokens[$next]['content']) === '') {
                 continue;
             }
             // Skip all empty tokens on the same line as the opener.
             if ($tokens[$next]['line'] === $tokens[$opener]['line'] && (isset(Tokens::$emptyTokens[$code]) === true || $code === T_CLOSE_TAG)) {
                 continue;
             }
             // We found the first bit of a code, or a comment on the
             // following line.
             break;
         }
         //end for
         if ($tokens[$next]['line'] === $tokens[$opener]['line']) {
             $error = 'Newline required after opening brace';
             $fix = $phpcsFile->addFixableError($error, $opener, 'NewlineAfterOpenBrace');
             if ($fix === true) {
                 $phpcsFile->fixer->beginChangeset();
                 for ($i = $opener + 1; $i < $next; $i++) {
                     if (trim($tokens[$i]['content']) !== '') {
                         break;
                     }
                     // Remove whitespace.
                     $phpcsFile->fixer->replaceToken($i, '');
                 }
                 $phpcsFile->fixer->addContent($opener, $phpcsFile->eolChar);
                 $phpcsFile->fixer->endChangeset();
             }
         }
         //end if
     } else {
         if ($tokens[$stackPtr]['code'] === T_WHILE) {
             // Zero spaces after parenthesis closer.
             $closer = $tokens[$stackPtr]['parenthesis_closer'];
             $found = 0;
             if ($tokens[$closer + 1]['code'] === T_WHITESPACE) {
                 if (strpos($tokens[$closer + 1]['content'], $phpcsFile->eolChar) !== false) {
                     $found = 'newline';
                 } else {
                     $found = strlen($tokens[$closer + 1]['content']);
                 }
             }
             if ($found !== 0) {
                 $error = 'Expected 0 spaces before semicolon; %s found';
                 $data = array($found);
                 $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceBeforeSemicolon', $data);
                 if ($fix === true) {
                     $phpcsFile->fixer->replaceToken($closer + 1, '');
                 }
             }
         }
     }
     //end if
     // Only want to check multi-keyword structures from here on.
     if ($tokens[$stackPtr]['code'] === T_DO) {
         if (isset($tokens[$stackPtr]['scope_closer']) === false) {
             return;
         }
         $closer = $tokens[$stackPtr]['scope_closer'];
     } else {
         if ($tokens[$stackPtr]['code'] === T_ELSE || $tokens[$stackPtr]['code'] === T_ELSEIF || $tokens[$stackPtr]['code'] === T_CATCH) {
             $closer = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true);
             if ($closer === false || $tokens[$closer]['code'] !== T_CLOSE_CURLY_BRACKET) {
                 return;
             }
         } else {
             return;
         }
     }
     // Single space after closing brace.
     $found = 1;
     if ($tokens[$closer + 1]['code'] !== T_WHITESPACE) {
         $found = 0;
     } else {
         if ($tokens[$closer + 1]['content'] !== ' ') {
             if (strpos($tokens[$closer + 1]['content'], $phpcsFile->eolChar) !== false) {
                 $found = 'newline';
             } else {
                 $found = strlen($tokens[$closer + 1]['content']);
             }
         }
     }
     if ($found !== 1) {
         $error = 'Expected 1 space after closing brace; %s found';
         $data = array($found);
         $fix = $phpcsFile->addFixableError($error, $closer, 'SpaceAfterCloseBrace', $data);
         if ($fix === true) {
             if ($found === 0) {
                 $phpcsFile->fixer->addContent($closer, ' ');
             } else {
                 $phpcsFile->fixer->replaceToken($closer + 1, ' ');
             }
         }
     }
 }
Example #10
0
 /**
  * Processes the pattern and verifies the code at $stackPtr.
  *
  * @param array                $patternInfo Information about the pattern used
  *                                          for checking, which includes are
  *                                          parsed token representation of the
  *                                          pattern.
  * @param PHP_CodeSniffer_File $phpcsFile   The PHP_CodeSniffer file where the
  *                                          token occurred.
  * @param int                  $stackPtr    The position in the tokens stack where
  *                                          the listening token type was found.
  *
  * @return array
  */
 protected function processPattern($patternInfo, File $phpcsFile, $stackPtr)
 {
     $tokens = $phpcsFile->getTokens();
     $pattern = $patternInfo['pattern'];
     $patternCode = $patternInfo['pattern_code'];
     $errors = array();
     $found = '';
     $ignoreTokens = array(T_WHITESPACE);
     if ($this->ignoreComments === true) {
         $ignoreTokens = array_merge($ignoreTokens, Tokens::$commentTokens);
     }
     $origStackPtr = $stackPtr;
     $hasError = false;
     if ($patternInfo['listen_pos'] > 0) {
         $stackPtr--;
         for ($i = $patternInfo['listen_pos'] - 1; $i >= 0; $i--) {
             if ($pattern[$i]['type'] === 'token') {
                 if ($pattern[$i]['token'] === T_WHITESPACE) {
                     if ($tokens[$stackPtr]['code'] === T_WHITESPACE) {
                         $found = $tokens[$stackPtr]['content'] . $found;
                     }
                     // Only check the size of the whitespace if this is not
                     // the first token. We don't care about the size of
                     // leading whitespace, just that there is some.
                     if ($i !== 0) {
                         if ($tokens[$stackPtr]['content'] !== $pattern[$i]['value']) {
                             $hasError = true;
                         }
                     }
                 } else {
                     // Check to see if this important token is the same as the
                     // previous important token in the pattern. If it is not,
                     // then the pattern cannot be for this piece of code.
                     $prev = $phpcsFile->findPrevious($ignoreTokens, $stackPtr, null, true);
                     if ($prev === false || $tokens[$prev]['code'] !== $pattern[$i]['token']) {
                         return false;
                     }
                     // If we skipped past some whitespace tokens, then add them
                     // to the found string.
                     $tokenContent = $phpcsFile->getTokensAsString($prev + 1, $stackPtr - $prev - 1);
                     $found = $tokens[$prev]['content'] . $tokenContent . $found;
                     if (isset($pattern[$i - 1]) === true && $pattern[$i - 1]['type'] === 'skip') {
                         $stackPtr = $prev;
                     } else {
                         $stackPtr = $prev - 1;
                     }
                 }
                 //end if
             } else {
                 if ($pattern[$i]['type'] === 'skip') {
                     // Skip to next piece of relevant code.
                     if ($pattern[$i]['to'] === 'parenthesis_closer') {
                         $to = 'parenthesis_opener';
                     } else {
                         $to = 'scope_opener';
                     }
                     // Find the previous opener.
                     $next = $phpcsFile->findPrevious($ignoreTokens, $stackPtr, null, true);
                     if ($next === false || isset($tokens[$next][$to]) === false) {
                         // If there was not opener, then we must be
                         // using the wrong pattern.
                         return false;
                     }
                     if ($to === 'parenthesis_opener') {
                         $found = '{' . $found;
                     } else {
                         $found = '(' . $found;
                     }
                     $found = '...' . $found;
                     // Skip to the opening token.
                     $stackPtr = $tokens[$next][$to] - 1;
                 } else {
                     if ($pattern[$i]['type'] === 'string') {
                         $found = 'abc';
                     } else {
                         if ($pattern[$i]['type'] === 'newline') {
                             if ($this->ignoreComments === true && isset(Tokens::$commentTokens[$tokens[$stackPtr]['code']]) === true) {
                                 $startComment = $phpcsFile->findPrevious(Tokens::$commentTokens, $stackPtr - 1, null, true);
                                 if ($tokens[$startComment]['line'] !== $tokens[$startComment + 1]['line']) {
                                     $startComment++;
                                 }
                                 $tokenContent = $phpcsFile->getTokensAsString($startComment, $stackPtr - $startComment + 1);
                                 $found = $tokenContent . $found;
                                 $stackPtr = $startComment - 1;
                             }
                             if ($tokens[$stackPtr]['code'] === T_WHITESPACE) {
                                 if ($tokens[$stackPtr]['content'] !== $phpcsFile->eolChar) {
                                     $found = $tokens[$stackPtr]['content'] . $found;
                                     // This may just be an indent that comes after a newline
                                     // so check the token before to make sure. If it is a newline, we
                                     // can ignore the error here.
                                     if ($tokens[$stackPtr - 1]['content'] !== $phpcsFile->eolChar && ($this->ignoreComments === true && isset(Tokens::$commentTokens[$tokens[$stackPtr - 1]['code']]) === false)) {
                                         $hasError = true;
                                     } else {
                                         $stackPtr--;
                                     }
                                 } else {
                                     $found = 'EOL' . $found;
                                 }
                             } else {
                                 $found = $tokens[$stackPtr]['content'] . $found;
                                 $hasError = true;
                             }
                             //end if
                             if ($hasError === false && $pattern[$i - 1]['type'] !== 'newline') {
                                 // Make sure they only have 1 newline.
                                 $prev = $phpcsFile->findPrevious($ignoreTokens, $stackPtr - 1, null, true);
                                 if ($prev !== false && $tokens[$prev]['line'] !== $tokens[$stackPtr]['line']) {
                                     $hasError = true;
                                 }
                             }
                         }
                     }
                 }
             }
             //end if
         }
         //end for
     }
     //end if
     $stackPtr = $origStackPtr;
     $lastAddedStackPtr = null;
     $patternLen = count($pattern);
     for ($i = $patternInfo['listen_pos']; $i < $patternLen; $i++) {
         if (isset($tokens[$stackPtr]) === false) {
             break;
         }
         if ($pattern[$i]['type'] === 'token') {
             if ($pattern[$i]['token'] === T_WHITESPACE) {
                 if ($this->ignoreComments === true) {
                     // If we are ignoring comments, check to see if this current
                     // token is a comment. If so skip it.
                     if (isset(Tokens::$commentTokens[$tokens[$stackPtr]['code']]) === true) {
                         continue;
                     }
                     // If the next token is a comment, the we need to skip the
                     // current token as we should allow a space before a
                     // comment for readability.
                     if (isset($tokens[$stackPtr + 1]) === true && isset(Tokens::$commentTokens[$tokens[$stackPtr + 1]['code']]) === true) {
                         continue;
                     }
                 }
                 $tokenContent = '';
                 if ($tokens[$stackPtr]['code'] === T_WHITESPACE) {
                     if (isset($pattern[$i + 1]) === false) {
                         // This is the last token in the pattern, so just compare
                         // the next token of content.
                         $tokenContent = $tokens[$stackPtr]['content'];
                     } else {
                         // Get all the whitespace to the next token.
                         $next = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr, null, true);
                         $tokenContent = $phpcsFile->getTokensAsString($stackPtr, $next - $stackPtr);
                         $lastAddedStackPtr = $stackPtr;
                         $stackPtr = $next;
                     }
                     //end if
                     if ($stackPtr !== $lastAddedStackPtr) {
                         $found .= $tokenContent;
                     }
                 } else {
                     if ($stackPtr !== $lastAddedStackPtr) {
                         $found .= $tokens[$stackPtr]['content'];
                         $lastAddedStackPtr = $stackPtr;
                     }
                 }
                 //end if
                 if (isset($pattern[$i + 1]) === true && $pattern[$i + 1]['type'] === 'skip') {
                     // The next token is a skip token, so we just need to make
                     // sure the whitespace we found has *at least* the
                     // whitespace required.
                     if (strpos($tokenContent, $pattern[$i]['value']) !== 0) {
                         $hasError = true;
                     }
                 } else {
                     if ($tokenContent !== $pattern[$i]['value']) {
                         $hasError = true;
                     }
                 }
             } else {
                 // Check to see if this important token is the same as the
                 // next important token in the pattern. If it is not, then
                 // the pattern cannot be for this piece of code.
                 $next = $phpcsFile->findNext($ignoreTokens, $stackPtr, null, true);
                 if ($next === false || $tokens[$next]['code'] !== $pattern[$i]['token']) {
                     // The next important token did not match the pattern.
                     return false;
                 }
                 if ($lastAddedStackPtr !== null) {
                     if (($tokens[$next]['code'] === T_OPEN_CURLY_BRACKET || $tokens[$next]['code'] === T_CLOSE_CURLY_BRACKET) && isset($tokens[$next]['scope_condition']) === true && $tokens[$next]['scope_condition'] > $lastAddedStackPtr) {
                         // This is a brace, but the owner of it is after the current
                         // token, which means it does not belong to any token in
                         // our pattern. This means the pattern is not for us.
                         return false;
                     }
                     if (($tokens[$next]['code'] === T_OPEN_PARENTHESIS || $tokens[$next]['code'] === T_CLOSE_PARENTHESIS) && isset($tokens[$next]['parenthesis_owner']) === true && $tokens[$next]['parenthesis_owner'] > $lastAddedStackPtr) {
                         // This is a bracket, but the owner of it is after the current
                         // token, which means it does not belong to any token in
                         // our pattern. This means the pattern is not for us.
                         return false;
                     }
                 }
                 //end if
                 // If we skipped past some whitespace tokens, then add them
                 // to the found string.
                 if ($next - $stackPtr > 0) {
                     $hasComment = false;
                     for ($j = $stackPtr; $j < $next; $j++) {
                         $found .= $tokens[$j]['content'];
                         if (isset(Tokens::$commentTokens[$tokens[$j]['code']]) === true) {
                             $hasComment = true;
                         }
                     }
                     // If we are not ignoring comments, this additional
                     // whitespace or comment is not allowed. If we are
                     // ignoring comments, there needs to be at least one
                     // comment for this to be allowed.
                     if ($this->ignoreComments === false || $this->ignoreComments === true && $hasComment === false) {
                         $hasError = true;
                     }
                     // Even when ignoring comments, we are not allowed to include
                     // newlines without the pattern specifying them, so
                     // everything should be on the same line.
                     if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) {
                         $hasError = true;
                     }
                 }
                 //end if
                 if ($next !== $lastAddedStackPtr) {
                     $found .= $tokens[$next]['content'];
                     $lastAddedStackPtr = $next;
                 }
                 if (isset($pattern[$i + 1]) === true && $pattern[$i + 1]['type'] === 'skip') {
                     $stackPtr = $next;
                 } else {
                     $stackPtr = $next + 1;
                 }
             }
             //end if
         } else {
             if ($pattern[$i]['type'] === 'skip') {
                 if ($pattern[$i]['to'] === 'unknown') {
                     $next = $phpcsFile->findNext($pattern[$i + 1]['token'], $stackPtr);
                     if ($next === false) {
                         // Couldn't find the next token, so we must
                         // be using the wrong pattern.
                         return false;
                     }
                     $found .= '...';
                     $stackPtr = $next;
                 } else {
                     // Find the previous opener.
                     $next = $phpcsFile->findPrevious(Tokens::$blockOpeners, $stackPtr);
                     if ($next === false || isset($tokens[$next][$pattern[$i]['to']]) === false) {
                         // If there was not opener, then we must
                         // be using the wrong pattern.
                         return false;
                     }
                     $found .= '...';
                     if ($pattern[$i]['to'] === 'parenthesis_closer') {
                         $found .= ')';
                     } else {
                         $found .= '}';
                     }
                     // Skip to the closing token.
                     $stackPtr = $tokens[$next][$pattern[$i]['to']] + 1;
                 }
                 //end if
             } else {
                 if ($pattern[$i]['type'] === 'string') {
                     if ($tokens[$stackPtr]['code'] !== T_STRING) {
                         $hasError = true;
                     }
                     if ($stackPtr !== $lastAddedStackPtr) {
                         $found .= 'abc';
                         $lastAddedStackPtr = $stackPtr;
                     }
                     $stackPtr++;
                 } else {
                     if ($pattern[$i]['type'] === 'newline') {
                         // Find the next token that contains a newline character.
                         $newline = 0;
                         for ($j = $stackPtr; $j < $phpcsFile->numTokens; $j++) {
                             if (strpos($tokens[$j]['content'], $phpcsFile->eolChar) !== false) {
                                 $newline = $j;
                                 break;
                             }
                         }
                         if ($newline === 0) {
                             // We didn't find a newline character in the rest of the file.
                             $next = $phpcsFile->numTokens - 1;
                             $hasError = true;
                         } else {
                             if ($this->ignoreComments === false) {
                                 // The newline character cannot be part of a comment.
                                 if (isset(Tokens::$commentTokens[$tokens[$newline]['code']]) === true) {
                                     $hasError = true;
                                 }
                             }
                             if ($newline === $stackPtr) {
                                 $next = $stackPtr + 1;
                             } else {
                                 // Check that there were no significant tokens that we
                                 // skipped over to find our newline character.
                                 $next = $phpcsFile->findNext($ignoreTokens, $stackPtr, null, true);
                                 if ($next < $newline) {
                                     // We skipped a non-ignored token.
                                     $hasError = true;
                                 } else {
                                     $next = $newline + 1;
                                 }
                             }
                         }
                         //end if
                         if ($stackPtr !== $lastAddedStackPtr) {
                             $found .= $phpcsFile->getTokensAsString($stackPtr, $next - $stackPtr);
                             $diff = $next - $stackPtr;
                             $lastAddedStackPtr = $next - 1;
                         }
                         $stackPtr = $next;
                     }
                 }
             }
         }
         //end if
     }
     //end for
     if ($hasError === true) {
         $error = $this->prepareError($found, $patternCode);
         $errors[$origStackPtr] = $error;
     }
     return $errors;
 }