<?php
/**
 * PHPCS cross-version compatibility helper class.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress;

use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Files\File;

/**
 * PHPCSHelper
 *
 * PHPCS cross-version compatibility helper class.
 *
 * Deals with files which cannot be aliased 1-on-1 as the original
 * class was split up into several classes.
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.13.0
 */
class PHPCSHelper {

	/**
	 * Get the PHPCS version number.
	 *
	 * @since 0.13.0
	 *
	 * @return string
	 */
	public static function get_version() {
		return Config::VERSION;
	}

	/**
	 * Pass config data to PHPCS.
	 *
	 * PHPCS cross-version compatibility helper.
	 *
	 * @since 0.13.0
	 *
	 * @param string      $key   The name of the config value.
	 * @param string|null $value The value to set. If null, the config entry
	 *                           is deleted, reverting it to the default value.
	 * @param boolean     $temp  Set this config data temporarily for this script run.
	 *                           This will not write the config data to the config file.
	 */
	public static function set_config_data( $key, $value, $temp = false ) {
		Config::setConfigData( $key, $value, $temp );
	}

	/**
	 * Get the value of a single PHPCS config key.
	 *
	 * @since 0.13.0
	 *
	 * @param string $key The name of the config value.
	 *
	 * @return string|null
	 */
	public static function get_config_data( $key ) {
		return Config::getConfigData( $key );
	}

	/**
	 * Get the tab width as passed to PHPCS from the command-line or the ruleset.
	 *
	 * @since 0.13.0
	 *
	 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed.
	 *
	 * @return int Tab width. Defaults to 4.
	 */
	public static function get_tab_width( File $phpcsFile ) {
		$tab_width = 4;

		if ( isset( $phpcsFile->config->tabWidth ) && $phpcsFile->config->tabWidth > 0 ) {
			$tab_width = $phpcsFile->config->tabWidth;
		}

		return $tab_width;
	}

