*/ public static $arrayTokenCodes = [ T_ARRAY, T_OPEN_SHORT_ARRAY, ]; /** @var array */ public static $typeKeywordTokenCodes = [ T_CLASS, T_TRAIT, T_INTERFACE, T_ENUM, ]; /** @var array */ public static $typeWithAnonymousClassKeywordTokenCodes = [ T_CLASS, T_ANON_CLASS, T_TRAIT, T_INTERFACE, T_ENUM, ]; /** @var array */ public static $ineffectiveTokenCodes = [ T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_DOC_COMMENT_OPEN_TAG, T_DOC_COMMENT_CLOSE_TAG, T_DOC_COMMENT_STAR, T_DOC_COMMENT_STRING, T_DOC_COMMENT_TAG, T_DOC_COMMENT_WHITESPACE, T_PHPCS_DISABLE, T_PHPCS_ENABLE, T_PHPCS_IGNORE, T_PHPCS_IGNORE_FILE, T_PHPCS_SET, ]; /** @var array */ public static $annotationTokenCodes = [ T_DOC_COMMENT_TAG, T_PHPCS_DISABLE, T_PHPCS_ENABLE, T_PHPCS_IGNORE, T_PHPCS_IGNORE_FILE, T_PHPCS_SET, ]; /** @var array */ public static $inlineCommentTokenCodes = [ T_COMMENT, T_PHPCS_DISABLE, T_PHPCS_ENABLE, T_PHPCS_IGNORE, T_PHPCS_IGNORE_FILE, T_PHPCS_SET, ]; /** @var array */ public static $earlyExitTokenCodes = [ T_RETURN, T_CONTINUE, T_BREAK, T_THROW, T_EXIT, ]; /** @var array */ public static $functionTokenCodes = [ T_FUNCTION, T_CLOSURE, T_FN, ]; /** @var array */ public static $propertyModifiersTokenCodes = [ T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC, ]; /** * @param int|string|array $types */ public static function findNext(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findNext($types, $startPointer, $endPointer, false); return $token === false ? null : $token; } /** * @param int|string|array $types * @return list */ public static function findNextAll(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): array { $pointers = []; $actualStartPointer = $startPointer; while (true) { $pointer = self::findNext($phpcsFile, $types, $actualStartPointer, $endPointer); if ($pointer === null) { break; } $pointers[] = $pointer; $actualStartPointer = $pointer + 1; } return $pointers; } /** * @param int|string|array $types */ public static function findNextContent(File $phpcsFile, $types, string $content, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findNext($types, $startPointer, $endPointer, false, $content); return $token === false ? null : $token; } /** * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findNextEffective(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int { return self::findNextExcluding($phpcsFile, self::$ineffectiveTokenCodes, $startPointer, $endPointer); } /** * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findNextNonWhitespace(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int { return self::findNextExcluding($phpcsFile, T_WHITESPACE, $startPointer, $endPointer); } /** * @param int|string|array $types * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findNextExcluding(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findNext($types, $startPointer, $endPointer, true); return $token === false ? null : $token; } /** * @param int|string|array $types */ public static function findNextLocal(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findNext($types, $startPointer, $endPointer, false, null, true); return $token === false ? null : $token; } /** * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findNextAnyToken(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int { return self::findNextExcluding($phpcsFile, [], $startPointer, $endPointer); } /** * @param int|string|array $types * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findPrevious(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findPrevious($types, $startPointer, $endPointer, false); return $token === false ? null : $token; } /** * @param int|string|array $types */ public static function findPreviousContent(File $phpcsFile, $types, string $content, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findPrevious($types, $startPointer, $endPointer, false, $content); return $token === false ? null : $token; } /** * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findPreviousEffective(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int { return self::findPreviousExcluding($phpcsFile, self::$ineffectiveTokenCodes, $startPointer, $endPointer); } /** * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findPreviousNonWhitespace(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int { return self::findPreviousExcluding($phpcsFile, T_WHITESPACE, $startPointer, $endPointer); } /** * @param int|string|array $types * @param int $startPointer Search starts at this token, inclusive * @param int|null $endPointer Search ends at this token, exclusive */ public static function findPreviousExcluding(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findPrevious($types, $startPointer, $endPointer, true); return $token === false ? null : $token; } /** * @param int|string|array $types */ public static function findPreviousLocal(File $phpcsFile, $types, int $startPointer, ?int $endPointer = null): ?int { /** @var int|false $token */ $token = $phpcsFile->findPrevious($types, $startPointer, $endPointer, false, null, true); return $token === false ? null : $token; } /** * @param int $pointer Search starts at this token, inclusive */ public static function findFirstTokenOnLine(File $phpcsFile, int $pointer): int { if ($pointer === 0) { return $pointer; } $tokens = $phpcsFile->getTokens(); $line = $tokens[$pointer]['line']; do { $pointer--; } while ($tokens[$pointer]['line'] === $line); return $pointer + 1; } /** * @param int $pointer Search starts at this token, inclusive */ public static function findLastTokenOnLine(File $phpcsFile, int $pointer): int { $tokens = $phpcsFile->getTokens(); $line = $tokens[$pointer]['line']; do { $pointer++; } while (array_key_exists($pointer, $tokens) && $tokens[$pointer]['line'] === $line); return $pointer - 1; } /** * @param int $pointer Search starts at this token, inclusive */ public static function findLastTokenOnPreviousLine(File $phpcsFile, int $pointer): int { $tokens = $phpcsFile->getTokens(); $line = $tokens[$pointer]['line']; do { $pointer--; } while ($tokens[$pointer]['line'] === $line); return $pointer; } /** * @param int $pointer Search starts at this token, inclusive */ public static function findFirstTokenOnNextLine(File $phpcsFile, int $pointer): ?int { $tokens = $phpcsFile->getTokens(); if ($pointer >= count($tokens)) { return null; } $line = $tokens[$pointer]['line']; do { $pointer++; if (!array_key_exists($pointer, $tokens)) { return null; } } while ($tokens[$pointer]['line'] === $line); return $pointer; } /** * @param int $pointer Search starts at this token, inclusive */ public static function findFirstNonWhitespaceOnLine(File $phpcsFile, int $pointer): int { if ($pointer === 0) { return $pointer; } $tokens = $phpcsFile->getTokens(); $line = $tokens[$pointer]['line']; do { $pointer--; } while ($pointer >= 0 && $tokens[$pointer]['line'] === $line); return self::findNextExcluding($phpcsFile, [T_WHITESPACE, T_DOC_COMMENT_WHITESPACE], $pointer + 1); } /** * @param int $pointer Search starts at this token, inclusive */ public static function findFirstNonWhitespaceOnNextLine(File $phpcsFile, int $pointer): ?int { $newLinePointer = self::findNextContent($phpcsFile, [T_WHITESPACE, T_DOC_COMMENT_WHITESPACE], $phpcsFile->eolChar, $pointer); if ($newLinePointer === null) { return null; } $nextPointer = self::findNextExcluding($phpcsFile, [T_WHITESPACE, T_DOC_COMMENT_WHITESPACE], $newLinePointer + 1); $tokens = $phpcsFile->getTokens(); if ($nextPointer !== null && $tokens[$pointer]['line'] === $tokens[$nextPointer]['line'] - 1) { return $nextPointer; } return null; } /** * @param int $pointer Search starts at this token, inclusive */ public static function findFirstNonWhitespaceOnPreviousLine(File $phpcsFile, int $pointer): ?int { $newLinePointerOnPreviousLine = self::findPreviousContent( $phpcsFile, [T_WHITESPACE, T_DOC_COMMENT_WHITESPACE], $phpcsFile->eolChar, $pointer ); if ($newLinePointerOnPreviousLine === null) { return null; } $newLinePointerBeforePreviousLine = self::findPreviousContent( $phpcsFile, [T_WHITESPACE, T_DOC_COMMENT_WHITESPACE], $phpcsFile->eolChar, $newLinePointerOnPreviousLine - 1 ); if ($newLinePointerBeforePreviousLine === null) { return null; } $nextPointer = self::findNextExcluding($phpcsFile, [T_WHITESPACE, T_DOC_COMMENT_WHITESPACE], $newLinePointerBeforePreviousLine + 1); $tokens = $phpcsFile->getTokens(); if ($nextPointer !== null && $tokens[$pointer]['line'] === $tokens[$nextPointer]['line'] + 1) { return $nextPointer; } return null; } public static function getContent(File $phpcsFile, int $startPointer, ?int $endPointer = null): string { $tokens = $phpcsFile->getTokens(); $endPointer = $endPointer ?? self::getLastTokenPointer($phpcsFile); $content = ''; for ($i = $startPointer; $i <= $endPointer; $i++) { $content .= $tokens[$i]['content']; } return $content; } public static function getLastTokenPointer(File $phpcsFile): int { $tokenCount = count($phpcsFile->getTokens()); if ($tokenCount === 0) { throw new EmptyFileException($phpcsFile->getFilename()); } return $tokenCount - 1; } /** * @return array */ public static function getNameTokenCodes(): array { return [T_STRING, T_NS_SEPARATOR, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE]; } /** * @return array */ public static function getOnlyNameTokenCodes(): array { return [T_STRING, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE]; } /** * @return array */ public static function getOnlyTypeHintTokenCodes(): array { static $typeHintTokenCodes = null; if ($typeHintTokenCodes === null) { $typeHintTokenCodes = array_merge( self::getNameTokenCodes(), [ T_SELF, T_PARENT, T_ARRAY_HINT, T_CALLABLE, T_FALSE, T_TRUE, T_NULL, ] ); } return $typeHintTokenCodes; } /** * @return array */ public static function getTypeHintTokenCodes(): array { static $typeHintTokenCodes = null; if ($typeHintTokenCodes === null) { $typeHintTokenCodes = array_merge( self::getOnlyTypeHintTokenCodes(), [T_TYPE_UNION, T_TYPE_INTERSECTION] ); } return $typeHintTokenCodes; } }