Chris@0: getFilename(), -4)); Chris@0: if ($fileExtension !== 'info') { Chris@0: return ($phpcsFile->numTokens + 1); Chris@0: } Chris@0: Chris@0: $contents = file_get_contents($phpcsFile->getFilename()); Chris@0: $info = self::drupalParseInfoFormat($contents); Chris@0: if (isset($info['files']) === true && is_array($info['files']) === true) { Chris@0: foreach ($info['files'] as $file) { Chris@0: $fileName = dirname($phpcsFile->getFilename()).'/'.$file; Chris@0: if (file_exists($fileName) === false) { Chris@0: // We need to find the position of the offending line in the Chris@0: // info file. Chris@0: $ptr = self::getPtr('files[]', $file, $phpcsFile); Chris@0: $error = 'Declared file was not found'; Chris@0: $phpcsFile->addError($error, $ptr, 'DeclaredFileNotFound'); Chris@0: continue; Chris@0: } Chris@0: Chris@0: // Read the file, parse its tokens and check if it actually contains Chris@0: // a class or interface definition. Chris@0: $searchTokens = token_get_all(file_get_contents($fileName)); Chris@0: foreach ($searchTokens as $token) { Chris@0: if (is_array($token) === true Chris@0: && in_array($token[0], array(T_CLASS, T_INTERFACE, T_TRAIT)) === true Chris@0: ) { Chris@0: continue 2; Chris@0: } Chris@0: } Chris@0: Chris@0: $ptr = self::getPtr('files[]', $file, $phpcsFile); Chris@0: $error = "It's only necessary to declare files[] if they declare a class or interface."; Chris@0: $phpcsFile->addError($error, $ptr, 'UnecessaryFileDeclaration'); Chris@0: }//end foreach Chris@0: }//end if Chris@0: Chris@0: return ($phpcsFile->numTokens + 1); Chris@0: Chris@0: }//end process() Chris@0: Chris@0: Chris@0: /** Chris@0: * Helper function that returns the position of the key in the info file. Chris@0: * Chris@17: * @param string $key Key name to search for. Chris@17: * @param string $value Corresponding value to search for. Chris@17: * @param \PHP_CodeSniffer\Files\File $infoFile Info file to search in. Chris@0: * Chris@0: * @return int|false Returns the stack position if the file name is found, false Chris@0: * otherwise. Chris@0: */ Chris@17: public static function getPtr($key, $value, File $infoFile) Chris@0: { Chris@0: foreach ($infoFile->getTokens() as $ptr => $tokenInfo) { Chris@0: if (preg_match('@^[\s]*'.preg_quote($key).'[\s]*=[\s]*["\']?'.preg_quote($value).'["\']?@', $tokenInfo['content']) === 1) { Chris@0: return $ptr; Chris@0: } Chris@0: } Chris@0: Chris@0: return false; Chris@0: Chris@0: }//end getPtr() Chris@0: Chris@0: Chris@0: /** Chris@0: * Parses a Drupal info file. Copied from Drupal core drupal_parse_info_format(). Chris@0: * Chris@0: * @param string $data The contents of the info file to parse Chris@0: * Chris@0: * @return array The info array. Chris@0: */ Chris@0: public static function drupalParseInfoFormat($data) Chris@0: { Chris@0: $info = array(); Chris@0: $constants = get_defined_constants(); Chris@0: Chris@0: if (preg_match_all( Chris@0: ' Chris@0: @^\s* # Start at the beginning of a line, ignoring leading whitespace Chris@0: ((?: Chris@0: [^=;\[\]]| # Key names cannot contain equal signs, semi-colons or square brackets, Chris@0: \[[^\[\]]*\] # unless they are balanced and not nested Chris@0: )+?) Chris@0: \s*=\s* # Key/value pairs are separated by equal signs (ignoring white-space) Chris@0: (?: Chris@0: ("(?:[^"]|(?<=\\\\)")*")| # Double-quoted string, which may contain slash-escaped quotes/slashes Chris@0: (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes Chris@0: ([^\r\n]*?) # Non-quoted string Chris@0: )\s*$ # Stop at the next end of a line, ignoring trailing whitespace Chris@0: @msx', Chris@0: $data, Chris@0: $matches, Chris@0: PREG_SET_ORDER Chris@0: ) !== false Chris@0: ) { Chris@0: foreach ($matches as $match) { Chris@0: // Fetch the key and value string. Chris@0: $i = 0; Chris@0: foreach (array('key', 'value1', 'value2', 'value3') as $var) { Chris@0: if (isset($match[++$i]) === true) { Chris@0: $$var = $match[$i]; Chris@0: } else { Chris@0: $$var = ''; Chris@0: } Chris@0: } Chris@0: Chris@0: $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3; Chris@0: Chris@0: // Parse array syntax. Chris@0: $keys = preg_split('/\]?\[/', rtrim($key, ']')); Chris@0: $last = array_pop($keys); Chris@0: $parent = &$info; Chris@0: Chris@0: // Create nested arrays. Chris@0: foreach ($keys as $key) { Chris@0: if ($key === '') { Chris@0: $key = count($parent); Chris@0: } Chris@0: Chris@0: if (isset($parent[$key]) === false || is_array($parent[$key]) === false) { Chris@0: $parent[$key] = array(); Chris@0: } Chris@0: Chris@0: $parent = &$parent[$key]; Chris@0: } Chris@0: Chris@0: // Handle PHP constants. Chris@0: if (isset($constants[$value]) === true) { Chris@0: $value = $constants[$value]; Chris@0: } Chris@0: Chris@0: // Insert actual value. Chris@0: if ($last === '') { Chris@0: $last = count($parent); Chris@0: } Chris@0: Chris@0: $parent[$last] = $value; Chris@0: }//end foreach Chris@0: }//end if Chris@0: Chris@0: return $info; Chris@0: Chris@0: }//end drupalParseInfoFormat() Chris@0: Chris@0: Chris@0: }//end class