	/**
	 * Check whether the `--ignore-annotations` option has been used.
	 *
	 * @since 0.13.0
	 *
	 * @param \PHP_CodeSniffer\Files\File $phpcsFile Optional. The current file being processed.
	 *
	 * @return bool True if annotations should be ignored, false otherwise.
	 */
	public static function ignore_annotations( File $phpcsFile = null ) {
		if ( isset( $phpcsFile, $phpcsFile->config->annotations ) ) {
			return ! $phpcsFile->config->annotations;
		} else {
			$annotations = Config::getConfigData( 'annotations' );
			if ( isset( $annotations ) ) {
				return ! $annotations;
			}
		}
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\PHP;

use WordPressCS\WordPress\Sniff;

/**
 * Verifies the correct usage of type cast keywords.
 *
 * Type casts should be:
 * - normalized, i.e. (float) not (real).
 *
 * Additionally, the use of the (unset) and (binary) casts is discouraged.
 *
 * @link    https://make.wordpress.org/core/handbook/best-practices/....
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   1.2.0
 * @since   2.0.0 No longer checks that type casts are lowercase or short form.
 *                Relevant PHPCS native sniffs have been included in the rulesets instead.
 */
class TypeCastsSniff extends Sniff {

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @return array
	 */
	public function register() {
		return array(
			\T_DOUBLE_CAST,
			\T_UNSET_CAST,
			\T_STRING_CAST,
			\T_BINARY_CAST,
		);
	}

	/**
	 * Processes this test, when one of its tokens is encountered.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return void
	 */
	public function process_token( $stackPtr ) {

		$token_code  = $this->tokens[ $stackPtr ]['code'];
		$typecast    = str_replace( ' ', '', $this->tokens[ $stackPtr ]['content'] );
		$typecast_lc = strtolower( $typecast );

		switch ( $token_code ) {
			case \T_DOUBLE_CAST:
				if ( '(float)' !== $typecast_lc ) {
					$fix = $this->phpcsFile->addFixableError(
						'Normalized type keywords must be used; expected "(float)" but found "%s"',
						$stackPtr,
						'DoubleRealFound',
						array( $typecast )
					);

					if ( true === $fix ) {
						$this->phpcsFile->fixer->replaceToken( $stackPtr, '(float)' );
					}
				}
				break;

			case \T_UNSET_CAST:
				$this->phpcsFile->addWarning(
					'Using the "(unset)" cast is strongly discouraged. Use the "unset()" language construct or assign "null" as the value to the variable instead.',
					$stackPtr,
					'UnsetFound'
				);
				break;

			case \T_STRING_CAST:
			case \T_BINARY_CAST:
				if ( \T_STRING_CAST === $token_code && '(binary)' !== $typecast_lc ) {
					break;
				}

				$this->phpcsFile->addWarning(
					'Using binary casting is strongly discouraged. Found: "%s"',
					$stackPtr,
					'BinaryFound',
					array( $typecast )
				);
				break;
		}
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\PHP;

use WordPressCS\WordPress\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Discourage the use of the PHP error silencing operator.
 *
 * This sniff allows the error operator to be used with a select list
 * of whitelisted functions, as no amount of error checking can prevent
 * PHP from throwing errors when those functions are used.
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   1.1.0
 */
class NoSilencedErrorsSniff extends Sniff {

	/**
	 * Number of tokens to display in the error message to show
	 * the error silencing context.
	 *
	 * @since 1.1.0
	 *
	 * @var int
	 */
	public $context_length = 6;

	/**
	 * Whether or not the `$function_whitelist` should be used.
	 *
	 * Defaults to true.
	 *
	 * This property only affects whether the standard function whitelist is
	 * used. The custom whitelist, if set, will always be respected.
	 *
	 * @since 1.1.0
	 *
	 * @var bool
	 */
	public $use_default_whitelist = true;

	/**
	 * User defined whitelist.
	 *
	 * Allows users to pass a list of additional functions to whitelist
	 * from their custom ruleset.
	 *
	 * @since 1.1.0
	 *
	 * @var array
	 */
	public $custom_whitelist = array();

	/**
	 * PHP native function whitelist.
	 *
	 * Errors caused by calls to any of these native PHP functions
	 * are allowed to be silenced as file system permissions and such
	 * can cause E_WARNINGs to be thrown which cannot be prevented via
	 * error checking.
	 *
	 * Note: only calls to global functions - in contrast to class methods -
	 * are taken into account.
	 *
	 * Only functions for which the PHP manual annotates that an
	 * error will be thrown on failure are accepted into this list.
	 *
	 * @since 1.1.0
	 *
	 * @var array <string function name> => <bool true>
	 */
	protected $function_whitelist = array(
		// Directory extension.
		'chdir'                 => true,
		'opendir'               => true,
		'scandir'               => true,

		// File extension.
		'file_exists'           => true,
		'file_get_contents'     => true,
		'file'                  => true,
		'fileatime'             => true,
		'filectime'             => true,
		'filegroup'             => true,
		'fileinode'             => true,
		'filemtime'             => true,
		'fileowner'             => true,
		'fileperms'             => true,
		'filesize'              => true,
		'filetype'              => true,
		'fopen'                 => true,
		'is_dir'                => true,
		'is_executable'         => true,
		'is_file'               => true,
		'is_link'               => true,
		'is_readable'           => true,
		'is_writable'           => true,
		'is_writeable'          => true,
		'lstat'                 => true,
		'mkdir'                 => true,
		'move_uploaded_file'    => true,
		'readfile'              => true,
		'readlink'              => true,
		'rename'                => true,
		'rmdir'                 => true,
		'stat'                  => true,
		'unlink'                => true,

		// FTP extension.
		'ftp_chdir'             => true,
		'ftp_login'             => true,
		'ftp_rename'            => true,

		// Stream extension.
		'stream_select'         => true,
		'stream_set_chunk_size' => true,

		// Zlib extension.
		'deflate_add'           => true,
		'deflate_init'          => true,
		'inflate_add'           => true,
		'inflate_init'          => true,
		'readgzfile'            => true,

		// Miscellaneous other functions.
		'imagecreatefromstring' => true,
		'parse_url'             => true, // Pre-PHP 5.3.3 an E_WARNING was thrown when URL parsing failed.
		'unserialize'           => true,
	);

	/**
	 * Tokens which are regarded as empty for the purpose of determining
	 * the name of the called function.
	 *
	 * This property is set from within the register() method.
	 *
	 * @since 1.1.0
	 *
	 * @var array
	 */
	private $empty_tokens = array();

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @since 1.1.0
	 *
	 * @return array
	 */
	public function register() {
		$this->empty_tokens                    = Tokens::$emptyTokens;
		$this->empty_tokens[ \T_NS_SEPARATOR ] = \T_NS_SEPARATOR;
		$this->empty_tokens[ \T_BITWISE_AND ]  = \T_BITWISE_AND;

		return array(
			\T_ASPERAND,
		);
	}

	/**
	 * Processes this test, when one of its tokens is encountered.
	 *
	 * @since 1.1.0
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 */
	public function process_token( $stackPtr ) {
		// Handle the user-defined custom function whitelist.
		$this->custom_whitelist = $this->merge_custom_array( $this->custom_whitelist, array(), false );
		$this->custom_whitelist = array_map( 'strtolower', $this->custom_whitelist );

		if ( true === $this->use_default_whitelist || ! empty( $this->custom_whitelist ) ) {
			/*
			 * Check if the error silencing is done for one of the whitelisted functions.
			 */
			$next_non_empty = $this->phpcsFile->findNext( $this->empty_tokens, ( $stackPtr + 1 ), null, true, null, true );
			if ( false !== $next_non_empty && \T_STRING === $this->tokens[ $next_non_empty ]['code'] ) {
				$has_parenthesis = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), null, true, null, true );
				if ( false !== $has_parenthesis && \T_OPEN_PARENTHESIS === $this->tokens[ $has_parenthesis ]['code'] ) {
					$function_name = strtolower( $this->tokens[ $next_non_empty ]['content'] );
					if ( ( true === $this->use_default_whitelist
						&& isset( $this->function_whitelist[ $function_name ] ) === true )
						|| in_array( $function_name, $this->custom_whitelist, true ) === true
					) {
						$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', 'whitelisted function call: ' . $function_name );
						return;
					}
				}
			}
		}

		$this->context_length = (int) $this->context_length;
		$context_length       = $this->context_length;
		if ( $this->context_length <= 0 ) {
			$context_length = 2;
		}

		// Prepare the "Found" string to display.
		$end_of_statement = $this->phpcsFile->findEndOfStatement( $stackPtr, \T_COMMA );
		if ( ( $end_of_statement - $stackPtr ) < $context_length ) {
			$context_length = ( $end_of_statement - $stackPtr );
		}
		$found = $this->phpcsFile->getTokensAsString( $stackPtr, $context_length );
		$found = str_replace( array( "\t", "\n", "\r" ), ' ', $found ) . '...';

		$error_msg = 'Silencing errors is strongly discouraged. Use proper error checking instead.';
		$data      = array();
		if ( $this->context_length > 0 ) {
			$error_msg .= ' Found: %s';
			$data[]     = $found;
		}

		$this->phpcsFile->addWarning(
			$error_msg,
			$stackPtr,
			'Discouraged',
			$data
		);

		if ( isset( $function_name ) ) {
			$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', $function_name );
		} else {
			$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', $found );
		}
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\WhiteSpace;

use PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace\OperatorSpacingSniff as PHPCS_Squiz_OperatorSpacingSniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Verify operator spacing, uses the Squiz sniff, but additionally also sniffs for the `!` (boolean not) operator.
 *
 * "Always put spaces after commas, and on both sides of logical, comparison, string and assignment operators."
 *
 * @link    https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#space-usage
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.1.0
 * @since   0.3.0  This sniff now has the ability to fix the issues it flags.
 * @since   0.12.0 This sniff used to be a copy of a very old and outdated version of the
 *                 upstream sniff.
 *                 Now, the sniff defers completely to the upstream sniff, adding just the
 *                 T_BOOLEAN_NOT and the logical operators (`&&` and the like) - via the
 *                 registration method and changing the value of the customizable
 *                 $ignoreNewlines property.
 * @since   0.13.0 Class name changed: this class is now namespaced.
 *
 * Last synced with base class June 2017 at commit 41127aa4764536f38f504fb3f7b8831f05919c89.
 * @link    https://github.com/squizlabs/PHP_CodeSniffer/blob/master/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php
 */
class OperatorSpacingSniff extends PHPCS_Squiz_OperatorSpacingSniff {

	/**
	 * Allow newlines instead of spaces.
	 *
	 * N.B.: The upstream sniff defaults to `false`.
	 *
	 * @var boolean
	 */
	public $ignoreNewlines = true;

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @return array
	 */
	public function register() {
		$tokens                   = parent::register();
		$tokens[ \T_BOOLEAN_NOT ] = \T_BOOLEAN_NOT;
		$tokens[ \T_INSTANCEOF ]  = \T_INSTANCEOF;
		$logical_operators        = Tokens::$booleanOperators;

		// Using array union to auto-dedup.
		return $tokens + $logical_operators;
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\WP;

use WordPressCS\WordPress\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Warns about overwriting WordPress native global variables.
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.3.0
 * @since   0.4.0  This class now extends the WordPressCS native `Sniff` class.
 * @since   0.12.0 The $wp_globals property has been moved to the `Sniff` class.
 * @since   0.13.0 Class name changed: this class is now namespaced.
 * @since   1.0.0  This sniff has been moved from the `Variables` category to the `WP`
 *                 category and renamed from `GlobalVariables` to `GlobalVariablesOverride`.
 * @since   1.1.0  The sniff now also detects variables being overriden in the global namespace.
 *
 * @uses    \WordPressCS\WordPress\Sniff::$custom_test_class_whitelist
 */
class GlobalVariablesOverrideSniff extends Sniff {

	/**
	 * Whether to treat all files as if they were included from
	 * a within function.
	 *
	 * This is mostly useful for projects containing views which are being
	 * included from within a function in another file, like themes.
	 *
	 * Note: enabling this is discouraged as there is no guarantee that
	 * the file will *never* be included from the global scope.
	 *
	 * @since 1.1.0
	 *
	 * @var bool
	 */
	public $treat_files_as_scoped = false;

	/**
	 * Scoped object and function structures to skip over as
	 * variables will have a different scope within those.
	 *
	 * @since 1.1.0
	 *
	 * @var array
	 */
	private $skip_over = array(
		\T_FUNCTION => true,
		\T_CLOSURE  => true,
	);

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @since 0.3.0
	 * @since 1.1.0 Added class tokens for improved test classes skipping.
	 *
	 * @return array
	 */
	public function register() {
		// Add the OO scope tokens to the $skip_over property.
		$this->skip_over += Tokens::$ooScopeTokens;

		$targets = array(
			\T_GLOBAL,
			\T_VARIABLE,
		);

		// Only used to skip over test classes.
		$targets += Tokens::$ooScopeTokens;

		return $targets;
	}

	/**
	 * Processes this test, when one of its tokens is encountered.
	 *
	 * @since 0.3.0
	 * @since 1.1.0 Split the token specific logic off into separate methods.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return int|void Integer stack pointer to skip forward or void to continue
	 *                  normal file processing.
	 */
	public function process_token( $stackPtr ) {

		$token = $this->tokens[ $stackPtr ];

		// Ignore variable overrides in test classes.
		if ( isset( Tokens::$ooScopeTokens[ $token['code'] ] ) ) {

			if ( true === $this->is_test_class( $stackPtr )
				&& $token['scope_condition'] === $stackPtr
				&& isset( $token['scope_closer'] )
			) {
				// Skip forward to end of test class.
				return $token['scope_closer'];
			}

			// Otherwise ignore the tokens as they were only registered to enable skipping over test classes.
			return;
		}

		/*
		 * Examine variables within a function scope based on a `global` statement in the
		 * function.
		 * Examine variable not within a function scope and access to the `$GLOBALS`
		 * variable based on the variable token.
		 */
		$in_function_scope = $this->phpcsFile->hasCondition( $stackPtr, array( \T_FUNCTION, \T_CLOSURE ) );

		if ( \T_VARIABLE === $token['code']
			&& ( '$GLOBALS' === $token['content']
				|| ( false === $in_function_scope && false === $this->treat_files_as_scoped ) )
		) {
			return $this->process_variable_assignment( $stackPtr );
		} elseif ( \T_GLOBAL === $token['code']
			&& ( true === $in_function_scope || true === $this->treat_files_as_scoped )
		) {
			return $this->process_global_statement( $stackPtr, $in_function_scope );
		}
	}

	/**
	 * Check that defined global variables are prefixed.
	 *
	 * @since 1.1.0 Logic was previously contained in the process_token() method.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return void
	 */
	protected function process_variable_assignment( $stackPtr ) {

		if ( $this->has_whitelist_comment( 'override', $stackPtr ) === true ) {
			return;
		}

		$token    = $this->tokens[ $stackPtr ];
		$var_name = substr( $token['content'], 1 ); // Strip the dollar sign.
		$data     = array();

		// Determine the variable name for `$GLOBALS['array_key']`.
		if ( 'GLOBALS' === $var_name ) {
			$bracketPtr = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );

			if ( false === $bracketPtr || \T_OPEN_SQUARE_BRACKET !== $this->tokens[ $bracketPtr ]['code'] || ! isset( $this->tokens[ $bracketPtr ]['bracket_closer'] ) ) {
				return;
			}

			// Retrieve the array key and avoid getting tripped up by some simple obfuscation.
			$var_name = '';
			$start    = ( $bracketPtr + 1 );
			for ( $ptr = $start; $ptr < $this->tokens[ $bracketPtr ]['bracket_closer']; $ptr++ ) {
				/*
				 * If the globals array key contains a variable, constant, function call
				 * or interpolated variable, bow out.
				 */
				if ( \T_VARIABLE === $this->tokens[ $ptr ]['code']
					|| \T_STRING === $this->tokens[ $ptr ]['code']
					|| \T_DOUBLE_QUOTED_STRING === $this->tokens[ $ptr ]['code']
				) {
					return;
				}

				if ( \T_CONSTANT_ENCAPSED_STRING === $this->tokens[ $ptr ]['code'] ) {
					$var_name .= $this->strip_quotes( $this->tokens[ $ptr ]['content'] );
				}
			}

			if ( '' === $var_name ) {
				// Shouldn't happen, but just in case.
				return;
			}

			// Set up the data for the error message.
			$data[] = '$GLOBALS[\'' . $var_name . '\']';
		}

		/*
		 * Is this one of the WP global variables ?
		 */
		if ( isset( $this->wp_globals[ $var_name ] ) === false ) {
			return;
		}

		/*
		 * Check if the variable value is being changed.
		 */
		if ( false === $this->is_assignment( $stackPtr )
			&& false === $this->is_foreach_as( $stackPtr )
		) {
			return;
		}

		/*
		 * Function parameters with the same name as a WP global variable are fine,
		 * including when they are being assigned a default value.
		 */
		if ( isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) {
			foreach ( $this->tokens[ $stackPtr ]['nested_parenthesis'] as $opener => $closer ) {
				if ( isset( $this->tokens[ $opener ]['parenthesis_owner'] )
					&& ( \T_FUNCTION === $this->tokens[ $this->tokens[ $opener ]['parenthesis_owner'] ]['code']
						|| \T_CLOSURE === $this->tokens[ $this->tokens[ $opener ]['parenthesis_owner'] ]['code'] )
				) {
					return;
				}
			}
			unset( $opener, $closer );
		}

		/*
		 * Class property declarations with the same name as WP global variables are fine.
		 */
		if ( true === $this->is_class_property( $stackPtr ) ) {
			return;
		}

		// Still here ? In that case, the WP global variable is being tampered with.
		$this->add_error( $stackPtr, $data );
	}

	/**
	 * Check that global variables imported into a function scope using a global statement
	 * are not being overruled.
	 *
	 * @since 1.1.0 Logic was previously contained in the process_token() method.
	 *
	 * @param int  $stackPtr          The position of the current token in the stack.
	 * @param bool $in_function_scope Whether the global statement is within a scoped function/closure.
	 *
	 * @return void
	 */
	protected function process_global_statement( $stackPtr, $in_function_scope ) {
		/*
		 * Collect the variables to watch for.
		 */
		$search = array();
		$ptr    = ( $stackPtr + 1 );
		while ( isset( $this->tokens[ $ptr ] ) ) {
			$var = $this->tokens[ $ptr ];

			// Halt the loop at end of statement.
			if ( \T_SEMICOLON === $var['code'] ) {
				break;
			}

			if ( \T_VARIABLE === $var['code'] ) {
				if ( isset( $this->wp_globals[ substr( $var['content'], 1 ) ] ) ) {
					$search[] = $var['content'];
				}
			}

			$ptr++;
		}
		unset( $var );

		if ( empty( $search ) ) {
			return;
		}

		/*
		 * Search for assignments to the imported global variables within the relevant scope.
		 */
		$start = $ptr;
		if ( true === $in_function_scope ) {
			$function_cond = $this->phpcsFile->getCondition( $stackPtr, \T_FUNCTION );
			$closure_cond  = $this->phpcsFile->getCondition( $stackPtr, \T_CLOSURE );
			$scope_cond    = max( $function_cond, $closure_cond ); // If false, it will evaluate as zero, so this is fine.
			if ( isset( $this->tokens[ $scope_cond ]['scope_closer'] ) === false ) {
				// Live coding or parse error.
				return;
			}
			$end = $this->tokens[ $scope_cond ]['scope_closer'];
		} else {
			// Global statement in the global namespace with file is being treated as scoped.
			$end = ( $this->phpcsFile->numTokens + 1 );
		}

		for ( $ptr = $start; $ptr < $end; $ptr++ ) {

			// Skip over nested functions, classes and the likes.
			if ( isset( $this->skip_over[ $this->tokens[ $ptr ]['code'] ] ) ) {
				if ( ! isset( $this->tokens[ $ptr ]['scope_closer'] ) ) {
					// Live coding or parse error.
					break;
				}

				$ptr = $this->tokens[ $ptr ]['scope_closer'];
				continue;
			}

			if ( \T_VARIABLE !== $this->tokens[ $ptr ]['code'] ) {
				continue;
			}

			if ( \in_array( $this->tokens[ $ptr ]['content'], $search, true ) === false ) {
				// Not one of the variables we're interested in.
				continue;
			}

			// Don't throw false positives for static class properties.
			if ( $this->is_class_object_call( $ptr ) === true ) {
				continue;
			}

			if ( true === $this->is_assignment( $ptr ) ) {
				$this->maybe_add_error( $ptr );
				continue;
			}

			// Check if this is a variable assignment within a `foreach()` declaration.
			if ( $this->is_foreach_as( $ptr ) === true ) {
				$this->maybe_add_error( $ptr );
			}
		}
	}

	/**
	 * Add the error if there is no whitelist comment present.
	 *
	 * @since 0.11.0
	 * @since 1.1.0  - Visibility changed from public to protected.
	 *               - Check for being in a test class moved to the process_token() method.
	 *
	 * @param int $stackPtr The position of the token to throw the error for.
	 *
	 * @return void
	 */
	protected function maybe_add_error( $stackPtr ) {
		if ( $this->has_whitelist_comment( 'override', $stackPtr ) === false ) {
			$this->add_error( $stackPtr );
		}
	}

	/**
	 * Add the error.
	 *
	 * @since 1.1.0
	 *
	 * @param int   $stackPtr The position of the token to throw the error for.
	 * @param array $data     Optional. Array containing one entry holding the
	 *                        name of the variable being overruled.
	 *                        Defaults to the 'content' of the $stackPtr token.
	 *
	 * @return void
	 */
	protected function add_error( $stackPtr, $data = array() ) {
		if ( empty( $data ) ) {
			$data[] = $this->tokens[ $stackPtr ]['content'];
		}

		$this->phpcsFile->addError(
			'Overriding WordPress globals is prohibited. Found assignment to %s',
			$stackPtr,
			'Prohibited',
			$data
		);
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\WhiteSpace;

use WordPressCS\WordPress\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Enforces spacing around logical operators and assignments, based upon Squiz code.
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.1.0
 * @since   2013-06-11 This sniff no longer supports JS.
 * @since   0.3.0      This sniff now has the ability to fix most errors it flags.
 * @since   0.7.0      This class now extends the WordPressCS native `Sniff` class.
 * @since   0.13.0     Class name changed: this class is now namespaced.
 *
 * Last synced with base class 2017-01-15 at commit b024ad84656c37ef5733c6998ebc1e60957b2277.
 * Note: This class has diverged quite far from the original. All the same, checking occasionally
 * to see if there are upstream fixes made from which this sniff can benefit, is warranted.
 * @link    https://github.com/squizlabs/PHP_CodeSniffer/blob/master/CodeSniffer/Standards/Squiz/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php
 */
class ControlStructureSpacingSniff extends Sniff {

	/**
	 * Check for blank lines on start/end of control structures.
	 *
	 * @var boolean
	 */
	public $blank_line_check = false;

	/**
	 * Check for blank lines after control structures.
	 *
	 * @var boolean
	 */
	public $blank_line_after_check = true;

	/**
	 * Require for space before T_COLON when using the alternative syntax for control structures.
	 *
	 * @var string one of 'required', 'forbidden', 'optional'
	 */
	public $space_before_colon = 'required';

	/**
	 * How many spaces should be between a T_CLOSURE and T_OPEN_PARENTHESIS.
	 *
	 * `function[*]() {...}`
	 *
	 * @since 0.7.0
	 *
	 * @var int
	 */
	public $spaces_before_closure_open_paren = -1;

	/**
	 * Tokens for which to ignore extra space on the inside of parenthesis.
	 *
	 * For functions, this is already checked by the Squiz.Functions.FunctionDeclarationArgumentSpacing sniff.
	 * For do / else / try, there are no parenthesis, so skip it.
	 *
	 * @since 0.11.0
	 *
	 * @var array
	 */
	private $ignore_extra_space_after_open_paren = array(
		\T_FUNCTION => true,
		\T_CLOSURE  => true,
		\T_DO       => true,
		\T_ELSE     => true,
		\T_TRY      => true,
	);

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @return array
	 */
	public function register() {
		return array(
			\T_IF,
			\T_WHILE,
			\T_FOREACH,
			\T_FOR,
			\T_SWITCH,
			\T_DO,
			\T_ELSE,
			\T_ELSEIF,
			\T_FUNCTION,
			\T_CLOSURE,
			\T_USE,
			\T_TRY,
			\T_CATCH,
		);
	}

	/**
	 * Processes this test, when one of its tokens is encountered.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return void
	 */
	public function process_token( $stackPtr ) {
		$this->spaces_before_closure_open_paren = (int) $this->spaces_before_closure_open_paren;

		if ( isset( $this->tokens[ ( $stackPtr + 1 ) ] ) && \T_WHITESPACE !== $this->tokens[ ( $stackPtr + 1 ) ]['code']
			&& ! ( \T_ELSE === $this->tokens[ $stackPtr ]['code'] && \T_COLON === $this->tokens[ ( $stackPtr + 1 ) ]['code'] )
			&& ! ( \T_CLOSURE === $this->tokens[ $stackPtr ]['code']
				&& 0 >= $this->spaces_before_closure_open_paren )
		) {
			$error = 'Space after opening control structure is required';
			$fix   = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceAfterStructureOpen' );

			if ( true === $fix ) {
				$this->phpcsFile->fixer->addContent( $stackPtr, ' ' );
			}
		}

		if ( ! isset( $this->tokens[ $stackPtr ]['scope_closer'] ) ) {

			if ( \T_USE === $this->tokens[ $stackPtr ]['code'] && 'closure' === $this->get_use_type( $stackPtr ) ) {
				$scopeOpener = $this->phpcsFile->findNext( \T_OPEN_CURLY_BRACKET, ( $stackPtr + 1 ) );
				$scopeCloser = $this->tokens[ $scopeOpener ]['scope_closer'];
			} elseif ( \T_WHILE !== $this->tokens[ $stackPtr ]['code'] ) {
				return;
			}
		} else {
			$scopeOpener = $this->tokens[ $stackPtr ]['scope_opener'];
			$scopeCloser = $this->tokens[ $stackPtr ]['scope_closer'];
		}

		// Alternative syntax.
		if ( isset( $scopeOpener ) && \T_COLON === $this->tokens[ $scopeOpener ]['code'] ) {

			if ( 'required' === $this->space_before_colon ) {

				if ( \T_WHITESPACE !== $this->tokens[ ( $scopeOpener - 1 ) ]['code'] ) {
					$error = 'Space between opening control structure and T_COLON is required';
					$fix   = $this->phpcsFile->addFixableError( $error, $scopeOpener, 'NoSpaceBetweenStructureColon' );

					if ( true === $fix ) {
						$this->phpcsFile->fixer->addContentBefore( $scopeOpener, ' ' );
					}
				}
			} elseif ( 'forbidden' === $this->space_before_colon ) {

				if ( \T_WHITESPACE === $this->tokens[ ( $scopeOpener - 1 ) ]['code'] ) {
					$error = 'Extra space between opening control structure and T_COLON found';
					$fix   = $this->phpcsFile->addFixableError( $error, ( $scopeOpener - 1 ), 'SpaceBetweenStructureColon' );

					if ( true === $fix ) {
						$this->phpcsFile->fixer->replaceToken( ( $scopeOpener - 1 ), '' );
					}
				}
			}
		}

		$parenthesisOpener = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );

		// If this is a function declaration.
		if ( \T_FUNCTION === $this->tokens[ $stackPtr ]['code'] ) {

			if ( \T_STRING === $this->tokens[ $parenthesisOpener ]['code'] ) {

				$function_name_ptr = $parenthesisOpener;

			} elseif ( \T_BITWISE_AND === $this->tokens[ $parenthesisOpener ]['code'] ) {

				// This function returns by reference (function &function_name() {}).
				$parenthesisOpener = $this->phpcsFile->findNext(
					Tokens::$emptyTokens,
					( $parenthesisOpener + 1 ),
					null,
					true
				);
				$function_name_ptr = $parenthesisOpener;
			}

			if ( isset( $function_name_ptr ) ) {
				$parenthesisOpener = $this->phpcsFile->findNext(
					Tokens::$emptyTokens,
					( $parenthesisOpener + 1 ),
					null,
					true
				);

				// Checking this: function my_function[*](...) {}.
				if ( ( $function_name_ptr + 1 ) !== $parenthesisOpener ) {

					$error = 'Space between function name and opening parenthesis is prohibited.';
					$fix   = $this->phpcsFile->addFixableError(
						$error,
						$stackPtr,
						'SpaceBeforeFunctionOpenParenthesis',
						$this->tokens[ ( $function_name_ptr + 1 ) ]['content']
					);

					if ( true === $fix ) {
						$this->phpcsFile->fixer->replaceToken( ( $function_name_ptr + 1 ), '' );
					}
				}
			}
		} elseif ( \T_CLOSURE === $this->tokens[ $stackPtr ]['code'] ) {

			// Check if there is a use () statement.
			if ( isset( $this->tokens[ $parenthesisOpener ]['parenthesis_closer'] ) ) {

				$usePtr = $this->phpcsFile->findNext(
					Tokens::$emptyTokens,
					( $this->tokens[ $parenthesisOpener ]['parenthesis_closer'] + 1 ),
					null,
					true,
					null,
					true
				);

				// If it is, we set that as the "scope opener".
				if ( \T_USE === $this->tokens[ $usePtr ]['code'] ) {
					$scopeOpener = $usePtr;
				}
			}
		}

		if ( \T_COLON !== $this->tokens[ $parenthesisOpener ]['code']
			&& \T_FUNCTION !== $this->tokens[ $stackPtr ]['code']
		) {

			if ( \T_CLOSURE === $this->tokens[ $stackPtr ]['code']
				&& 0 === $this->spaces_before_closure_open_paren
			) {

				if ( ( $stackPtr + 1 ) !== $parenthesisOpener ) {
					// Checking this: function[*](...) {}.
					$error = 'Space before closure opening parenthesis is prohibited';
					$fix   = $this->phpcsFile->addFixableError( $error, $stackPtr, 'SpaceBeforeClosureOpenParenthesis' );

					if ( true === $fix ) {
						$this->phpcsFile->fixer->replaceToken( ( $stackPtr + 1 ), '' );
					}
				}
			} elseif (
				(
					\T_CLOSURE !== $this->tokens[ $stackPtr ]['code']
					|| 1 === $this->spaces_before_closure_open_paren
				)
				&& ( $stackPtr + 1 ) === $parenthesisOpener
			) {

				// Checking this: if[*](...) {}.
				$error = 'No space before opening parenthesis is prohibited';
				$fix   = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceBeforeOpenParenthesis' );

				if ( true === $fix ) {
					$this->phpcsFile->fixer->addContent( $stackPtr, ' ' );
				}
			}
		}

		if ( \T_WHITESPACE === $this->tokens[ ( $stackPtr + 1 ) ]['code']
			&& ' ' !== $this->tokens[ ( $stackPtr + 1 ) ]['content']
		) {
			// Checking this: if [*](...) {}.
			$error = 'Expected exactly one space before opening parenthesis; "%s" found.';
			$fix   = $this->phpcsFile->addFixableError(
				$error,
				$stackPtr,
				'ExtraSpaceBeforeOpenParenthesis',
				$this->tokens[ ( $stackPtr + 1 ) ]['content']
			);

			if ( true === $fix ) {
				$this->phpcsFile->fixer->replaceToken( ( $stackPtr + 1 ), ' ' );
			}
		}

		if ( \T_CLOSE_PARENTHESIS !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['code'] ) {
			if ( \T_WHITESPACE !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['code'] ) {
				// Checking this: $value = my_function([*]...).
				$error = 'No space after opening parenthesis is prohibited';
				$fix   = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceAfterOpenParenthesis' );

				if ( true === $fix ) {
					$this->phpcsFile->fixer->addContent( $parenthesisOpener, ' ' );
				}
			} elseif ( ( ' ' !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['content']
				&& "\n" !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['content']
				&& "\r\n" !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['content'] )
				&& ! isset( $this->ignore_extra_space_after_open_paren[ $this->tokens[ $stackPtr ]['code'] ] )
			) {
				// Checking this: if ([*]...) {}.
				$error = 'Expected exactly one space after opening parenthesis; "%s" found.';
				$fix   = $this->phpcsFile->addFixableError(
					$error,
					$stackPtr,
					'ExtraSpaceAfterOpenParenthesis',
					$this->tokens[ ( $parenthesisOpener + 1 ) ]['content']
				);

				if ( true === $fix ) {
					$this->phpcsFile->fixer->replaceToken( ( $parenthesisOpener + 1 ), ' ' );
				}
			}
		}

		if ( isset( $this->tokens[ $parenthesisOpener ]['parenthesis_closer'] ) ) {

			$parenthesisCloser = $this->tokens[ $parenthesisOpener ]['parenthesis_closer'];

			if ( \T_CLOSE_PARENTHESIS !== $this->tokens[ ( $parenthesisOpener + 1 ) ]['code'] ) {

				// Checking this: if (...[*]) {}.
				if ( \T_WHITESPACE !== $this->tokens[ ( $parenthesisCloser - 1 ) ]['code'] ) {
					$error = 'No space before closing parenthesis is prohibited';
					$fix   = $this->phpcsFile->addFixableError( $error, $parenthesisCloser, 'NoSpaceBeforeCloseParenthesis' );

					if ( true === $fix ) {
						$this->phpcsFile->fixer->addContentBefore( $parenthesisCloser, ' ' );
					}
				} elseif ( ' ' !== $this->tokens[ ( $parenthesisCloser - 1 ) ]['content'] ) {
					$prevNonEmpty = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $parenthesisCloser - 1 ), null, true );
					if ( $this->tokens[ ( $parenthesisCloser ) ]['line'] === $this->tokens[ ( $prevNonEmpty + 1 ) ]['line'] ) {
						$error = 'Expected exactly one space before closing parenthesis; "%s" found.';
						$fix   = $this->phpcsFile->addFixableError(
							$error,
							$stackPtr,
							'ExtraSpaceBeforeCloseParenthesis',
							$this->tokens[ ( $parenthesisCloser - 1 ) ]['content']
						);

						if ( true === $fix ) {
							$this->phpcsFile->fixer->replaceToken( ( $parenthesisCloser - 1 ), ' ' );
						}
					}
				}

				if ( \T_WHITESPACE !== $this->tokens[ ( $parenthesisCloser + 1 ) ]['code']
					&& ! ( // Do NOT flag : immediately following ) for return types declarations.
						\T_COLON === $this->tokens[ ( $parenthesisCloser + 1 ) ]['code']
						&& in_array( $this->tokens[ $this->tokens[ $parenthesisCloser ]['parenthesis_owner'] ]['code'], array( \T_FUNCTION, \T_CLOSURE ), true )
					)
					&& ( isset( $scopeOpener ) && \T_COLON !== $this->tokens[ $scopeOpener ]['code'] )
				) {
					$error = 'Space between opening control structure and closing parenthesis is required';
					$fix   = $this->phpcsFile->addFixableError( $error, $scopeOpener, 'NoSpaceAfterCloseParenthesis' );

					if ( true === $fix ) {
						$this->phpcsFile->fixer->addContentBefore( $scopeOpener, ' ' );
					}
				}
			}

			// Ignore this for function declarations. Handled by the OpeningFunctionBraceKernighanRitchie sniff.
			if ( \T_FUNCTION !== $this->tokens[ $stackPtr ]['code']
				&& \T_CLOSURE !== $this->tokens[ $stackPtr ]['code']
				&& isset( $this->tokens[ $parenthesisOpener ]['parenthesis_owner'] )
				&& ( isset( $scopeOpener )
				&& $this->tokens[ $parenthesisCloser ]['line'] !== $this->tokens[ $scopeOpener ]['line'] )
			) {
				$error = 'Opening brace should be on the same line as the declaration';
				$fix   = $this->phpcsFile->addFixableError( $error, $parenthesisOpener, 'OpenBraceNotSameLine' );

				if ( true === $fix ) {
					$this->phpcsFile->fixer->beginChangeset();

					for ( $i = ( $parenthesisCloser + 1 ); $i < $scopeOpener; $i++ ) {
						$this->phpcsFile->fixer->replaceToken( $i, '' );
					}

					$this->phpcsFile->fixer->addContent( $parenthesisCloser, ' ' );
					$this->phpcsFile->fixer->endChangeset();
				}
				return;

			} elseif ( \T_WHITESPACE === $this->tokens[ ( $parenthesisCloser + 1 ) ]['code']
				&& ' ' !== $this->tokens[ ( $parenthesisCloser + 1 ) ]['content']
			) {

				// Checking this: if (...) [*]{}.
				$error = 'Expected exactly one space between closing parenthesis and opening control structure; "%s" found.';
				$fix   = $this->phpcsFile->addFixableError(
					$error,
					$stackPtr,
					'ExtraSpaceAfterCloseParenthesis',
					$this->tokens[ ( $parenthesisCloser + 1 ) ]['content']
				);

				if ( true === $fix ) {
					$this->phpcsFile->fixer->replaceToken( ( $parenthesisCloser + 1 ), ' ' );
				}
			}
		}

		if ( false !== $this->blank_line_check && isset( $scopeOpener ) ) {
			$firstContent = $this->phpcsFile->findNext( \T_WHITESPACE, ( $scopeOpener + 1 ), null, true );

			// We ignore spacing for some structures that tend to have their own rules.
			$ignore  = array(
				\T_FUNCTION             => true,
				\T_CLOSURE              => true,
				\T_DOC_COMMENT_OPEN_TAG => true,
				\T_CLOSE_TAG            => true,
				\T_COMMENT              => true,
			);
			$ignore += Tokens::$ooScopeTokens;

			if ( ! isset( $ignore[ $this->tokens[ $firstContent ]['code'] ] )
				&& $this->tokens[ $firstContent ]['line'] > ( $this->tokens[ $scopeOpener ]['line'] + 1 )
			) {
				$error = 'Blank line found at start of control structure';
				$fix   = $this->phpcsFile->addFixableError( $error, $scopeOpener, 'BlankLineAfterStart' );

				if ( true === $fix ) {
					$this->phpcsFile->fixer->beginChangeset();

					for ( $i = ( $scopeOpener + 1 ); $i < $firstContent; $i++ ) {
						if ( $this->tokens[ $i ]['line'] === $this->tokens[ $firstContent ]['line'] ) {
							break;
						}
						$this->phpcsFile->fixer->replaceToken( $i, '' );
					}

					$this->phpcsFile->fixer->addNewline( $scopeOpener );
					$this->phpcsFile->fixer->endChangeset();
				}
			}

			if ( $firstContent !== $scopeCloser ) {
				$lastContent = $this->phpcsFile->findPrevious( \T_WHITESPACE, ( $scopeCloser - 1 ), null, true );

				$lastNonEmptyContent = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $scopeCloser - 1 ), null, true );

				$checkToken = $lastContent;
				if ( isset( $this->tokens[ $lastNonEmptyContent ]['scope_condition'] ) ) {
					$checkToken = $this->tokens[ $lastNonEmptyContent ]['scope_condition'];
				}

				if ( ! isset( $ignore[ $this->tokens[ $checkToken ]['code'] ] )
					&& $this->tokens[ $lastContent ]['line'] <= ( $this->tokens[ $scopeCloser ]['line'] - 2 )
				) {
					for ( $i = ( $scopeCloser - 1 ); $i > $lastContent; $i-- ) {
						if ( $this->tokens[ $i ]['line'] < $this->tokens[ $scopeCloser ]['line']
							&& \T_OPEN_TAG !== $this->tokens[ $firstContent ]['code']
						) {
							// TODO: Reporting error at empty line won't highlight it in IDE.
							$error = 'Blank line found at end of control structure';
							$fix   = $this->phpcsFile->addFixableError( $error, $i, 'BlankLineBeforeEnd' );

							if ( true === $fix ) {
								$this->phpcsFile->fixer->beginChangeset();

								for ( $j = ( $lastContent + 1 ); $j < $scopeCloser; $j++ ) {
									if ( $this->tokens[ $j ]['line'] === $this->tokens[ $scopeCloser ]['line'] ) {
										break;
									}
									$this->phpcsFile->fixer->replaceToken( $j, '' );
								}

								/*
								 * PHPCS annotations, like normal inline comments, are tokenized including
								 * the new line at the end, so don't add any extra as it would cause a fixer
								 * conflict.
								 */
								if ( \T_COMMENT !== $this->tokens[ $lastContent ]['code']
									&& ! isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $lastContent ]['code'] ] ) ) {
									$this->phpcsFile->fixer->addNewlineBefore( $j );
								}

								$this->phpcsFile->fixer->endChangeset();
							}
							break;
						}
					}
				}
			}
			unset( $ignore );
		}

