diff --git a/phpstan.neon b/phpstan.neon index c3af9c45..4fa0bf43 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -13,20 +13,30 @@ parameters: - '*/tests/**/Fixture/*' ignoreErrors: - # partial enum - - '#Method Symplify\\CodingStandard\\TokenRunner\\Analyzer\\FixerAnalyzer\\BlockFinder\:\:(getBlockTypeByContent|getBlockTypeByToken)\(\) never returns \d+ so it can be removed from the return type#' - - path: tests/bootstrap.php message: '#Instantiated class PHP_CodeSniffer\\Util\\Tokens not found#' - '#Constant T_OPEN_CURLY_BRACKET|T_START_NOWDOC not found#' - - '#Method Symplify\\CodingStandard\\TokenRunner\\Traverser\\ArrayBlockInfoFinder\:\:reverseTokens\(\) should return array but returns array#' # unused generics - '#Class (.*?) implements generic interface PhpCsFixer\\Fixer\\ConfigurableFixerInterface but does not specify its types\: TFixerInputConfig, TFixerComputedConfig#' # conditional check to allow various php versions - - message: '#Comparison operation ">\=" between int<80200, 80499> and (.*?) is always true#' + message: '#Comparison operation ">\=" between int<80200, 80599> and (.*?) is always true#' path: src/TokenAnalyzer/DocblockRelatedParamNamesResolver.php + + # offset access issues + - + message: '#Offset int\|null might not exist on PhpCsFixer\\Tokenizer\\Tokens#' + path: src/Fixer/Naming/ClassNameResolver.php + + - + message: '#Offset int\|null might not exist on PhpCsFixer\\Tokenizer\\Tokens#' + path: src/Fixer/Naming/MethodNameResolver.php + + # array filter issue + - + message: '#Parameter \#1 \$array \(array\) to function array_filter does not contain falsy values, the array will always stay the same#' + path: src/TokenRunner/Traverser/TokenReverser.php diff --git a/rector.php b/rector.php index 117979ed..b65f0b5b 100644 --- a/rector.php +++ b/rector.php @@ -8,7 +8,7 @@ ->withPaths([__DIR__ . '/config', __DIR__ . '/src', __DIR__ . '/tests']) ->withRootFiles() ->withPhpSets() - ->withPreparedSets(codeQuality: true, codingStyle: true, naming: true, earlyReturn: true, privatization: true) + ->withPreparedSets(codeQuality: true, codingStyle: true, privatization: true, naming: true, earlyReturn: true) ->withImportNames() ->withSkip([ '*/Source/*', diff --git a/src/TokenRunner/Analyzer/FixerAnalyzer/TokenSkipper.php b/src/TokenRunner/Analyzer/FixerAnalyzer/TokenSkipper.php index aa577dc2..54614f21 100644 --- a/src/TokenRunner/Analyzer/FixerAnalyzer/TokenSkipper.php +++ b/src/TokenRunner/Analyzer/FixerAnalyzer/TokenSkipper.php @@ -57,10 +57,18 @@ public function skipBlocksReversed(Tokens $tokens, int $position): int { /** @var Token $token */ $token = $tokens[$position]; - if (! $token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE) && ! $token->equals(')')) { + if (! $token->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_CLOSE) && ! $token->equals(')') && ! $token->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) { return $position; } + // Check if this is an attribute closing bracket + if ($token->isGivenKind(CT::T_ATTRIBUTE_CLOSE)) { + $attributeStartPosition = $this->findAttributeStart($tokens, $position); + if ($attributeStartPosition !== null) { + return $attributeStartPosition; + } + } + $blockInfo = $this->blockFinder->findInTokensByEdge($tokens, $position); if (! $blockInfo instanceof BlockInfo) { throw new ShouldNotHappenException(); @@ -68,4 +76,26 @@ public function skipBlocksReversed(Tokens $tokens, int $position): int return $blockInfo->getStart(); } + + /** + * @param Tokens $tokens + */ + private function findAttributeStart(Tokens $tokens, int $closingBracketPosition): ?int + { + // Search backwards for T_ATTRIBUTE token (#[) + for ($i = $closingBracketPosition - 1; $i >= 0; --$i) { + $currentToken = $tokens[$i]; + + if ($currentToken->isGivenKind(T_ATTRIBUTE)) { + return $i; + } + + // If we hit another ] or reach a statement boundary, stop searching + if ($currentToken->equals(']') || $currentToken->equals(';') || $currentToken->equals('{') || $currentToken->equals('}')) { + break; + } + } + + return null; + } } diff --git a/src/TokenRunner/Transformer/FixerTransformer/TokensNewliner.php b/src/TokenRunner/Transformer/FixerTransformer/TokensNewliner.php index 95780d4b..eca2e39e 100644 --- a/src/TokenRunner/Transformer/FixerTransformer/TokensNewliner.php +++ b/src/TokenRunner/Transformer/FixerTransformer/TokensNewliner.php @@ -51,11 +51,11 @@ public function breakItems(BlockInfo $blockInfo, Tokens $tokens, int $kind): voi // again, from the bottom to the top for ($i = $blockInfo->getEnd() - 1; $i >= $blockInfo->getStart(); --$i) { + $i = $this->tokenSkipper->skipBlocksReversed($tokens, $i); + /** @var Token $currentToken */ $currentToken = $tokens[$i]; - $i = $this->tokenSkipper->skipBlocksReversed($tokens, $i); - // 2. new line after each comma ",", instead of just space if ($currentToken->getContent() === ',') { if ($this->isLastItem($tokens, $i)) { diff --git a/tests/Fixer/Spacing/StandaloneLinePromotedPropertyFixer/Fixture/skip_attributes.php.inc b/tests/Fixer/Spacing/StandaloneLinePromotedPropertyFixer/Fixture/skip_attributes.php.inc new file mode 100644 index 00000000..460eb0cb --- /dev/null +++ b/tests/Fixer/Spacing/StandaloneLinePromotedPropertyFixer/Fixture/skip_attributes.php.inc @@ -0,0 +1,96 @@ + +----- +