/**
  * 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();
     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;
     }
 }
Example #3
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(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();
     // 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 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 class member variables.
  *
  * @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
  */
 protected function processmembervar(PHP_CodeSniffer_File $phpcsfile, $stackptr)
 {
     $tokens = $phpcsfile->gettokens();
     $membername = ltrim($tokens[$stackptr]['content'], '$');
     if (preg_match('/[A-Z]+/', $membername)) {
         $error = "Member variable \"{$membername}\" must be all lower-case";
         $phpcsfile->adderror($error, $stackptr);
         return;
     }
     // Must not be preceded by 'var' keyword
     $keyword = $phpcsfile->findprevious(T_VAR, $stackptr);
     if ($tokens[$keyword]['line'] == $tokens[$stackptr]['line']) {
         $error = "The 'var' keyword is not permitted." . 'Visibility must be explicitly declared with public, private or protected';
         $phpcsfile->adderror($error, $stackptr);
         return;
     }
 }
 /**
  * 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);
         }
     }
 }
Example #9
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(PHP_CodeSniffer_File $phpcsfile, $stackptr)
 {
     // We are only interested if this is the first open tag.
     if ($stackptr !== 0) {
         if ($phpcsfile->findprevious(T_OPEN_TAG, $stackptr - 1) !== false) {
             return;
         }
     }
     if ($phpcsfile->eolChar !== $this->eolChar) {
         $expected = $this->eolChar;
         $expected = str_replace("\n", '\\n', $expected);
         $expected = str_replace("\r", '\\r', $expected);
         $found = $phpcsfile->eolChar;
         $found = str_replace("\n", '\\n', $found);
         $found = str_replace("\r", '\\r', $found);
         $error = "end of line character is invalid; expected \"{$expected}\" but found \"{$found}\"";
         $phpcsfile->adderror($error, $stackptr);
     }
 }
Example #10
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(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 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);
     }
 }
Example #13
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(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);
                }
            }
        }
    }
Example #14
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(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();
     // Skip tokens that are the names of functions or classes
     // within their definitions. For example:
     // function myFunction...
     // "myFunction" is T_STRING but we should skip because it is not a
     // function or method *call*.
     $functionname = $stackptr;
     $functionkeyword = $phpcsfile->findprevious(PHP_CodeSniffer_tokens::$emptyTokens, $stackptr - 1, null, true);
     if ($tokens[$functionkeyword]['code'] === T_FUNCTION || $tokens[$functionkeyword]['code'] === T_CLASS) {
         return;
     }
     // If the next non-whitespace token after the function or method call
     // is not an opening parenthesis then it cant really be a *call*.
     $openbracket = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $functionname + 1, null, true);
     if ($tokens[$openbracket]['code'] !== T_OPEN_PARENTHESIS) {
         return;
     }
     $closebracket = $tokens[$openbracket]['parenthesis_closer'];
     $nextseparator = $openbracket;
     while (($nextseparator = $phpcsfile->findnext(array(T_COMMA, T_VARIABLE), $nextseparator + 1, $closebracket)) !== false) {
         // Make sure the comma or variable belongs directly to this function call,
         // and is not inside a nested function call or array.
         $brackets = $tokens[$nextseparator]['nested_parenthesis'];
         $lastbracket = array_pop($brackets);
         if ($lastbracket !== $closebracket) {
             continue;
         }
         if ($tokens[$nextseparator]['code'] === T_COMMA) {
             if ($tokens[$nextseparator - 1]['code'] === T_WHITESPACE) {
                 $error = 'Space found before comma in function call';
                 $phpcsfile->addwarning($error, $stackptr);
             }
             if ($tokens[$nextseparator + 1]['code'] !== T_WHITESPACE) {
                 $error = 'No space found after comma in function call';
                 $phpcsfile->addwarning($error, $stackptr);
             } else {
                 // If there is a newline in the space, then the must be formatting
                 // each argument on a newline, which is valid, so ignore it.
                 if (strpos($tokens[$nextseparator + 1]['content'], $phpcsfile->eolChar) === false) {
                     $space = strlen($tokens[$nextseparator + 1]['content']);
                     if ($space > 1) {
                         $error = 'Expected 1 space after comma in function call; ';
                         $error .= $space . ' found';
                         $phpcsfile->addwarning($error, $stackptr);
                     }
                 }
             }
         } else {
             // token is a variable.
             $nexttoken = $phpcsfile->findnext(PHP_CodeSniffer_tokens::$emptyTokens, $nextseparator + 1, $closebracket, true);
             if ($nexttoken !== false) {
                 if ($tokens[$nexttoken]['code'] === T_EQUAL) {
                     if ($tokens[$nexttoken - 1]['code'] !== T_WHITESPACE) {
                         $error = 'Expected 1 space before = sign of default value';
                         $phpcsfile->addwarning($error, $stackptr);
                     }
                     if ($tokens[$nexttoken + 1]['code'] !== T_WHITESPACE) {
                         $error = 'Expected 1 space after = sign of default value';
                         $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();
     $constname = $tokens[$stackptr]['content'];
     // If this token is in a heredoc, ignore it.
     if ($phpcsfile->hasCondition($stackptr, T_START_HEREDOC) === true) {
         return;
     }
     // If the next non-whitespace token after this token
     // is not an opening parenthesis then it is not a function call.
     $openbracket = $phpcsfile->findnext(array(T_WHITESPACE), $stackptr + 1, null, true);
     if ($tokens[$openbracket]['code'] !== T_OPEN_PARENTHESIS) {
         $functionkeyword = $phpcsfile->findprevious(array(T_WHITESPACE, T_COMMA, T_COMMENT, T_STRING), $stackptr - 1, null, true);
         $declarations = array(T_FUNCTION, T_CLASS, T_INTERFACE, T_IMPLEMENTS, T_EXTENDS, T_INSTANCEOF, T_NEW);
         if (in_array($tokens[$functionkeyword]['code'], $declarations) === true) {
             // This is just a declaration; no constants here.
             return;
         }
         if ($tokens[$functionkeyword]['code'] === T_CONST) {
             // This is a class constant.
             if (strtoupper($constname) !== $constname) {
                 $error = 'Class constants must be uppercase; expected ' . strtoupper($constname) . " but found {$constname}";
                 $phpcsfile->adderror($error, $stackptr);
             }
             return;
         }
         // Is this a class name?
         $nextptr = $phpcsfile->findnext(array(T_WHITESPACE), $stackptr + 1, null, true);
         if ($tokens[$nextptr]['code'] === T_DOUBLE_COLON) {
             return;
         }
         // Is this a type hint?
         if ($tokens[$nextptr]['code'] === T_VARIABLE) {
             return;
         } else {
             if ($phpcsfile->isReference($nextptr) === true) {
                 return;
             }
         }
         // Is this a member var name?
         $prevptr = $phpcsfile->findprevious(array(T_WHITESPACE), $stackptr - 1, null, true);
         if ($tokens[$prevptr]['code'] === T_OBJECT_OPERATOR) {
             return;
         }
         // Is this an instance of declare()
         $prevptr = $phpcsfile->findprevious(array(T_WHITESPACE, T_OPEN_PARENTHESIS), $stackptr - 1, null, true);
         if ($tokens[$prevptr]['code'] === T_DECLARE) {
             return;
         }
         // This is a real constant.
         if (strtoupper($constname) !== $constname) {
             $error = 'Constants must be uppercase; expected ' . strtoupper($constname) . " but found {$constname}";
             $phpcsfile->adderror($error, $stackptr);
         }
     } else {
         if (strtolower($constname) === 'define' || strtolower($constname) === 'constant') {
             /*
                 This may be a "define" or "constant" function call.
             */
             // The next non-whitespace token must be the constant name.
             $constptr = $phpcsfile->findnext(array(T_WHITESPACE), $openbracket + 1, null, true);
             if ($tokens[$constptr]['code'] !== T_CONSTANT_ENCAPSED_STRING) {
                 return;
             }
             $constname = $tokens[$constptr]['content'];
             if (strtoupper($constname) !== $constname) {
                 $error = 'Constants must be uppercase; expected ' . strtoupper($constname) . " but found {$constname}";
                 $phpcsfile->adderror($error, $stackptr);
             }
         }
     }
 }