		if ( ! isset( $scopeCloser ) || true !== $this->blank_line_after_check ) {
			return;
		}

		// {@internal This is just for the blank line check. Only whitespace should be considered,
		// not "other" empty tokens.}}
		$trailingContent = $this->phpcsFile->findNext( \T_WHITESPACE, ( $scopeCloser + 1 ), null, true );
		if ( false === $trailingContent ) {
			return;
		}

		if ( \T_COMMENT === $this->tokens[ $trailingContent ]['code']
			|| isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $trailingContent ]['code'] ] )
		) {
			// Special exception for code where the comment about
			// an ELSE or ELSEIF is written between the control structures.
			$nextCode = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $scopeCloser + 1 ), null, true );

			if ( \T_ELSE === $this->tokens[ $nextCode ]['code'] || \T_ELSEIF === $this->tokens[ $nextCode ]['code'] ) {
				$trailingContent = $nextCode;
			}

			// Move past end comments.
			if ( $this->tokens[ $trailingContent ]['line'] === $this->tokens[ $scopeCloser ]['line'] ) {
				if ( preg_match( '`^//[ ]?end`i', $this->tokens[ $trailingContent ]['content'], $matches ) > 0 ) {
					$scopeCloser     = $trailingContent;
					$trailingContent = $this->phpcsFile->findNext( \T_WHITESPACE, ( $trailingContent + 1 ), null, true );
				}
			}
		}

		if ( \T_ELSE === $this->tokens[ $trailingContent ]['code'] && \T_IF === $this->tokens[ $stackPtr ]['code'] ) {
			// IF with ELSE.
			return;
		}

		if ( \T_WHILE === $this->tokens[ $trailingContent ]['code'] && \T_DO === $this->tokens[ $stackPtr ]['code'] ) {
			// DO with WHILE.
			return;
		}

		if ( \T_CLOSE_TAG === $this->tokens[ $trailingContent ]['code'] ) {
			// At the end of the script or embedded code.
			return;
		}

		if ( isset( $this->tokens[ $trailingContent ]['scope_condition'] )
			&& \T_CLOSE_CURLY_BRACKET === $this->tokens[ $trailingContent ]['code']
		) {
			// Another control structure's closing brace.
			$owner = $this->tokens[ $trailingContent ]['scope_condition'];
			if ( \in_array( $this->tokens[ $owner ]['code'], array( \T_FUNCTION, \T_CLOSURE, \T_CLASS, \T_ANON_CLASS, \T_INTERFACE, \T_TRAIT ), true ) ) {
				// The next content is the closing brace of a function, class, interface or trait
				// so normal function/class rules apply and we can ignore it.
				return;
			}

			if ( ( $this->tokens[ $scopeCloser ]['line'] + 1 ) !== $this->tokens[ $trailingContent ]['line'] ) {
				// TODO: Won't cover following case: "} echo 'OK';".
				$error = 'Blank line found after control structure';
				$fix   = $this->phpcsFile->addFixableError( $error, $scopeCloser, 'BlankLineAfterEnd' );

				if ( true === $fix ) {
					$this->phpcsFile->fixer->beginChangeset();

					$i = ( $scopeCloser + 1 );
					while ( $this->tokens[ $i ]['line'] !== $this->tokens[ $trailingContent ]['line'] ) {
						$this->phpcsFile->fixer->replaceToken( $i, '' );
						$i++;
					}

					// TODO: Instead a separate error should be triggered when content comes right after closing brace.
					if ( \T_COMMENT !== $this->tokens[ $scopeCloser ]['code']
						&& isset( Tokens::$phpcsCommentTokens[ $this->tokens[ $scopeCloser ]['code'] ] ) === false
					) {
						$this->phpcsFile->fixer->addNewlineBefore( $trailingContent );
					}
					$this->phpcsFile->fixer->endChangeset();
				}
			}
		}
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\WP;

