1501 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1501 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * This file is part of the VariableAnalysis addon for PHP_CodeSniffer.
 | 
						|
 *
 | 
						|
 * PHP version 5
 | 
						|
 *
 | 
						|
 * @category  PHP
 | 
						|
 * @package   PHP_CodeSniffer
 | 
						|
 * @author    Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @copyright 2011-2012 Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
 | 
						|
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Holds details of a scope.
 | 
						|
 *
 | 
						|
 * @category  PHP
 | 
						|
 * @package   PHP_CodeSniffer
 | 
						|
 * @author    Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @copyright 2011-2012 Sam Graham <php-codesniffer-plugins BLAHBLAH illusori.co.uk>
 | 
						|
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 | 
						|
 */
 | 
						|
class ScopeInfo {
 | 
						|
    public $owner;
 | 
						|
    public $opener;
 | 
						|
    public $closer;
 | 
						|
    public $variables = array();
 | 
						|
 | 
						|
    function __construct($currScope) {
 | 
						|
        $this->owner = $currScope;
 | 
						|
        // TODO: extract opener/closer
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Holds details of a variable within a scope.
 | 
						|
 *
 | 
						|
 * @category  PHP
 | 
						|
 * @package   PHP_CodeSniffer
 | 
						|
 * @author    Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @copyright 2011 Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 | 
						|
 */
 | 
						|
class VariableInfo {
 | 
						|
    public $name;
 | 
						|
    /**
 | 
						|
     * What scope the variable has: local, param, static, global, bound
 | 
						|
     */
 | 
						|
    public $scopeType;
 | 
						|
    public $typeHint;
 | 
						|
    public $passByReference = false;
 | 
						|
    public $firstDeclared;
 | 
						|
    public $firstInitialized;
 | 
						|
    public $firstRead;
 | 
						|
    public $ignoreUnused = false;
 | 
						|
    static $scopeTypeDescriptions = array(
 | 
						|
        'local'  => 'variable',
 | 
						|
        'param'  => 'function parameter',
 | 
						|
        'static' => 'static variable',
 | 
						|
        'global' => 'global variable',
 | 
						|
        'bound'  => 'bound variable',
 | 
						|
        );
 | 
						|
 | 
						|
    function __construct($varName) {
 | 
						|
        $this->name = $varName;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks the for undefined function variables.
 | 
						|
 *
 | 
						|
 * This sniff checks that all function variables
 | 
						|
 * are defined in the function body.
 | 
						|
 *
 | 
						|
 * @category  PHP
 | 
						|
 * @package   PHP_CodeSniffer
 | 
						|
 * @author    Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @copyright 2011 Sam Graham <php-codesniffer-variableanalysis BLAHBLAH illusori.co.uk>
 | 
						|
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 | 
						|
 */
 | 
						|
class TTCodeStandard_Sniffs_CodeAnalysis_VariableAnalysisSniff implements PHP_CodeSniffer_Sniff
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * The current phpcsFile being checked.
 | 
						|
     *
 | 
						|
     * @var phpcsFile
 | 
						|
     */
 | 
						|
    protected $currentFile = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * A list of scopes encountered so far and the variables within them.
 | 
						|
     */
 | 
						|
    private $_scopes = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * A regexp for matching variable names in double-quoted strings.
 | 
						|
     */
 | 
						|
    private $_double_quoted_variable_regexp = '|(?<!\\\\)(?:\\\\{2})*\${?([a-zA-Z0-9_]+)}?|';
 | 
						|
 | 
						|
    /**
 | 
						|
     *  Array of known pass-by-reference functions and the argument(s) which are passed
 | 
						|
     *  by reference, the arguments are numbered starting from 1 and an elipsis '...'
 | 
						|
     *  means all argument numbers after the previous should be considered pass-by-reference.
 | 
						|
     */
 | 
						|
    private $_passByRefFunctions = array(
 | 
						|
        '__soapCall' => array(5),
 | 
						|
        'addFunction' => array(3),
 | 
						|
        'addTask' => array(3),
 | 
						|
        'addTaskBackground' => array(3),
 | 
						|
        'addTaskHigh' => array(3),
 | 
						|
        'addTaskHighBackground' => array(3),
 | 
						|
        'addTaskLow' => array(3),
 | 
						|
        'addTaskLowBackground' => array(3),
 | 
						|
        'addTaskStatus' => array(2),
 | 
						|
        'apc_dec' => array(3),
 | 
						|
        'apc_fetch' => array(2),
 | 
						|
        'apc_inc' => array(3),
 | 
						|
        'areConfusable' => array(3),
 | 
						|
        'array_multisort' => array(1),
 | 
						|
        'array_pop' => array(1),
 | 
						|
        'array_push' => array(1),
 | 
						|
        'array_replace' => array(1),
 | 
						|
        'array_replace_recursive' => array(1, 2, 3, '...'),
 | 
						|
        'array_shift' => array(1),
 | 
						|
        'array_splice' => array(1),
 | 
						|
        'array_unshift' => array(1),
 | 
						|
        'array_walk' => array(1),
 | 
						|
        'array_walk_recursive' => array(1),
 | 
						|
        'arsort' => array(1),
 | 
						|
        'asort' => array(1),
 | 
						|
        'asort' => array(1),
 | 
						|
        'bindColumn' => array(2),
 | 
						|
        'bindParam' => array(2),
 | 
						|
        'bind_param' => array(2, 3, '...'),
 | 
						|
        'bind_result' => array(1, 2, '...'),
 | 
						|
        'call_user_method' => array(2),
 | 
						|
        'call_user_method_array' => array(2),
 | 
						|
        'curl_multi_exec' => array(2),
 | 
						|
        'curl_multi_info_read' => array(2),
 | 
						|
        'current' => array(1),
 | 
						|
        'dbplus_curr' => array(2),
 | 
						|
        'dbplus_first' => array(2),
 | 
						|
        'dbplus_info' => array(3),
 | 
						|
        'dbplus_last' => array(2),
 | 
						|
        'dbplus_next' => array(2),
 | 
						|
        'dbplus_prev' => array(2),
 | 
						|
        'dbplus_tremove' => array(3),
 | 
						|
        'dns_get_record' => array(3, 4),
 | 
						|
        'domxml_open_file' => array(3),
 | 
						|
        'domxml_open_mem' => array(3),
 | 
						|
        'each' => array(1),
 | 
						|
        'enchant_dict_quick_check' => array(3),
 | 
						|
        'end' => array(1),
 | 
						|
        'ereg' => array(3),
 | 
						|
        'eregi' => array(3),
 | 
						|
        'exec' => array(2, 3),
 | 
						|
        'exif_thumbnail' => array(1, 2, 3),
 | 
						|
        'expect_expectl' => array(3),
 | 
						|
        'extract' => array(1),
 | 
						|
        'filter' => array(3),
 | 
						|
        'flock' => array(2,3),
 | 
						|
        'fscanf' => array(2, 3, '...'),
 | 
						|
        'fsockopen' => array(3, 4),
 | 
						|
        'ftp_alloc' => array(3),
 | 
						|
        'get' => array(2, 3),
 | 
						|
        'getByKey' => array(4),
 | 
						|
        'getMulti' => array(2),
 | 
						|
        'getMultiByKey' => array(3),
 | 
						|
        'getimagesize' => array(2),
 | 
						|
        'getmxrr' => array(2, 3),
 | 
						|
        'gnupg_decryptverify' => array(3),
 | 
						|
        'gnupg_verify' => array(4),
 | 
						|
        'grapheme_extract' => array(5),
 | 
						|
        'headers_sent' => array(1, 2),
 | 
						|
        'http_build_url' => array(4),
 | 
						|
        'http_get' => array(3),
 | 
						|
        'http_head' => array(3),
 | 
						|
        'http_negotiate_charset' => array(2),
 | 
						|
        'http_negotiate_content_type' => array(2),
 | 
						|
        'http_negotiate_language' => array(2),
 | 
						|
        'http_post_data' => array(4),
 | 
						|
        'http_post_fields' => array(5),
 | 
						|
        'http_put_data' => array(4),
 | 
						|
        'http_put_file' => array(4),
 | 
						|
        'http_put_stream' => array(4),
 | 
						|
        'http_request' => array(5),
 | 
						|
        'isSuspicious' => array(2),
 | 
						|
        'is_callable' => array(3),
 | 
						|
        'key' => array(1),
 | 
						|
        'krsort' => array(1),
 | 
						|
        'ksort' => array(1),
 | 
						|
        'ldap_get_option' => array(3),
 | 
						|
        'ldap_parse_reference' => array(3),
 | 
						|
        'ldap_parse_result' => array(3, 4, 5, 6),
 | 
						|
        'localtime' => array(2),
 | 
						|
        'm_completeauthorizations' => array(2),
 | 
						|
        'maxdb_stmt_bind_param' => array(3, 4, '...'),
 | 
						|
        'maxdb_stmt_bind_result' => array(2, 3, '...'),
 | 
						|
        'mb_convert_variables' => array(3, 4, '...'),
 | 
						|
        'mb_parse_str' => array(2),
 | 
						|
        'mqseries_back' => array(2, 3),
 | 
						|
        'mqseries_begin' => array(3, 4),
 | 
						|
        'mqseries_close' => array(4, 5),
 | 
						|
        'mqseries_cmit' => array(2, 3),
 | 
						|
        'mqseries_conn' => array(2, 3, 4),
 | 
						|
        'mqseries_connx' => array(2, 3, 4, 5),
 | 
						|
        'mqseries_disc' => array(2, 3),
 | 
						|
        'mqseries_get' => array(3, 4, 5, 6, 7, 8, 9),
 | 
						|
        'mqseries_inq' => array(6, 8, 9, 10),
 | 
						|
        'mqseries_open' => array(2, 4, 5, 6),
 | 
						|
        'mqseries_put' => array(3, 4, 6, 7),
 | 
						|
        'mqseries_put1' => array(2, 3, 4, 6, 7),
 | 
						|
        'mqseries_set' => array(9, 10),
 | 
						|
        'msg_receive' => array(3, 5, 8),
 | 
						|
        'msg_send' => array(6),
 | 
						|
        'mssql_bind' => array(3),
 | 
						|
        'natcasesort' => array(1),
 | 
						|
        'natsort' => array(1),
 | 
						|
        'ncurses_color_content' => array(2, 3, 4),
 | 
						|
        'ncurses_getmaxyx' => array(2, 3),
 | 
						|
        'ncurses_getmouse' => array(1),
 | 
						|
        'ncurses_getyx' => array(2, 3),
 | 
						|
        'ncurses_instr' => array(1),
 | 
						|
        'ncurses_mouse_trafo' => array(1, 2),
 | 
						|
        'ncurses_mousemask' => array(2),
 | 
						|
        'ncurses_pair_content' => array(2, 3),
 | 
						|
        'ncurses_wmouse_trafo' => array(2, 3),
 | 
						|
        'newt_button_bar' => array(1),
 | 
						|
        'newt_form_run' => array(2),
 | 
						|
        'newt_get_screen_size' => array(1, 2),
 | 
						|
        'newt_grid_get_size' => array(2, 3),
 | 
						|
        'newt_reflow_text' => array(5, 6),
 | 
						|
        'newt_win_entries' => array(7),
 | 
						|
        'newt_win_menu' => array(8),
 | 
						|
        'next' => array(1),
 | 
						|
        'oci_bind_array_by_name' => array(3),
 | 
						|
        'oci_bind_by_name' => array(3),
 | 
						|
        'oci_define_by_name' => array(3),
 | 
						|
        'oci_fetch_all' => array(2),
 | 
						|
        'ocifetchinto' => array(2),
 | 
						|
        'odbc_fetch_into' => array(2),
 | 
						|
        'openssl_csr_export' => array(2),
 | 
						|
        'openssl_csr_new' => array(2),
 | 
						|
        'openssl_open' => array(2),
 | 
						|
        'openssl_pkcs12_export' => array(2),
 | 
						|
        'openssl_pkcs12_read' => array(2),
 | 
						|
        'openssl_pkey_export' => array(2),
 | 
						|
        'openssl_private_decrypt' => array(2),
 | 
						|
        'openssl_private_encrypt' => array(2),
 | 
						|
        'openssl_public_decrypt' => array(2),
 | 
						|
        'openssl_public_encrypt' => array(2),
 | 
						|
        'openssl_random_pseudo_bytes' => array(2),
 | 
						|
        'openssl_seal' => array(2, 3),
 | 
						|
        'openssl_sign' => array(2),
 | 
						|
        'openssl_x509_export' => array(2),
 | 
						|
        'ovrimos_fetch_into' => array(2),
 | 
						|
        'parse' => array(2,3),
 | 
						|
        'parseCurrency' => array(2, 3),
 | 
						|
        'parse_str' => array(2),
 | 
						|
        'parsekit_compile_file' => array(2),
 | 
						|
        'parsekit_compile_string' => array(2),
 | 
						|
        'passthru' => array(2),
 | 
						|
        'pcntl_sigprocmask' => array(3),
 | 
						|
        'pcntl_sigtimedwait' => array(2),
 | 
						|
        'pcntl_sigwaitinfo' => array(2),
 | 
						|
        'pcntl_wait' => array(1),
 | 
						|
        'pcntl_waitpid' => array(2),
 | 
						|
        'pfsockopen' => array(3, 4),
 | 
						|
        'php_check_syntax' => array(2),
 | 
						|
        'poll' => array(1, 2, 3),
 | 
						|
        'preg_filter' => array(5),
 | 
						|
        'preg_match' => array(3),
 | 
						|
        'preg_match_all' => array(3),
 | 
						|
        'preg_replace' => array(5),
 | 
						|
        'preg_replace_callback' => array(5),
 | 
						|
        'prev' => array(1),
 | 
						|
        'proc_open' => array(3),
 | 
						|
        'query' => array(3),
 | 
						|
        'queryExec' => array(2),
 | 
						|
        'reset' => array(1),
 | 
						|
        'rsort' => array(1),
 | 
						|
        'settype' => array(1),
 | 
						|
        'shuffle' => array(1),
 | 
						|
        'similar_text' => array(3),
 | 
						|
        'socket_create_pair' => array(4),
 | 
						|
        'socket_getpeername' => array(2, 3),
 | 
						|
        'socket_getsockname' => array(2, 3),
 | 
						|
        'socket_recv' => array(2),
 | 
						|
        'socket_recvfrom' => array(2, 5, 6),
 | 
						|
        'socket_select' => array(1, 2, 3),
 | 
						|
        'sort' => array(1),
 | 
						|
        'sortWithSortKeys' => array(1),
 | 
						|
        'sqlite_exec' => array(3),
 | 
						|
        'sqlite_factory' => array(3),
 | 
						|
        'sqlite_open' => array(3),
 | 
						|
        'sqlite_popen' => array(3),
 | 
						|
        'sqlite_query' => array(4),
 | 
						|
        'sqlite_query' => array(4),
 | 
						|
        'sqlite_unbuffered_query' => array(4),
 | 
						|
        'sscanf' => array(3, '...'),
 | 
						|
        'str_ireplace' => array(4),
 | 
						|
        'str_replace' => array(4),
 | 
						|
        'stream_open' => array(4),
 | 
						|
        'stream_select' => array(1, 2, 3),
 | 
						|
        'stream_socket_accept' => array(3),
 | 
						|
        'stream_socket_client' => array(2, 3),
 | 
						|
        'stream_socket_recvfrom' => array(4),
 | 
						|
        'stream_socket_server' => array(2, 3),
 | 
						|
        'system' => array(2),
 | 
						|
        'uasort' => array(1),
 | 
						|
        'uksort' => array(1),
 | 
						|
        'unbufferedQuery' => array(3),
 | 
						|
        'usort' => array(1),
 | 
						|
        'wincache_ucache_dec' => array(3),
 | 
						|
        'wincache_ucache_get' => array(2),
 | 
						|
        'wincache_ucache_inc' => array(3),
 | 
						|
        'xdiff_string_merge3' => array(4),
 | 
						|
        'xdiff_string_patch' => array(4),
 | 
						|
        'xml_parse_into_struct' => array(3, 4),
 | 
						|
        'xml_set_object' => array(2),
 | 
						|
        'xmlrpc_decode_request' => array(2),
 | 
						|
        'xmlrpc_set_type' => array(1),
 | 
						|
        'xslt_set_object' => array(2),
 | 
						|
        'yaml_parse' => array(3),
 | 
						|
        'yaml_parse_file' => array(3),
 | 
						|
        'yaml_parse_url' => array(3),
 | 
						|
        'yaz_ccl_parse' => array(3),
 | 
						|
        'yaz_hits' => array(2),
 | 
						|
        'yaz_scan_result' => array(2),
 | 
						|
        'yaz_wait' => array(1),
 | 
						|
        );
 | 
						|
 | 
						|
    /**
 | 
						|
     *  Allows an install to extend the list of known pass-by-reference functions
 | 
						|
     *  by defining generic.codeanalysis.variableanalysis.sitePassByRefFunctions.
 | 
						|
     */
 | 
						|
    public $sitePassByRefFunctions = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     *  Allows exceptions in a catch block to be unused without provoking unused-var warning.
 | 
						|
     *  Set generic.codeanalysis.variableanalysis.allowUnusedCaughtExceptions to a true value.
 | 
						|
     */
 | 
						|
    public $allowUnusedCaughtExceptions = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     *  Allow function parameters to be unused without provoking unused-var warning.
 | 
						|
     *  Set generic.codeanalysis.variableanalysis.allowUnusedFunctionParameters to a true value.
 | 
						|
     */
 | 
						|
    public $allowUnusedFunctionParameters = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     *  A list of names of placeholder variables that you want to ignore from
 | 
						|
     *  unused variable warnings, ie things like $junk.
 | 
						|
     */
 | 
						|
    public $validUnusedVariableNames = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns an array of tokens this test wants to listen for.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function register() {
 | 
						|
        //  Magic to modfy $_passByRefFunctions with any site-specific settings.
 | 
						|
        if (!empty($this->sitePassByRefFunctions)) {
 | 
						|
            foreach (preg_split('/\s+/', trim($this->sitePassByRefFunctions)) as $line) {
 | 
						|
                list ($function, $args) = explode(':', $line);
 | 
						|
                $this->_passByRefFunctions[$function] = explode(',', $args);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!empty($this->validUnusedVariableNames)) {
 | 
						|
            $this->validUnusedVariableNames =
 | 
						|
                preg_split('/\s+/', trim($this->validUnusedVariableNames));
 | 
						|
        }
 | 
						|
        return array(
 | 
						|
            T_VARIABLE,
 | 
						|
            T_DOUBLE_QUOTED_STRING,
 | 
						|
            T_HEREDOC,
 | 
						|
            T_CLOSE_CURLY_BRACKET,
 | 
						|
            T_STRING,
 | 
						|
            );
 | 
						|
    }//end register()
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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];
 | 
						|
 | 
						|
        //if ($token['content'] == '$param') {
 | 
						|
        //echo "Found token on line {$token['line']}.\n" . print_r($token, true);
 | 
						|
        //}
 | 
						|
 | 
						|
        if ($this->currentFile !== $phpcsFile) {
 | 
						|
            $this->currentFile = $phpcsFile;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($token['code'] === T_VARIABLE) {
 | 
						|
            return $this->processVariable($phpcsFile, $stackPtr);
 | 
						|
        }
 | 
						|
        if (($token['code'] === T_DOUBLE_QUOTED_STRING) ||
 | 
						|
            ($token['code'] === T_HEREDOC)) {
 | 
						|
            return $this->processVariableInString($phpcsFile, $stackPtr);
 | 
						|
        }
 | 
						|
        if (($token['code'] === T_STRING) && ($token['content'] === 'compact')) {
 | 
						|
            return $this->processCompact($phpcsFile, $stackPtr);
 | 
						|
        }
 | 
						|
        if (($token['code'] === T_CLOSE_CURLY_BRACKET) &&
 | 
						|
            isset($token['scope_condition'])) {
 | 
						|
            return $this->processScopeClose($phpcsFile, $token['scope_condition']);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    function normalizeVarName($varName) {
 | 
						|
        $varName = preg_replace('/[{}$]/', '', $varName);
 | 
						|
        return $varName;
 | 
						|
    }
 | 
						|
 | 
						|
    function scopeKey($currScope) {
 | 
						|
        if ($currScope === false) {
 | 
						|
            $currScope = 'file';
 | 
						|
        }
 | 
						|
        return ($this->currentFile ? $this->currentFile->getFilename() : 'unknown file') .
 | 
						|
            ':' . $currScope;
 | 
						|
    }
 | 
						|
 | 
						|
    //  Warning: this is an autovivifying get
 | 
						|
    function getScopeInfo($currScope, $autoCreate = true) {
 | 
						|
        $scopeKey = $this->scopeKey($currScope);
 | 
						|
        if (!isset($this->_scopes[$scopeKey])) {
 | 
						|
            if (!$autoCreate) {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
            $this->_scopes[$scopeKey] = new ScopeInfo($currScope);
 | 
						|
        }
 | 
						|
        return $this->_scopes[$scopeKey];
 | 
						|
    }
 | 
						|
 | 
						|
    function getVariableInfo($varName, $currScope, $autoCreate = true) {
 | 
						|
        $scopeInfo = $this->getScopeInfo($currScope, $autoCreate);
 | 
						|
        if (!isset($scopeInfo->variables[$varName])) {
 | 
						|
            if (!$autoCreate) {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
            $scopeInfo->variables[$varName] = new VariableInfo($varName);
 | 
						|
            if ($this->validUnusedVariableNames &&
 | 
						|
                in_array($varName, $this->validUnusedVariableNames)) {
 | 
						|
                $scopeInfo->variables[$varName]->ignoreUnused = true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $scopeInfo->variables[$varName];
 | 
						|
    }
 | 
						|
 | 
						|
    function markVariableAssignment($varName, $stackPtr, $currScope) {
 | 
						|
        $varInfo = $this->getVariableInfo($varName, $currScope);
 | 
						|
        if (!isset($varInfo->scopeType)) {
 | 
						|
            $varInfo->scopeType = 'local';
 | 
						|
        }
 | 
						|
        if (isset($varInfo->firstInitialized) && ($varInfo->firstInitialized <= $stackPtr)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        $varInfo->firstInitialized = $stackPtr;
 | 
						|
    }
 | 
						|
 | 
						|
    function markVariableDeclaration($varName, $scopeType, $typeHint, $stackPtr, $currScope, $permitMatchingRedeclaration = false) {
 | 
						|
        $varInfo = $this->getVariableInfo($varName, $currScope);
 | 
						|
        if (isset($varInfo->scopeType)) {
 | 
						|
            if (($permitMatchingRedeclaration === false) ||
 | 
						|
                ($varInfo->scopeType !== $scopeType)) {
 | 
						|
                //  Issue redeclaration/reuse warning
 | 
						|
                //  Note: we check off scopeType not firstDeclared, this is so that
 | 
						|
                //    we catch declarations that come after implicit declarations like
 | 
						|
                //    use of a variable as a local.
 | 
						|
                $this->currentFile->addWarning(
 | 
						|
                    "Redeclaration of %s %s as %s.",
 | 
						|
                    $stackPtr,
 | 
						|
                    'VariableRedeclaration',
 | 
						|
                    array(
 | 
						|
                        VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
 | 
						|
                        "\${$varName}",
 | 
						|
                        VariableInfo::$scopeTypeDescriptions[$scopeType],
 | 
						|
                        )
 | 
						|
                    );
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $varInfo->scopeType = $scopeType;
 | 
						|
        if (isset($typeHint)) {
 | 
						|
            $varInfo->typeHint = $typeHint;
 | 
						|
        }
 | 
						|
        if (isset($varInfo->firstDeclared) && ($varInfo->firstDeclared <= $stackPtr)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        $varInfo->firstDeclared = $stackPtr;
 | 
						|
    }
 | 
						|
 | 
						|
    function markVariableRead($varName, $stackPtr, $currScope) {
 | 
						|
        $varInfo = $this->getVariableInfo($varName, $currScope);
 | 
						|
        if (isset($varInfo->firstRead) && ($varInfo->firstRead <= $stackPtr)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        $varInfo->firstRead = $stackPtr;
 | 
						|
    }
 | 
						|
 | 
						|
    function isVariableInitialized($varName, $stackPtr, $currScope) {
 | 
						|
        $varInfo = $this->getVariableInfo($varName, $currScope);
 | 
						|
        if (isset($varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function isVariableUndefined($varName, $stackPtr, $currScope) {
 | 
						|
        $varInfo = $this->getVariableInfo($varName, $currScope, false);
 | 
						|
        if ( $varInfo->ignoreUnused ) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        if (isset($varInfo->firstDeclared) && $varInfo->firstDeclared <= $stackPtr) {
 | 
						|
            // TODO: do we want to check scopeType here?
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        if (isset($varInfo->firstInitialized) && $varInfo->firstInitialized <= $stackPtr) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    function markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope) {
 | 
						|
        $this->markVariableRead($varName, $stackPtr, $currScope);
 | 
						|
 | 
						|
        if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
 | 
						|
            // We haven't been defined by this point.
 | 
						|
            $phpcsFile->addWarning("Variable %s is undefined.", $stackPtr,
 | 
						|
                'UndefinedVariable',
 | 
						|
                array("\${$varName}"));
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    function findFunctionPrototype(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        // Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
 | 
						|
        // so we look backwards from the opening bracket for the first thing that
 | 
						|
        // isn't a function name, reference sigil or whitespace and check if
 | 
						|
        // it's a function keyword.
 | 
						|
        $functionPtr = $phpcsFile->findPrevious(array(T_STRING, T_WHITESPACE, T_BITWISE_AND),
 | 
						|
            $openPtr - 1, null, true, null, true);
 | 
						|
        if (($functionPtr !== false) &&
 | 
						|
            ($tokens[$functionPtr]['code'] === T_FUNCTION)) {
 | 
						|
            return $functionPtr;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function findVariableScope(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        $in_class = false;
 | 
						|
        if (!empty($token['conditions'])) {
 | 
						|
            foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
 | 
						|
                if (($scopeCode === T_FUNCTION) || ($scopeCode === T_CLOSURE)) {
 | 
						|
                    return $scopePtr;
 | 
						|
                }
 | 
						|
                if (($scopeCode === T_CLASS) || ($scopeCode === T_INTERFACE)) {
 | 
						|
                    $in_class = true;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (($scopePtr = $this->findFunctionPrototype($phpcsFile, $stackPtr)) !== false) {
 | 
						|
            return $scopePtr;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($in_class) {
 | 
						|
            // Member var of a class, we don't care.
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // File scope, hmm, lets use first token of file?
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    function isNextThingAnAssign(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
 | 
						|
        // Is the next non-whitespace an assignment?
 | 
						|
        $nextPtr = $phpcsFile->findNext(T_WHITESPACE, $stackPtr + 1, null, true, null, true);
 | 
						|
        if ($nextPtr !== false) {
 | 
						|
            if ($tokens[$nextPtr]['code'] === T_EQUAL) {
 | 
						|
                return $nextPtr;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function findWhereAssignExecuted(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
 | 
						|
        //  Write should be recorded at the next statement to ensure we treat
 | 
						|
        //  the assign as happening after the RHS execution.
 | 
						|
        //  eg: $var = $var + 1; -> RHS could still be undef.
 | 
						|
        //  However, if we're within a bracketed expression, we take place at
 | 
						|
        //  the closing bracket, if that's first.
 | 
						|
        //  eg: echo (($var = 12) && ($var == 12));
 | 
						|
        $semicolonPtr = $phpcsFile->findNext(T_SEMICOLON, $stackPtr + 1, null, false, null, true);
 | 
						|
        $closePtr = false;
 | 
						|
        if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) !== false) {
 | 
						|
            if (isset($tokens[$openPtr]['parenthesis_closer'])) {
 | 
						|
                $closePtr = $tokens[$openPtr]['parenthesis_closer'];
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($semicolonPtr === false) {
 | 
						|
            if ($closePtr === false) {
 | 
						|
                // TODO: panic
 | 
						|
                return $stackPtr;
 | 
						|
            }
 | 
						|
            return $closePtr;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($closePtr < $semicolonPtr) {
 | 
						|
            return $closePtr;
 | 
						|
        }
 | 
						|
 | 
						|
        return $semicolonPtr;
 | 
						|
    }
 | 
						|
 | 
						|
    function findContainingBrackets(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
 | 
						|
        if (isset($tokens[$stackPtr]['nested_parenthesis'])) {
 | 
						|
            $openPtrs = array_keys($tokens[$stackPtr]['nested_parenthesis']);
 | 
						|
            return end($openPtrs);
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    function findFunctionCall(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
 | 
						|
        if ($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) {
 | 
						|
            // First non-whitespace thing and see if it's a T_STRING function name
 | 
						|
            $functionPtr = $phpcsFile->findPrevious(T_WHITESPACE,
 | 
						|
                $openPtr - 1, null, true, null, true);
 | 
						|
            if ($tokens[$functionPtr]['code'] === T_STRING) {
 | 
						|
                return $functionPtr;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    function findFunctionCallArguments(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
 | 
						|
        // Slight hack: also allow this to find args for array constructor.
 | 
						|
        // TODO: probably should refactor into three functions: arg-finding and bracket-finding
 | 
						|
        if (($tokens[$stackPtr]['code'] !== T_STRING) && ($tokens[$stackPtr]['code'] !== T_ARRAY)) {
 | 
						|
            // Assume $stackPtr is something within the brackets, find our function call
 | 
						|
            if (($stackPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // $stackPtr is the function name, find our brackets after it
 | 
						|
        $openPtr = $phpcsFile->findNext(T_WHITESPACE,
 | 
						|
            $stackPtr + 1, null, true, null, true);
 | 
						|
        if (($openPtr === false) || ($tokens[$openPtr]['code'] !== T_OPEN_PARENTHESIS)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!isset($tokens[$openPtr]['parenthesis_closer'])) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $closePtr = $tokens[$openPtr]['parenthesis_closer'];
 | 
						|
 | 
						|
        $argPtrs = array();
 | 
						|
        $lastPtr = $openPtr;
 | 
						|
        $lastArgComma = $openPtr;
 | 
						|
        while (($nextPtr = $phpcsFile->findNext(T_COMMA, $lastPtr + 1, $closePtr)) !== false) {
 | 
						|
            if ($this->findContainingBrackets($phpcsFile, $nextPtr) == $openPtr) {
 | 
						|
                // Comma is at our level of brackets, it's an argument delimiter.
 | 
						|
                array_push($argPtrs, range($lastArgComma + 1, $nextPtr - 1));
 | 
						|
                $lastArgComma = $nextPtr;
 | 
						|
            }
 | 
						|
            $lastPtr = $nextPtr;
 | 
						|
        }
 | 
						|
        array_push($argPtrs, range($lastArgComma + 1, $closePtr - 1));
 | 
						|
 | 
						|
        return $argPtrs;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForFunctionPrototype(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a function or closure parameter?
 | 
						|
        // It would be nice to get the list of function parameters from watching for
 | 
						|
        // T_FUNCTION, but AbstractVariableSniff and AbstractScopeSniff define everything
 | 
						|
        // we need to do that as private or final, so we have to do it this hackish way.
 | 
						|
        if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
 | 
						|
        // so we look backwards from the opening bracket for the first thing that
 | 
						|
        // isn't a function name, reference sigil or whitespace and check if
 | 
						|
        // it's a function keyword.
 | 
						|
        $functionPtr = $phpcsFile->findPrevious(array(T_STRING, T_WHITESPACE, T_BITWISE_AND),
 | 
						|
            $openPtr - 1, null, true, null, true);
 | 
						|
        if (($functionPtr !== false) &&
 | 
						|
            (($tokens[$functionPtr]['code'] === T_FUNCTION) ||
 | 
						|
             ($tokens[$functionPtr]['code'] === T_CLOSURE))) {
 | 
						|
            // TODO: typeHint
 | 
						|
            $this->markVariableDeclaration($varName, 'param', null, $stackPtr, $functionPtr);
 | 
						|
            // Are we pass-by-reference?
 | 
						|
            $referencePtr = $phpcsFile->findPrevious(T_WHITESPACE,
 | 
						|
                $stackPtr - 1, null, true, null, true);
 | 
						|
            if (($referencePtr !== false) && ($tokens[$referencePtr]['code'] === T_BITWISE_AND)) {
 | 
						|
                $varInfo = $this->getVariableInfo($varName, $functionPtr);
 | 
						|
                $varInfo->passByReference = true;
 | 
						|
            }
 | 
						|
            //  Are we optional with a default?
 | 
						|
            if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) {
 | 
						|
                $this->markVariableAssignment($varName, $stackPtr, $functionPtr);
 | 
						|
            }
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        // Is it a use keyword?  Use is both a read and a define, fun!
 | 
						|
        if (($functionPtr !== false) && ($tokens[$functionPtr]['code'] === T_USE)) {
 | 
						|
            $this->markVariableRead($varName, $stackPtr, $currScope);
 | 
						|
            if ($this->isVariableUndefined($varName, $stackPtr, $currScope) === true) {
 | 
						|
                // We haven't been defined by this point.
 | 
						|
                $phpcsFile->addWarning("Variable %s is undefined.", $stackPtr,
 | 
						|
                    'UndefinedVariable',
 | 
						|
                    array("\${$varName}"));
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            // $functionPtr is at the use, we need the function keyword for start of scope.
 | 
						|
            $functionPtr = $phpcsFile->findPrevious(T_CLOSURE,
 | 
						|
                $functionPtr - 1, $currScope + 1, false, null, true);
 | 
						|
            if ($functionPtr !== false) {
 | 
						|
                // TODO: typeHints in use?
 | 
						|
                $this->markVariableDeclaration($varName, 'bound', null, $stackPtr, $functionPtr);
 | 
						|
                $this->markVariableAssignment($varName, $stackPtr, $functionPtr);
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForCatchBlock(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a catch block parameter?
 | 
						|
        if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
 | 
						|
        // so we look backwards from the opening bracket for the first thing that
 | 
						|
        // isn't a function name, reference sigil or whitespace and check if
 | 
						|
        // it's a function keyword.
 | 
						|
        $catchPtr = $phpcsFile->findPrevious(T_WHITESPACE,
 | 
						|
            $openPtr - 1, null, true, null, true);
 | 
						|
        if (($catchPtr !== false) &&
 | 
						|
            ($tokens[$catchPtr]['code'] === T_CATCH)) {
 | 
						|
            // Scope of the exception var is actually the function, not just the catch block.
 | 
						|
            // TODO: typeHint
 | 
						|
            $this->markVariableDeclaration($varName, 'local', null, $stackPtr, $currScope, true);
 | 
						|
            $this->markVariableAssignment($varName, $stackPtr, $currScope);
 | 
						|
            if ($this->allowUnusedCaughtExceptions) {
 | 
						|
                $varInfo = $this->getVariableInfo($varName, $currScope);
 | 
						|
                $varInfo->ignoreUnused = true;
 | 
						|
            }
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForThisWithinClass(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we $this within a class?
 | 
						|
        if (($varName != 'this') || empty($token['conditions'])) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
 | 
						|
            //  $this within a closure is invalid
 | 
						|
            //  Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes.
 | 
						|
            if ($tokens[$scopePtr]['code'] === T_CLOSURE) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            if ($scopeCode === T_CLASS) {
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForSuperGlobal(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a superglobal variable?
 | 
						|
        if (in_array($varName, array(
 | 
						|
            'GLOBALS',
 | 
						|
            '_SERVER',
 | 
						|
            '_GET',
 | 
						|
            '_POST',
 | 
						|
            '_FILES',
 | 
						|
            '_COOKIE',
 | 
						|
            '_SESSION',
 | 
						|
            '_REQUEST',
 | 
						|
            '_ENV',
 | 
						|
            'argv',
 | 
						|
            'argc',
 | 
						|
            ))) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForStaticMember(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a static member?
 | 
						|
        $doubleColonPtr = $stackPtr - 1;
 | 
						|
        if ($tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        $classNamePtr   = $stackPtr - 2;
 | 
						|
        if (($tokens[$classNamePtr]['code'] !== T_STRING) &&
 | 
						|
            ($tokens[$classNamePtr]['code'] !== T_SELF) &&
 | 
						|
            ($tokens[$classNamePtr]['code'] !== T_STATIC)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we refering to self:: outside a class?
 | 
						|
        // TODO: not sure this is our business or should be some other sniff.
 | 
						|
        if (($tokens[$classNamePtr]['code'] === T_SELF) ||
 | 
						|
            ($tokens[$classNamePtr]['code'] === T_STATIC)) {
 | 
						|
            if ($tokens[$classNamePtr]['code'] === T_SELF) {
 | 
						|
                $err_class = 'SelfOutsideClass';
 | 
						|
                $err_desc  = 'self::';
 | 
						|
            } else {
 | 
						|
                $err_class = 'StaticOutsideClass';
 | 
						|
                $err_desc  = 'static::';
 | 
						|
            }
 | 
						|
            if (!empty($token['conditions'])) {
 | 
						|
                foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
 | 
						|
                    //  self within a closure is invalid
 | 
						|
                    //  Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes.
 | 
						|
                    if ($tokens[$scopePtr]['code'] === T_CLOSURE) {
 | 
						|
                        $phpcsFile->addError("Use of {$err_desc}%s inside closure.", $stackPtr,
 | 
						|
                            $err_class,
 | 
						|
                            array("\${$varName}"));
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                    if ($scopeCode === T_CLASS) {
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $phpcsFile->addError("Use of {$err_desc}%s outside class definition.", $stackPtr,
 | 
						|
                $err_class,
 | 
						|
                array("\${$varName}"));
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForAssignment(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Is the next non-whitespace an assignment?
 | 
						|
        if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Plain ol' assignment. Simpl(ish).
 | 
						|
        if (($writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr)) === false) {
 | 
						|
            $writtenPtr = $stackPtr;  // I dunno
 | 
						|
        }
 | 
						|
        $this->markVariableAssignment($varName, $writtenPtr, $currScope);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForListAssignment(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // OK, are we within a list (...) construct?
 | 
						|
        if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, $openPtr - 1, null, true, null, true);
 | 
						|
        if (($prevPtr === false) || ($tokens[$prevPtr]['code'] !== T_LIST)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // OK, we're a list (...) construct... are we being assigned to?
 | 
						|
        $closePtr = $tokens[$openPtr]['parenthesis_closer'];
 | 
						|
        if (($assignPtr = $this->isNextThingAnAssign($phpcsFile, $closePtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Yes, we're being assigned.
 | 
						|
        $writtenPtr = $this->findWhereAssignExecuted($phpcsFile, $assignPtr);
 | 
						|
        $this->markVariableAssignment($varName, $writtenPtr, $currScope);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForGlobalDeclaration(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a global declaration?
 | 
						|
        // Search backwards for first token that isn't whitespace, comma or variable.
 | 
						|
        $globalPtr = $phpcsFile->findPrevious(
 | 
						|
            array(T_WHITESPACE, T_VARIABLE, T_COMMA),
 | 
						|
            $stackPtr - 1, null, true, null, true);
 | 
						|
        if (($globalPtr === false) || ($tokens[$globalPtr]['code'] !== T_GLOBAL)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // It's a global declaration.
 | 
						|
        $this->markVariableDeclaration($varName, 'global', null, $stackPtr, $currScope);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForStaticDeclaration(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a static declaration?
 | 
						|
        // Static declarations are a bit more complicated than globals, since they
 | 
						|
        // can contain assignments. The assignment is compile-time however so can
 | 
						|
        // only be constant values, which makes life manageable.
 | 
						|
        //
 | 
						|
        // Just to complicate matters further, late static binding constants
 | 
						|
        // take the form static::CONSTANT and are invalid within static variable
 | 
						|
        // assignments, but we don't want to accidentally match their use of the
 | 
						|
        // static keyword.
 | 
						|
        //
 | 
						|
        // Valid values are:
 | 
						|
        //   number         T_MINUS T_LNUMBER T_DNUMBER
 | 
						|
        //   string         T_CONSTANT_ENCAPSED_STRING
 | 
						|
        //   heredoc        T_START_HEREDOC T_HEREDOC T_END_HEREDOC
 | 
						|
        //   nowdoc         T_START_NOWDOC T_NOWDOC T_END_NOWDOC
 | 
						|
        //   define         T_STRING
 | 
						|
        //   class constant T_STRING T_DOUBLE_COLON T_STRING
 | 
						|
        // Search backwards for first token that isn't whitespace, comma, variable,
 | 
						|
        // equals, or on the list of assignable constant values above.
 | 
						|
        $staticPtr = $phpcsFile->findPrevious(
 | 
						|
            array(
 | 
						|
                T_WHITESPACE, T_VARIABLE, T_COMMA, T_EQUAL,
 | 
						|
                T_MINUS, T_LNUMBER, T_DNUMBER,
 | 
						|
                T_CONSTANT_ENCAPSED_STRING,
 | 
						|
                T_STRING,
 | 
						|
                T_DOUBLE_COLON,
 | 
						|
                T_START_HEREDOC, T_HEREDOC, T_END_HEREDOC,
 | 
						|
                T_START_NOWDOC, T_NOWDOC, T_END_NOWDOC,
 | 
						|
                ),
 | 
						|
            $stackPtr - 1, null, true, null, true);
 | 
						|
        if (($staticPtr === false) || ($tokens[$staticPtr]['code'] !== T_STATIC)) {
 | 
						|
            //if ($varName == 'static4') {
 | 
						|
            //    echo "Failing token:\n" . print_r($tokens[$staticPtr], true);
 | 
						|
            //}
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Is it a late static binding static::?
 | 
						|
        // If so, this isn't the static keyword we're looking for, but since
 | 
						|
        // static:: isn't allowed in a compile-time constant, we also know
 | 
						|
        // we can't be part of a static declaration anyway, so there's no
 | 
						|
        // need to look any further.
 | 
						|
        $lateStaticBindingPtr = $phpcsFile->findNext(T_WHITESPACE, $staticPtr + 1, null, true, null, true);
 | 
						|
        if (($lateStaticBindingPtr !== false) && ($tokens[$lateStaticBindingPtr]['code'] === T_DOUBLE_COLON)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // It's a static declaration.
 | 
						|
        $this->markVariableDeclaration($varName, 'static', null, $stackPtr, $currScope);
 | 
						|
        if ($this->isNextThingAnAssign($phpcsFile, $stackPtr) !== false) {
 | 
						|
            $this->markVariableAssignment($varName, $stackPtr, $currScope);
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForForeachLoopVar(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a foreach loopvar?
 | 
						|
        if (($openPtr = $this->findContainingBrackets($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Is there an 'as' token between us and the opening bracket?
 | 
						|
        if ($phpcsFile->findPrevious(T_AS, $stackPtr - 1, $openPtr) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $this->markVariableAssignment($varName, $stackPtr, $currScope);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForPassByReferenceFunctionCall(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we pass-by-reference to known pass-by-reference function?
 | 
						|
        if (($functionPtr = $this->findFunctionCall($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // Is our function a known pass-by-reference function?
 | 
						|
        $functionName = $tokens[$functionPtr]['content'];
 | 
						|
        if (!isset($this->_passByRefFunctions[$functionName])) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $refArgs = $this->_passByRefFunctions[$functionName];
 | 
						|
 | 
						|
        if (($argPtrs = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        // We're within a function call arguments list, find which arg we are.
 | 
						|
        $argPos = false;
 | 
						|
        foreach ($argPtrs as $idx => $ptrs) {
 | 
						|
            if (in_array($stackPtr, $ptrs)) {
 | 
						|
                $argPos = $idx + 1;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($argPos === false) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        if (!in_array($argPos, $refArgs)) {
 | 
						|
            // Our arg wasn't mentioned explicitly, are we after an elipsis catch-all?
 | 
						|
            if (($elipsis = array_search('...', $refArgs)) === false) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            if ($argPos < $refArgs[$elipsis - 1]) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Our argument position matches that of a pass-by-ref argument,
 | 
						|
        // check that we're the only part of the argument expression.
 | 
						|
        foreach ($argPtrs[$argPos - 1] as $ptr) {
 | 
						|
            if ($ptr === $stackPtr) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if ($tokens[$ptr]['code'] !== T_WHITESPACE) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Just us, we can mark it as a write.
 | 
						|
        $this->markVariableAssignment($varName, $stackPtr, $currScope);
 | 
						|
        // It's a read as well for purposes of used-variables.
 | 
						|
        $this->markVariableRead($varName, $stackPtr, $currScope);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    protected function checkForSymbolicObjectProperty(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $varName,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        // Are we a symbolic object property/function derefeference?
 | 
						|
        // Search backwards for first token that isn't whitespace, is it a "->" operator?
 | 
						|
        $objectOperatorPtr = $phpcsFile->findPrevious(
 | 
						|
            T_WHITESPACE,
 | 
						|
            $stackPtr - 1, null, true, null, true);
 | 
						|
        if (($objectOperatorPtr === false) || ($tokens[$objectOperatorPtr]['code'] !== T_OBJECT_OPERATOR)) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Called to process class member vars.
 | 
						|
     *
 | 
						|
     * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer 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();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
        // TODO: don't care for now
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Called to process normal member vars.
 | 
						|
     *
 | 
						|
     * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
 | 
						|
     *                                        token was found.
 | 
						|
     * @param int                  $stackPtr  The position where the token was found.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    protected function processVariable(
 | 
						|
        PHP_CodeSniffer_File $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        $varName = $this->normalizeVarName($token['content']);
 | 
						|
        if (($currScope = $this->findVariableScope($phpcsFile, $stackPtr)) === false) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        //static $dump_token = false;
 | 
						|
        //if ($varName == 'property') {
 | 
						|
        //    $dump_token = true;
 | 
						|
        //}
 | 
						|
        //if ($dump_token) {
 | 
						|
        //    echo "Found variable {$varName} on line {$token['line']} in scope {$currScope}.\n" . print_r($token, true);
 | 
						|
        //    echo "Prev:\n" . print_r($tokens[$stackPtr - 1], true);
 | 
						|
        //}
 | 
						|
 | 
						|
        // Determine if variable is being assigned or read.
 | 
						|
 | 
						|
        // Read methods that preempt assignment:
 | 
						|
        //   Are we a $object->$property type symbolic reference?
 | 
						|
 | 
						|
        // Possible assignment methods:
 | 
						|
        //   Is a mandatory function/closure parameter
 | 
						|
        //   Is an optional function/closure parameter with non-null value
 | 
						|
        //   Is closure use declaration of a variable defined within containing scope
 | 
						|
        //   catch (...) block start
 | 
						|
        //   $this within a class (but not within a closure).
 | 
						|
        //   $GLOBALS, $_REQUEST, etc superglobals.
 | 
						|
        //   $var part of class::$var static member
 | 
						|
        //   Assignment via =
 | 
						|
        //   Assignment via list (...) =
 | 
						|
        //   Declares as a global
 | 
						|
        //   Declares as a static
 | 
						|
        //   Assignment via foreach (... as ...) { }
 | 
						|
        //   Pass-by-reference to known pass-by-reference function
 | 
						|
 | 
						|
        // Are we a $object->$property type symbolic reference?
 | 
						|
        if ($this->checkForSymbolicObjectProperty($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we a function or closure parameter?
 | 
						|
        if ($this->checkForFunctionPrototype($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we a catch parameter?
 | 
						|
        if ($this->checkForCatchBlock($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we $this within a class?
 | 
						|
        if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we a $GLOBALS, $_REQUEST, etc superglobal?
 | 
						|
        if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // $var part of class::$var static member
 | 
						|
        if ($this->checkForStaticMember($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Is the next non-whitespace an assignment?
 | 
						|
        if ($this->checkForAssignment($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // OK, are we within a list (...) = construct?
 | 
						|
        if ($this->checkForListAssignment($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we a global declaration?
 | 
						|
        if ($this->checkForGlobalDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we a static declaration?
 | 
						|
        if ($this->checkForStaticDeclaration($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we a foreach loopvar?
 | 
						|
        if ($this->checkForForeachLoopVar($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // Are we pass-by-reference to known pass-by-reference function?
 | 
						|
        if ($this->checkForPassByReferenceFunctionCall($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // OK, we don't appear to be a write to the var, assume we're a read.
 | 
						|
        $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Called to process variables found in double quoted strings.
 | 
						|
     *
 | 
						|
     * Note that there may be more than one variable in the string, which will
 | 
						|
     * result only in one call for the string.
 | 
						|
     *
 | 
						|
     * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
 | 
						|
     *                                        token was found.
 | 
						|
     * @param int                  $stackPtr  The position where the double quoted
 | 
						|
     *                                        string was found.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    protected function processVariableInString(
 | 
						|
        PHP_CodeSniffer_File
 | 
						|
        $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        if (!preg_match_all($this->_double_quoted_variable_regexp, $token['content'], $matches)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        $currScope = $this->findVariableScope($phpcsFile, $stackPtr);
 | 
						|
        foreach ($matches[1] as $varName) {
 | 
						|
            $varName = $this->normalizeVarName($varName);
 | 
						|
            // Are we $this within a class?
 | 
						|
            if ($this->checkForThisWithinClass($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if ($this->checkForSuperGlobal($phpcsFile, $stackPtr, $varName, $currScope)) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $stackPtr, $currScope);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    protected function processCompactArguments(
 | 
						|
        PHP_CodeSniffer_File
 | 
						|
        $phpcsFile,
 | 
						|
        $stackPtr,
 | 
						|
        $arguments,
 | 
						|
        $currScope
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        foreach ($arguments as $argumentPtrs) {
 | 
						|
            $argumentPtrs = array_values(array_filter($argumentPtrs,
 | 
						|
                function ($argumentPtr) use ($tokens) {
 | 
						|
                    return $tokens[$argumentPtr]['code'] !== T_WHITESPACE;
 | 
						|
                }));
 | 
						|
            if (empty($argumentPtrs)) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if (!isset($tokens[$argumentPtrs[0]])) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            $argument_first_token = $tokens[$argumentPtrs[0]];
 | 
						|
            if ($argument_first_token['code'] === T_ARRAY) {
 | 
						|
                // It's an array argument, recurse.
 | 
						|
                if (($array_arguments = $this->findFunctionCallArguments($phpcsFile, $argumentPtrs[0])) !== false) {
 | 
						|
                    $this->processCompactArguments($phpcsFile, $stackPtr, $array_arguments, $currScope);
 | 
						|
                }
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if (count($argumentPtrs) > 1) {
 | 
						|
                // Complex argument, we can't handle it, ignore.
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if ($argument_first_token['code'] === T_CONSTANT_ENCAPSED_STRING) {
 | 
						|
                // Single-quoted string literal, ie compact('whatever').
 | 
						|
                // Substr is to strip the enclosing single-quotes.
 | 
						|
                $varName = substr($argument_first_token['content'], 1, -1);
 | 
						|
                $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if ($argument_first_token['code'] === T_DOUBLE_QUOTED_STRING) {
 | 
						|
                // Double-quoted string literal.
 | 
						|
                if (preg_match($this->_double_quoted_variable_regexp, $argument_first_token['content'])) {
 | 
						|
                    // Bail if the string needs variable expansion, that's runtime stuff.
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
                // Substr is to strip the enclosing double-quotes.
 | 
						|
                $varName = substr($argument_first_token['content'], 1, -1);
 | 
						|
                $this->markVariableReadAndWarnIfUndefined($phpcsFile, $varName, $argumentPtrs[0], $currScope);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Called to process variables named in a call to compact().
 | 
						|
     *
 | 
						|
     * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
 | 
						|
     *                                        token was found.
 | 
						|
     * @param int                  $stackPtr  The position where the call to compact()
 | 
						|
     *                                        was found.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    protected function processCompact(
 | 
						|
        PHP_CodeSniffer_File
 | 
						|
        $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $tokens = $phpcsFile->getTokens();
 | 
						|
        $token  = $tokens[$stackPtr];
 | 
						|
 | 
						|
        $currScope = $this->findVariableScope($phpcsFile, $stackPtr);
 | 
						|
 | 
						|
        if (($arguments = $this->findFunctionCallArguments($phpcsFile, $stackPtr)) !== false) {
 | 
						|
            $this->processCompactArguments($phpcsFile, $stackPtr, $arguments, $currScope);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Called to process the end of a scope.
 | 
						|
     *
 | 
						|
     * Note that although triggered by the closing curly brace of the scope, $stackPtr is
 | 
						|
     * the scope conditional, not the closing curly brace.
 | 
						|
     *
 | 
						|
     * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this
 | 
						|
     *                                        token was found.
 | 
						|
     * @param int                  $stackPtr  The position of the scope conditional.
 | 
						|
     *
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    protected function processScopeClose(
 | 
						|
        PHP_CodeSniffer_File
 | 
						|
        $phpcsFile,
 | 
						|
        $stackPtr
 | 
						|
    ) {
 | 
						|
        $scopeInfo = $this->getScopeInfo($stackPtr, false);
 | 
						|
        if (is_null($scopeInfo)) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        foreach ($scopeInfo->variables as $varInfo) {
 | 
						|
            if ($varInfo->ignoreUnused || isset($varInfo->firstRead)) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if ($this->allowUnusedFunctionParameters && $varInfo->scopeType == 'param') {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if ($varInfo->passByReference && isset($varInfo->firstInitialized)) {
 | 
						|
                // If we're pass-by-reference then it's a common pattern to
 | 
						|
                // use the variable to return data to the caller, so any
 | 
						|
                // assignment also counts as "variable use" for the purposes
 | 
						|
                // of "unused variable" warnings.
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if (isset($varInfo->firstDeclared)) {
 | 
						|
                $phpcsFile->addWarning(
 | 
						|
                    "Unused %s %s.",
 | 
						|
                    $varInfo->firstDeclared,
 | 
						|
                    'UnusedVariable',
 | 
						|
                    array(
 | 
						|
                        VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
 | 
						|
                        "\${$varInfo->name}",
 | 
						|
                        )
 | 
						|
                    );
 | 
						|
            }
 | 
						|
            if (isset($varInfo->firstInitialized)) {
 | 
						|
                $phpcsFile->addWarning(
 | 
						|
                    "Unused %s %s.",
 | 
						|
                    $varInfo->firstInitialized,
 | 
						|
                    'UnusedVariable',
 | 
						|
                    array(
 | 
						|
                        VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
 | 
						|
                        "\${$varInfo->name}",
 | 
						|
                        )
 | 
						|
                    );
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}//end class
 | 
						|
 | 
						|
?>
 |