Example #17
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(PHP_CodeSniffer_File $phpcsfile, $stackptr)
 {
     $find = array(T_COMMENT, T_DOC_COMMENT, T_CLASS, T_FUNCTION, T_OPEN_TAG);
     $commentend = $phpcsfile->findprevious($find, $stackptr - 1);
     if ($commentend === false) {
         return;
     }
     $this->currentfile = $phpcsfile;
     $tokens = $phpcsfile->gettokens();
     // If the token that we found was a class or a function, then this
     // function has no doc comment.
     $code = $tokens[$commentend]['code'];
     if ($code === T_COMMENT) {
         $error = 'You must use "/**" style comments for a function comment';
         $phpcsfile->adderror($error, $stackptr);
         return;
     } else {
         if ($code !== T_DOC_COMMENT) {
             $phpcsfile->adderror('Missing function doc comment', $stackptr);
             return;
         }
     }
     // If there is any code between the function keyword and the doc block
     // then the doc block is not for us.
     $ignore = PHP_CodeSniffer_tokens::$scopeModifiers;
     $ignore[] = T_STATIC;
     $ignore[] = T_WHITESPACE;
     $ignore[] = T_ABSTRACT;
     $ignore[] = T_FINAL;
     $prevtoken = $phpcsfile->findprevious($ignore, $stackptr - 1, null, true);
     if ($prevtoken !== $commentend) {
         $phpcsfile->adderror('Missing function doc comment', $stackptr);
         return;
     }
     $this->_functiontoken = $stackptr;
     foreach ($tokens[$stackptr]['conditions'] as $condptr => $condition) {
         if ($condition === T_CLASS || $condition === T_INTERFACE) {
             $this->_classtoken = $condptr;
             break;
         }
     }
     // If the first T_OPEN_TAG is right before the comment, it is probably
     // a file comment.
     $commentstart = $phpcsfile->findprevious(T_DOC_COMMENT, $commentend - 1, null, true) + 1;
     $prevtoken = $phpcsfile->findprevious(T_WHITESPACE, $commentstart - 1, null, true);
     if ($tokens[$prevtoken]['code'] === T_OPEN_TAG) {
         // Is this the first open tag?
         if ($stackptr === 0 || $phpcsfile->findprevious(T_OPEN_TAG, $prevtoken - 1) === false) {
             $phpcsfile->adderror('Missing function doc comment', $stackptr);
             return;
         }
     }
     $comment = $phpcsfile->gettokensAsString($commentstart, $commentend - $commentstart + 1);
     $this->_methodname = $phpcsfile->getDeclarationname($stackptr);
     try {
         $this->commentparser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($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 = 'Function doc comment is empty';
         $phpcsfile->adderror($error, $commentstart);
         return;
     }
     $this->processparams($commentstart);
     $this->processreturn($commentstart, $commentend);
     $this->processthrows($commentstart);
     // 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 function 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 function comment';
             $phpcsfile->adderror($error, $commentstart + $newlinecount + 1);
         }
         $newlinecount += $newlinebetween;
     }
     // Exactly one blank line before tags.
     $params = $this->commentparser->gettagOrders();
     if (count($params) > 1) {
         $newlinespan = $comment->getNewlineAfter();
         if ($newlinespan !== 2) {
             $error = 'There must be exactly one blank line before the tags in function comment';
             if ($long !== '') {
                 $newlinecount += substr_count($long, $phpcsfile->eolChar) - $newlinespan + 1;
             }
             $phpcsfile->addwarning($error, $commentstart + $newlinecount);
             $short = rtrim($short, $phpcsfile->eolChar . ' ');
         }
     }
 }