use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff;

/**
 * Restricts the use of various deprecated WordPress functions and suggests alternatives.
 *
 * This sniff will throw an error when usage of deprecated functions is detected
 * if the function was deprecated before the minimum supported WP version;
 * a warning otherwise.
 * By default, it is set to presume that a project will support the current
 * WP version and up to three releases before.
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.11.0
 * @since   0.13.0 Class name changed: this class is now namespaced.
 * @since   0.14.0 Now has the ability to handle minimum supported WP version
 *                 being provided via the command-line or as as <config> value
 *                 in a custom ruleset.
 *
 * @uses    \WordPressCS\WordPress\Sniff::$minimum_supported_version
 */
class DeprecatedFunctionsSniff extends AbstractFunctionRestrictionsSniff {

	/**
	 * List of deprecated functions with alternative when available.
	 *
	 * To be updated after every major release.
	 * Last updated for WordPress 4.8.
	 *
	 * Version numbers should be fully qualified.
	 * Replacement functions should have parentheses.
	 *
	 * To retrieve a function list for comparison, the following tool is available:
	 * https://github.com/JDGrimes/wp-deprecated-code-scanner
	 *
	 * @var array
	 */
	private $deprecated_functions = array(

		// WP 0.71.
		'the_category_head' => array(
			'alt'     => 'get_the_category_by_ID()',
			'version' => '0.71',
		),
		'the_category_ID' => array(
			'alt'     => 'get_the_category()',
			'version' => '0.71',
		),

		// WP 1.2.0.
		'permalink_link' => array(
			'alt'     => 'the_permalink()',
			'version' => '1.2.0',
		),

		// WP 1.5.0.
		'start_wp' => array(
			// Verified correct alternative.
			'alt'     => 'the Loop',
			'version' => '1.5.0',
		),

		// WP 1.5.1.
		'get_postdata' => array(
			'alt'     => 'get_post()',
			'version' => '1.5.1',
		),

		// WP 2.0.0.
		'create_user' => array(
			'alt'     => 'wp_create_user()',
			'version' => '2.0.0',
		),
		'next_post' => array(
			'alt'     => 'next_post_link()',
			'version' => '2.0.0',
		),
		'previous_post' => array(
			'alt'     => 'previous_post_link()',
			'version' => '2.0.0',
		),
		'user_can_create_draft' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_create_post' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_delete_post' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_delete_post_comments' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_edit_post' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_edit_post_comments' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_edit_post_date' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_edit_user' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),
		'user_can_set_post_date' => array(
			'alt'     => 'current_user_can()',
			'version' => '2.0.0',
		),

		// WP 2.1.0.
		'dropdown_cats' => array(
			'alt'     => 'wp_dropdown_categories()',
			'version' => '2.1.0',
		),
		'get_archives' => array(
			'alt'     => 'wp_get_archives()',
			'version' => '2.1.0',
		),
		'get_author_link' => array(
			'alt'     => 'get_author_posts_url()',
			'version' => '2.1.0',
		),
		'get_autotoggle' => array(
			'alt'     => '',
			'version' => '2.1.0',
		),
		'get_link' => array(
			'alt'     => 'get_bookmark()',
			'version' => '2.1.0',
		),
		'get_linkcatname' => array(
			'alt'     => 'get_category()',
			'version' => '2.1.0',
		),
		'get_linkobjects' => array(
			'alt'     => 'get_bookmarks()',
			'version' => '2.1.0',
		),
		'get_linkobjectsbyname' => array(
			'alt'     => 'get_bookmarks()',
			'version' => '2.1.0',
		),
		'get_linkrating' => array(
			'alt'     => 'sanitize_bookmark_field()',
			'version' => '2.1.0',
		),
		'get_links' => array(
			'alt'     => 'get_bookmarks()',
			'version' => '2.1.0',
		),
		'get_links_list' => array(
			'alt'     => 'wp_list_bookmarks()',
			'version' => '2.1.0',
		),
		'get_links_withrating' => array(
			'alt'     => 'get_bookmarks()',
			'version' => '2.1.0',
		),
		'get_linksbyname' => array(
			'alt'     => 'get_bookmarks()',
			'version' => '2.1.0',
		),
		'get_linksbyname_withrating' => array(
			'alt'     => 'get_bookmarks()',
			'version' => '2.1.0',
		),
		'get_settings' => array(
			'alt'     => 'get_option()',
			'version' => '2.1.0',
		),
		'link_pages' => array(
			'alt'     => 'wp_link_pages()',
			'version' => '2.1.0',
		),
		'links_popup_script' => array(
			'alt'     => '',
			'version' => '2.1.0',
		),
		'list_authors' => array(
			'alt'     => 'wp_list_authors()',
			'version' => '2.1.0',
		),
		'list_cats' => array(
			'alt'     => 'wp_list_categories()',
			'version' => '2.1.0',
		),
		'tinymce_include' => array(
			'alt'     => 'wp_editor()',
			'version' => '2.1.0',
		),
		'wp_get_links' => array(
			'alt'     => 'wp_list_bookmarks()',
			'version' => '2.1.0',
		),
		'wp_get_linksbyname' => array(
			'alt'     => 'wp_list_bookmarks()',
			'version' => '2.1.0',
		),
		'wp_get_post_cats' => array(
			'alt'     => 'wp_get_post_categories()',
			'version' => '2.1.0',
		),
		'wp_list_cats' => array(
			'alt'     => 'wp_list_categories()',
			'version' => '2.1.0',
		),
		'wp_set_post_cats' => array(
			'alt'     => 'wp_set_post_categories()',
			'version' => '2.1.0',
		),

		// WP 2.2.0.
		'comments_rss' => array(
			'alt'     => 'get_post_comments_feed_link()',
			'version' => '2.2.0',
		),

		// WP 2.3.0.
		'permalink_single_rss' => array(
			'alt'     => 'the_permalink_rss()',
			'version' => '2.3.0',
		),

		// WP 2.5.0.
		'comments_rss_link' => array(
			'alt'     => 'post_comments_feed_link()',
			'version' => '2.5.0',
		),
		'documentation_link' => array(
			'alt'     => '',
			'version' => '2.5.0',
		),
		'get_attachment_icon' => array(
			'alt'     => 'wp_get_attachment_image()',
			'version' => '2.5.0',
		),
		'get_attachment_icon_src' => array(
			'alt'     => 'wp_get_attachment_image_src()',
			'version' => '2.5.0',
		),
		'get_attachment_innerHTML' => array(
			'alt'     => 'wp_get_attachment_image()',
			'version' => '2.5.0',
		),
		'get_author_rss_link' => array(
			'alt'     => 'get_author_feed_link()',
			'version' => '2.5.0',
		),
		'get_category_rss_link' => array(
			'alt'     => 'get_category_feed_link()',
			'version' => '2.5.0',
		),
		'get_the_attachment_link' => array(
			'alt'     => 'wp_get_attachment_link()',
			'version' => '2.5.0',
		),
		'gzip_compression' => array(
			'alt'     => '',
			'version' => '2.5.0',
		),
		'wp_clearcookie' => array(
			'alt'     => 'wp_clear_auth_cookie()',
			'version' => '2.5.0',
		),
		'wp_get_cookie_login' => array(
			'alt'     => '',
			'version' => '2.5.0',
		),
		'wp_login' => array(
			'alt'     => 'wp_signon()',
			'version' => '2.5.0',
		),
		'wp_setcookie' => array(
			'alt'     => 'wp_set_auth_cookie()',
			'version' => '2.5.0',
		),

		// WP 2.6.0.
		'dropdown_categories' => array(
			'alt'     => 'wp_category_checklist()',
			'version' => '2.6.0',
		),
		'dropdown_link_categories' => array(
			'alt'     => 'wp_link_category_checklist()',
			'version' => '2.6.0',
		),

		// WP 2.7.0.
		'get_commentdata' => array(
			'alt'     => 'get_comment()',
			'version' => '2.7.0',
		),
		// This is a method i.e. WP_Filesystem_Base::find_base_dir() See #731.
		'find_base_dir' => array(
			'alt'     => 'WP_Filesystem::abspath()',
			'version' => '2.7.0',
		),
		// This is a method i.e. WP_Filesystem_Base::get_base_dir() See #731.
		'get_base_dir' => array(
			'alt'     => 'WP_Filesystem::abspath()',
			'version' => '2.7.0',
		),

		// WP 2.8.0.
		'__ngettext' => array(
			'alt'     => '_n()',
			'version' => '2.8.0',
		),
		'__ngettext_noop' => array(
			'alt'     => '_n_noop()',
			'version' => '2.8.0',
		),
		'attribute_escape' => array(
			'alt'     => 'esc_attr()',
			'version' => '2.8.0',
		),
		'get_author_name' => array(
			'alt'     => 'get_the_author_meta(\'display_name\')',
			'version' => '2.8.0',
		),
		'get_category_children' => array(
			'alt'     => 'get_term_children()',
			'version' => '2.8.0',
		),
		'get_catname' => array(
			'alt'     => 'get_cat_name()',
			'version' => '2.8.0',
		),
		'get_the_author_aim' => array(
			'alt'     => 'get_the_author_meta(\'aim\')',
			'version' => '2.8.0',
		),
		'get_the_author_description' => array(
			'alt'     => 'get_the_author_meta(\'description\')',
			'version' => '2.8.0',
		),
		'get_the_author_email' => array(
			'alt'     => 'get_the_author_meta(\'email\')',
			'version' => '2.8.0',
		),
		'get_the_author_firstname' => array(
			'alt'     => 'get_the_author_meta(\'first_name\')',
			'version' => '2.8.0',
		),
		'get_the_author_icq' => array(
			'alt'     => 'get_the_author_meta(\'icq\')',
			'version' => '2.8.0',
		),
		'get_the_author_ID' => array(
			'alt'     => 'get_the_author_meta(\'ID\')',
			'version' => '2.8.0',
		),
		'get_the_author_lastname' => array(
			'alt'     => 'get_the_author_meta(\'last_name\')',
			'version' => '2.8.0',
		),
		'get_the_author_login' => array(
			'alt'     => 'get_the_author_meta(\'login\')',
			'version' => '2.8.0',
		),
		'get_the_author_msn' => array(
			'alt'     => 'get_the_author_meta(\'msn\')',
			'version' => '2.8.0',
		),
		'get_the_author_nickname' => array(
			'alt'     => 'get_the_author_meta(\'nickname\')',
			'version' => '2.8.0',
		),
		'get_the_author_url' => array(
			'alt'     => 'get_the_author_meta(\'url\')',
			'version' => '2.8.0',
		),
		'get_the_author_yim' => array(
			'alt'     => 'get_the_author_meta(\'yim\')',
			'version' => '2.8.0',
		),
		'js_escape' => array(
			'alt'     => 'esc_js()',
			'version' => '2.8.0',
		),
		'register_sidebar_widget' => array(
			'alt'     => 'wp_register_sidebar_widget()',
			'version' => '2.8.0',
		),
		'register_widget_control' => array(
			'alt'     => 'wp_register_widget_control()',
			'version' => '2.8.0',
		),
		'sanitize_url' => array(
			'alt'     => 'esc_url_raw()',
			'version' => '2.8.0',
		),
		'the_author_aim' => array(
			'alt'     => 'the_author_meta(\'aim\')',
			'version' => '2.8.0',
		),
		'the_author_description' => array(
			'alt'     => 'the_author_meta(\'description\')',
			'version' => '2.8.0',
		),
		'the_author_email' => array(
			'alt'     => 'the_author_meta(\'email\')',
			'version' => '2.8.0',
		),
		'the_author_firstname' => array(
			'alt'     => 'the_author_meta(\'first_name\')',
			'version' => '2.8.0',
		),
		'the_author_icq' => array(
			'alt'     => 'the_author_meta(\'icq\')',
			'version' => '2.8.0',
		),
		'the_author_ID' => array(
			'alt'     => 'the_author_meta(\'ID\')',
			'version' => '2.8.0',
		),
		'the_author_lastname' => array(
			'alt'     => 'the_author_meta(\'last_name\')',
			'version' => '2.8.0',
		),
		'the_author_login' => array(
			'alt'     => 'the_author_meta(\'login\')',
			'version' => '2.8.0',
		),
		'the_author_msn' => array(
			'alt'     => 'the_author_meta(\'msn\')',
			'version' => '2.8.0',
		),
		'the_author_nickname' => array(
			'alt'     => 'the_author_meta(\'nickname\')',
			'version' => '2.8.0',
		),
		'the_author_url' => array(
			'alt'     => 'the_author_meta(\'url\')',
			'version' => '2.8.0',
		),
		'the_author_yim' => array(
			'alt'     => 'the_author_meta(\'yim\')',
			'version' => '2.8.0',
		),
		'unregister_sidebar_widget' => array(
			'alt'     => 'wp_unregister_sidebar_widget()',
			'version' => '2.8.0',
		),
		'unregister_widget_control' => array(
			'alt'     => 'wp_unregister_widget_control()',
			'version' => '2.8.0',
		),
		'wp_specialchars' => array(
			'alt'     => 'esc_html()',
			'version' => '2.8.0',
		),

		// WP 2.9.0.
		'_c' => array(
			'alt'     => '_x()',
			'version' => '2.9.0',
		),
		'_nc' => array(
			'alt'     => '_nx()',
			'version' => '2.9.0',
		),
		'get_real_file_to_edit' => array(
			'alt'     => '',
			'version' => '2.9.0',
		),
		'make_url_footnote' => array(
			'alt'     => '',
			'version' => '2.9.0',
		),
		'the_content_rss' => array(
			'alt'     => 'the_content_feed()',
			'version' => '2.9.0',
		),
		'translate_with_context' => array(
			'alt'     => '_x()',
			'version' => '2.9.0',
		),

		// WP 3.0.0.
		'activate_sitewide_plugin' => array(
			'alt'     => 'activate_plugin()',
			'version' => '3.0.0',
		),
		'add_option_update_handler' => array(
			'alt'     => 'register_setting()',
			'version' => '3.0.0',
		),
		'automatic_feed_links' => array(
			'alt'     => 'add_theme_support( \'automatic-feed-links\' )',
			'version' => '3.0.0',
		),
		'clean_url' => array(
			'alt'     => 'esc_url()',
			'version' => '3.0.0',
		),
		'clear_global_post_cache' => array(
			'alt'     => 'clean_post_cache()',
			'version' => '3.0.0',
		),
		'codepress_footer_js' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'codepress_get_lang' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'deactivate_sitewide_plugin' => array(
			'alt'     => 'deactivate_plugin()',
			'version' => '3.0.0',
		),
		'delete_usermeta' => array(
			'alt'     => 'delete_user_meta()',
			'version' => '3.0.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'funky_javascript_callback' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'funky_javascript_fix' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'generate_random_password' => array(
			'alt'     => 'wp_generate_password()',
			'version' => '3.0.0',
		),
		'get_alloptions' => array(
			'alt'     => 'wp_load_alloptions()',
			'version' => '3.0.0',
		),
		'get_blog_list' => array(
			'alt'     => 'wp_get_sites()',
			'version' => '3.0.0',
		),
		'get_most_active_blogs' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'get_profile' => array(
			'alt'     => 'get_the_author_meta()',
			'version' => '3.0.0',
		),
		'get_user_details' => array(
			'alt'     => 'get_user_by()',
			'version' => '3.0.0',
		),
		'get_usermeta' => array(
			'alt'     => 'get_user_meta()',
			'version' => '3.0.0',
		),
		'get_usernumposts' => array(
			'alt'     => 'count_user_posts()',
			'version' => '3.0.0',
		),
		'graceful_fail' => array(
			'alt'     => 'wp_die()',
			'version' => '3.0.0',
		),
		// Verified version & alternative.
		'install_blog_defaults' => array(
			'alt'     => 'wp_install_defaults',
			'version' => '3.0.0',
		),
		'is_main_blog' => array(
			'alt'     => 'is_main_site()',
			'version' => '3.0.0',
		),
		'is_site_admin' => array(
			'alt'     => 'is_super_admin()',
			'version' => '3.0.0',
		),
		'is_taxonomy' => array(
			'alt'     => 'taxonomy_exists()',
			'version' => '3.0.0',
		),
		'is_term' => array(
			'alt'     => 'term_exists()',
			'version' => '3.0.0',
		),
		'is_wpmu_sitewide_plugin' => array(
			'alt'     => 'is_network_only_plugin()',
			'version' => '3.0.0',
		),
		'mu_options' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'remove_option_update_handler' => array(
			'alt'     => 'unregister_setting()',
			'version' => '3.0.0',
		),
		'set_current_user' => array(
			'alt'     => 'wp_set_current_user()',
			'version' => '3.0.0',
		),
		'update_usermeta' => array(
			'alt'     => 'update_user_meta()',
			'version' => '3.0.0',
		),
		'use_codepress' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),
		'validate_email' => array(
			'alt'     => 'is_email()',
			'version' => '3.0.0',
		),
		'wp_dropdown_cats' => array(
			'alt'     => 'wp_dropdown_categories()',
			'version' => '3.0.0',
		),
		'wp_shrink_dimensions' => array(
			'alt'     => 'wp_constrain_dimensions()',
			'version' => '3.0.0',
		),
		'wpmu_checkAvailableSpace' => array(
			'alt'     => 'is_upload_space_available()',
			'version' => '3.0.0',
		),
		'wpmu_menu' => array(
			'alt'     => '',
			'version' => '3.0.0',
		),

