/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip invalid statement. if (isset($token['parenthesis_opener']) === false) { return; } $next = ++$token['parenthesis_opener']; $end = --$token['parenthesis_closer']; $parts = array(0, 0, 0); $index = 0; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if ($code === T_SEMICOLON) { ++$index; } else { if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === false) { ++$parts[$index]; } } } if ($parts[0] === 0 && $parts[2] === 0 && $parts[1] > 0) { $error = 'This FOR loop can be simplified to a WHILE loop'; $phpcsfile->addwarning($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-loop without body. if (isset($token['scope_opener']) === false) { return; } // Find incrementors for outer loop. $outer = $this->findincrementers($tokens, $token); // Skip if empty. if (count($outer) === 0) { return; } // Find nested for loops. $start = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $start <= $end; ++$start) { if ($tokens[$start]['code'] !== T_FOR) { continue; } $inner = $this->findincrementers($tokens, $tokens[$start]); $diff = array_intersect($outer, $inner); if (count($diff) !== 0) { $error = sprintf('Loop incrementor (%s) jumbling with inner loop', join(', ', $diff)); $phpcsfile->addwarning($error, $stackptr); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if (isset($tokens[$stackptr]['scope_opener']) === false) { // Ignore the ELSE in ELSE IF. We'll process the IF part later. if ($tokens[$stackptr]['code'] === T_ELSE && $tokens[$stackptr + 2]['code'] === T_IF) { return; } if ($tokens[$stackptr]['code'] === T_WHILE) { // This could be from a DO WHILE, which doesn't have an opening brace. $lastcontent = $phpcsfile->findprevious(T_WHITESPACE, $stackptr - 1, null, true); if ($tokens[$lastcontent]['code'] === T_CLOSE_CURLY_BRACKET) { $brace = $tokens[$lastcontent]; if (isset($brace['scope_condition']) === true) { $condition = $tokens[$brace['scope_condition']]; if ($condition['code'] === T_DO) { return; } } } } // This is a control structure without an opening brace, // so it is an inline statement. if ($this->error === true) { $phpcsfile->adderror('Inline control structures are not allowed', $stackptr); } else { $phpcsfile->addwarning('Inline control structures are discouraged', $stackptr); } return; } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $workingstring = $tokens[$stackptr]['content']; // Check if it's a double quoted string. if (strpos($workingstring, '"') === false) { return; } // Make sure it's not a part of a string started above. // If it is, then we have already checked it. if ($workingstring[0] !== '"') { return; } // Work through the following tokens, in case this string is stretched // over multiple Lines. for ($i = $stackptr + 1; $i < $phpcsfile->numTokens; $i++) { if ($tokens[$i]['type'] !== 'T_CONSTANT_ENCAPSED_STRING') { break; } $workingstring .= $tokens[$i]['content']; } $allowedchars = array('\\n', '\\r', '\\f', '\\t', '\\v', '\\x', '\'', '$'); foreach ($allowedchars as $testchar) { if (strpos($workingstring, $testchar) !== false) { return; } } $error = "String {$workingstring} does not require double quotes; use single quotes instead"; $phpcsfile->addwarning($error, $stackptr); }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-statements without body. if (isset($token['scope_opener']) === false) { return; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; $emptybody = true; for (; $next <= $end; ++$next) { if (in_array($tokens[$next]['code'], PHP_CodeSniffer_tokens::$emptyTokens) === false) { $emptybody = false; break; } } if ($emptybody === true) { // Get token identifier. $name = $phpcsfile->gettokensAsString($stackptr, 1); $error = sprintf('Empty %s statement detected', strtoupper($name)); if ($this->_tokens[$token['code']] === true) { $phpcsfile->adderror($error, $stackptr); } else { $phpcsfile->addwarning($error, $stackptr); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if (isset($tokens[$stackptr]['scope_opener']) === false) { $error = 'possible parse error: '; $error .= $tokens[$stackptr]['content']; $error .= ' missing opening or closing brace'; $phpcsfile->addwarning($error, $stackptr); return; } $curlybrace = $tokens[$stackptr]['scope_opener']; $lastcontent = $phpcsfile->findprevious(T_WHITESPACE, $curlybrace - 1, $stackptr, true); $classline = $tokens[$lastcontent]['line']; $braceline = $tokens[$curlybrace]['line']; if ($braceline != $classline) { $error = 'Opening brace of a '; $error .= $tokens[$stackptr]['content']; $error .= ' must be on the same line as the definition'; $phpcsfile->adderror($error, $curlybrace); return; } if ($tokens[$curlybrace - 1]['code'] === T_WHITESPACE) { $prevcontent = $tokens[$curlybrace - 1]['content']; if ($prevcontent !== $phpcsfile->eolChar) { $blankspace = substr($prevcontent, strpos($prevcontent, $phpcsfile->eolChar)); $spaces = strlen($blankspace); if ($spaces !== 1) { $error = "Expected 1 space before opening brace; {$spaces} found"; $phpcsfile->adderror($error, $curlybrace); } } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-loop without body. if (isset($token['parenthesis_opener']) === false) { return; } $next = ++$token['parenthesis_opener']; $end = --$token['parenthesis_closer']; $goodcondition = false; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === true) { continue; } else { if ($code !== T_TRUE && $code !== T_FALSE) { $goodcondition = true; } } } if ($goodcondition === false) { $error = 'Avoid IF statements that are always true or false'; $phpcsfile->addwarning($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); //$nexttoken = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, ($stackptr + 1), null, true); //if ($tokens[$nexttoken]['code'] === T_OPEN_PARENTHESIS) { // $error = '"'.$tokens[$stackptr]['content'].'"'; // $error .= ' is a statement, not a function; '; // $error .= 'no parentheses are required'; // $phpcsfile->adderror($error, $stackptr); //} $incondition = count($tokens[$stackptr]['conditions']) !== 0 ? true : false; // Check to see if this including statement is within the parenthesis of a condition. // If that's the case then we need to process it as being within a condition, as they // are checking the return value. if (isset($tokens[$stackptr]['nested_parenthesis']) === true) { foreach ($tokens[$stackptr]['nested_parenthesis'] as $left => $right) { if (isset($tokens[$left]['parenthesis_owner']) === true) { $incondition = true; } } } // Check to see if they are assigning the return value of this including call. // If they are then they are probably checking it, so its conditional. $previous = $phpcsfile->findprevious(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr - 1, null, true); if (in_array($tokens[$previous]['code'], PHP_CodeSniffer_tokens::$assignmentTokens) === true) { // The have assigned the return value to it, so its conditional. $incondition = true; } $tokencode = $tokens[$stackptr]['code']; if ($incondition === true) { // We are inside a conditional statement. We need an include_once. if ($tokencode === T_REQUIRE_ONCE) { $error = 'File is being conditionally included; '; $error .= 'use "include_once" instead'; $phpcsfile->adderror($error, $stackptr); } else { if ($tokencode === T_REQUIRE) { $error = 'File is being conditionally included; '; $error .= 'use "include" instead'; $phpcsfile->adderror($error, $stackptr); } } } else { // We are unconditionally including, we need a require_once. if ($tokencode === T_INCLUDE_ONCE) { $error = 'File is being unconditionally included; '; $error .= 'use "require_once" instead'; $phpcsfile->adderror($error, $stackptr); } else { if ($tokencode === T_INCLUDE) { $error = 'File is being unconditionally included; '; $error .= 'use "require" instead'; $phpcsfile->adderror($error, $stackptr); } } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $last_token = end($tokens); if ($last_token['code'] === T_CLOSE_TAG) { $error = 'Closing PHP tag is not required at the end of the file. Please remove.'; $phpcsfile->addwarning($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $keyword = $tokens[$stackptr]['content']; if (strtolower($keyword) !== $keyword) { $error = 'TRUE, FALSE and NULL must be lowercase; expected "' . strtolower($keyword) . '" but found "' . $keyword . '"'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if ($tokens[$stackptr]['content'][0] === '#') { $error = 'Perl-style comments are not allowed. Use "// Comment."'; $error .= ' or "/* comment */" instead.'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // Find the next non-empty token. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr + 1, null, true); if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { // Not a function call. return; } if (isset($tokens[$next]['parenthesis_closer']) === false) { // Not a function call. return; } // Find the previous non-empty token. $previous = $phpcsfile->findprevious(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr - 1, null, true); if ($tokens[$previous]['code'] === T_FUNCTION) { // It's a function definition, not a function call. return; } if ($tokens[$previous]['code'] === T_NEW) { // We are creating an object, not calling a function. return; } if ($stackptr + 1 !== $next) { // Checking this: $value = my_function[*](...). $error = 'Space before opening parenthesis of function call prohibited'; $phpcsfile->adderror($error, $stackptr); } if ($tokens[$next + 1]['code'] === T_WHITESPACE) { // Checking this: $value = my_function([*]...). $error = 'Space after opening parenthesis of function call prohibited'; $phpcsfile->adderror($error, $stackptr); } $closer = $tokens[$next]['parenthesis_closer']; if ($tokens[$closer - 1]['code'] === T_WHITESPACE) { // Checking this: $value = my_function(...[*]). $between = $phpcsfile->findnext(T_WHITESPACE, $next + 1, null, true); // Only throw an error if there is some content between the parenthesis. // IE. Checking for this: $value = my_function(). // If there is no content, then we would have thrown an error in the // previous IF statement because it would look like this: // $value = my_function( ). if ($between !== $closer) { $error = 'Space before closing parenthesis of function call prohibited'; $phpcsfile->adderror($error, $closer); } } $next = $phpcsfile->findnext(T_WHITESPACE, $closer + 1, null, true); if ($tokens[$next]['code'] === T_SEMICOLON) { if (in_array($tokens[$closer + 1]['code'], PHP_CodeSniffer_tokens::$emptyTokens) === true) { $error = 'Space after closing parenthesis of function call prohibited'; $phpcsfile->adderror($error, $closer); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $classname = $phpcsfile->findnext(T_STRING, $stackptr); $name = trim($tokens[$classname]['content']); // Make sure that the word is all lowercase if (!preg_match('/[a-z]?/', $name)) { $error = ucfirst($tokens[$stackptr]['content']) . ' name is not valid, must be all lower-case'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $content = $tokens[$stackptr]['content']; if ($content !== strtolower($content)) { $type = strtoupper($content); $expected = strtolower($content); $error = "{$type} keyword must be lowercase; expected \"{$expected}\" but found \"{$content}\""; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if ($tokens[$stackptr + 1]['code'] !== T_WHITESPACE) { $error = 'A cast statement must be followed by a single space'; $phpcsfile->adderror($error, $stackptr); return; } if ($tokens[$stackptr + 1]['content'] !== ' ') { $error = 'A cast statement must be followed by a single space'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // Make sure this is whitespace used for indentation. $line = $tokens[$stackptr]['line']; if ($stackptr > 0 && $tokens[$stackptr - 1]['line'] === $line) { return; } if (strpos($tokens[$stackptr]['content'], "\t") !== false) { $error = 'Spaces must be used to indent lines; tabs are not allowed'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // If this is an inline condition (ie. there is no scope opener), then // return, as this is not a new scope. if (isset($tokens[$stackptr]['scope_closer']) === false) { return; } // We need to actually find the first piece of content on this line, // as if this is a method with tokens before it (public, static etc) // or an if with an else before it, then we need to start the scope // checking from there, rather than the current token. $linestart = $stackptr - 1; for ($linestart; $linestart > 0; $linestart--) { if (strpos($tokens[$linestart]['content'], $phpcsfile->eolChar) !== false) { break; } } // We found a new line, now go forward and find the first non-whitespace // token. $linestart = $phpcsfile->findnext(array(T_WHITESPACE), $linestart + 1, null, true); $startcolumn = $tokens[$linestart]['column']; $scopestart = $tokens[$stackptr]['scope_opener']; $scopeend = $tokens[$stackptr]['scope_closer']; // Check that the closing brace is on its own line. $lastcontent = $phpcsfile->findprevious(array(T_WHITESPACE), $scopeend - 1, $scopestart, true); if ($tokens[$lastcontent]['line'] === $tokens[$scopeend]['line']) { $error = 'Closing brace must be on a line by itself'; $phpcsfile->adderror($error, $scopeend); return; } // Check now that the closing brace is lined up correctly. $braceindent = $tokens[$scopeend]['column']; $isbreakcloser = $tokens[$scopeend]['code'] === T_BREAK; if (in_array($tokens[$stackptr]['code'], array(T_CASE, T_DEFAULT)) === true && $isbreakcloser === true) { // BREAK statements should be indented 4 spaces from the // CASE or DEFAULT statement. if ($braceindent !== $startcolumn + 4) { $error = 'Break statement indented incorrectly; expected ' . ($startcolumn + 3) . ' spaces, found ' . ($braceindent - 1); $phpcsfile->adderror($error, $scopeend); } } else { if (in_array($tokens[$stackptr]['code'], array(T_CASE, T_DEFAULT))) { $startcolumn -= 4; } if ($braceindent !== $startcolumn) { $error = 'Closing brace indented incorrectly; expected ' . ($startcolumn - 1) . ' spaces, found ' . ($braceindent - 1); $phpcsfile->adderror($error, $scopeend); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); if ($tokens[$stackptr]['code'] !== T_STRING) { $content = $tokens[$stackptr]['content']; if ($content !== strtolower($content)) { $type = strtoupper($content); $expected = strtolower($content); $error = "{$type} keyword must be lowercase; expected \"{$expected}\" but found \"{$content}\""; $phpcsfile->adderror($error, $stackptr); } return; } // Make sure this is a function call. $next = $phpcsfile->findnext(T_WHITESPACE, $stackptr + 1, null, true); if ($next === false) { // Not a function call. return; } if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { // Not a function call. return; } $prev = $phpcsfile->findprevious(T_WHITESPACE, $stackptr - 1, null, true); if ($tokens[$prev]['code'] === T_FUNCTION) { // Function declaration, not a function call. return; } if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR) { // Not an inbuilt function. return; } if ($tokens[$prev]['code'] === T_DOUBLE_COLON) { // Not an inbuilt function. return; } // Make sure it is an inbuilt PHP function. // PHP_CodeSniffer doesn't include/require any files, so no // user defined global functions can exist, except for // PHP_CodeSniffer ones. $content = $tokens[$stackptr]['content']; if (function_exists($content) === false) { return; } if ($content !== strtolower($content)) { $expected = strtolower($content); $error = "Calls to inbuilt PHP functions must be lowercase; expected \"{$expected}\" but found \"{$content}\""; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $previoustoken = $stackptr - 1; // Move back until we find the previous non-whitespace, non-comment token do { $previoustoken = $phpcsfile->findprevious(array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT), $previoustoken - 1, null, true); } while ($tokens[$previoustoken]['line'] == $tokens[$stackptr]['line']); $previous_non_ws_token = $tokens[$previoustoken]; // If this token is immediately on the line before this control structure, print a warning if ($previous_non_ws_token['line'] == $tokens[$stackptr]['line'] - 1) { // Exception: do {EOL...} while (...); if ($tokens[$stackptr]['code'] == T_WHILE && $tokens[$stackptr - 1]['code'] == T_CLOSE_CURLY_BRACKET) { // Ignore do...while (see above) } else { $phpcsfile->addWarning('You should add a blank line before control structures', $stackptr); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $firstcontent = $phpcsfile->findnext(array(T_WHITESPACE), $stackptr + 1, null, true); // If the first non-whitespace token is not an opening parenthesis, then we are not concerned. if ($tokens[$firstcontent]['code'] !== T_OPEN_PARENTHESIS) { return; } $endofstatement = $phpcsfile->findnext(array(T_SEMICOLON), $stackptr, null, false); // If the token before the semi-colon is not a closing parenthesis, then we are not concerned. if ($tokens[$endofstatement - 1]['code'] !== T_CLOSE_PARENTHESIS) { return; } if ($phpcsfile->findnext(PHP_CodeSniffer_tokens::$operators, $stackptr, $endofstatement, false) === false) { // There are no arithmetic operators in this. $error = 'Echoed strings should not be bracketed'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // Make sure this is the first open tag. $previousopentag = $phpcsfile->findprevious(array(T_OPEN_TAG), $stackptr - 1); if ($previousopentag !== false) { return; } $tokencount = 0; $currentlinecontent = ''; $currentline = 1; for (; $tokencount < $phpcsfile->numTokens; $tokencount++) { if ($tokens[$tokencount]['line'] === $currentline) { $currentlinecontent .= $tokens[$tokencount]['content']; } else { $currentlinecontent = trim($currentlinecontent, $phpcsfile->eolChar); $this->checklinelength($phpcsfile, $tokencount - 1, $currentlinecontent); $currentlinecontent = $tokens[$tokencount]['content']; $currentline++; } } $this->checklinelength($phpcsfile, $tokencount - 1, $currentlinecontent); }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip for-statements without body. if (isset($token['scope_opener']) === false) { return; } // Fetch previous token. $prev = $phpcsfile->findprevious(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr - 1, null, true); // Skip for non final class. if ($prev === false || $tokens[$prev]['code'] !== T_FINAL) { return; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $next <= $end; ++$next) { if ($tokens[$next]['code'] === T_FINAL) { $error = 'Unnecessary FINAL modifier in FINAL class'; $phpcsfile->addwarning($error, $next); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { // If short open tags are off, then any short open tags will be converted // to inline_html tags so we can just ignore them. // If its on, then we want to ban the use of them. $option = ini_get('short_open_tag'); // Ini_get returns a string "0" if short open tags is off. if ($option === '0') { return; } $tokens = $phpcsfile->gettokens(); $opentag = $tokens[$stackptr]; if ($opentag['content'] === '<?') { $error = 'Short PHP opening tag used. Found "' . $opentag['content'] . '" Expected "<?php".'; $phpcsfile->adderror($error, $stackptr); } if ($opentag['code'] === T_OPEN_TAG_WITH_ECHO) { $nextvar = $tokens[$phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr + 1, null, true)]; $error = 'Short PHP opening tag used with echo. Found "'; $error .= $opentag['content'] . ' ' . $nextvar['content'] . ' ..." but expected "<?php echo ' . $nextvar['content'] . ' ...".'; $phpcsfile->adderror($error, $stackptr); } }
/** * 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. * * @return void */ protected function processmembervar(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // There needs to be 1 blank line before the var, not counting comments. $prevlinetoken = null; for ($i = $stackptr - 1; $i > 0; $i--) { if (in_array($tokens[$i]['code'], PHP_CodeSniffer_tokens::$commentTokens) === true) { // Skip comments. continue; } else { if (strpos($tokens[$i]['content'], $phpcsfile->eolChar) === false) { // Not the end of the line. continue; } else { // If this is a WHITESPACE token, and the token right before // it is a DOC_COMMENT, then it is just the newline after the // member var's comment, and can be skipped. if ($tokens[$i]['code'] === T_WHITESPACE && in_array($tokens[$i - 1]['code'], PHP_CodeSniffer_tokens::$commentTokens) === true) { continue; } $prevlinetoken = $i; break; } } } if (is_null($prevlinetoken) === true) { // Never found the previous line, which means // there are 0 blank lines before the member var. $foundlines = 0; } else { $prevcontent = $phpcsfile->findprevious(array(T_WHITESPACE, T_DOC_COMMENT), $prevlinetoken, null, true); $foundlines = $tokens[$prevlinetoken]['line'] - $tokens[$prevcontent]['line']; } if ($foundlines !== 1) { // $phpcsfile->adderror("Expected 1 blank line before member var; $foundlines found", $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip invalid statement. if (isset($token['parenthesis_opener']) === false) { return; } $next = ++$token['parenthesis_opener']; $end = --$token['parenthesis_closer']; $position = 0; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if ($code === T_SEMICOLON) { ++$position; } if ($position < 1) { continue; } else { if ($position > 1) { break; } else { if ($code !== T_VARIABLE && $code !== T_STRING) { continue; } } } // Find next non empty token, if it is a open curly brace we have a // function call. $index = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); if ($tokens[$index]['code'] === T_OPEN_PARENTHESIS) { $error = 'Avoid function calls in a FOR loop test part'; $phpcsfile->addwarning($error, $stackptr); break; } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip function without body. if (isset($token['scope_opener']) === false) { return; } // Get function name. $methodname = $phpcsfile->getdeclarationname($stackptr); // Get all parameters from method signature. $signature = array(); foreach ($phpcsfile->getmethodparameters($stackptr) as $param) { $signature[] = $param['name']; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === true) { continue; } else { if ($code === T_RETURN) { continue; } } break; } // Any token except 'parent' indicates correct code. if ($tokens[$next]['code'] !== T_PARENT) { return; } // Find next non empty token index, should be double colon. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code. if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { return; } // Find next non empty token index, should be the function name. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code or other method. if ($next === false || $tokens[$next]['content'] !== $methodname) { return; } // Find next non empty token index, should be the open parenthesis. $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code. if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { return; } $validparametertypes = array(T_VARIABLE, T_LNUMBER, T_CONSTANT_ENCAPSED_STRING); $parameters = array(''); $parenthesiscount = 1; $count = count($tokens); for (++$next; $next < $count; ++$next) { $code = $tokens[$next]['code']; if ($code === T_OPEN_PARENTHESIS) { ++$parenthesiscount; } else { if ($code === T_CLOSE_PARENTHESIS) { --$parenthesiscount; } else { if ($parenthesiscount === 1 && $code === T_COMMA) { $parameters[] = ''; } else { if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === false) { $parameters[count($parameters) - 1] .= $tokens[$next]['content']; } } } } if ($parenthesiscount === 0) { break; } } $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { return; } // Check rest of the scope. for (++$next; $next <= $end; ++$next) { $code = $tokens[$next]['code']; // Skip for any other content. if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === false) { return; } } $parameters = array_map('trim', $parameters); $parameters = array_filter($parameters); if (count($parameters) === count($signature) && $parameters === $signature) { $phpcsfile->addwarning('Useless method overriding detected', $stackptr); } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $this->currentfile = $phpcsfile; // We are only interested if this is the first open tag. if ($stackptr !== 0) { if ($phpcsfile->findprevious(T_OPEN_TAG, $stackptr - 1) !== false) { return; } } $tokens = $phpcsfile->gettokens(); // Find the next non whitespace token. $commentstart = $phpcsfile->findnext(T_WHITESPACE, $stackptr + 1, null, true); // Look for $Id$ and boilerplate if ($tokens[$commentstart]['code'] != T_COMMENT) { $phpcsfile->adderror('File must begin with License boilerplate', $stackptr + 1); return; } else { if (preg_match('|\\$Id|i', $tokens[$commentstart]['content'])) { $phpcsfile->addwarning("\$Id\$ tag is no longer required, please remove.", $stackptr + 1); return; } } // now look for boilerplate, must be immediately after the first line $boilerplate = '// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>.'; $nexttoken = $phpcsfile->findnext(T_WHITESPACE, $stackptr + 1, null, true); $boilerplate_lines = preg_split('/[\\n\\r]+/', $boilerplate); if (rtrim($tokens[$nexttoken]['content']) != $boilerplate_lines[0]) { $phpcsfile->adderror('You must include the Moodle boilerplate at the top of the file', $nexttoken); return; } $boilerplate_index = 0; foreach ($boilerplate_lines as $line) { $nexttoken = $phpcsfile->findnext(T_COMMENT, $nexttoken); if (rtrim($tokens[$nexttoken]['content']) != $boilerplate_lines[$boilerplate_index]) { $phpcsfile->adderror('Badly formatted boilerplate. Please copy-paste exactly', $nexttoken); return; } $nexttoken++; $boilerplate_index++; } $filedoctoken = $phpcsfile->findnext(T_WHITESPACE, $nexttoken + 1, null, true); if ($tokens[$filedoctoken]['code'] === T_CLOSE_TAG) { // We are only interested if this is the first open tag. return; } else { if ($tokens[$filedoctoken]['code'] === T_COMMENT) { $phpcsfile->adderror('You must use "/**" style comments for a file comment', $filedoctoken + 1); return; } else { if ($filedoctoken === false || $tokens[$filedoctoken]['code'] !== T_DOC_COMMENT) { $phpcsfile->adderror('Missing file doc comment', $filedoctoken + 1); return; } else { // Extract the header comment docblock. $commentend = $phpcsfile->findnext(T_DOC_COMMENT, $filedoctoken + 1, null, true) - 1; // Check if there is only 1 doc comment between the open tag and class token. $nexttoken = array(T_ABSTRACT, T_CLASS, T_FUNCTION, T_DOC_COMMENT); $commentnext = $phpcsfile->findnext($nexttoken, $commentend + 1); if ($commentnext !== false && $tokens[$commentnext]['code'] !== T_DOC_COMMENT) { // Found a class token right after comment doc block. $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $commentend + 1, $commentnext, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $newlinetoken + 1, $commentnext, false, $phpcsfile->eolChar); if ($newlinetoken === false) { // No blank line between the class token and the doc block. // The doc block is most likely a class comment. $phpcsfile->adderror('Missing file doc comment', $stackptr + 1); return; } } } $comment = $phpcsfile->gettokensAsString($filedoctoken, $commentend - $filedoctoken + 1); // Parse the header comment docblock. try { $this->commentparser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsfile); $this->commentparser->parse(); } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { $line = $e->getlinewithinComment() + $filedoctoken; $phpcsfile->adderror($e->getMessage(), $line); return; } $comment = $this->commentparser->getComment(); if (is_null($comment) === true) { $error = 'File doc comment is empty'; $phpcsfile->adderror($error, $filedoctoken); return; } // No extra newline before short description. $short = $comment->getShortComment(); $newlinecount = 0; $newlinespan = strspn($short, $phpcsfile->eolChar); if ($short !== '' && $newlinespan > 0) { $line = $newlinespan > 1 ? 'newlines' : 'newline'; $error = "Extra {$line} found before file comment short description"; $phpcsfile->adderror($error, $filedoctoken + 1); } $newlinecount = substr_count($short, $phpcsfile->eolChar) + 1; // Exactly one blank line between short and long description. $long = $comment->getlongcomment(); if (empty($long) === false) { $between = $comment->getWhiteSpacebetween(); $newlinebetween = substr_count($between, $phpcsfile->eolChar); if ($newlinebetween !== 2) { $error = 'There should be exactly one blank line between descriptions in file comment'; $phpcsfile->addwarning($error, $filedoctoken + $newlinecount + 1); } $newlinecount += $newlinebetween; } // Exactly one blank line before tags. $tags = $this->commentparser->gettagOrders(); if (count($tags) > 1) { $newlinespan = $comment->getNewlineAfter(); if ($newlinespan !== 2) { $error = 'There must be exactly one blank line before the tags in file comment'; if ($long !== '') { $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1; } $phpcsfile->addwarning($error, $filedoctoken + $newlinecount); $short = rtrim($short, $phpcsfile->eolChar . ' '); } } // Check the PHP Version. /* if (strstr(strtolower($long), 'php version') === false) { $error = 'PHP version not specified'; $phpcsfile->addwarning($error, $commentend); } */ // Check each tag. $this->processtags($filedoctoken, $commentend); } } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { // Modify array of required tags $this->tags['package']['required'] = false; $this->tags['copyright']['required'] = false; $this->tags['author']['required'] = false; $this->currentfile = $phpcsfile; $tokens = $phpcsfile->gettokens(); $type = strtolower($tokens[$stackptr]['content']); $find = array(T_ABSTRACT, T_WHITESPACE, T_FINAL); // Extract the class comment docblock. $commentend = $phpcsfile->findprevious($find, $stackptr - 1, null, true); if ($commentend !== false && $tokens[$commentend]['code'] === T_COMMENT) { $phpcsfile->adderror("You must use \"/**\" style comments for a {$type} comment", $stackptr); return; } else { if ($commentend === false || $tokens[$commentend]['code'] !== T_DOC_COMMENT) { $phpcsfile->adderror("Missing {$type} doc comment", $stackptr); return; } } $commentstart = $phpcsfile->findprevious(T_DOC_COMMENT, $commentend - 1, null, true) + 1; $commentnext = $phpcsfile->findprevious(T_WHITESPACE, $commentend + 1, $stackptr, false, $phpcsfile->eolChar); // Distinguish file and class comment. $prevclasstoken = $phpcsfile->findprevious(T_CLASS, $stackptr - 1); if ($prevclasstoken === false) { // This is the first class token in this file, need extra checks. $prevnoncomment = $phpcsfile->findprevious(T_DOC_COMMENT, $commentstart - 1, null, true); if ($prevnoncomment !== false) { $prevcomment = $phpcsfile->findprevious(T_DOC_COMMENT, $prevnoncomment - 1); if ($prevcomment === false) { // There is only 1 doc comment between open tag and class token. $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $commentend + 1, $stackptr, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { $newlinetoken = $phpcsfile->findnext(T_WHITESPACE, $newlinetoken + 1, $stackptr, false, $phpcsfile->eolChar); if ($newlinetoken !== false) { // Blank line between the class and the doc block. // The doc block is most likely a file comment. $phpcsfile->adderror("Missing {$type} doc comment", $stackptr + 1); return; } } } } } $comment = $phpcsfile->gettokensAsString($commentstart, $commentend - $commentstart + 1); // Parse the class comment.docblock. try { $this->commentparser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsfile); $this->commentparser->parse(); } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { $line = $e->getlinewithinComment() + $commentstart; $phpcsfile->adderror($e->getMessage(), $line); return; } $comment = $this->commentparser->getComment(); if (is_null($comment) === true) { $error = ucfirst($type) . ' doc comment is empty'; $phpcsfile->adderror($error, $commentstart); return; } // No extra newline before short description. $short = $comment->getShortComment(); $newlinecount = 0; $newlinespan = strspn($short, $phpcsfile->eolChar); if ($short !== '' && $newlinespan > 0) { $line = $newlinespan > 1 ? 'newlines' : 'newline'; $error = "Extra {$line} found before {$type} comment short description"; $phpcsfile->adderror($error, $commentstart + 1); } $newlinecount = substr_count($short, $phpcsfile->eolChar) + 1; // Exactly one blank line between short and long description. $long = $comment->getlongcomment(); if (empty($long) === false) { $between = $comment->getWhiteSpacebetween(); $newlinebetween = substr_count($between, $phpcsfile->eolChar); if ($newlinebetween !== 2) { $error = "There must be exactly one blank line between descriptions in {$type} comments"; $phpcsfile->adderror($error, $commentstart + $newlinecount + 1); } $newlinecount += $newlinebetween; } // Exactly one blank line before tags. $tags = $this->commentparser->gettagOrders(); if (count($tags) > 1) { $newlinespan = $comment->getNewlineAfter(); if ($newlinespan !== 2) { $error = "There must be exactly one blank line before the tags in {$type} comments"; if ($long !== '') { $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1; } $phpcsfile->addwarning($error, $commentstart + $newlinecount); $short = rtrim($short, $phpcsfile->eolChar . ' '); } } // Check each tag. $this->processtags($commentstart, $commentend); }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); $token = $tokens[$stackptr]; // Skip broken function declarations. if (isset($token['scope_opener']) === false || isset($token['parenthesis_opener']) === false) { return; } $params = array(); foreach ($phpcsfile->getmethodparameters($stackptr) as $param) { $params[$param['name']] = $stackptr; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; $emptybody = true; for (; $next <= $end; ++$next) { $token = $tokens[$next]; $code = $token['code']; // Ingorable tokens. if (in_array($code, PHP_CodeSniffer_tokens::$emptyTokens) === true) { continue; } else { if ($code === T_THROW && $emptybody === true) { // Throw statement and an empty body indicate an interface method. return; } else { if ($code === T_RETURN && $emptybody === true) { // Return statement and an empty body indicate an interface method. $tmp = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $next + 1, null, true); if ($tmp === false) { return; } // There is a return. if ($tokens[$tmp] === T_SEMICOLON) { return; } $tmp = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $tmp + 1, null, true); // There is a return <token>. if ($tmp !== false && $tokens[$tmp] === T_SEMICOLON) { return; } } } } $emptybody = false; if ($code === T_VARIABLE && isset($params[$token['content']]) === true) { unset($params[$token['content']]); } else { if ($code === T_DOUBLE_QUOTED_STRING) { // tokenize double quote string. $strtokens = token_get_all(sprintf('<?php %s;?>', $token['content'])); foreach ($strtokens as $tok) { if (is_array($tok) === false || $tok[0] !== T_VARIABLE) { continue; } if (isset($params[$tok[1]]) === true) { unset($params[$tok[1]]); } } } } } if ($emptybody === false && count($params) > 0) { foreach ($params as $paramname => $position) { $error = 'The method parameter ' . $paramname . ' is never used'; $phpcsfile->addwarning($error, $position); } } }
/** * 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(PHP_CodeSniffer_File $phpcsfile, $stackptr) { $tokens = $phpcsfile->gettokens(); // If this is an inline condition (ie. there is no scope opener), then // return, as this is not a new scope. if (isset($tokens[$stackptr]['scope_opener']) === false) { return; } if ($tokens[$stackptr]['code'] === T_ELSE) { $next = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr + 1, null, true); // We will handle the T_IF token in another call to process. if ($tokens[$next]['code'] === T_IF) { return; } } // Find the first token on this line. $firsttoken = $stackptr; for ($i = $stackptr; $i >= 0; $i--) { // Record the first code token on the line. if (in_array($tokens[$i]['code'], PHP_CodeSniffer_tokens::$emptyTokens) === false) { $firsttoken = $i; } // It's the start of the line, so we've found our first php token. if ($tokens[$i]['column'] === 1) { break; } } // Based on the conditions that surround this token, determine the // indent that we expect this current content to be. $expectedindent = $this->calculateexpectedindent($tokens, $firsttoken); if ($tokens[$firsttoken]['column'] !== $expectedindent) { $error = 'line indented incorrectly; expected '; $error .= $expectedindent - 1 . ' spaces, found '; $error .= $tokens[$firsttoken]['column'] - 1; $phpcsfile->adderror($error, $stackptr); } $scopeopener = $tokens[$stackptr]['scope_opener']; $scopecloser = $tokens[$stackptr]['scope_closer']; // Some scopes are expected not to have indents. if (in_array($tokens[$firsttoken]['code'], $this->nonindentingscopes) === false) { $indent = $expectedindent + $this->indent; } else { $indent = $expectedindent; } $newline = false; $commentopen = false; $inheredoc = false; // Only loop over the content beween the opening and closing brace, not // the braces themselves. for ($i = $scopeopener + 1; $i < $scopecloser; $i++) { // If this token is another scope, skip it as it will be handled by // another call to this sniff. if (in_array($tokens[$i]['code'], PHP_CodeSniffer_tokens::$scopeOpeners) === true) { if (isset($tokens[$i]['scope_opener']) === true) { $i = $tokens[$i]['scope_closer']; } else { // If this token does not have a scope_opener indice, then // it's probably an inline scope, so let's skip to the next // semicolon. Inline scopes include inline if's, abstract methods etc. $nexttoken = $phpcsfile->findnext(T_SEMICOLON, $i, $scopecloser); if ($nexttoken !== false) { $i = $nexttoken; } } continue; } // If this is a HEREDOC then we need to ignore it as the whitespace // before the contents within the HEREDOC are considered part of the content. if ($tokens[$i]['code'] === T_START_HEREDOC) { $inheredoc = true; continue; } else { if ($inheredoc === true) { if ($tokens[$i]['code'] === T_END_HEREDOC) { $inheredoc = false; } continue; } } if ($tokens[$i]['column'] === 1) { // We started a newline. $newline = true; } if ($newline === true && $tokens[$i]['code'] !== T_WHITESPACE) { // If we started a newline and we find a token that is not // whitespace, then this must be the first token on the line that // must be indented. $newline = false; $firsttoken = $i; $column = $tokens[$firsttoken]['column']; // Special case for non-PHP code. if ($tokens[$firsttoken]['code'] === T_INLINE_HTML) { $trimmedcontentlength = strlen(ltrim($tokens[$firsttoken]['content'])); if ($trimmedcontentlength === 0) { continue; } $contentlength = strlen($tokens[$firsttoken]['content']); $column = $contentlength - $trimmedcontentlength + 1; } // Check to see if this constant string spans multiple lines. // If so, then make sure that the strings on lines other than the // first line are indented appropriately, based on their whitespace. if (in_array($tokens[$firsttoken]['code'], PHP_CodeSniffer_tokens::$stringTokens) === true) { if (in_array($tokens[$firsttoken - 1]['code'], PHP_CodeSniffer_tokens::$stringTokens) === true) { // If we find a string that directly follows another string // then its just a string that spans multiple lines, so we // don't need to check for indenting. continue; } } // This is a special condition for T_DOC_COMMENT and C-style // comments, which contain whitespace between each line. if (in_array($tokens[$firsttoken]['code'], array(T_COMMENT, T_DOC_COMMENT)) === true) { $content = trim($tokens[$firsttoken]['content']); if (preg_match('|^/\\*|', $content) !== 0) { // Check to see if the end of the comment is on the same line // as the start of the comment. If it is, then we don't // have to worry about opening a comment. if (preg_match('|\\*/$|', $content) === 0) { // We don't have to calculate the column for the start // of the comment as there is a whitespace token before it. $commentopen = true; } } else { if ($commentopen === true) { if ($content === '') { // We are in a comment, but this line has nothing on it // so let's skip it. continue; } $contentlength = strlen($tokens[$firsttoken]['content']); $trimmedcontentlength = strlen(ltrim($tokens[$firsttoken]['content'])); $column = $contentlength - $trimmedcontentlength + 1; if (preg_match('|\\*/$|', $content) !== 0) { $commentopen = false; } } } } // The token at the start of the line, needs to have its' column // greater than the relative indent we set above. If it is less, // an error should be shown. if ($column !== $indent) { if ($this->exact === true || $column < $indent) { $error = 'line indented incorrectly; expected '; if ($this->exact === false) { $error .= 'at least '; } $error .= $indent - 1 . ' spaces, found '; $error .= $column - 1; $phpcsfile->adderror($error, $firsttoken); } } } } }