Find this useful? Enter your email to receive occasional updates for securing PHP code.
Signing you up...
Thank you for signing up!
PHP Decode
<?php declare(strict_types=1); /* * This file is part of PHP CS Fixer. * * (c) Fabien..
Decoded Output download
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <[email protected]>
* Dariusz Rumiski <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\ControlStructure;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
use Symfony\Component\OptionsResolver\Options;
/**
* Fixer for rule defined in PSR2 5.2.
*
* @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
*
* @phpstan-type _AutogeneratedInputConfiguration array{
* comment_text?: string
* }
* @phpstan-type _AutogeneratedComputedConfiguration array{
* comment_text: string
* }
*/
final class NoBreakCommentFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
{
/** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
use ConfigurableFixerTrait;
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'There must be a comment when fall-through is intentional in a non-empty case body.',
[
new CodeSample(
'<?php
switch ($foo) {
case 1:
foo();
case 2:
bar();
// no break
break;
case 3:
baz();
}
'
),
new CodeSample(
'<?php
switch ($foo) {
case 1:
foo();
case 2:
foo();
}
',
['comment_text' => 'some comment']
),
],
'Adds a "no break" comment before fall-through cases, and removes it if there is no fall-through.'
);
}
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_SWITCH);
}
/**
* {@inheritdoc}
*
* Must run after NoUselessElseFixer.
*/
public function getPriority(): int
{
return 0;
}
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('comment_text', 'The text to use in the added comment and to detect it.'))
->setAllowedTypes(['string'])
->setAllowedValues([
static function (string $value): bool {
if (Preg::match('/\R/', $value)) {
throw new InvalidOptionsException('The comment text must not contain new lines.');
}
return true;
},
])
->setNormalizer(static fn (Options $options, string $value): string => rtrim($value))
->setDefault('no break')
->getOption(),
]);
}
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = \count($tokens) - 1; $index >= 0; --$index) {
if ($tokens[$index]->isGivenKind(T_DEFAULT)) {
if ($tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_DOUBLE_ARROW)) {
continue; // this is "default" from "match"
}
} elseif (!$tokens[$index]->isGivenKind(T_CASE)) {
continue;
}
$this->fixCase($tokens, $tokens->getNextTokenOfKind($index, [':', ';']));
}
}
private function fixCase(Tokens $tokens, int $casePosition): void
{
$empty = true;
$fallThrough = true;
$commentPosition = null;
for ($i = $casePosition + 1, $max = \count($tokens); $i < $max; ++$i) {
if ($tokens[$i]->isGivenKind([...self::getParenthesisedStructureKinds(), T_ELSE, T_DO, T_CLASS])) {
$empty = false;
$i = $this->getStructureEnd($tokens, $i);
continue;
}
if ($tokens[$i]->isGivenKind([T_BREAK, T_CONTINUE, T_RETURN, T_EXIT, T_GOTO])) {
$fallThrough = false;
continue;
}
if ($tokens[$i]->isGivenKind(T_THROW)) {
$previousIndex = $tokens->getPrevMeaningfulToken($i);
if ($previousIndex === $casePosition || $tokens[$previousIndex]->equalsAny(['{', ';', '}', [T_OPEN_TAG]])) {
$fallThrough = false;
}
continue;
}
if ($tokens[$i]->equals('}') || $tokens[$i]->isGivenKind(T_ENDSWITCH)) {
if (null !== $commentPosition) {
$this->removeComment($tokens, $commentPosition);
}
break;
}
if ($this->isNoBreakComment($tokens[$i])) {
$commentPosition = $i;
continue;
}
if ($tokens[$i]->isGivenKind([T_CASE, T_DEFAULT])) {
if (!$empty && $fallThrough) {
if (null !== $commentPosition && $tokens->getPrevNonWhitespace($i) !== $commentPosition) {
$this->removeComment($tokens, $commentPosition);
$commentPosition = null;
}
if (null === $commentPosition) {
$this->insertCommentAt($tokens, $i);
} else {
$text = $this->configuration['comment_text'];
$tokens[$commentPosition] = new Token([
$tokens[$commentPosition]->getId(),
str_ireplace($text, $text, $tokens[$commentPosition]->getContent()),
]);
$this->ensureNewLineAt($tokens, $commentPosition);
}
} elseif (null !== $commentPosition) {
$this->removeComment($tokens, $commentPosition);
}
break;
}
if (!$tokens[$i]->isGivenKind([T_COMMENT, T_WHITESPACE])) {
$empty = false;
}
}
}
private function isNoBreakComment(Token $token): bool
{
if (!$token->isComment()) {
return false;
}
$text = preg_quote($this->configuration['comment_text'], '~');
return Preg::match("~^((//|#)\s*{$text}\s*)|(/\*\*?\s*{$text}(\s+.*)*\*/)$~i", $token->getContent());
}
private function insertCommentAt(Tokens $tokens, int $casePosition): void
{
$lineEnding = $this->whitespacesConfig->getLineEnding();
$newlinePosition = $this->ensureNewLineAt($tokens, $casePosition);
$newlineToken = $tokens[$newlinePosition];
$nbNewlines = substr_count($newlineToken->getContent(), $lineEnding);
if ($newlineToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $newlineToken->getContent())) {
++$nbNewlines;
} elseif ($tokens[$newlinePosition - 1]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$newlinePosition - 1]->getContent())) {
++$nbNewlines;
if (!Preg::match('/\R/', $newlineToken->getContent())) {
$tokens[$newlinePosition] = new Token([$newlineToken->getId(), $lineEnding.$newlineToken->getContent()]);
}
}
if ($nbNewlines > 1) {
Preg::match('/^(.*?)(\R\h*)$/s', $newlineToken->getContent(), $matches);
$indent = WhitespacesAnalyzer::detectIndent($tokens, $newlinePosition - 1);
$tokens[$newlinePosition] = new Token([$newlineToken->getId(), $matches[1].$lineEnding.$indent]);
$tokens->insertAt(++$newlinePosition, new Token([T_WHITESPACE, $matches[2]]));
}
$tokens->insertAt($newlinePosition, new Token([T_COMMENT, '// '.$this->configuration['comment_text']]));
$this->ensureNewLineAt($tokens, $newlinePosition);
}
/**
* @return int The newline token position
*/
private function ensureNewLineAt(Tokens $tokens, int $position): int
{
$lineEnding = $this->whitespacesConfig->getLineEnding();
$content = $lineEnding.WhitespacesAnalyzer::detectIndent($tokens, $position);
$whitespaceToken = $tokens[$position - 1];
if (!$whitespaceToken->isGivenKind(T_WHITESPACE)) {
if ($whitespaceToken->isGivenKind(T_OPEN_TAG)) {
$content = Preg::replace('/\R/', '', $content);
if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
$tokens[$position - 1] = new Token([T_OPEN_TAG, Preg::replace('/\s+$/', $lineEnding, $whitespaceToken->getContent())]);
}
}
if ('' !== $content) {
$tokens->insertAt($position, new Token([T_WHITESPACE, $content]));
return $position;
}
return $position - 1;
}
if ($tokens[$position - 2]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$position - 2]->getContent())) {
$content = Preg::replace('/^\R/', '', $content);
}
if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
$tokens[$position - 1] = new Token([T_WHITESPACE, $content]);
}
return $position - 1;
}
private function removeComment(Tokens $tokens, int $commentPosition): void
{
if ($tokens[$tokens->getPrevNonWhitespace($commentPosition)]->isGivenKind(T_OPEN_TAG)) {
$whitespacePosition = $commentPosition + 1;
$regex = '/^\R\h*/';
} else {
$whitespacePosition = $commentPosition - 1;
$regex = '/\R\h*$/';
}
$whitespaceToken = $tokens[$whitespacePosition];
if ($whitespaceToken->isGivenKind(T_WHITESPACE)) {
$content = Preg::replace($regex, '', $whitespaceToken->getContent());
$tokens->ensureWhitespaceAtIndex($whitespacePosition, 0, $content);
}
$tokens->clearTokenAndMergeSurroundingWhitespace($commentPosition);
}
private function getStructureEnd(Tokens $tokens, int $position): int
{
$initialToken = $tokens[$position];
if ($initialToken->isGivenKind(self::getParenthesisedStructureKinds())) {
$position = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$tokens->getNextTokenOfKind($position, ['('])
);
} elseif ($initialToken->isGivenKind(T_CLASS)) {
$openParenthesisPosition = $tokens->getNextMeaningfulToken($position);
if ('(' === $tokens[$openParenthesisPosition]->getContent()) {
$position = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$openParenthesisPosition
);
}
}
$position = $tokens->getNextMeaningfulToken($position);
if ('{' !== $tokens[$position]->getContent()) {
return $tokens->getNextTokenOfKind($position, [';']);
}
$position = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $position);
if ($initialToken->isGivenKind(T_DO)) {
$position = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$tokens->getNextTokenOfKind($position, ['('])
);
return $tokens->getNextTokenOfKind($position, [';']);
}
return $position;
}
/**
* @return list<int>
*/
private static function getParenthesisedStructureKinds(): array
{
static $structureKinds = null;
if (null === $structureKinds) {
$structureKinds = [T_FOR, T_FOREACH, T_WHILE, T_IF, T_ELSEIF, T_SWITCH, T_FUNCTION];
if (\defined('T_MATCH')) { // @TODO: drop condition when PHP 8.0+ is required
$structureKinds[] = T_MATCH;
}
}
return $structureKinds;
}
}
?>
Did this file decode correctly?
Original Code
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <[email protected]>
* Dariusz Rumiski <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\ControlStructure;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\ConfigurableFixerTrait;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
use Symfony\Component\OptionsResolver\Options;
/**
* Fixer for rule defined in PSR2 5.2.
*
* @implements ConfigurableFixerInterface<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration>
*
* @phpstan-type _AutogeneratedInputConfiguration array{
* comment_text?: string
* }
* @phpstan-type _AutogeneratedComputedConfiguration array{
* comment_text: string
* }
*/
final class NoBreakCommentFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
{
/** @use ConfigurableFixerTrait<_AutogeneratedInputConfiguration, _AutogeneratedComputedConfiguration> */
use ConfigurableFixerTrait;
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'There must be a comment when fall-through is intentional in a non-empty case body.',
[
new CodeSample(
'<?php
switch ($foo) {
case 1:
foo();
case 2:
bar();
// no break
break;
case 3:
baz();
}
'
),
new CodeSample(
'<?php
switch ($foo) {
case 1:
foo();
case 2:
foo();
}
',
['comment_text' => 'some comment']
),
],
'Adds a "no break" comment before fall-through cases, and removes it if there is no fall-through.'
);
}
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_SWITCH);
}
/**
* {@inheritdoc}
*
* Must run after NoUselessElseFixer.
*/
public function getPriority(): int
{
return 0;
}
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('comment_text', 'The text to use in the added comment and to detect it.'))
->setAllowedTypes(['string'])
->setAllowedValues([
static function (string $value): bool {
if (Preg::match('/\R/', $value)) {
throw new InvalidOptionsException('The comment text must not contain new lines.');
}
return true;
},
])
->setNormalizer(static fn (Options $options, string $value): string => rtrim($value))
->setDefault('no break')
->getOption(),
]);
}
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = \count($tokens) - 1; $index >= 0; --$index) {
if ($tokens[$index]->isGivenKind(T_DEFAULT)) {
if ($tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_DOUBLE_ARROW)) {
continue; // this is "default" from "match"
}
} elseif (!$tokens[$index]->isGivenKind(T_CASE)) {
continue;
}
$this->fixCase($tokens, $tokens->getNextTokenOfKind($index, [':', ';']));
}
}
private function fixCase(Tokens $tokens, int $casePosition): void
{
$empty = true;
$fallThrough = true;
$commentPosition = null;
for ($i = $casePosition + 1, $max = \count($tokens); $i < $max; ++$i) {
if ($tokens[$i]->isGivenKind([...self::getParenthesisedStructureKinds(), T_ELSE, T_DO, T_CLASS])) {
$empty = false;
$i = $this->getStructureEnd($tokens, $i);
continue;
}
if ($tokens[$i]->isGivenKind([T_BREAK, T_CONTINUE, T_RETURN, T_EXIT, T_GOTO])) {
$fallThrough = false;
continue;
}
if ($tokens[$i]->isGivenKind(T_THROW)) {
$previousIndex = $tokens->getPrevMeaningfulToken($i);
if ($previousIndex === $casePosition || $tokens[$previousIndex]->equalsAny(['{', ';', '}', [T_OPEN_TAG]])) {
$fallThrough = false;
}
continue;
}
if ($tokens[$i]->equals('}') || $tokens[$i]->isGivenKind(T_ENDSWITCH)) {
if (null !== $commentPosition) {
$this->removeComment($tokens, $commentPosition);
}
break;
}
if ($this->isNoBreakComment($tokens[$i])) {
$commentPosition = $i;
continue;
}
if ($tokens[$i]->isGivenKind([T_CASE, T_DEFAULT])) {
if (!$empty && $fallThrough) {
if (null !== $commentPosition && $tokens->getPrevNonWhitespace($i) !== $commentPosition) {
$this->removeComment($tokens, $commentPosition);
$commentPosition = null;
}
if (null === $commentPosition) {
$this->insertCommentAt($tokens, $i);
} else {
$text = $this->configuration['comment_text'];
$tokens[$commentPosition] = new Token([
$tokens[$commentPosition]->getId(),
str_ireplace($text, $text, $tokens[$commentPosition]->getContent()),
]);
$this->ensureNewLineAt($tokens, $commentPosition);
}
} elseif (null !== $commentPosition) {
$this->removeComment($tokens, $commentPosition);
}
break;
}
if (!$tokens[$i]->isGivenKind([T_COMMENT, T_WHITESPACE])) {
$empty = false;
}
}
}
private function isNoBreakComment(Token $token): bool
{
if (!$token->isComment()) {
return false;
}
$text = preg_quote($this->configuration['comment_text'], '~');
return Preg::match("~^((//|#)\\s*{$text}\\s*)|(/\\*\\*?\\s*{$text}(\\s+.*)*\\*/)$~i", $token->getContent());
}
private function insertCommentAt(Tokens $tokens, int $casePosition): void
{
$lineEnding = $this->whitespacesConfig->getLineEnding();
$newlinePosition = $this->ensureNewLineAt($tokens, $casePosition);
$newlineToken = $tokens[$newlinePosition];
$nbNewlines = substr_count($newlineToken->getContent(), $lineEnding);
if ($newlineToken->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $newlineToken->getContent())) {
++$nbNewlines;
} elseif ($tokens[$newlinePosition - 1]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$newlinePosition - 1]->getContent())) {
++$nbNewlines;
if (!Preg::match('/\R/', $newlineToken->getContent())) {
$tokens[$newlinePosition] = new Token([$newlineToken->getId(), $lineEnding.$newlineToken->getContent()]);
}
}
if ($nbNewlines > 1) {
Preg::match('/^(.*?)(\R\h*)$/s', $newlineToken->getContent(), $matches);
$indent = WhitespacesAnalyzer::detectIndent($tokens, $newlinePosition - 1);
$tokens[$newlinePosition] = new Token([$newlineToken->getId(), $matches[1].$lineEnding.$indent]);
$tokens->insertAt(++$newlinePosition, new Token([T_WHITESPACE, $matches[2]]));
}
$tokens->insertAt($newlinePosition, new Token([T_COMMENT, '// '.$this->configuration['comment_text']]));
$this->ensureNewLineAt($tokens, $newlinePosition);
}
/**
* @return int The newline token position
*/
private function ensureNewLineAt(Tokens $tokens, int $position): int
{
$lineEnding = $this->whitespacesConfig->getLineEnding();
$content = $lineEnding.WhitespacesAnalyzer::detectIndent($tokens, $position);
$whitespaceToken = $tokens[$position - 1];
if (!$whitespaceToken->isGivenKind(T_WHITESPACE)) {
if ($whitespaceToken->isGivenKind(T_OPEN_TAG)) {
$content = Preg::replace('/\R/', '', $content);
if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
$tokens[$position - 1] = new Token([T_OPEN_TAG, Preg::replace('/\s+$/', $lineEnding, $whitespaceToken->getContent())]);
}
}
if ('' !== $content) {
$tokens->insertAt($position, new Token([T_WHITESPACE, $content]));
return $position;
}
return $position - 1;
}
if ($tokens[$position - 2]->isGivenKind(T_OPEN_TAG) && Preg::match('/\R/', $tokens[$position - 2]->getContent())) {
$content = Preg::replace('/^\R/', '', $content);
}
if (!Preg::match('/\R/', $whitespaceToken->getContent())) {
$tokens[$position - 1] = new Token([T_WHITESPACE, $content]);
}
return $position - 1;
}
private function removeComment(Tokens $tokens, int $commentPosition): void
{
if ($tokens[$tokens->getPrevNonWhitespace($commentPosition)]->isGivenKind(T_OPEN_TAG)) {
$whitespacePosition = $commentPosition + 1;
$regex = '/^\R\h*/';
} else {
$whitespacePosition = $commentPosition - 1;
$regex = '/\R\h*$/';
}
$whitespaceToken = $tokens[$whitespacePosition];
if ($whitespaceToken->isGivenKind(T_WHITESPACE)) {
$content = Preg::replace($regex, '', $whitespaceToken->getContent());
$tokens->ensureWhitespaceAtIndex($whitespacePosition, 0, $content);
}
$tokens->clearTokenAndMergeSurroundingWhitespace($commentPosition);
}
private function getStructureEnd(Tokens $tokens, int $position): int
{
$initialToken = $tokens[$position];
if ($initialToken->isGivenKind(self::getParenthesisedStructureKinds())) {
$position = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$tokens->getNextTokenOfKind($position, ['('])
);
} elseif ($initialToken->isGivenKind(T_CLASS)) {
$openParenthesisPosition = $tokens->getNextMeaningfulToken($position);
if ('(' === $tokens[$openParenthesisPosition]->getContent()) {
$position = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$openParenthesisPosition
);
}
}
$position = $tokens->getNextMeaningfulToken($position);
if ('{' !== $tokens[$position]->getContent()) {
return $tokens->getNextTokenOfKind($position, [';']);
}
$position = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $position);
if ($initialToken->isGivenKind(T_DO)) {
$position = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$tokens->getNextTokenOfKind($position, ['('])
);
return $tokens->getNextTokenOfKind($position, [';']);
}
return $position;
}
/**
* @return list<int>
*/
private static function getParenthesisedStructureKinds(): array
{
static $structureKinds = null;
if (null === $structureKinds) {
$structureKinds = [T_FOR, T_FOREACH, T_WHILE, T_IF, T_ELSEIF, T_SWITCH, T_FUNCTION];
if (\defined('T_MATCH')) { // @TODO: drop condition when PHP 8.0+ is required
$structureKinds[] = T_MATCH;
}
}
return $structureKinds;
}
}
Function Calls
None |
Stats
MD5 | 93a805e75a136d10fb496d766add7860 |
Eval Count | 0 |
Decode Time | 91 ms |