		// WP 3.1.0.
		'get_author_user_ids' => array(
			'alt'     => 'get_users()',
			'version' => '3.1.0',
		),
		'get_dashboard_blog' => array(
			'alt'     => 'get_site()',
			'version' => '3.1.0',
		),
		'get_editable_authors' => array(
			'alt'     => 'get_users()',
			'version' => '3.1.0',
		),
		'get_editable_user_ids' => array(
			'alt'     => 'get_users()',
			'version' => '3.1.0',
		),
		'get_nonauthor_user_ids' => array(
			'alt'     => 'get_users()',
			'version' => '3.1.0',
		),
		'get_others_drafts' => array(
			'alt'     => '',
			'version' => '3.1.0',
		),
		'get_others_pending' => array(
			'alt'     => '',
			'version' => '3.1.0',
		),
		'get_others_unpublished_posts' => array(
			'alt'     => '',
			'version' => '3.1.0',
		),
		'get_users_of_blog' => array(
			'alt'     => 'get_users()',
			'version' => '3.1.0',
		),
		'install_themes_feature_list' => array(
			'alt'     => 'get_theme_feature_list()',
			'version' => '3.1.0',
		),
		'is_plugin_page' => array(
			// Verified correct alternative.
			'alt'     => 'global $plugin_page and/or get_plugin_page_hookname() hooks',
			'version' => '3.1.0',
		),
		'update_category_cache' => array(
			'alt'     => '',
			'version' => '3.1.0',
		),

