From d130f477c4cc94507e03a5a990d37d4b05fb105a Mon Sep 17 00:00:00 2001 From: John Rayes Date: Thu, 11 Jun 2026 03:12:17 -0700 Subject: [PATCH 1/4] Further improves SectionComments --- .github/phpcs/SectionComments.php | 148 ++++++++++++++++-------------- 1 file changed, 80 insertions(+), 68 deletions(-) diff --git a/.github/phpcs/SectionComments.php b/.github/phpcs/SectionComments.php index 3441cd9fda1..98634f4bf12 100644 --- a/.github/phpcs/SectionComments.php +++ b/.github/phpcs/SectionComments.php @@ -99,10 +99,10 @@ public function __construct() ]; foreach ($this->comments as $type => $string) { - $regexes[$type] = preg_replace('/\s+/', '\s+', preg_quote($string, '/')); + $words[] = trim($string, "/* \n\t"); } - $this->comment_regex = implode('|', $regexes); + $this->comment_regex = '/^\/[*\s]+(?:' . implode('|', $words) . ')[*\s]+\/$/'; } public function getName(): string @@ -207,32 +207,16 @@ public function isCandidate(Tokens $tokens): bool protected function applyFix(\SplFileInfo $file, Tokens $tokens): void { - // First remove any existing section comments. + $existing = []; + foreach ($tokens as $key => $token) { - if ($token->getName() === 'T_COMMENT') { - if (preg_match('/^' . $this->comment_regex . '$/', $token->getContent())) { - $tokens->clearAt($key); - - if ($tokens[$key + 1]->isWhitespace()) { - $tokens[$key + 1] = new Token([ - T_WHITESPACE, - "\n\n\t", - ]); - } else { - $tokens->insertAt( - $key + 1, - new Token([ - T_WHITESPACE, - "\n\n\t", - ]), - ); - } + if ($token->getId() === T_COMMENT) { + if (preg_match($this->comment_regex, $token->getContent())) { + $existing[$key] = true; } } } - $tokens->clearEmptyTokens(); - // Does this file contain an enumeration? $is_enum = $tokens->isAnyTokenKindsFound([T_ENUM]); @@ -254,57 +238,58 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void $in = []; foreach ($tokens as $key => $token) { - $name = $token->getName(); + $id = $token->getId(); // Build up the list of token types so that we can figure out // which comment type we will want. if (\in_array( - $name, - empty($in) ? [ - 'T_PUBLIC', - 'T_PROTECTED', - 'T_PRIVATE', - $is_enum && !$exists['case'] ? 'T_CASE' : NAN, + $id, + $in === [] ? [ + T_PUBLIC, + T_PROTECTED, + T_PRIVATE, + $is_enum && !$exists['case'] ? T_CASE : -1, ] : [ - 'T_CONST', - 'T_STATIC', - 'T_VARIABLE', - 'T_FUNCTION', + T_CONST, + T_STATIC, + T_VARIABLE, + T_FUNCTION, ], + true, )) { - $in[$name] = $key; + $in[$id] = $key; } // Which comment type do we want to insert? - if (\array_key_exists('T_CONST', $in)) { + if (isset($in[T_CONST])) { $insert_type = 'const'; - } elseif ($is_enum && !$exists['case'] && \array_key_exists('T_CASE', $in)) { + } elseif ($is_enum && !$exists['case'] && isset($in[T_CASE])) { $insert_type = 'case'; - } elseif (\array_key_exists('T_VARIABLE', $in)) { - if (\array_key_exists('T_STATIC', $in)) { - if (\array_key_exists('T_PUBLIC', $in)) { + } elseif (isset($in[T_VARIABLE])) { + if (isset($in[T_STATIC])) { + if (isset($in[T_PUBLIC])) { $insert_type = 'public_static_property'; - } elseif (\array_key_exists('T_PROTECTED', $in) || \array_key_exists('T_PRIVATE', $in)) { + } elseif (isset($in[T_PROTECTED]) || isset($in[T_PRIVATE])) { $insert_type = 'internal_static_property'; } } else { - if (\array_key_exists('T_PUBLIC', $in)) { + if (isset($in[T_PUBLIC])) { $insert_type = 'public_property'; - } elseif (\array_key_exists('T_PROTECTED', $in) || \array_key_exists('T_PRIVATE', $in)) { + } elseif (isset($in[T_PROTECTED]) || isset($in[T_PRIVATE])) { $insert_type = 'internal_property'; } } - } elseif (\array_key_exists('T_FUNCTION', $in)) { - if (\array_key_exists('T_STATIC', $in)) { - if (\array_key_exists('T_PUBLIC', $in)) { + } elseif (isset($in[T_FUNCTION])) { + if (isset($in[T_STATIC])) { + if (isset($in[T_PUBLIC])) { $insert_type = 'public_static_method'; - } elseif (\array_key_exists('T_PROTECTED', $in) || \array_key_exists('T_PRIVATE', $in)) { + } elseif (isset($in[T_PROTECTED]) || isset($in[T_PRIVATE])) { $insert_type = 'internal_static_method'; } } else { - if (\array_key_exists('T_PUBLIC', $in)) { + if (isset($in[T_PUBLIC])) { $insert_type = 'public_method'; - } elseif (\array_key_exists('T_PROTECTED', $in) || \array_key_exists('T_PRIVATE', $in)) { + } elseif (isset($in[T_PROTECTED]) || isset($in[T_PRIVATE])) { $insert_type = 'internal_method'; } } @@ -332,27 +317,44 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void // Now we need to take one step forward again. $insert_at++; - // Create the comment to insert. - $to_insert = [ - new Token([ - T_COMMENT, - $this->comments[$insert_type], - ]), - ]; - - // If necessary, also insert some whitespace. - if (!$tokens[$insert_at]->isWhitespace()) { - $to_insert[] = new Token([ - T_WHITESPACE, - "\n\n\t", - ]); - } + if ($tokens[$insert_at]->getContent() !== $this->comments[$insert_type]) { + // Create the comment to insert. + $to_insert = [ + new Token([ + T_COMMENT, + $this->comments[$insert_type], + ]), + ]; + + // If necessary, also insert some whitespace. + if (!$tokens[$insert_at]->isWhitespace()) { + $to_insert[] = new Token([ + T_WHITESPACE, + "\n\n\t", + ]); + } + + // Insert our comment. + $slices[$insert_at] = $to_insert; + + // This comment type has now been done. + $exists[$insert_type] = true; + } else { + // Normalize whitespace. + if ($tokens[$insert_at + 1]->isWhitespace()) { + $tokens[$insert_at + 1] = new Token([ + T_WHITESPACE, + "\n\n\t", + ]); + } - // Insert our comment. - $slices[$insert_at] = $to_insert; + $exists[$insert_type] = true; - // This comment type has now been done. - $exists[$insert_type] = true; + // Do not remove this token. + if (isset($existing[$insert_at])) { + unset($existing[$insert_at]); + } + } } $in = []; @@ -360,6 +362,16 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void } } + // Any existing tokens to empty out? + foreach ($existing as $key => $_) { + $tokens->clearAt($key); + + // If necessary, also delete whitespace. + if ($tokens[$key + 1]->isWhitespace()) { + $tokens->clearAt($key + 1); + } + } + // Insert comments. if ($slices !== []) { $tokens->insertSlices($slices); From ed25b387f295490ad66e605ba06f5cf0cbb2c7dd Mon Sep 17 00:00:00 2001 From: John Rayes Date: Thu, 18 Jun 2026 08:34:28 -0700 Subject: [PATCH 2/4] normalizes whitespace around existing section comment --- .github/phpcs/SectionComments.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/phpcs/SectionComments.php b/.github/phpcs/SectionComments.php index 98634f4bf12..cb34a415f90 100644 --- a/.github/phpcs/SectionComments.php +++ b/.github/phpcs/SectionComments.php @@ -341,6 +341,15 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void $exists[$insert_type] = true; } else { // Normalize whitespace. + if ($tokens[$insert_at - 1]->isWhitespace()) { + $prev = $tokens->getPrevMeaningfulToken($insert_at); + + $tokens[$insert_at - 1] = new Token([ + T_WHITESPACE, + $tokens[$prev]->equals('{') ? "\n\t" : "\n\n\t", + ]); + } + if ($tokens[$insert_at + 1]->isWhitespace()) { $tokens[$insert_at + 1] = new Token([ T_WHITESPACE, From c01ddf6c47e264d7e683a5bf63d5a4134f1fe45c Mon Sep 17 00:00:00 2001 From: John Rayes Date: Thu, 18 Jun 2026 17:54:23 -0700 Subject: [PATCH 3/4] Include attributes in tokens to skip --- .github/phpcs/SectionComments.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/phpcs/SectionComments.php b/.github/phpcs/SectionComments.php index cb34a415f90..62417e13481 100644 --- a/.github/phpcs/SectionComments.php +++ b/.github/phpcs/SectionComments.php @@ -19,6 +19,7 @@ use PhpCsFixer\FixerDefinition\CodeSample; use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; +use PhpCsFixer\Tokenizer\CT; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; @@ -317,6 +318,21 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void // Now we need to take one step forward again. $insert_at++; + // Rewind to the first attribute in an attribute group. + while ($tokens[$prev_index = $tokens->getPrevMeaningfulToken($insert_at)]->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) { + $insert_at = $tokens->findBlockStart(Tokens::BLOCK_TYPE_ATTRIBUTE, $prev_index); + + while ( + isset($tokens[$insert_at - 1]) + && ($tokens[$insert_at - 1]->isWhitespace() || $tokens[$insert_at - 1]->isComment()) + ) { + $insert_at--; + } + + // Now we need to take one step forward again. + $insert_at++; + } + if ($tokens[$insert_at]->getContent() !== $this->comments[$insert_type]) { // Create the comment to insert. $to_insert = [ From 330f18e5d6407ca198890acdf757ad48feb370f9 Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sun, 12 Jul 2026 03:22:56 -0700 Subject: [PATCH 4/4] Update .github/phpcs/SectionComments.php Co-authored-by: Jon Stovell --- .github/phpcs/SectionComments.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/phpcs/SectionComments.php b/.github/phpcs/SectionComments.php index 62417e13481..6f92b89ad77 100644 --- a/.github/phpcs/SectionComments.php +++ b/.github/phpcs/SectionComments.php @@ -249,7 +249,7 @@ protected function applyFix(\SplFileInfo $file, Tokens $tokens): void T_PUBLIC, T_PROTECTED, T_PRIVATE, - $is_enum && !$exists['case'] ? T_CASE : -1, + $is_enum && !$exists['case'] ? T_CASE : NAN, ] : [ T_CONST, T_STATIC,