From 040c5dbc0819ec4f9b9ea5dcaa2489cc8a1b5a1b Mon Sep 17 00:00:00 2001 From: "cristian.almohalla" Date: Wed, 19 Nov 2025 16:39:07 +0100 Subject: [PATCH 1/3] feat: RequireSingleLineMethod rule --- ...thodSignatureExceptWithAttributesSniff.php | 287 ++++++++++++++++++ src/ruleset.xml | 3 + 2 files changed, 290 insertions(+) create mode 100644 src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php diff --git a/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php b/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php new file mode 100644 index 0000000..8a839b7 --- /dev/null +++ b/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php @@ -0,0 +1,287 @@ + */ + public array $includedMethodPatterns = []; + + /** @var list|null */ + public ?array $includedMethodNormalizedPatterns = null; + + /** @var list */ + public array $excludedMethodPatterns = []; + + /** @var list|null */ + public ?array $excludedMethodNormalizedPatterns = null; + + public function register(): array + { + return [T_FUNCTION]; + } + + public function process(File $phpcsFile, $methodPointer): void + { + $this->maxLineLength = $this->normalizeInteger($this->maxLineLength); + + if (!$this->isMethod($phpcsFile, $methodPointer)) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + [$signatureStartPointer, $signatureEndPointer] = $this->getSignatureStartAndEndPointers($phpcsFile, $methodPointer); + + if ($tokens[$signatureStartPointer]['line'] === $tokens[$signatureEndPointer]['line']) { + return; + } + + // CUSTOM: Check if there are attributes in the method parameters + if ($this->hasAttributesInParameters($phpcsFile, $methodPointer)) { + // Allow multi-line when attributes are present + return; + } + + $signature = $this->getSignature($phpcsFile, $signatureStartPointer, $signatureEndPointer); + $methodName = $this->getName($phpcsFile, $methodPointer); + + if ( + count($this->includedMethodPatterns) !== 0 + && !$this->isMethodNameInPatterns($methodName, $this->getIncludedMethodNormalizedPatterns()) + ) { + return; + } + + if ( + count($this->excludedMethodPatterns) !== 0 + && $this->isMethodNameInPatterns($methodName, $this->getExcludedMethodNormalizedPatterns()) + ) { + return; + } + + if ($this->maxLineLength !== 0 && strlen($signature) > $this->maxLineLength) { + return; + } + + $error = sprintf('Signature of method "%s" should be placed on a single line.', $methodName); + $fix = $phpcsFile->addFixableError($error, $methodPointer, self::CODE_REQUIRED_SINGLE_LINE_SIGNATURE); + if (!$fix) { + return; + } + + $phpcsFile->fixer->beginChangeset(); + + $this->fixerChange($phpcsFile, $signatureStartPointer, $signatureEndPointer, $signature); + + $phpcsFile->fixer->endChangeset(); + } + + /** + * CUSTOM: Check if method has attributes in parameters + */ + private function hasAttributesInParameters(File $phpcsFile, int $methodPointer): bool + { + $tokens = $phpcsFile->getTokens(); + + if (!isset($tokens[$methodPointer]['parenthesis_opener']) + || !isset($tokens[$methodPointer]['parenthesis_closer']) + ) { + return false; + } + + $openParenthesis = $tokens[$methodPointer]['parenthesis_opener']; + $closeParenthesis = $tokens[$methodPointer]['parenthesis_closer']; + + for ($i = $openParenthesis + 1; $i < $closeParenthesis; $i++) { + if ($tokens[$i]['code'] === T_ATTRIBUTE) { + return true; + } + } + + return false; + } + + /** + * @return array + */ + protected function getSignatureStartAndEndPointers(File $phpcsFile, int $methodPointer): array + { + $signatureStartPointer = $this->findFirstTokenOnLine($phpcsFile, $methodPointer); + + /** @var int $pointerAfterSignatureEnd */ + $pointerAfterSignatureEnd = $this->findNext($phpcsFile, [T_OPEN_CURLY_BRACKET, T_SEMICOLON], $methodPointer + 1); + if ($phpcsFile->getTokens()[$pointerAfterSignatureEnd]['code'] === T_SEMICOLON) { + return [$signatureStartPointer, $pointerAfterSignatureEnd]; + } + + /** @var int $signatureEndPointer */ + $signatureEndPointer = $this->findPreviousEffective($phpcsFile, $pointerAfterSignatureEnd - 1); + + return [$signatureStartPointer, $signatureEndPointer]; + } + + protected function getSignature(File $phpcsFile, int $signatureStartPointer, int $signatureEndPointer): string + { + $signature = $this->getContent($phpcsFile, $signatureStartPointer, $signatureEndPointer); + $signature = preg_replace(sprintf('~%s[ \t]*~', $phpcsFile->eolChar), ' ', $signature); + assert(is_string($signature)); + + $signature = str_replace(['( ', ' )'], ['(', ')'], $signature); + $signature = rtrim($signature); + + return $signature; + } + + /** + * @param list $normalizedPatterns + */ + private function isMethodNameInPatterns(string $methodName, array $normalizedPatterns): bool + { + foreach ($normalizedPatterns as $pattern) { + if (!$this->isValidRegularExpression($pattern)) { + throw new Exception(sprintf('%s is not valid PCRE pattern.', $pattern)); + } + + if (preg_match($pattern, $methodName) !== 0) { + return true; + } + } + + return false; + } + + /** + * @return list + */ + private function getIncludedMethodNormalizedPatterns(): array + { + $this->includedMethodNormalizedPatterns ??= $this->normalizeArray($this->includedMethodPatterns); + return $this->includedMethodNormalizedPatterns; + } + + /** + * @return list + */ + private function getExcludedMethodNormalizedPatterns(): array + { + $this->excludedMethodNormalizedPatterns ??= $this->normalizeArray($this->excludedMethodPatterns); + return $this->excludedMethodNormalizedPatterns; + } + + // Helper methods simplified from Slevomat helpers + + private function normalizeInteger(int $value): int + { + return $value; + } + + private function normalizeArray(array $value): array + { + return $value; + } + + private function isValidRegularExpression(string $pattern): bool + { + return @preg_match($pattern, '') !== false; + } + + private function isMethod(File $phpcsFile, int $functionPointer): bool + { + $tokens = $phpcsFile->getTokens(); + + if (!isset($tokens[$functionPointer]['conditions'])) { + return false; + } + + foreach ($tokens[$functionPointer]['conditions'] as $conditionTokenCode) { + if ($conditionTokenCode === T_ANON_CLASS || $conditionTokenCode === T_CLASS || $conditionTokenCode === T_INTERFACE || $conditionTokenCode === T_TRAIT || $conditionTokenCode === T_ENUM) { + return true; + } + } + + return false; + } + + private function getName(File $phpcsFile, int $functionPointer): string + { + return $phpcsFile->getDeclarationName($functionPointer); + } + + private function findFirstTokenOnLine(File $phpcsFile, int $pointer): int + { + $tokens = $phpcsFile->getTokens(); + $line = $tokens[$pointer]['line']; + + do { + $pointer--; + } while (isset($tokens[$pointer]) && $tokens[$pointer]['line'] === $line); + + return $pointer + 1; + } + + private function findNext(File $phpcsFile, array $types, int $start): ?int + { + return $phpcsFile->findNext($types, $start); + } + + private function findPreviousEffective(File $phpcsFile, int $pointer): ?int + { + return $phpcsFile->findPrevious(T_WHITESPACE, $pointer, null, true); + } + + private function getContent(File $phpcsFile, int $start, int $end): string + { + $tokens = $phpcsFile->getTokens(); + $content = ''; + + for ($i = $start; $i <= $end; $i++) { + $content .= $tokens[$i]['content']; + } + + return $content; + } + + private function fixerChange(File $phpcsFile, int $start, int $end, string $replacement): void + { + for ($i = $start; $i <= $end; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->addContent($start, $replacement); + } +} diff --git a/src/ruleset.xml b/src/ruleset.xml index a9a552a..65cb81b 100644 --- a/src/ruleset.xml +++ b/src/ruleset.xml @@ -7,6 +7,7 @@ + @@ -102,4 +103,6 @@ + + From f76167d4f280e1265d455b90e3f125905cade05d Mon Sep 17 00:00:00 2001 From: "cristian.almohalla" Date: Thu, 20 Nov 2025 09:11:33 +0100 Subject: [PATCH 2/3] feat: RequireSingleLineMethod rule --- ...thodSignatureExceptWithAttributesSniff.php | 275 ++++++++++++++++++ src/ruleset.xml | 3 + 2 files changed, 278 insertions(+) create mode 100644 src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php diff --git a/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php b/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php new file mode 100644 index 0000000..aec340b --- /dev/null +++ b/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php @@ -0,0 +1,275 @@ + */ + public array $includedMethodPatterns = []; + + /** @var list|null */ + public ?array $includedMethodNormalizedPatterns = null; + + /** @var list */ + public array $excludedMethodPatterns = []; + + /** @var list|null */ + public ?array $excludedMethodNormalizedPatterns = null; + + public function register(): array + { + return [T_FUNCTION]; + } + + public function process(File $phpcsFile, $methodPointer): void + { + if (!$this->isMethod($phpcsFile, $methodPointer)) { + return; + } + + $tokens = $phpcsFile->getTokens(); + + [$signatureStartPointer, $signatureEndPointer] = $this->getSignatureStartAndEndPointers($phpcsFile, $methodPointer); + + if ($tokens[$signatureStartPointer]['line'] === $tokens[$signatureEndPointer]['line']) { + return; + } + + // CUSTOM: Check if there are attributes in the method parameters + if ($this->hasAttributesInParameters($phpcsFile, $methodPointer)) { + // Allow multi-line when attributes are present + return; + } + + $signature = $this->getSignature($phpcsFile, $signatureStartPointer, $signatureEndPointer); + $methodName = $this->getName($phpcsFile, $methodPointer); + + if ( + count($this->includedMethodPatterns) !== 0 + && !$this->isMethodNameInPatterns($methodName, $this->getIncludedMethodNormalizedPatterns()) + ) { + return; + } + + if ( + count($this->excludedMethodPatterns) !== 0 + && $this->isMethodNameInPatterns($methodName, $this->getExcludedMethodNormalizedPatterns()) + ) { + return; + } + + if ($this->maxLineLength !== 0 && strlen($signature) > $this->maxLineLength) { + return; + } + + $error = sprintf('Signature of method "%s" should be placed on a single line.', $methodName); + $fix = $phpcsFile->addFixableError($error, $methodPointer, self::CODE_REQUIRED_SINGLE_LINE_SIGNATURE); + if (!$fix) { + return; + } + + $phpcsFile->fixer->beginChangeset(); + + $this->fixerChange($phpcsFile, $signatureStartPointer, $signatureEndPointer, $signature); + + $phpcsFile->fixer->endChangeset(); + } + + /** + * CUSTOM: Check if method has attributes in parameters + */ + private function hasAttributesInParameters(File $phpcsFile, int $methodPointer): bool + { + $tokens = $phpcsFile->getTokens(); + + if (!isset($tokens[$methodPointer]['parenthesis_opener']) + || !isset($tokens[$methodPointer]['parenthesis_closer']) + ) { + return false; + } + + $openParenthesis = $tokens[$methodPointer]['parenthesis_opener']; + $closeParenthesis = $tokens[$methodPointer]['parenthesis_closer']; + + for ($i = $openParenthesis + 1; $i < $closeParenthesis; $i++) { + if ($tokens[$i]['code'] === T_ATTRIBUTE) { + return true; + } + } + + return false; + } + + /** + * @return array + */ + protected function getSignatureStartAndEndPointers(File $phpcsFile, int $methodPointer): array + { + $signatureStartPointer = $this->findFirstTokenOnLine($phpcsFile, $methodPointer); + + /** @var int $pointerAfterSignatureEnd */ + $pointerAfterSignatureEnd = $this->findNext($phpcsFile, [T_OPEN_CURLY_BRACKET, T_SEMICOLON], $methodPointer + 1); + if ($phpcsFile->getTokens()[$pointerAfterSignatureEnd]['code'] === T_SEMICOLON) { + return [$signatureStartPointer, $pointerAfterSignatureEnd]; + } + + /** @var int $signatureEndPointer */ + $signatureEndPointer = $this->findPreviousEffective($phpcsFile, $pointerAfterSignatureEnd - 1); + + return [$signatureStartPointer, $signatureEndPointer]; + } + + protected function getSignature(File $phpcsFile, int $signatureStartPointer, int $signatureEndPointer): string + { + $signature = $this->getContent($phpcsFile, $signatureStartPointer, $signatureEndPointer); + $signature = preg_replace(sprintf('~%s[ \t]*~', $phpcsFile->eolChar), ' ', $signature); + assert(is_string($signature)); + + $signature = str_replace(['( ', ' )'], ['(', ')'], $signature); + $signature = rtrim($signature); + + return $signature; + } + + /** + * @param list $normalizedPatterns + */ + private function isMethodNameInPatterns(string $methodName, array $normalizedPatterns): bool + { + foreach ($normalizedPatterns as $pattern) { + if (!$this->isValidRegularExpression($pattern)) { + throw new Exception(sprintf('%s is not valid PCRE pattern.', $pattern)); + } + + if (preg_match($pattern, $methodName) !== 0) { + return true; + } + } + + return false; + } + + /** + * @return list + */ + private function getIncludedMethodNormalizedPatterns(): array + { + $this->includedMethodNormalizedPatterns ??= $this->includedMethodPatterns; + return $this->includedMethodNormalizedPatterns; + } + + /** + * @return list + */ + private function getExcludedMethodNormalizedPatterns(): array + { + $this->excludedMethodNormalizedPatterns ??= $this->excludedMethodPatterns; + return $this->excludedMethodNormalizedPatterns; + } + + // Helper methods simplified from Slevomat helpers + + private function isValidRegularExpression(string $pattern): bool + { + return @preg_match($pattern, '') !== false; + } + + private function isMethod(File $phpcsFile, int $functionPointer): bool + { + $tokens = $phpcsFile->getTokens(); + + if (!isset($tokens[$functionPointer]['conditions'])) { + return false; + } + + foreach ($tokens[$functionPointer]['conditions'] as $conditionTokenCode) { + if ($conditionTokenCode === T_ANON_CLASS || $conditionTokenCode === T_CLASS || $conditionTokenCode === T_INTERFACE || $conditionTokenCode === T_TRAIT || $conditionTokenCode === T_ENUM) { + return true; + } + } + + return false; + } + + private function getName(File $phpcsFile, int $functionPointer): string + { + return $phpcsFile->getDeclarationName($functionPointer); + } + + private function findFirstTokenOnLine(File $phpcsFile, int $pointer): int + { + $tokens = $phpcsFile->getTokens(); + $line = $tokens[$pointer]['line']; + + do { + $pointer--; + } while (isset($tokens[$pointer]) && $tokens[$pointer]['line'] === $line); + + return $pointer + 1; + } + + private function findNext(File $phpcsFile, array $types, int $start): ?int + { + return $phpcsFile->findNext($types, $start); + } + + private function findPreviousEffective(File $phpcsFile, int $pointer): ?int + { + return $phpcsFile->findPrevious(T_WHITESPACE, $pointer, null, true); + } + + private function getContent(File $phpcsFile, int $start, int $end): string + { + $tokens = $phpcsFile->getTokens(); + $content = ''; + + for ($i = $start; $i <= $end; $i++) { + $content .= $tokens[$i]['content']; + } + + return $content; + } + + private function fixerChange(File $phpcsFile, int $start, int $end, string $replacement): void + { + for ($i = $start; $i <= $end; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->addContent($start, $replacement); + } +} diff --git a/src/ruleset.xml b/src/ruleset.xml index a9a552a..65cb81b 100644 --- a/src/ruleset.xml +++ b/src/ruleset.xml @@ -7,6 +7,7 @@ + @@ -102,4 +103,6 @@ + + From bf98e447aaba5820e8f184c3b0408e841705fd6d Mon Sep 17 00:00:00 2001 From: Zoilo Mora Date: Thu, 20 Nov 2025 09:29:04 +0100 Subject: [PATCH 3/3] feat: Removed all duplicated code from the original library. Extended the class and implemented the custom change. --- ...thodSignatureExceptWithAttributesSniff.php | 174 ++---------------- 1 file changed, 15 insertions(+), 159 deletions(-) diff --git a/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php b/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php index 8a839b7..8fb3c30 100644 --- a/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php +++ b/src/Sniffs/Classes/RequireSingleLineMethodSignatureExceptWithAttributesSniff.php @@ -5,61 +5,29 @@ use Exception; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Sniffs\Sniff; +use SlevomatCodingStandard\Helpers\FixerHelper; +use SlevomatCodingStandard\Helpers\FunctionHelper; +use SlevomatCodingStandard\Helpers\SniffSettingsHelper; +use SlevomatCodingStandard\Sniffs\Classes\RequireSingleLineMethodSignatureSniff; use function count; use function preg_match; -use function preg_replace; use function sprintf; use function strlen; -use function assert; -use function is_string; -use function str_replace; -use function rtrim; -use const T_FUNCTION; -use const T_OPEN_CURLY_BRACKET; -use const T_SEMICOLON; use const T_ATTRIBUTE; -use const T_WHITESPACE; -use const T_ANON_CLASS; -use const T_CLASS; -use const T_INTERFACE; -use const T_TRAIT; -use const T_ENUM; /** * Custom sniff that requires single-line method signatures, * except when attributes are present in parameters. * - * Based on SlevomatCodingStandard\Sniffs\Classes\RequireSingleLineMethodSignatureSniff + * Based on SlevomatCodingStandard\Sniffs\Classes\RequireSingleLineMethodSignatureSniff (v8.22.1) */ -class RequireSingleLineMethodSignatureExceptWithAttributesSniff implements Sniff +class RequireSingleLineMethodSignatureExceptWithAttributesSniff extends RequireSingleLineMethodSignatureSniff { - public const CODE_REQUIRED_SINGLE_LINE_SIGNATURE = 'RequiredSingleLineSignature'; - - public int $maxLineLength = 120; - - /** @var list */ - public array $includedMethodPatterns = []; - - /** @var list|null */ - public ?array $includedMethodNormalizedPatterns = null; - - /** @var list */ - public array $excludedMethodPatterns = []; - - /** @var list|null */ - public ?array $excludedMethodNormalizedPatterns = null; - - public function register(): array - { - return [T_FUNCTION]; - } - public function process(File $phpcsFile, $methodPointer): void { - $this->maxLineLength = $this->normalizeInteger($this->maxLineLength); + $this->maxLineLength = SniffSettingsHelper::normalizeInteger($this->maxLineLength); - if (!$this->isMethod($phpcsFile, $methodPointer)) { + if (!FunctionHelper::isMethod($phpcsFile, $methodPointer)) { return; } @@ -71,14 +39,15 @@ public function process(File $phpcsFile, $methodPointer): void return; } - // CUSTOM: Check if there are attributes in the method parameters + #region CUSTOM: Check if there are attributes in the method parameters if ($this->hasAttributesInParameters($phpcsFile, $methodPointer)) { // Allow multi-line when attributes are present return; } + #endregion $signature = $this->getSignature($phpcsFile, $signatureStartPointer, $signatureEndPointer); - $methodName = $this->getName($phpcsFile, $methodPointer); + $methodName = FunctionHelper::getName($phpcsFile, $methodPointer); if ( count($this->includedMethodPatterns) !== 0 @@ -106,7 +75,7 @@ public function process(File $phpcsFile, $methodPointer): void $phpcsFile->fixer->beginChangeset(); - $this->fixerChange($phpcsFile, $signatureStartPointer, $signatureEndPointer, $signature); + FixerHelper::change($phpcsFile, $signatureStartPointer, $signatureEndPointer, $signature); $phpcsFile->fixer->endChangeset(); } @@ -136,44 +105,13 @@ private function hasAttributesInParameters(File $phpcsFile, int $methodPointer): return false; } - /** - * @return array - */ - protected function getSignatureStartAndEndPointers(File $phpcsFile, int $methodPointer): array - { - $signatureStartPointer = $this->findFirstTokenOnLine($phpcsFile, $methodPointer); - - /** @var int $pointerAfterSignatureEnd */ - $pointerAfterSignatureEnd = $this->findNext($phpcsFile, [T_OPEN_CURLY_BRACKET, T_SEMICOLON], $methodPointer + 1); - if ($phpcsFile->getTokens()[$pointerAfterSignatureEnd]['code'] === T_SEMICOLON) { - return [$signatureStartPointer, $pointerAfterSignatureEnd]; - } - - /** @var int $signatureEndPointer */ - $signatureEndPointer = $this->findPreviousEffective($phpcsFile, $pointerAfterSignatureEnd - 1); - - return [$signatureStartPointer, $signatureEndPointer]; - } - - protected function getSignature(File $phpcsFile, int $signatureStartPointer, int $signatureEndPointer): string - { - $signature = $this->getContent($phpcsFile, $signatureStartPointer, $signatureEndPointer); - $signature = preg_replace(sprintf('~%s[ \t]*~', $phpcsFile->eolChar), ' ', $signature); - assert(is_string($signature)); - - $signature = str_replace(['( ', ' )'], ['(', ')'], $signature); - $signature = rtrim($signature); - - return $signature; - } - /** * @param list $normalizedPatterns */ private function isMethodNameInPatterns(string $methodName, array $normalizedPatterns): bool { foreach ($normalizedPatterns as $pattern) { - if (!$this->isValidRegularExpression($pattern)) { + if (!SniffSettingsHelper::isValidRegularExpression($pattern)) { throw new Exception(sprintf('%s is not valid PCRE pattern.', $pattern)); } @@ -190,7 +128,7 @@ private function isMethodNameInPatterns(string $methodName, array $normalizedPat */ private function getIncludedMethodNormalizedPatterns(): array { - $this->includedMethodNormalizedPatterns ??= $this->normalizeArray($this->includedMethodPatterns); + $this->includedMethodNormalizedPatterns ??= SniffSettingsHelper::normalizeArray($this->includedMethodPatterns); return $this->includedMethodNormalizedPatterns; } @@ -199,89 +137,7 @@ private function getIncludedMethodNormalizedPatterns(): array */ private function getExcludedMethodNormalizedPatterns(): array { - $this->excludedMethodNormalizedPatterns ??= $this->normalizeArray($this->excludedMethodPatterns); + $this->excludedMethodNormalizedPatterns ??= SniffSettingsHelper::normalizeArray($this->excludedMethodPatterns); return $this->excludedMethodNormalizedPatterns; } - - // Helper methods simplified from Slevomat helpers - - private function normalizeInteger(int $value): int - { - return $value; - } - - private function normalizeArray(array $value): array - { - return $value; - } - - private function isValidRegularExpression(string $pattern): bool - { - return @preg_match($pattern, '') !== false; - } - - private function isMethod(File $phpcsFile, int $functionPointer): bool - { - $tokens = $phpcsFile->getTokens(); - - if (!isset($tokens[$functionPointer]['conditions'])) { - return false; - } - - foreach ($tokens[$functionPointer]['conditions'] as $conditionTokenCode) { - if ($conditionTokenCode === T_ANON_CLASS || $conditionTokenCode === T_CLASS || $conditionTokenCode === T_INTERFACE || $conditionTokenCode === T_TRAIT || $conditionTokenCode === T_ENUM) { - return true; - } - } - - return false; - } - - private function getName(File $phpcsFile, int $functionPointer): string - { - return $phpcsFile->getDeclarationName($functionPointer); - } - - private function findFirstTokenOnLine(File $phpcsFile, int $pointer): int - { - $tokens = $phpcsFile->getTokens(); - $line = $tokens[$pointer]['line']; - - do { - $pointer--; - } while (isset($tokens[$pointer]) && $tokens[$pointer]['line'] === $line); - - return $pointer + 1; - } - - private function findNext(File $phpcsFile, array $types, int $start): ?int - { - return $phpcsFile->findNext($types, $start); - } - - private function findPreviousEffective(File $phpcsFile, int $pointer): ?int - { - return $phpcsFile->findPrevious(T_WHITESPACE, $pointer, null, true); - } - - private function getContent(File $phpcsFile, int $start, int $end): string - { - $tokens = $phpcsFile->getTokens(); - $content = ''; - - for ($i = $start; $i <= $end; $i++) { - $content .= $tokens[$i]['content']; - } - - return $content; - } - - private function fixerChange(File $phpcsFile, int $start, int $end, string $replacement): void - { - for ($i = $start; $i <= $end; $i++) { - $phpcsFile->fixer->replaceToken($i, ''); - } - - $phpcsFile->fixer->addContent($start, $replacement); - } }