		// WP 3.2.0.
		'favorite_actions' => array(
			'alt'     => 'WP_Admin_Bar',
			'version' => '3.2.0',
		),
		'wp_dashboard_quick_press_output' => array(
			'alt'     => 'wp_dashboard_quick_press()',
			'version' => '3.2.0',
		),
		'wp_timezone_supported' => array(
			'alt'     => '',
			'version' => '3.2.0',
		),

		// WP 3.3.0.
		'add_contextual_help' => array(
			'alt'     => 'get_current_screen()->add_help_tab()',
			'version' => '3.3.0',
		),
		'get_boundary_post_rel_link' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'get_index_rel_link' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'get_parent_post_rel_link' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'get_user_by_email' => array(
			'alt'     => 'get_user_by(\'email\')',
			'version' => '3.3.0',
		),
		'get_user_metavalues' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'get_userdatabylogin' => array(
			'alt'     => 'get_user_by(\'login\')',
			'version' => '3.3.0',
		),
		'index_rel_link' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'is_blog_user' => array(
			'alt'     => 'is_user_member_of_blog()',
			'version' => '3.3.0',
		),
		'media_upload_audio' => array(
			'alt'     => 'wp_media_upload_handler()',
			'version' => '3.3.0',
		),
		'media_upload_file' => array(
			'alt'     => 'wp_media_upload_handler()',
			'version' => '3.3.0',
		),
		'media_upload_image' => array(
			'alt'     => 'wp_media_upload_handler()',
			'version' => '3.3.0',
		),
		'media_upload_video' => array(
			'alt'     => 'wp_media_upload_handler()',
			'version' => '3.3.0',
		),
		'parent_post_rel_link' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'sanitize_user_object' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'screen_layout' => array(
			'alt'     => '$current_screen->render_screen_layout()',
			'version' => '3.3.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'screen_meta' => array(
			'alt'     => '$current_screen->render_screen_meta()',
			'version' => '3.3.0',
		),
		'screen_options' => array(
			'alt'     => '$current_screen->render_per_page_options()',
			'version' => '3.3.0',
		),
		'start_post_rel_link' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'the_editor' => array(
			'alt'     => 'wp_editor()',
			'version' => '3.3.0',
		),
		'type_url_form_audio' => array(
			'alt'     => 'wp_media_insert_url_form(\'audio\')',
			'version' => '3.3.0',
		),
		'type_url_form_file' => array(
			'alt'     => 'wp_media_insert_url_form(\'file\')',
			'version' => '3.3.0',
		),
		'type_url_form_image' => array(
			'alt'     => 'wp_media_insert_url_form(\'image\')',
			'version' => '3.3.0',
		),
		'type_url_form_video' => array(
			'alt'     => 'wp_media_insert_url_form(\'video\')',
			'version' => '3.3.0',
		),
		'wp_admin_bar_dashboard_view_site_menu' => array(
			'alt'     => '',
			'version' => '3.3.0',
		),
		'wp_preload_dialogs' => array(
			'alt'     => 'wp_editor()',
			'version' => '3.3.0',
		),
		'wp_print_editor_js' => array(
			'alt'     => 'wp_editor()',
			'version' => '3.3.0',
		),
		'wp_quicktags' => array(
			'alt'     => 'wp_editor()',
			'version' => '3.3.0',
		),
		'wp_tiny_mce' => array(
			'alt'     => 'wp_editor()',
			'version' => '3.3.0',
		),
		'wpmu_admin_do_redirect' => array(
			'alt'     => 'wp_redirect()',
			'version' => '3.3.0',
		),
		'wpmu_admin_redirect_add_updated_param' => array(
			'alt'     => 'add_query_arg()',
			'version' => '3.3.0',
		),

		// WP 3.4.0.
		'add_custom_background' => array(
			'alt'     => 'add_theme_support( \'custom-background\', $args )',
			'version' => '3.4.0',
		),
		'add_custom_image_header' => array(
			'alt'     => 'add_theme_support( \'custom-header\', $args )',
			'version' => '3.4.0',
		),
		'clean_page_cache' => array(
			'alt'     => 'clean_post_cache()',
			'version' => '3.4.0',
		),
		'clean_pre' => array(
			'alt'     => '',
			'version' => '3.4.0',
		),
		'current_theme_info' => array(
			'alt'     => 'wp_get_theme()',
			'version' => '3.4.0',
		),
		'debug_fclose' => array(
			'alt'     => 'error_log()',
			'version' => '3.4.0',
		),
		'debug_fopen' => array(
			'alt'     => 'error_log()',
			'version' => '3.4.0',
		),
		'debug_fwrite' => array(
			'alt'     => 'error_log()',
			'version' => '3.4.0',
		),
		'display_theme' => array(
			'alt'     => '',
			'version' => '3.4.0',
		),
		'get_allowed_themes' => array(
			'alt'     => 'wp_get_themes( array( \'allowed\' => true ) )',
			'version' => '3.4.0',
		),
		'get_broken_themes' => array(
			'alt'     => 'wp_get_themes( array( \'errors\' => true )',
			'version' => '3.4.0',
		),
		'get_current_theme' => array(
			'alt'     => 'wp_get_theme()',
			'version' => '3.4.0',
		),
		'get_site_allowed_themes' => array(
			'alt'     => 'WP_Theme::get_allowed_on_network()',
			'version' => '3.4.0',
		),
		'get_theme' => array(
			'alt'     => 'wp_get_theme( $stylesheet )',
			'version' => '3.4.0',
		),
		'get_theme_data' => array(
			'alt'     => 'wp_get_theme()',
			'version' => '3.4.0',
		),
		'get_themes' => array(
			'alt'     => 'wp_get_themes()',
			'version' => '3.4.0',
		),
		'logIO' => array(
			'alt'     => 'error_log()',
			'version' => '3.4.0',
		),
		'remove_custom_background' => array(
			'alt'     => 'remove_theme_support( \'custom-background\' )',
			'version' => '3.4.0',
		),
		'remove_custom_image_header' => array(
			'alt'     => 'remove_theme_support( \'custom-header\' )',
			'version' => '3.4.0',
		),
		'update_page_cache' => array(
			'alt'     => 'update_post_cache()',
			'version' => '3.4.0',
		),
		'wpmu_get_blog_allowedthemes' => array(
			'alt'     => 'WP_Theme::get_allowed_on_site()',
			'version' => '3.4.0',
		),

