/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $function = $phpcsFile->getCondition($stackPtr, T_FUNCTION); if ($function === false) { // Not a nested function. return; } $class = $phpcsFile->getCondition($stackPtr, T_ANON_CLASS); if ($class !== false && $class > $function) { // Ignore methods in anon classes. return; } $prev = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); if ($tokens[$prev]['code'] === T_EQUAL) { // Ignore closures. return; } $error = 'The use of inner functions is forbidden'; $phpcsFile->addError($error, $stackPtr, 'NotAllowed'); }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param integer $stackPtr The position where the token was found. * @param integer $currScope The current scope opener token. * * @return void */ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) { $tokens = $phpcsFile->getTokens(); // Determine the name of the class that the static function // is being called on. $classNameToken = $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true); // Don't process class names represented by variables as this can be // an inexact science. if ($tokens[$classNameToken]['code'] === T_VARIABLE) { return; } $className = $tokens[$classNameToken]['content']; if (isset($this->ignore[strtolower($className)]) === true) { return; } $includedClasses = array(); $fileName = strtolower($phpcsFile->getFilename()); $matches = array(); if (preg_match('|/systems/(.*)/([^/]+)?actions.inc$|', $fileName, $matches) !== 0) { // This is an actions file, which means we don't // have to include the system in which it exists. $includedClasses[$matches[2]] = true; // Or a system it implements. $class = $phpcsFile->getCondition($stackPtr, T_CLASS); $implements = $phpcsFile->findNext(T_IMPLEMENTS, $class, $class + 10); if ($implements !== false) { $implementsClass = $phpcsFile->findNext(T_STRING, $implements); $implementsClassName = strtolower($tokens[$implementsClass]['content']); if (substr($implementsClassName, -7) === 'actions') { $includedClasses[substr($implementsClassName, 0, -7)] = true; } } } // Go searching for includeSystem and includeAsset calls within this // function, or the inclusion of .inc files, which // would be library files. for ($i = $currScope + 1; $i < $stackPtr; $i++) { $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); if ($name !== false) { $includedClasses[$name] = true; // Special case for Widgets cause they are, well, special. } else { if (strtolower($tokens[$i]['content']) === 'includewidget') { $typeName = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, $i + 1); $typeName = trim($tokens[$typeName]['content'], " '"); $includedClasses[strtolower($typeName) . 'widgettype'] = true; } } } // Now go searching for includeSystem, includeAsset or require/include // calls outside our scope. If we are in a class, look outside the // class. If we are not, look outside the function. $condPtr = $currScope; if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) { if ($condType === T_CLASS) { break; } } } for ($i = 0; $i < $condPtr; $i++) { // Skip other scopes. if (isset($tokens[$i]['scope_closer']) === true) { $i = $tokens[$i]['scope_closer']; continue; } $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); if ($name !== false) { $includedClasses[$name] = true; } } // If we are in a testing class, we might have also included // some systems and classes in our setUp() method. $setupFunction = null; if ($phpcsFile->hasCondition($stackPtr, T_CLASS) === true) { foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) { if ($condType === T_CLASS) { // Is this is a testing class? $name = $phpcsFile->findNext(T_STRING, $condPtr); $name = $tokens[$name]['content']; if (substr($name, -8) === 'UnitTest') { // Look for a method called setUp(). $end = $tokens[$condPtr]['scope_closer']; $function = $phpcsFile->findNext(T_FUNCTION, $condPtr + 1, $end); while ($function !== false) { $name = $phpcsFile->findNext(T_STRING, $function); if ($tokens[$name]['content'] === 'setUp') { $setupFunction = $function; break; } $function = $phpcsFile->findNext(T_FUNCTION, $function + 1, $end); } } } } //end foreach } //end if if ($setupFunction !== null) { $start = $tokens[$setupFunction]['scope_opener'] + 1; $end = $tokens[$setupFunction]['scope_closer']; for ($i = $start; $i < $end; $i++) { $name = $this->getIncludedClassFromToken($phpcsFile, $tokens, $i); if ($name !== false) { $includedClasses[$name] = true; } } } //end if if (isset($includedClasses[strtolower($className)]) === false) { $error = 'Static method called on non-included class or system "%s"; include system with Channels::includeSystem() or include class with require_once'; $data = array($className); $phpcsFile->addError($error, $stackPtr, 'NotIncludedCall', $data); } }