Missing dependancies
This commit is contained in:
+295
@@ -0,0 +1,295 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of PHP CS Fixer.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace PhpCsFixer\Fixer\Semicolon;
|
||||
|
||||
use PhpCsFixer\AbstractFixer;
|
||||
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
|
||||
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\Token;
|
||||
use PhpCsFixer\Tokenizer\Tokens;
|
||||
|
||||
/**
|
||||
* @author Graham Campbell <hello@gjcampbell.co.uk>
|
||||
* @author Egidijus Girčys <e.gircys@gmail.com>
|
||||
*/
|
||||
final class MultilineWhitespaceBeforeSemicolonsFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public const STRATEGY_NO_MULTI_LINE = 'no_multi_line';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public const STRATEGY_NEW_LINE_FOR_CHAINED_CALLS = 'new_line_for_chained_calls';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition(): FixerDefinitionInterface
|
||||
{
|
||||
return new FixerDefinition(
|
||||
'Forbid multi-line whitespace before the closing semicolon or move the semicolon to the new line for chained calls.',
|
||||
[
|
||||
new CodeSample(
|
||||
'<?php
|
||||
function foo () {
|
||||
return 1 + 2
|
||||
;
|
||||
}
|
||||
'
|
||||
),
|
||||
new CodeSample(
|
||||
'<?php
|
||||
$this->method1()
|
||||
->method2()
|
||||
->method(3);
|
||||
?>
|
||||
',
|
||||
['strategy' => self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS]
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Must run before SpaceAfterSemicolonFixer.
|
||||
* Must run after CombineConsecutiveIssetsFixer, GetClassToClassKeywordFixer, NoEmptyStatementFixer, SimplifiedIfReturnFixer, SingleImportPerStatementFixer.
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCandidate(Tokens $tokens): bool
|
||||
{
|
||||
return $tokens->isTokenKindFound(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
|
||||
{
|
||||
return new FixerConfigurationResolver([
|
||||
(new FixerOptionBuilder(
|
||||
'strategy',
|
||||
'Forbid multi-line whitespace or move the semicolon to the new line for chained calls.'
|
||||
))
|
||||
->setAllowedValues([self::STRATEGY_NO_MULTI_LINE, self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS])
|
||||
->setDefault(self::STRATEGY_NO_MULTI_LINE)
|
||||
->getOption(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
|
||||
{
|
||||
if (self::STRATEGY_NEW_LINE_FOR_CHAINED_CALLS === $this->configuration['strategy']) {
|
||||
$this->applyChainedCallsFix($tokens);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (self::STRATEGY_NO_MULTI_LINE === $this->configuration['strategy']) {
|
||||
$this->applyNoMultiLineFix($tokens);
|
||||
}
|
||||
}
|
||||
|
||||
private function applyNoMultiLineFix(Tokens $tokens): void
|
||||
{
|
||||
$lineEnding = $this->whitespacesConfig->getLineEnding();
|
||||
|
||||
foreach ($tokens as $index => $token) {
|
||||
if (!$token->equals(';')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$previousIndex = $index - 1;
|
||||
$previous = $tokens[$previousIndex];
|
||||
if (!$previous->isWhitespace() || !str_contains($previous->getContent(), "\n")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = $previous->getContent();
|
||||
if (str_starts_with($content, $lineEnding) && $tokens[$index - 2]->isComment()) {
|
||||
$tokens->ensureWhitespaceAtIndex($previousIndex, 0, $lineEnding);
|
||||
} else {
|
||||
$tokens->clearAt($previousIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function applyChainedCallsFix(Tokens $tokens): void
|
||||
{
|
||||
for ($index = \count($tokens) - 1; $index >= 0; --$index) {
|
||||
// continue if token is not a semicolon
|
||||
if (!$tokens[$index]->equals(';')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the indent of the chained call, null in case it's not a chained call
|
||||
$indent = $this->findWhitespaceBeforeFirstCall($index - 1, $tokens);
|
||||
|
||||
if (null === $indent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// unset semicolon
|
||||
$tokens->clearAt($index);
|
||||
|
||||
// find the line ending token index after the semicolon
|
||||
$index = $this->getNewLineIndex($index, $tokens);
|
||||
|
||||
// line ending string of the last method call
|
||||
$lineEnding = $this->whitespacesConfig->getLineEnding();
|
||||
|
||||
// appended new line to the last method call
|
||||
$newline = new Token([T_WHITESPACE, $lineEnding.$indent]);
|
||||
|
||||
// insert the new line with indented semicolon
|
||||
$tokens->insertAt($index, [$newline, new Token(';')]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index for the new line. Return the given index when there's no new line.
|
||||
*/
|
||||
private function getNewLineIndex(int $index, Tokens $tokens): int
|
||||
{
|
||||
$lineEnding = $this->whitespacesConfig->getLineEnding();
|
||||
|
||||
for ($index, $count = \count($tokens); $index < $count; ++$index) {
|
||||
if (false !== strstr($tokens[$index]->getContent(), $lineEnding)) {
|
||||
return $index;
|
||||
}
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the semicolon closes a chained call and returns the whitespace of the first call at $index.
|
||||
* i.e. it will return the whitespace marked with '____' in the example underneath.
|
||||
*
|
||||
* ..
|
||||
* ____$this->methodCall()
|
||||
* ->anotherCall();
|
||||
* ..
|
||||
*/
|
||||
private function findWhitespaceBeforeFirstCall(int $index, Tokens $tokens): ?string
|
||||
{
|
||||
// semicolon followed by a closing bracket?
|
||||
if (!$tokens[$index]->equals(')')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// find opening bracket
|
||||
$openingBrackets = 1;
|
||||
for (--$index; $index > 0; --$index) {
|
||||
if ($tokens[$index]->equals(')')) {
|
||||
++$openingBrackets;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($tokens[$index]->equals('(')) {
|
||||
if (1 === $openingBrackets) {
|
||||
break;
|
||||
}
|
||||
--$openingBrackets;
|
||||
}
|
||||
}
|
||||
|
||||
// method name
|
||||
if (!$tokens[--$index]->isGivenKind(T_STRING)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ->, ?-> or ::
|
||||
if (!$tokens[--$index]->isObjectOperator() && !$tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// white space
|
||||
if (!$tokens[--$index]->isGivenKind(T_WHITESPACE)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$closingBrackets = 0;
|
||||
for ($index; $index >= 0; --$index) {
|
||||
if ($tokens[$index]->equals(')')) {
|
||||
++$closingBrackets;
|
||||
}
|
||||
|
||||
if ($tokens[$index]->equals('(')) {
|
||||
--$closingBrackets;
|
||||
}
|
||||
|
||||
// must be the variable of the first call in the chain
|
||||
if ($tokens[$index]->isGivenKind([T_VARIABLE, T_RETURN, T_STRING]) && 0 === $closingBrackets) {
|
||||
if ($tokens[--$index]->isGivenKind(T_WHITESPACE)
|
||||
|| $tokens[$index]->isGivenKind(T_OPEN_TAG)) {
|
||||
return $this->getIndentAt($tokens, $index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getIndentAt(Tokens $tokens, int $index): ?string
|
||||
{
|
||||
$content = '';
|
||||
$lineEnding = $this->whitespacesConfig->getLineEnding();
|
||||
|
||||
// find line ending token
|
||||
for ($index; $index > 0; --$index) {
|
||||
if (false !== strstr($tokens[$index]->getContent(), $lineEnding)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($tokens[$index]->isWhitespace()) {
|
||||
$content = $tokens[$index]->getContent();
|
||||
--$index;
|
||||
}
|
||||
|
||||
if ($tokens[$index]->isGivenKind(T_OPEN_TAG)) {
|
||||
$content = $tokens[$index]->getContent().$content;
|
||||
}
|
||||
|
||||
if (1 === Preg::match('/\R{1}(\h*)$/', $content, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of PHP CS Fixer.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace PhpCsFixer\Fixer\Semicolon;
|
||||
|
||||
use PhpCsFixer\AbstractFixer;
|
||||
use PhpCsFixer\FixerDefinition\CodeSample;
|
||||
use PhpCsFixer\FixerDefinition\FixerDefinition;
|
||||
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
|
||||
use PhpCsFixer\Tokenizer\Tokens;
|
||||
use PhpCsFixer\Tokenizer\TokensAnalyzer;
|
||||
|
||||
/**
|
||||
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*/
|
||||
final class NoEmptyStatementFixer extends AbstractFixer
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition(): FixerDefinitionInterface
|
||||
{
|
||||
return new FixerDefinition(
|
||||
'Remove useless (semicolon) statements.',
|
||||
[
|
||||
new CodeSample("<?php \$a = 1;;\n"),
|
||||
new CodeSample("<?php echo 1;2;\n"),
|
||||
new CodeSample("<?php while(foo()){\n continue 1;\n}\n"),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Must run before BracesFixer, CombineConsecutiveUnsetsFixer, EmptyLoopBodyFixer, MultilineWhitespaceBeforeSemicolonsFixer, NoExtraBlankLinesFixer, NoMultipleStatementsPerLineFixer, NoSinglelineWhitespaceBeforeSemicolonsFixer, NoTrailingWhitespaceFixer, NoUselessElseFixer, NoUselessReturnFixer, NoWhitespaceInBlankLineFixer, ReturnAssignmentFixer, SpaceAfterSemicolonFixer, SwitchCaseSemicolonToColonFixer.
|
||||
* Must run after NoUselessSprintfFixer.
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCandidate(Tokens $tokens): bool
|
||||
{
|
||||
return $tokens->isTokenKindFound(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
|
||||
{
|
||||
for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
|
||||
if ($tokens[$index]->isGivenKind([T_BREAK, T_CONTINUE])) {
|
||||
$index = $tokens->getNextMeaningfulToken($index);
|
||||
|
||||
if ($tokens[$index]->equals([T_LNUMBER, '1'])) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip T_FOR parenthesis to ignore double `;` like `for ($i = 1; ; ++$i) {...}`
|
||||
if ($tokens[$index]->isGivenKind(T_FOR)) {
|
||||
$index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextMeaningfulToken($index)) + 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$tokens[$index]->equals(';')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($index);
|
||||
|
||||
// A semicolon can always be removed if it follows a semicolon, '{' or opening tag.
|
||||
if ($tokens[$previousMeaningfulIndex]->equalsAny(['{', ';', [T_OPEN_TAG]])) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// A semicolon might be removed if it follows a '}' but only if the brace is part of certain structures.
|
||||
if ($tokens[$previousMeaningfulIndex]->equals('}')) {
|
||||
$this->fixSemicolonAfterCurlyBraceClose($tokens, $index, $previousMeaningfulIndex);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// A semicolon might be removed together with its noop statement, for example "<?php 1;"
|
||||
$prePreviousMeaningfulIndex = $tokens->getPrevMeaningfulToken($previousMeaningfulIndex);
|
||||
|
||||
if (
|
||||
$tokens[$prePreviousMeaningfulIndex]->equalsAny([';', '{', '}', [T_OPEN_TAG]])
|
||||
&& $tokens[$previousMeaningfulIndex]->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_DNUMBER, T_LNUMBER, T_STRING, T_VARIABLE])
|
||||
) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($previousMeaningfulIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix semicolon after closing curly brace if needed.
|
||||
*
|
||||
* Test for the following cases
|
||||
* - just '{' '}' block (following open tag or ';')
|
||||
* - if, else, elseif
|
||||
* - interface, trait, class (but not anonymous)
|
||||
* - catch, finally (but not try)
|
||||
* - for, foreach, while (but not 'do - while')
|
||||
* - switch
|
||||
* - function (declaration, but not lambda)
|
||||
* - declare (with '{' '}')
|
||||
* - namespace (with '{' '}')
|
||||
*
|
||||
* @param int $index Semicolon index
|
||||
*/
|
||||
private function fixSemicolonAfterCurlyBraceClose(Tokens $tokens, int $index, int $curlyCloseIndex): void
|
||||
{
|
||||
static $beforeCurlyOpeningKinds = null;
|
||||
|
||||
if (null === $beforeCurlyOpeningKinds) {
|
||||
$beforeCurlyOpeningKinds = [T_ELSE, T_FINALLY, T_NAMESPACE, T_OPEN_TAG];
|
||||
}
|
||||
|
||||
$curlyOpeningIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $curlyCloseIndex);
|
||||
$beforeCurlyOpeningIndex = $tokens->getPrevMeaningfulToken($curlyOpeningIndex);
|
||||
|
||||
if ($tokens[$beforeCurlyOpeningIndex]->isGivenKind($beforeCurlyOpeningKinds) || $tokens[$beforeCurlyOpeningIndex]->equalsAny([';', '{', '}'])) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check for namespaces and class, interface and trait definitions
|
||||
if ($tokens[$beforeCurlyOpeningIndex]->isGivenKind(T_STRING)) {
|
||||
$classyTestIndex = $tokens->getPrevMeaningfulToken($beforeCurlyOpeningIndex);
|
||||
|
||||
while ($tokens[$classyTestIndex]->equals(',') || $tokens[$classyTestIndex]->isGivenKind([T_STRING, T_NS_SEPARATOR, T_EXTENDS, T_IMPLEMENTS])) {
|
||||
$classyTestIndex = $tokens->getPrevMeaningfulToken($classyTestIndex);
|
||||
}
|
||||
|
||||
$tokensAnalyzer = new TokensAnalyzer($tokens);
|
||||
|
||||
if (
|
||||
$tokens[$classyTestIndex]->isGivenKind(T_NAMESPACE)
|
||||
|| ($tokens[$classyTestIndex]->isClassy() && !$tokensAnalyzer->isAnonymousClass($classyTestIndex))
|
||||
) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// early return check, below only control structures with conditions are fixed
|
||||
if (!$tokens[$beforeCurlyOpeningIndex]->equals(')')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$openingBraceIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $beforeCurlyOpeningIndex);
|
||||
$beforeOpeningBraceIndex = $tokens->getPrevMeaningfulToken($openingBraceIndex);
|
||||
|
||||
if ($tokens[$beforeOpeningBraceIndex]->isGivenKind([T_IF, T_ELSEIF, T_FOR, T_FOREACH, T_WHILE, T_SWITCH, T_CATCH, T_DECLARE])) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// check for function definition
|
||||
if ($tokens[$beforeOpeningBraceIndex]->isGivenKind(T_STRING)) {
|
||||
$beforeStringIndex = $tokens->getPrevMeaningfulToken($beforeOpeningBraceIndex);
|
||||
|
||||
if ($tokens[$beforeStringIndex]->isGivenKind(T_FUNCTION)) {
|
||||
$tokens->clearTokenAndMergeSurroundingWhitespace($index); // implicit return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of PHP CS Fixer.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace PhpCsFixer\Fixer\Semicolon;
|
||||
|
||||
use PhpCsFixer\AbstractFixer;
|
||||
use PhpCsFixer\FixerDefinition\CodeSample;
|
||||
use PhpCsFixer\FixerDefinition\FixerDefinition;
|
||||
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
|
||||
use PhpCsFixer\Tokenizer\Tokens;
|
||||
|
||||
/**
|
||||
* @author Graham Campbell <hello@gjcampbell.co.uk>
|
||||
*/
|
||||
final class NoSinglelineWhitespaceBeforeSemicolonsFixer extends AbstractFixer
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition(): FixerDefinitionInterface
|
||||
{
|
||||
return new FixerDefinition(
|
||||
'Single-line whitespace before closing semicolon are prohibited.',
|
||||
[new CodeSample("<?php \$this->foo() ;\n")]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Must run after CombineConsecutiveIssetsFixer, FunctionToConstantFixer, NoEmptyStatementFixer, NoUnneededImportAliasFixer, SimplifiedIfReturnFixer, SingleImportPerStatementFixer.
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCandidate(Tokens $tokens): bool
|
||||
{
|
||||
return $tokens->isTokenKindFound(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
|
||||
{
|
||||
foreach ($tokens as $index => $token) {
|
||||
if (!$token->equals(';') || !$tokens[$index - 1]->isWhitespace(" \t")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($tokens[$index - 2]->equals(';')) {
|
||||
// do not remove all whitespace before the semicolon because it is also whitespace after another semicolon
|
||||
$tokens->ensureWhitespaceAtIndex($index - 1, 0, ' ');
|
||||
} elseif (!$tokens[$index - 2]->isComment()) {
|
||||
$tokens->clearAt($index - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of PHP CS Fixer.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace PhpCsFixer\Fixer\Semicolon;
|
||||
|
||||
use PhpCsFixer\AbstractFixer;
|
||||
use PhpCsFixer\FixerDefinition\CodeSample;
|
||||
use PhpCsFixer\FixerDefinition\FixerDefinition;
|
||||
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
|
||||
use PhpCsFixer\Tokenizer\Token;
|
||||
use PhpCsFixer\Tokenizer\Tokens;
|
||||
|
||||
final class SemicolonAfterInstructionFixer extends AbstractFixer
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition(): FixerDefinitionInterface
|
||||
{
|
||||
return new FixerDefinition(
|
||||
'Instructions must be terminated with a semicolon.',
|
||||
[new CodeSample("<?php echo 1 ?>\n")]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Must run before SimplifiedIfReturnFixer.
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCandidate(Tokens $tokens): bool
|
||||
{
|
||||
return $tokens->isTokenKindFound(T_CLOSE_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
|
||||
{
|
||||
for ($index = \count($tokens) - 1; $index > 1; --$index) {
|
||||
if (!$tokens[$index]->isGivenKind(T_CLOSE_TAG)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prev = $tokens->getPrevMeaningfulToken($index);
|
||||
if ($tokens[$prev]->equalsAny([';', '{', '}', ':', [T_OPEN_TAG]])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tokens->insertAt($prev + 1, new Token(';'));
|
||||
}
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of PHP CS Fixer.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace PhpCsFixer\Fixer\Semicolon;
|
||||
|
||||
use PhpCsFixer\AbstractFixer;
|
||||
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
|
||||
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\Token;
|
||||
use PhpCsFixer\Tokenizer\Tokens;
|
||||
|
||||
final class SpaceAfterSemicolonFixer extends AbstractFixer implements ConfigurableFixerInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition(): FixerDefinitionInterface
|
||||
{
|
||||
return new FixerDefinition(
|
||||
'Fix whitespace after a semicolon.',
|
||||
[
|
||||
new CodeSample(
|
||||
"<?php
|
||||
sample(); \$test = 1;
|
||||
sample();\$test = 2;
|
||||
for ( ;;++\$sample) {
|
||||
}\n"
|
||||
),
|
||||
new CodeSample("<?php\nfor (\$i = 0; ; ++\$i) {\n}\n", [
|
||||
'remove_in_empty_for_expressions' => true,
|
||||
]),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Must run after CombineConsecutiveUnsetsFixer, MultilineWhitespaceBeforeSemicolonsFixer, NoEmptyStatementFixer, OrderedClassElementsFixer, SingleImportPerStatementFixer, SingleTraitInsertPerStatementFixer.
|
||||
*/
|
||||
public function getPriority(): int
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCandidate(Tokens $tokens): bool
|
||||
{
|
||||
return $tokens->isTokenKindFound(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
|
||||
{
|
||||
return new FixerConfigurationResolver([
|
||||
(new FixerOptionBuilder('remove_in_empty_for_expressions', 'Whether spaces should be removed for empty `for` expressions.'))
|
||||
->setAllowedTypes(['bool'])
|
||||
->setDefault(false)
|
||||
->getOption(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
|
||||
{
|
||||
$insideForParenthesesUntil = null;
|
||||
|
||||
for ($index = 0, $max = \count($tokens) - 1; $index < $max; ++$index) {
|
||||
if (true === $this->configuration['remove_in_empty_for_expressions']) {
|
||||
if ($tokens[$index]->isGivenKind(T_FOR)) {
|
||||
$index = $tokens->getNextMeaningfulToken($index);
|
||||
$insideForParenthesesUntil = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($index === $insideForParenthesesUntil) {
|
||||
$insideForParenthesesUntil = null;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$tokens[$index]->equals(';')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$tokens[$index + 1]->isWhitespace()) {
|
||||
if (
|
||||
!$tokens[$index + 1]->equalsAny([')', [T_INLINE_HTML]]) && (
|
||||
false === $this->configuration['remove_in_empty_for_expressions']
|
||||
|| !$tokens[$index + 1]->equals(';')
|
||||
)
|
||||
) {
|
||||
$tokens->insertAt($index + 1, new Token([T_WHITESPACE, ' ']));
|
||||
++$max;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
null !== $insideForParenthesesUntil
|
||||
&& ($tokens[$index + 2]->equals(';') || $index + 2 === $insideForParenthesesUntil)
|
||||
&& !Preg::match('/\R/', $tokens[$index + 1]->getContent())
|
||||
) {
|
||||
$tokens->clearAt($index + 1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($tokens[$index + 2])
|
||||
&& !$tokens[$index + 1]->equals([T_WHITESPACE, ' '])
|
||||
&& $tokens[$index + 1]->isWhitespace(" \t")
|
||||
&& !$tokens[$index + 2]->isComment()
|
||||
&& !$tokens[$index + 2]->equals(')')
|
||||
) {
|
||||
$tokens[$index + 1] = new Token([T_WHITESPACE, ' ']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user