		// WP 3.4.1.
		'wp_explain_nonce' => array(
			'alt'     => 'wp_nonce_ays()',
			'version' => '3.4.1',
		),

		// WP 3.5.0.
		'_flip_image_resource' => array(
			'alt'     => 'WP_Image_Editor::flip()',
			'version' => '3.5.0',
		),
		'_get_post_ancestors' => array(
			'alt'     => '',
			'version' => '3.5.0',
		),
		'_insert_into_post_button' => array(
			'alt'     => '',
			'version' => '3.5.0',
		),
		'_media_button' => array(
			'alt'     => '',
			'version' => '3.5.0',
		),
		'_rotate_image_resource' => array(
			'alt'     => 'WP_Image_Editor::rotate()',
			'version' => '3.5.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'_save_post_hook' => array(
			'alt'     => '',
			'version' => '3.5.0',
		),
		'gd_edit_image_support' => array(
			'alt'     => 'wp_image_editor_supports()',
			'version' => '3.5.0',
		),
		'get_default_page_to_edit' => array(
			'alt'     => 'get_default_post_to_edit( \'page\' )',
			'version' => '3.5.0',
		),
		'get_post_to_edit' => array(
			'alt'     => 'get_post()',
			'version' => '3.5.0',
		),
		'get_udims' => array(
			'alt'     => 'wp_constrain_dimensions()',
			'version' => '3.5.0',
		),
		'image_resize' => array(
			'alt'     => 'wp_get_image_editor()',
			'version' => '3.5.0',
		),
		'sticky_class' => array(
			'alt'     => 'post_class()',
			'version' => '3.5.0',
		),
		'user_pass_ok' => array(
			'alt'     => 'wp_authenticate()',
			'version' => '3.5.0',
		),
		'wp_cache_reset' => array(
			'alt'     => 'WP_Object_Cache::reset()',
			'version' => '3.5.0',
		),
		'wp_create_thumbnail' => array(
			'alt'     => 'image_resize()',
			'version' => '3.5.0',
		),
		'wp_get_single_post' => array(
			'alt'     => 'get_post()',
			'version' => '3.5.0',
		),
		'wp_load_image' => array(
			'alt'     => 'wp_get_image_editor()',
			'version' => '3.5.0',
		),

		// WP 3.6.0.
		'get_user_id_from_string' => array(
			'alt'     => 'get_user_by()',
			'version' => '3.6.0',
		),
		'wp_convert_bytes_to_hr' => array(
			'alt'     => 'size_format()',
			'version' => '3.6.0',
		),
		'wp_nav_menu_locations_meta_box' => array(
			'alt'     => '',
			'version' => '3.6.0',
		),

		// WP 3.7.0.
		'_search_terms_tidy' => array(
			'alt'     => '',
			'version' => '3.7.0',
		),
		'get_blogaddress_by_domain' => array(
			'alt'     => '',
			'version' => '3.7.0',
		),
		'the_attachment_links' => array(
			'alt'     => '',
			'version' => '3.7.0',
		),
		'wp_update_core' => array(
			'alt'     => 'new Core_Upgrader();',
			'version' => '3.7.0',
		),
		'wp_update_plugin' => array(
			'alt'     => 'new Plugin_Upgrader();',
			'version' => '3.7.0',
		),
		'wp_update_theme' => array(
			'alt'     => 'new Theme_Upgrader();',
			'version' => '3.7.0',
		),

		// WP 3.8.0.
		'get_screen_icon' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		'screen_icon' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_incoming_links' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_incoming_links_control' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_incoming_links_output' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_plugins' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_primary_control' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_recent_comments_control' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_secondary' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_secondary_control' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_dashboard_secondary_output' => array(
			'alt'     => '',
			'version' => '3.8.0',
		),

		// WP 3.9.0.
		'_relocate_children' => array(
			'alt'     => '',
			'version' => '3.9.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'default_topic_count_text' => array(
			'alt'     => '',
			'version' => '3.9.0',
		),
		'format_to_post' => array(
			'alt'     => '',
			'version' => '3.9.0',
		),
		'get_current_site_name' => array(
			'alt'     => 'get_current_site()',
			'version' => '3.9.0',
		),
		'rich_edit_exists' => array(
			'alt'     => '',
			'version' => '3.9.0',
		),
		'wpmu_current_site' => array(
			'alt'     => '',
			'version' => '3.9.0',
		),

		// WP 4.0.0.
		'get_all_category_ids' => array(
			'alt'     => 'get_terms()',
			'version' => '4.0.0',
		),
		'like_escape' => array(
			'alt'     => 'wpdb::esc_like()',
			'version' => '4.0.0',
		),
		'url_is_accessable_via_ssl' => array(
			'alt'     => '',
			'version' => '4.0.0',
		),

		// WP 4.1.0.
		// This is a method from the WP_Customize_Image_Control class. See #731.
		'add_tab' => array(
			'alt'     => '',
			'version' => '4.1.0',
		),
		// This is a method from the WP_Customize_Image_Control class. See #731.
		'prepare_control' => array(
			'alt'     => '',
			'version' => '4.1.0',
		),
		// This is a method from the WP_Customize_Image_Control class. See #731.
		'print_tab_image' => array(
			'alt'     => '',
			'version' => '4.1.0',
		),
		// This is a method from the WP_Customize_Image_Control class. See #731.
		'remove_tab' => array(
			'alt'     => '',
			'version' => '4.1.0',
		),

		// WP 4.2.0.
		// This is a method from the WP_Customize_Widgets class. See #731.
		'prepreview_added_sidebars_widgets' => array(
			'alt'     => 'the \'customize_dynamic_setting_args\' filter',
			'version' => '4.2.0',
		),
		// This is a method from the WP_Customize_Widgets class. See #731.
		'prepreview_added_widget_instance' => array(
			'alt'     => 'the \'customize_dynamic_setting_args\' filter',
			'version' => '4.2.0',
		),
		// This is a method from the WP_Customize_Widgets class. See #731.
		'remove_prepreview_filters' => array(
			'alt'     => 'the \'customize_dynamic_setting_args\' filter',
			'version' => '4.2.0',
		),
		// This is a method from the WP_Customize_Widgets class. See #731.
		'setup_widget_addition_previews' => array(
			'alt'     => 'the \'customize_dynamic_setting_args\' filter',
			'version' => '4.2.0',
		),

		// WP 4.3.0.
		'_preview_theme_stylesheet_filter' => array(
			'alt'     => '',
			'version' => '4.3.0',
		),
		'_preview_theme_template_filter' => array(
			'alt'     => '',
			'version' => '4.3.0',
		),
		'preview_theme' => array(
			'alt'     => '',
			'version' => '4.3.0',
		),
		'preview_theme_ob_filter' => array(
			'alt'     => '',
			'version' => '4.3.0',
		),
		'preview_theme_ob_filter_callback' => array(
			'alt'     => '',
			'version' => '4.3.0',
		),
		// Verified; see https://core.trac.wordpress.org/ticket/41121, patch 3.
		'wp_ajax_wp_fullscreen_save_post' => array(
			'alt'     => '',
			'version' => '4.3.0',
		),
		'wp_htmledit_pre' => array(
			'alt'     => 'format_for_editor()',
			'version' => '4.3.0',
		),
		'wp_richedit_pre' => array(
			'alt'     => 'format_for_editor()',
			'version' => '4.3.0',
		),

		// WP 4.4.0.
		'create_empty_blog' => array(
			'alt'     => '',
			'version' => '4.4.0',
		),
		'force_ssl_login' => array(
			'alt'     => 'force_ssl_admin()',
			'version' => '4.4.0',
		),
		'get_admin_users_for_domain' => array(
			'alt'     => '',
			'version' => '4.4.0',
		),
		'post_permalink' => array(
			'alt'     => 'get_permalink()',
			'version' => '4.4.0',
		),
		'wp_get_http' => array(
			'alt'     => 'the WP_Http class',
			'version' => '4.4.0',
		),
		// This is a method i.e. WP_Widget_Recent_Comments::flush_widget_cache() See #731.
		'flush_widget_cache' => array(
			'alt'     => '',
			'version' => '4.4.0',
		),

		// WP 4.5.0.
		'add_object_page' => array(
			'alt'     => 'add_menu_page()',
			'version' => '4.5.0',
		),
		'add_utility_page' => array(
			'alt'     => 'add_menu_page()',
			'version' => '4.5.0',
		),
		'comments_popup_script' => array(
			'alt'     => '',
			'version' => '4.5.0',
		),
		'get_comments_popup_template' => array(
			'alt'     => '',
			'version' => '4.5.0',
		),
		'get_currentuserinfo' => array(
			'alt'     => 'wp_get_current_user()',
			'version' => '4.5.0',
		),
		'is_comments_popup' => array(
			'alt'     => '',
			'version' => '4.5.0',
		),
		'popuplinks' => array(
			'alt'     => '',
			'version' => '4.5.0',
		),

		// WP 4.6.0.
		'post_form_autocomplete_off' => array(
			'alt'     => '',
			'version' => '4.6.0',
		),
		'wp_embed_handler_googlevideo' => array(
			'alt'     => '',
			'version' => '4.6.0',
		),
		'wp_get_sites' => array(
			'alt'     => 'get_sites()',
			'version' => '4.6.0',
		),

		// WP 4.7.0.
		'_sort_nav_menu_items' => array(
			'alt'     => 'wp_list_sort()',
			'version' => '4.7.0',
		),
		'_usort_terms_by_ID' => array(
			'alt'     => 'wp_list_sort()',
			'version' => '4.7.0',
		),
		'_usort_terms_by_name' => array(
			'alt'     => 'wp_list_sort()',
			'version' => '4.7.0',
		),
		'get_paged_template' => array(
			'alt'     => '',
			'version' => '4.7.0',
		),
		'wp_get_network' => array(
			'alt'     => 'get_network()',
			'version' => '4.7.0',
		),
		'wp_kses_js_entities' => array(
			'alt'     => '',
			'version' => '4.7.0',
		),

		// WP 4.8.0.
		'wp_dashboard_plugins_output' => array(
			'alt'     => '',
			'version' => '4.8.0',
		),

		// WP 4.9.0.
		'get_shortcut_link' => array(
			'alt'     => '',
			'version' => '4.9.0',
		),
		'is_user_option_local' => array(
			'alt'     => '',
			'version' => '4.9.0',
		),
		'wp_ajax_press_this_add_category' => array(
			'alt'     => '',
			'version' => '4.9.0',
		),
		'wp_ajax_press_this_save_post' => array(
			'alt'     => '',
			'version' => '4.9.0',
		),

		// WP 5.1.0.
		'insert_blog' => array(
			'alt'     => 'wp_insert_site()',
			'version' => '5.1.0',
		),
		'install_blog' => array(
			'alt'     => '',
			'version' => '5.1.0',
		),
	);

	/**
	 * Groups of functions to restrict.
	 *
	 * @return array
	 */
	public function getGroups() {
		// Make sure all array keys are lowercase.
		$this->deprecated_functions = array_change_key_case( $this->deprecated_functions, CASE_LOWER );

		return array(
			'deprecated_functions' => array(
				'functions' => array_keys( $this->deprecated_functions ),
			),
		);
	}

	/**
	 * Process a matched token.
	 *
	 * @param int    $stackPtr        The position of the current token in the stack.
	 * @param array  $group_name      The name of the group which was matched. Will
	 *                                always be 'deprecated_functions'.
	 * @param string $matched_content The token content (function name) which was matched.
	 *
	 * @return void
	 */
	public function process_matched_token( $stackPtr, $group_name, $matched_content ) {

		$this->get_wp_version_from_cl();

		$function_name = strtolower( $matched_content );

		$message = '%s() has been deprecated since WordPress version %s.';
		$data    = array(
			$matched_content,
			$this->deprecated_functions[ $function_name ]['version'],
		);

		if ( ! empty( $this->deprecated_functions[ $function_name ]['alt'] ) ) {
			$message .= ' Use %s instead.';
			$data[]   = $this->deprecated_functions[ $function_name ]['alt'];
		}

		$this->addMessage(
			$message,
			$stackPtr,
			( version_compare( $this->deprecated_functions[ $function_name ]['version'], $this->minimum_supported_version, '<' ) ),
			$this->string_to_errorcode( $matched_content . 'Found' ),
			$data
		);
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress\Sniffs\WhiteSpace;

use WordPressCS\WordPress\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Ensure cast statements don't contain whitespace, but *are* surrounded by whitespace, based upon Squiz code.
 *
 * @link    https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#space-usage
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.3.0
 * @since   0.11.0 This sniff now has the ability to fix the issues it flags.
 * @since   0.11.0 The error level for all errors thrown by this sniff has been raised from warning to error.
 * @since   0.12.0 This class now extends the WordPressCS native `Sniff` class.
 * @since   0.13.0 Class name changed: this class is now namespaced.
 */
class CastStructureSpacingSniff extends Sniff {

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @return array
	 */
	public function register() {
		return Tokens::$castTokens;
	}

	/**
	 * Processes this test, when one of its tokens is encountered.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return void
	 */
	public function process_token( $stackPtr ) {

		if ( \T_WHITESPACE !== $this->tokens[ ( $stackPtr - 1 ) ]['code'] ) {
			$error = 'No space before opening casting parenthesis is prohibited';
			$fix   = $this->phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceBeforeOpenParenthesis' );
			if ( true === $fix ) {
				$this->phpcsFile->fixer->addContentBefore( $stackPtr, ' ' );
			}
		}
	}

}


<?php
/**
 * WordPress Coding Standard.
 *
 * @package WPCS\WordPressCodingStandards
 * @link    https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards
 * @license https://opensource.org/licenses/MIT MIT
 */

namespace WordPressCS\WordPress;

use WordPressCS\WordPress\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
 * Restricts usage of some functions.
 *
 * @package WPCS\WordPressCodingStandards
 *
 * @since   0.3.0
 * @since   0.10.0 Class became a proper abstract class. This was already the behaviour.
 *                 Moved the file and renamed the class from
 *                 `\WordPressCS\WordPress\Sniffs\Functions\FunctionRestrictionsSniff` to
 *                 `\WordPressCS\WordPress\AbstractFunctionRestrictionsSniff`.
 * @since   0.11.0 Extends the WordPressCS native `Sniff` class.
 */
abstract class AbstractFunctionRestrictionsSniff extends Sniff {

	/**
	 * Exclude groups.
	 *
	 * Example: 'switch_to_blog,user_meta'
	 *
	 * @since 0.3.0
	 * @since 1.0.0 This property now expects to be passed an array.
	 *              Previously a comma-delimited string was expected.
	 *
	 * @var array
	 */
	public $exclude = array();

	/**
	 * Groups of function data to check against.
	 * Don't use this in extended classes, override getGroups() instead.
	 * This is only used for Unit tests.
	 *
	 * @since 0.10.0
	 *
	 * @var array
	 */
	public static $unittest_groups = array();

	/**
	 * Regex pattern with placeholder for the function names.
	 *
	 * @since 0.10.0
	 *
	 * @var string
	 */
	protected $regex_pattern = '`\b(?:%s)\b`i';

	/**
	 * Cache for the group information.
	 *
	 * @since 0.10.0
	 *
	 * @var array
	 */
	protected $groups = array();

	/**
	 * Cache for the excluded groups information.
	 *
	 * @since 0.11.0
	 *
	 * @var array
	 */
	protected $excluded_groups = array();

	/**
	 * Regex containing the name of all functions handled by a sniff.
	 *
	 * Set in `register()` and used to do an initial check.
	 *
	 * @var string
	 */
	private $prelim_check_regex;

	/**
	 * Groups of functions to restrict.
	 *
	 * This method should be overridden in extending classes.
	 *
	 * Example: groups => array(
	 *     'lambda' => array(
	 *         'type'      => 'error' | 'warning',
	 *         'message'   => 'Use anonymous functions instead please!',
	 *         'functions' => array( 'file_get_contents', 'create_function', 'mysql_*' ),
	 *         // Only useful when using wildcards:
	 *         'whitelist' => array( 'mysql_to_rfc3339' => true, ),
	 *     )
	 * )
	 *
	 * You can use * wildcards to target a group of functions.
	 * When you use * wildcards, you may inadvertently restrict too many
	 * functions. In that case you can add the `whitelist` key to
	 * whitelist individual functions to prevent false positives.
	 *
	 * @return array
	 */
	abstract public function getGroups();

	/**
	 * Returns an array of tokens this test wants to listen for.
	 *
	 * @return array
	 */
	public function register() {
		// Prepare the function group regular expressions only once.
		if ( false === $this->setup_groups( 'functions' ) ) {
			return array();
		}

		return array(
			\T_STRING,
		);
	}

	/**
	 * Set up the regular expressions for each group.
	 *
	 * @since 0.10.0
	 *
	 * @param string $key The group array index key where the input for the regular expression can be found.
	 * @return bool True if the groups were setup. False if not.
	 */
	protected function setup_groups( $key ) {
		// Prepare the function group regular expressions only once.
		$this->groups = $this->getGroups();

		if ( empty( $this->groups ) && empty( self::$unittest_groups ) ) {
			return false;
		}

		// Allow for adding extra unit tests.
		if ( ! empty( self::$unittest_groups ) ) {
			$this->groups = array_merge( $this->groups, self::$unittest_groups );
		}

		$all_items = array();
		foreach ( $this->groups as $groupName => $group ) {
			if ( empty( $group[ $key ] ) ) {
				unset( $this->groups[ $groupName ] );
			} else {
				$items       = array_map( array( $this, 'prepare_name_for_regex' ), $group[ $key ] );
				$all_items[] = $items;
				$items       = implode( '|', $items );

				$this->groups[ $groupName ]['regex'] = sprintf( $this->regex_pattern, $items );
			}
		}

		if ( empty( $this->groups ) ) {
			return false;
		}

		// Create one "super-regex" to allow for initial filtering.
		$all_items                = \call_user_func_array( 'array_merge', $all_items );
		$all_items                = implode( '|', array_unique( $all_items ) );
		$this->prelim_check_regex = sprintf( $this->regex_pattern, $all_items );

		return true;
	}

	/**
	 * Processes this test, when one of its tokens is encountered.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return int|void Integer stack pointer to skip forward or void to continue
	 *                  normal file processing.
	 */
	public function process_token( $stackPtr ) {

		$this->excluded_groups = $this->merge_custom_array( $this->exclude );
		if ( array_diff_key( $this->groups, $this->excluded_groups ) === array() ) {
			// All groups have been excluded.
			// Don't remove the listener as the exclude property can be changed inline.
			return;
		}

		// Preliminary check. If the content of the T_STRING is not one of the functions we're
		// looking for, we can bow out before doing the heavy lifting of checking whether
		// this is a function call.
		if ( preg_match( $this->prelim_check_regex, $this->tokens[ $stackPtr ]['content'] ) !== 1 ) {
			return;
		}

		if ( true === $this->is_targetted_token( $stackPtr ) ) {
			return $this->check_for_matches( $stackPtr );
		}
	}

	/**
	 * Verify is the current token is a function call.
	 *
	 * @since 0.11.0 Split out from the `process()` method.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return bool
	 */
	public function is_targetted_token( $stackPtr ) {

		// Exclude function definitions, class methods, and namespaced calls.
		if ( \T_STRING === $this->tokens[ $stackPtr ]['code'] ) {
			if ( $this->is_class_object_call( $stackPtr ) === true ) {
				return false;
			}

			if ( $this->is_token_namespaced( $stackPtr ) === true ) {
				return false;
			}

			$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );

			if ( false !== $prev ) {
				// Skip sniffing if calling a same-named method, or on function definitions.
				$skipped = array(
					\T_FUNCTION        => \T_FUNCTION,
					\T_CLASS           => \T_CLASS,
					\T_AS              => \T_AS, // Use declaration alias.
				);

				if ( isset( $skipped[ $this->tokens[ $prev ]['code'] ] ) ) {
					return false;
				}
			}

			return true;
		}

		return false;
	}

	/**
	 * Verify if the current token is one of the targetted functions.
	 *
	 * @since 0.11.0 Split out from the `process()` method.
	 *
	 * @param int $stackPtr The position of the current token in the stack.
	 *
	 * @return int|void Integer stack pointer to skip forward or void to continue
	 *                  normal file processing.
	 */
	public function check_for_matches( $stackPtr ) {
		$token_content = strtolower( $this->tokens[ $stackPtr ]['content'] );
		$skip_to       = array();

		foreach ( $this->groups as $groupName => $group ) {

			if ( isset( $this->excluded_groups[ $groupName ] ) ) {
				continue;
			}

			if ( isset( $group['whitelist'][ $token_content ] ) ) {
				continue;
			}

			if ( preg_match( $group['regex'], $token_content ) === 1 ) {
				$skip_to[] = $this->process_matched_token( $stackPtr, $groupName, $token_content );
			}
		}

		if ( empty( $skip_to ) || min( $skip_to ) === 0 ) {
			return;
		}

		return min( $skip_to );
	}

	/**
	 * Process a matched token.
	 *
	 * @since 0.11.0 Split out from the `process()` method.
	 *
	 * @param int    $stackPtr        The position of the current token in the stack.
	 * @param string $group_name      The name of the group which was matched.
	 * @param string $matched_content The token content (function name) which was matched.
	 *
	 * @return int|void Integer stack pointer to skip forward or void to continue
	 *                  normal file processing.
	 */
	public function process_matched_token( $stackPtr, $group_name, $matched_content ) {

		$this->addMessage(
			$this->groups[ $group_name ]['message'],
			$stackPtr,
			( 'error' === $this->groups[ $group_name ]['type'] ),
			$this->string_to_errorcode( $group_name . '_' . $matched_content ),
			array( $matched_content )
		);
	}

	/**
	 * Prepare the function name for use in a regular expression.
	 *
	 * The getGroups() method allows for providing function names with a wildcard * to target
	 * a group of functions. This prepare routine takes that into account while still safely
	 * escaping the function name for use in a regular expression.
	 *
	 * @since 0.10.0
	 *
	 * @param string $function Function name.
	 * @return string Regex escaped function name.
	 */
	protected function prepare_name_for_regex( $function ) {
		$function = str_replace( array( '.*', '*' ), '@@', $function ); // Replace wildcards with placeholder.
		$function = preg_quote( $function, '`' );
		$function = str_replace( '@@', '.*', $function ); // Replace placeholder with regex wildcard.

		return $function;
	}

}