<?php

/*
 * 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\Operator;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;

/**
 * @author Gregor Harlan <gharlan@web.de>
 * @author Kuba Werłos <werlos@gmail.com>
 */
final class IncrementStyleFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    /**
     * @internal
     */
    const STYLE_PRE = 'pre';

    /**
     * @internal
     */
    const STYLE_POST = 'post';

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Pre- or post-increment and decrement operators should be used if possible.',
            [
                new CodeSample("<?php\n\$a++;\n\$b--;\n"),
                new CodeSample(
                    "<?php\n++\$a;\n--\$b;\n",
                    ['style' => self::STYLE_POST]
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound([T_INC, T_DEC]);
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolver([
            (new FixerOptionBuilder('style', 'Whether to use pre- or post-increment and decrement operators.'))
                ->setAllowedValues([self::STYLE_PRE, self::STYLE_POST])
                ->setDefault(self::STYLE_PRE)
                ->getOption(),
        ]);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $tokensAnalyzer = new TokensAnalyzer($tokens);

        for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
            $token = $tokens[$index];

            if (!$token->isGivenKind([T_INC, T_DEC])) {
                continue;
            }

            if (self::STYLE_PRE === $this->configuration['style'] && $tokensAnalyzer->isUnarySuccessorOperator($index)) {
                $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
                if (!$nextToken->equalsAny([';', ')'])) {
                    continue;
                }

                $startIndex = $this->findStart($tokens, $index);

                $prevToken = $tokens[$tokens->getPrevMeaningfulToken($startIndex)];
                if ($prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG]])) {
                    $tokens->clearAt($index);
                    $tokens->insertAt($startIndex, clone $token);
                }
            } elseif (self::STYLE_POST === $this->configuration['style'] && $tokensAnalyzer->isUnaryPredecessorOperator($index)) {
                $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
                if (!$prevToken->equalsAny([';', '{', '}', [T_OPEN_TAG]])) {
                    continue;
                }

                $endIndex = $this->findEnd($tokens, $index);

                $nextToken = $tokens[$tokens->getNextMeaningfulToken($endIndex)];
                if ($nextToken->equalsAny([';', ')'])) {
                    $tokens->clearAt($index);
                    $tokens->insertAt($tokens->getNextNonWhitespace($endIndex), clone $token);
                }
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return int
     */
    private function findEnd(Tokens $tokens, $index)
    {
        $nextIndex = $tokens->getNextMeaningfulToken($index);
        $nextToken = $tokens[$nextIndex];

        while ($nextToken->equalsAny([
            '$',
            '[',
            [CT::T_DYNAMIC_PROP_BRACE_OPEN],
            [CT::T_DYNAMIC_VAR_BRACE_OPEN],
            [T_NS_SEPARATOR],
            [T_STATIC],
            [T_STRING],
            [T_VARIABLE],
        ])) {
            $blockType = Tokens::detectBlockType($nextToken);
            if (null !== $blockType) {
                $nextIndex = $tokens->findBlockEnd($blockType['type'], $nextIndex);
            }
            $index = $nextIndex;
            $nextIndex = $tokens->getNextMeaningfulToken($nextIndex);
            $nextToken = $tokens[$nextIndex];
        }

        if ($nextToken->isGivenKind(T_OBJECT_OPERATOR)) {
            return $this->findEnd($tokens, $nextIndex);
        }

        if ($nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
            return $this->findEnd($tokens, $tokens->getNextMeaningfulToken($nextIndex));
        }

        return $index;
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return int
     */
    private function findStart(Tokens $tokens, $index)
    {
        do {
            $index = $tokens->getPrevMeaningfulToken($index);
            $token = $tokens[$index];

            $blockType = Tokens::detectBlockType($token);
            if (null !== $blockType && !$blockType['isStart']) {
                $index = $tokens->findBlockStart($blockType['type'], $index);
                $token = $tokens[$index];
            }
        } while (!$token->equalsAny(['$', [T_VARIABLE]]));

        $prevIndex = $tokens->getPrevMeaningfulToken($index);
        $prevToken = $tokens[$prevIndex];

        if ($prevToken->equals('$')) {
            $index = $prevIndex;
            $prevIndex = $tokens->getPrevMeaningfulToken($index);
            $prevToken = $tokens[$prevIndex];
        }

        if ($prevToken->isGivenKind(T_OBJECT_OPERATOR)) {
            return $this->findStart($tokens, $prevIndex);
        }

        if ($prevToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)) {
            $prevPrevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
            if (!$tokens[$prevPrevIndex]->isGivenKind([T_STATIC, T_STRING])) {
                return $this->findStart($tokens, $prevIndex);
            }

            $index = $tokens->getTokenNotOfKindSibling($prevIndex, -1, [[T_NS_SEPARATOR], [T_STATIC], [T_STRING]]);
            $index = $tokens->getNextMeaningfulToken($index);
        }

        return $index;
    }
}


<?php

/*
 * 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;

use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use Symfony\Component\Finder\Finder as SymfonyFinder;
use Symfony\Component\Finder\SplFileInfo;

/**
 * Class provides a way to create a group of fixers.
 *
 * Fixers may be registered (made the factory aware of them) by
 * registering a custom fixer and default, built in fixers.
 * Then, one can attach Config instance to fixer instances.
 *
 * Finally factory creates a ready to use group of fixers.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * @internal
 */
final class FixerFactory
{
    /**
     * @var FixerNameValidator
     */
    private $nameValidator;

    /**
     * @var FixerInterface[]
     */
    private $fixers = [];

    /**
     * @var FixerInterface[] Associative array of fixers with names as keys
     */
    private $fixersByName = [];

    public function __construct()
    {
        $this->nameValidator = new FixerNameValidator();
    }

    /**
     * Create instance.
     *
     * @return FixerFactory
     */
    public static function create()
    {
        return new self();
    }

    public function setWhitespacesConfig(WhitespacesFixerConfig $config)
    {
        foreach ($this->fixers as $fixer) {
            if ($fixer instanceof WhitespacesAwareFixerInterface) {
                $fixer->setWhitespacesConfig($config);
            }
        }

        return $this;
    }

    /**
     * @return FixerInterface[]
     */
    public function getFixers()
    {
        $this->fixers = Utils::sortFixers($this->fixers);

        return $this->fixers;
    }

    /**
     * @return $this
     */
    public function registerBuiltInFixers()
    {
        static $builtInFixers = null;

        if (null === $builtInFixers) {
            $builtInFixers = [];

            /** @var SplFileInfo $file */
            foreach (SymfonyFinder::create()->files()->in(__DIR__.'/Fixer') as $file) {
                $relativeNamespace = $file->getRelativePath();
                $fixerClass = 'PhpCsFixer\\Fixer\\'.($relativeNamespace ? $relativeNamespace.'\\' : '').$file->getBasename('.php');
                if ('Fixer' === substr($fixerClass, -5)) {
                    $builtInFixers[] = $fixerClass;
                }
            }
        }

        foreach ($builtInFixers as $class) {
            $this->registerFixer(new $class(), false);
        }

        return $this;
    }

    /**
     * @param FixerInterface[] $fixers
     *
     * @return $this
     */
    public function registerCustomFixers(array $fixers)
    {
        foreach ($fixers as $fixer) {
            $this->registerFixer($fixer, true);
        }

        return $this;
    }

    /**
     * @param FixerInterface $fixer
     * @param bool           $isCustom
     *
     * @return $this
     */
    public function registerFixer(FixerInterface $fixer, $isCustom)
    {
        $name = $fixer->getName();

        if (isset($this->fixersByName[$name])) {
            throw new \UnexpectedValueException(sprintf('Fixer named "%s" is already registered.', $name));
        }

        if (!$this->nameValidator->isValid($name, $isCustom)) {
            throw new \UnexpectedValueException(sprintf('Fixer named "%s" has invalid name.', $name));
        }

        $this->fixers[] = $fixer;
        $this->fixersByName[$name] = $fixer;

        return $this;
    }

    /**
     * Apply RuleSet on fixers to filter out all unwanted fixers.
     *
     * @param RuleSetInterface $ruleSet
     *
     * @return $this
     */
    public function useRuleSet(RuleSetInterface $ruleSet)
    {
        $fixers = [];
        $fixersByName = [];
        $fixerConflicts = [];

        $fixerNames = array_keys($ruleSet->getRules());
        foreach ($fixerNames as $name) {
            if (!\array_key_exists($name, $this->fixersByName)) {
                throw new \UnexpectedValueException(sprintf('Rule "%s" does not exist.', $name));
            }

            $fixer = $this->fixersByName[$name];

            $config = $ruleSet->getRuleConfiguration($name);
            if (null !== $config) {
                if ($fixer instanceof ConfigurableFixerInterface) {
                    if (!\is_array($config) || !\count($config)) {
                        throw new InvalidFixerConfigurationException($fixer->getName(), 'Configuration must be an array and may not be empty.');
                    }

                    $fixer->configure($config);
                } else {
                    throw new InvalidFixerConfigurationException($fixer->getName(), 'Is not configurable.');
                }
            }

            $fixers[] = $fixer;
            $fixersByName[$name] = $fixer;

            $conflicts = array_intersect($this->getFixersConflicts($fixer), $fixerNames);
            if (\count($conflicts) > 0) {
                $fixerConflicts[$name] = $conflicts;
            }
        }

        if (\count($fixerConflicts) > 0) {
            throw new \UnexpectedValueException($this->generateConflictMessage($fixerConflicts));
        }

        $this->fixers = $fixers;
        $this->fixersByName = $fixersByName;

        return $this;
    }

    /**
     * Check if fixer exists.
     *
     * @param string $name
     *
     * @return bool
     */
    public function hasRule($name)
    {
        return isset($this->fixersByName[$name]);
    }

    /**
     * @param FixerInterface $fixer
     *
     * @return null|string[]
     */
    private function getFixersConflicts(FixerInterface $fixer)
    {
        static $conflictMap = [
            'no_blank_lines_before_namespace' => ['single_blank_line_before_namespace'],
        ];

        $fixerName = $fixer->getName();

        return \array_key_exists($fixerName, $conflictMap) ? $conflictMap[$fixerName] : [];
    }

    /**
     * @param array<string, string[]> $fixerConflicts
     *
     * @return string
     */
    private function generateConflictMessage(array $fixerConflicts)
    {
        $message = 'Rule contains conflicting fixers:';
        $report = [];
        foreach ($fixerConflicts as $fixer => $fixers) {
            // filter mutual conflicts
            $report[$fixer] = array_filter(
                $fixers,
                static function ($candidate) use ($report, $fixer) {
                    return !\array_key_exists($candidate, $report) || !\in_array($fixer, $report[$candidate], true);
                }
            );

            if (\count($report[$fixer]) > 0) {
                $message .= sprintf("\n- \"%s\" with \"%s\"", $fixer, implode('", "', $report[$fixer]));
            }
        }

        return $message;
    }
}


<?php

/*
 * 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\Tokenizer\Transformer;

use PhpCsFixer\Tokenizer\AbstractTransformer;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * Transform const/function import tokens.
 *
 * Performed transformations:
 * - T_CONST into CT::T_CONST_IMPORT
 * - T_FUNCTION into CT::T_FUNCTION_IMPORT
 *
 * @author Gregor Harlan <gharlan@web.de>
 *
 * @internal
 */
final class ImportTransformer extends AbstractTransformer
{
    /**
     * {@inheritdoc}
     */
    public function getCustomTokens()
    {
        return [CT::T_CONST_IMPORT, CT::T_FUNCTION_IMPORT];
    }

    /**
     * {@inheritdoc}
     */
    public function getRequiredPhpVersionId()
    {
        return 50600;
    }

    /**
     * {@inheritdoc}
     */
    public function process(Tokens $tokens, Token $token, $index)
    {
        if (!$token->isGivenKind([T_CONST, T_FUNCTION])) {
            return;
        }

        $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];

        if ($prevToken->isGivenKind(T_USE)) {
            $tokens[$index] = new Token([
                $token->isGivenKind(T_FUNCTION) ? CT::T_FUNCTION_IMPORT : CT::T_CONST_IMPORT,
                $token->getContent(),
            ]);
        }
    }
}


<?php

/*
 * 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\CastNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author SpacePossum
 */
final class NoShortBoolCastFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run before the CastSpacesFixer
        return -9;
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Short cast `bool` using double exclamation mark should not be used.',
            [new CodeSample("<?php\n\$a = !!\$b;\n")]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound('!');
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        for ($index = \count($tokens) - 1; $index > 1; --$index) {
            if ($tokens[$index]->equals('!')) {
                $index = $this->fixShortCast($tokens, $index);
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return int
     */
    private function fixShortCast(Tokens $tokens, $index)
    {
        for ($i = $index - 1; $i > 1; --$i) {
            if ($tokens[$i]->equals('!')) {
                $this->fixShortCastToBoolCast($tokens, $i, $index);

                break;
            }

            if (!$tokens[$i]->isComment() && !$tokens[$i]->isWhitespace()) {
                break;
            }
        }

        return $i;
    }

    /**
     * @param Tokens $tokens
     * @param int    $start
     * @param int    $end
     */
    private function fixShortCastToBoolCast(Tokens $tokens, $start, $end)
    {
        for (; $start <= $end; ++$start) {
            if (
                !$tokens[$start]->isComment()
                && !($tokens[$start]->isWhitespace() && $tokens[$start - 1]->isComment())
            ) {
                $tokens->clearAt($start);
            }
        }

        $tokens->insertAt($start, new Token([T_BOOL_CAST, '(bool)']));
    }
}


<?php

/*
 * 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\ArrayNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\VersionSpecification;
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Gregor Harlan <gharlan@web.de>
 * @author Sebastiaan Stok <s.stok@rollerscapes.net>
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author SpacePossum
 */
final class ArraySyntaxFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    private $candidateTokenKind;
    private $fixCallback;

    /**
     * {@inheritdoc}
     */
    public function configure(array $configuration = null)
    {
        parent::configure($configuration);

        $this->resolveCandidateTokenKind();
        $this->resolveFixCallback();
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'PHP arrays should be declared using the configured syntax.',
            [
                new CodeSample(
                    "<?php\n[1,2];\n"
                ),
                new VersionSpecificCodeSample(
                    "<?php\narray(1,2);\n",
                    new VersionSpecification(50400),
                    ['syntax' => 'short']
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run before the BinaryOperatorSpacesFixer and TernaryOperatorSpacesFixer.
        return 1;
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound($this->candidateTokenKind);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $callback = $this->fixCallback;
        for ($index = $tokens->count() - 1; 0 <= $index; --$index) {
            if ($tokens[$index]->isGivenKind($this->candidateTokenKind)) {
                $this->{$callback}($tokens, $index);
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolver([
            (new FixerOptionBuilder('syntax', 'Whether to use the `long` or `short` array syntax.'))
                ->setAllowedValues(['long', 'short'])
                ->setDefault('long')
                ->getOption(),
        ]);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     */
    private function fixToLongArraySyntax(Tokens $tokens, $index)
    {
        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $index);

        $tokens[$index] = new Token('(');
        $tokens[$closeIndex] = new Token(')');

        $tokens->insertAt($index, new Token([T_ARRAY, 'array']));
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     */
    private function fixToShortArraySyntax(Tokens $tokens, $index)
    {
        $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);

        $tokens[$openIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']);
        $tokens[$closeIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']);

        $tokens->clearTokenAndMergeSurroundingWhitespace($index);
    }

    private function resolveFixCallback()
    {
        $this->fixCallback = sprintf('fixTo%sArraySyntax', ucfirst($this->configuration['syntax']));
    }

    private function resolveCandidateTokenKind()
    {
        $this->candidateTokenKind = 'long' === $this->configuration['syntax'] ? CT::T_ARRAY_SQUARE_BRACE_OPEN : T_ARRAY;
    }
}


<?php

/*
 * 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\FunctionNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Kuba Werłos <werlos@gmail.com>
 */
final class ImplodeCallFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Function `implode` must be called with 2 arguments in the documented order.',
            [
                new CodeSample("<?php\nimplode(\$pieces, '');\n"),
                new CodeSample("<?php\nimplode(\$pieces);\n"),
            ],
            null,
            'Risky when the function `implode` is overridden.'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isRisky()
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_STRING);
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // must be run after NoAliasFunctionsFixer
        // must be run before MethodArgumentSpaceFixer
        return -1;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $functionsAnalyzer = new FunctionsAnalyzer();

        foreach ($tokens as $index => $token) {
            if (!$tokens[$index]->equals([T_STRING, 'implode'], false)) {
                continue;
            }

            if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
                continue;
            }

            $argumentsIndices = $this->getArgumentIndices($tokens, $index);

            if (1 === \count($argumentsIndices)) {
                $firstArgumentIndex = key($argumentsIndices);
                $tokens->insertAt($firstArgumentIndex, [
                    new Token([T_CONSTANT_ENCAPSED_STRING, "''"]),
                    new Token(','),
                    new Token([T_WHITESPACE, ' ']),
                ]);

                continue;
            }

            if (2 === \count($argumentsIndices)) {
                list($firstArgumentIndex, $secondArgumentIndex) = array_keys($argumentsIndices);

                // If the first argument is string we have nothing to do
                if ($tokens[$firstArgumentIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
                    continue;
                }
                // If the second argument is not string we cannot make a swap
                if (!$tokens[$secondArgumentIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
                    continue;
                }

                // collect tokens from first argument
                $firstArgumentEndIndex = $argumentsIndices[key($argumentsIndices)];
                $newSecondArgumentTokens = [];
                for ($i = key($argumentsIndices); $i <= $firstArgumentEndIndex; ++$i) {
                    $newSecondArgumentTokens[] = clone $tokens[$i];
                    $tokens->clearAt($i);
                }

                $tokens->insertAt($firstArgumentIndex, clone $tokens[$secondArgumentIndex]);

                // insert above increased the second argument index
                ++$secondArgumentIndex;
                $tokens->clearAt($secondArgumentIndex);
                $tokens->insertAt($secondArgumentIndex, $newSecondArgumentTokens);
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $functionNameIndex
     *
     * @return array<int, int> In the format: startIndex => endIndex
     */
    private function getArgumentIndices(Tokens $tokens, $functionNameIndex)
    {
        $argumentsAnalyzer = new ArgumentsAnalyzer();

        $openParenthesis = $tokens->getNextTokenOfKind($functionNameIndex, ['(']);
        $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis);

        $indices = [];

        foreach ($argumentsAnalyzer->getArguments($tokens, $openParenthesis, $closeParenthesis) as $startIndexCandidate => $endIndex) {
            $indices[$tokens->getNextMeaningfulToken($startIndexCandidate - 1)] = $tokens->getPrevMeaningfulToken($endIndex + 1);
        }

        return $indices;
    }
}


<?php

/*
 * 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\Phpdoc;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Utils;

/**
 * @author Ceeram <ceeram@cakephp.org>
 * @author Graham Campbell <graham@alt-three.com>
 */
final class PhpdocIndentFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Docblocks should have the same indentation as the documented subject.',
            [new CodeSample('<?php
class DocBlocks
{
/**
 * Test constants
 */
    const INDENT = 1;
}
')]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        /*
         * Should be run before all other docblock fixers apart from the
         * phpdoc_to_comment fixer to make sure all fixers apply correct
         * indentation to new code they add, and the phpdoc_params fixer only
         * works on correctly indented docblocks. We also need to be running
         * after the psr2 indentation fixer for obvious reasons.
         * comments.
         */
        return 20;
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_DOC_COMMENT);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($tokens as $index => $token) {
            if (!$token->isGivenKind(T_DOC_COMMENT)) {
                continue;
            }

            $nextIndex = $tokens->getNextMeaningfulToken($index);

            // skip if there is no next token or if next token is block end `}`
            if (null === $nextIndex || $tokens[$nextIndex]->equals('}')) {
                continue;
            }

            $prevIndex = $index - 1;
            $prevToken = $tokens[$prevIndex];

            // ignore inline docblocks
            if (
                $prevToken->isGivenKind(T_OPEN_TAG)
                || ($prevToken->isWhitespace(" \t") && !$tokens[$index - 2]->isGivenKind(T_OPEN_TAG))
                || $prevToken->equalsAny([';', ',', '{', '('])
            ) {
                continue;
            }

            $indent = '';
            if ($tokens[$nextIndex - 1]->isWhitespace()) {
                $indent = Utils::calculateTrailingWhitespaceIndent($tokens[$nextIndex - 1]);
            }

            $newPrevContent = $this->fixWhitespaceBeforeDocblock($prevToken->getContent(), $indent);
            if ($newPrevContent) {
                if ($prevToken->isArray()) {
                    $tokens[$prevIndex] = new Token([$prevToken->getId(), $newPrevContent]);
                } else {
                    $tokens[$prevIndex] = new Token($newPrevContent);
                }
            } else {
                $tokens->clearAt($prevIndex);
            }

            $tokens[$index] = new Token([T_DOC_COMMENT, $this->fixDocBlock($token->getContent(), $indent)]);
        }
    }

    /**
     * Fix indentation of Docblock.
     *
     * @param string $content Docblock contents
     * @param string $indent  Indentation to apply
     *
     * @return string Dockblock contents including correct indentation
     */
    private function fixDocBlock($content, $indent)
    {
        return ltrim(Preg::replace('/^[ \t]*\*/m', $indent.' *', $content));
    }

    /**
     * @param string $content Whitespace before Docblock
     * @param string $indent  Indentation of the documented subject
     *
     * @return string Whitespace including correct indentation for Dockblock after this whitespace
     */
    private function fixWhitespaceBeforeDocblock($content, $indent)
    {
        return rtrim($content, " \t").$indent;
    }
}


<?php

/*
 * 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;

use PhpCsFixer\Fixer\FunctionNotation\NativeFunctionInvocationFixer;
use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;

/**
 * Set of rules to be used by fixer.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author SpacePossum
 *
 * @internal
 */
final class RuleSet implements RuleSetInterface
{
    private $setDefinitions = [
        '@PSR1' => [
            'encoding' => true,
            'full_opening_tag' => true,
        ],
        '@PSR2' => [
            '@PSR1' => true,
            'blank_line_after_namespace' => true,
            'braces' => true,
            'class_definition' => true,
            'elseif' => true,
            'function_declaration' => true,
            'indentation_type' => true,
            'line_ending' => true,
            'lowercase_constants' => true,
            'lowercase_keywords' => true,
            'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
            'no_break_comment' => true,
            'no_closing_tag' => true,
            'no_spaces_after_function_name' => true,
            'no_spaces_inside_parenthesis' => true,
            'no_trailing_whitespace' => true,
            'no_trailing_whitespace_in_comment' => true,
            'single_blank_line_at_eof' => true,
            'single_class_element_per_statement' => ['elements' => ['property']],
            'single_import_per_statement' => true,
            'single_line_after_imports' => true,
            'switch_case_semicolon_to_colon' => true,
            'switch_case_space' => true,
            'visibility_required' => true,
        ],
        '@Symfony' => [
            '@PSR2' => true,
            'binary_operator_spaces' => true,
            'blank_line_after_opening_tag' => true,
            'blank_line_before_statement' => [
                'statements' => ['return'],
            ],
            'braces' => [
                'allow_single_line_closure' => true,
            ],
            'cast_spaces' => true,
            'class_attributes_separation' => ['elements' => ['method']],
            'class_definition' => ['single_line' => true],
            'concat_space' => ['spacing' => 'none'],
            'declare_equal_normalize' => true,
            'function_typehint_space' => true,
            'include' => true,
            'increment_style' => true,
            'lowercase_cast' => true,
            'lowercase_static_reference' => true,
            'magic_constant_casing' => true,
            'magic_method_casing' => true,
            'method_argument_space' => true,
            'native_function_casing' => true,
            'new_with_braces' => true,
            'no_blank_lines_after_class_opening' => true,
            'no_blank_lines_after_phpdoc' => true,
            'no_empty_comment' => true,
            'no_empty_phpdoc' => true,
            'no_empty_statement' => true,
            'no_extra_blank_lines' => ['tokens' => [
                'curly_brace_block',
                'extra',
                'parenthesis_brace_block',
                'square_brace_block',
                'throw',
                'use',
            ]],
            'no_leading_import_slash' => true,
            'no_leading_namespace_whitespace' => true,
            'no_mixed_echo_print' => ['use' => 'echo'],
            'no_multiline_whitespace_around_double_arrow' => true,
            'no_short_bool_cast' => true,
            'no_singleline_whitespace_before_semicolons' => true,
            'no_spaces_around_offset' => true,
            'no_trailing_comma_in_list_call' => true,
            'no_trailing_comma_in_singleline_array' => true,
            'no_unneeded_control_parentheses' => true,
            'no_unneeded_curly_braces' => true,
            'no_unneeded_final_method' => true,
            'no_unused_imports' => true,
            'no_whitespace_before_comma_in_array' => true,
            'no_whitespace_in_blank_line' => true,
            'normalize_index_brace' => true,
            'object_operator_without_whitespace' => true,
            'php_unit_fqcn_annotation' => true,
            'phpdoc_align' => [
                // @TODO: on 3.0 switch whole rule to `=> true`, currently we use custom config that will be default on 3.0
                'tags' => [
                    'method',
                    'param',
                    'property',
                    'return',
                    'throws',
                    'type',
                    'var',
                ],
            ],
            'phpdoc_annotation_without_dot' => true,
            'phpdoc_indent' => true,
            'phpdoc_inline_tag' => true,
            'phpdoc_no_access' => true,
            'phpdoc_no_alias_tag' => true,
            'phpdoc_no_empty_return' => true,
            'phpdoc_no_package' => true,
            'phpdoc_no_useless_inheritdoc' => true,
            'phpdoc_return_self_reference' => true,
            'phpdoc_scalar' => true,
            'phpdoc_separation' => true,
            'phpdoc_single_line_var_spacing' => true,
            'phpdoc_summary' => true,
            'phpdoc_to_comment' => true,
            'phpdoc_trim' => true,
            'phpdoc_types' => true,
            'phpdoc_types_order' => [
                'null_adjustment' => 'always_last',
                'sort_algorithm' => 'none',
            ],
            'phpdoc_var_without_name' => true,
            'protected_to_private' => true,
            'return_type_declaration' => true,
            'semicolon_after_instruction' => true,
            'short_scalar_cast' => true,
            'single_blank_line_before_namespace' => true,
            'single_class_element_per_statement' => true,
            'single_line_comment_style' => [
                'comment_types' => ['hash'],
            ],
            'single_quote' => true,
            'space_after_semicolon' => [
                'remove_in_empty_for_expressions' => true,
            ],
            'standardize_increment' => true,
            'standardize_not_equals' => true,
            'ternary_operator_spaces' => true,
            'trailing_comma_in_multiline_array' => true,
            'trim_array_spaces' => true,
            'unary_operator_spaces' => true,
            'whitespace_after_comma_in_array' => true,
            'yoda_style' => true,
        ],
        '@Symfony:risky' => [
            'dir_constant' => true,
            'ereg_to_preg' => true,
            'error_suppression' => true,
            'fopen_flag_order' => true,
            'fopen_flags' => ['b_mode' => false],
            'function_to_constant' => true,
            'implode_call' => true,
            'is_null' => true,
            'modernize_types_casting' => true,
            'native_constant_invocation' => [
                'fix_built_in' => false,
                'include' => [
                    'DIRECTORY_SEPARATOR',
                    'PHP_SAPI',
                    'PHP_VERSION_ID',
                ],
                'scope' => 'namespaced',
            ],
            'native_function_invocation' => [
                'include' => [NativeFunctionInvocationFixer::SET_COMPILER_OPTIMIZED],
                'scope' => 'namespaced',
                'strict' => true,
            ],
            'no_alias_functions' => true,
            'no_homoglyph_names' => true,
            'non_printable_character' => [
                'use_escape_sequences_in_strings' => false,
            ],
            'php_unit_construct' => true,
            'psr4' => true,
            'self_accessor' => true,
            'set_type_to_cast' => true,
        ],
        '@PhpCsFixer' => [
            '@Symfony' => true,
            'align_multiline_comment' => true,
            'array_indentation' => true,
            'array_syntax' => ['syntax' => 'short'],
            'blank_line_before_statement' => true,
            'combine_consecutive_issets' => true,
            'combine_consecutive_unsets' => true,
            'compact_nullable_typehint' => true,
            'escape_implicit_backslashes' => true,
            'explicit_indirect_variable' => true,
            'explicit_string_variable' => true,
            'fully_qualified_strict_types' => true,
            'heredoc_to_nowdoc' => true,
            'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
            'method_chaining_indentation' => true,
            'multiline_comment_opening_closing' => true,
            'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
            'no_alternative_syntax' => true,
            'no_binary_string' => true,
            'no_extra_blank_lines' => ['tokens' => [
                'break',
                'continue',
                'curly_brace_block',
                'extra',
                'parenthesis_brace_block',
                'return',
                'square_brace_block',
                'throw',
                'use',
            ]],
            'no_null_property_initialization' => true,
            'no_short_echo_tag' => true,
            'no_superfluous_elseif' => true,
            'no_unneeded_curly_braces' => true,
            'no_unneeded_final_method' => true,
            'no_unset_cast' => true,
            'no_useless_else' => true,
            'no_useless_return' => true,
            'ordered_class_elements' => true,
            'ordered_imports' => true,
            'php_unit_internal_class' => true,
            'php_unit_method_casing' => true,
            'php_unit_ordered_covers' => true,
            'php_unit_test_class_requires_covers' => true,
            'phpdoc_add_missing_param_annotation' => true,
            'phpdoc_order' => true,
            'phpdoc_trim_consecutive_blank_line_separation' => true,
            'phpdoc_types_order' => true,
            'phpdoc_var_annotation_correct_order' => true,
            'return_assignment' => true,
            'single_line_comment_style' => true,
        ],
        '@PhpCsFixer:risky' => [
            '@Symfony:risky' => true,
            'comment_to_phpdoc' => true,
            'final_internal_class' => true,
            'function_to_constant' => ['functions' => [
                'get_called_class',
                'get_class',
                'php_sapi_name',
                'phpversion',
                'pi',
            ]],
            'logical_operators' => true,
            'no_unreachable_default_argument_value' => true,
            'no_unset_on_property' => true,
            'php_unit_set_up_tear_down_visibility' => true,
            'php_unit_strict' => true,
            'php_unit_test_annotation' => true,
            'php_unit_test_case_static_method_calls' => true,
            'strict_comparison' => true,
            'strict_param' => true,
            'string_line_ending' => true,
        ],
        '@DoctrineAnnotation' => [
            'doctrine_annotation_array_assignment' => [
                'operator' => ':',
            ],
            'doctrine_annotation_braces' => true,
            'doctrine_annotation_indentation' => true,
            'doctrine_annotation_spaces' => [
                'before_array_assignments_colon' => false,
            ],
        ],
        '@PHP56Migration' => [],
        '@PHP56Migration:risky' => [
            'pow_to_exponentiation' => true,
        ],
        '@PHP70Migration' => [
            '@PHP56Migration' => true,
            'ternary_to_null_coalescing' => true,
        ],
        '@PHP70Migration:risky' => [
            '@PHP56Migration:risky' => true,
            'combine_nested_dirname' => true,
            'declare_strict_types' => true,
            'non_printable_character' => [
                'use_escape_sequences_in_strings' => true,
            ],
            'random_api_migration' => ['replacements' => [
                'mt_rand' => 'random_int',
                'rand' => 'random_int',
            ]],
        ],
        '@PHP71Migration' => [
            '@PHP70Migration' => true,
            'visibility_required' => ['elements' => [
                'const',
                'method',
                'property',
            ]],
        ],
        '@PHP71Migration:risky' => [
            '@PHP70Migration:risky' => true,
            'void_return' => true,
        ],
        '@PHPUnit30Migration:risky' => [
            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_3_0],
        ],
        '@PHPUnit32Migration:risky' => [
            '@PHPUnit30Migration:risky' => true,
            'php_unit_no_expectation_annotation' => ['target' => PhpUnitTargetVersion::VERSION_3_2],
        ],
        '@PHPUnit35Migration:risky' => [
            '@PHPUnit32Migration:risky' => true,
            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_3_5],
        ],
        '@PHPUnit43Migration:risky' => [
            '@PHPUnit35Migration:risky' => true,
            'php_unit_no_expectation_annotation' => ['target' => PhpUnitTargetVersion::VERSION_4_3],
        ],
        '@PHPUnit48Migration:risky' => [
            '@PHPUnit43Migration:risky' => true,
            'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_4_8],
        ],
        '@PHPUnit50Migration:risky' => [
            '@PHPUnit48Migration:risky' => true,
            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_5_0],
        ],
        '@PHPUnit52Migration:risky' => [
            '@PHPUnit50Migration:risky' => true,
            'php_unit_expectation' => ['target' => PhpUnitTargetVersion::VERSION_5_2],
        ],
        '@PHPUnit54Migration:risky' => [
            '@PHPUnit52Migration:risky' => true,
            'php_unit_mock' => ['target' => PhpUnitTargetVersion::VERSION_5_4],
        ],
        '@PHPUnit55Migration:risky' => [
            '@PHPUnit54Migration:risky' => true,
            'php_unit_mock' => ['target' => PhpUnitTargetVersion::VERSION_5_5],
        ],
        '@PHPUnit56Migration:risky' => [
            '@PHPUnit55Migration:risky' => true,
            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_5_6],
            'php_unit_expectation' => ['target' => PhpUnitTargetVersion::VERSION_5_6],
        ],
        '@PHPUnit57Migration:risky' => [
            '@PHPUnit56Migration:risky' => true,
            'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_5_7],
        ],
        '@PHPUnit60Migration:risky' => [
            '@PHPUnit57Migration:risky' => true,
            'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_6_0],
        ],
    ];

    /**
     * Set that was used to generate group of rules.
     *
     * The key is name of rule or set, value is bool if the rule/set should be used.
     *
     * @var array
     */
    private $set;

    /**
     * Group of rules generated from input set.
     *
     * The key is name of rule, value is bool if the rule/set should be used.
     * The key must not point to any set.
     *
     * @var array
     */
    private $rules;

    public function __construct(array $set = [])
    {
        foreach ($set as $key => $value) {
            if (\is_int($key)) {
                throw new \InvalidArgumentException(sprintf('Missing value for "%s" rule/set.', $value));
            }
        }

        $this->set = $set;
        $this->resolveSet();
    }

    public static function create(array $set = [])
    {
        return new self($set);
    }

    /**
     * {@inheritdoc}
     */
    public function hasRule($rule)
    {
        return \array_key_exists($rule, $this->rules);
    }

    /**
     * {@inheritdoc}
     */
    public function getRuleConfiguration($rule)
    {
        if (!$this->hasRule($rule)) {
            throw new \InvalidArgumentException(sprintf('Rule "%s" is not in the set.', $rule));
        }

        if (true === $this->rules[$rule]) {
            return null;
        }

        return $this->rules[$rule];
    }

    /**
     * {@inheritdoc}
     */
    public function getRules()
    {
        return $this->rules;
    }

    /**
     * {@inheritdoc}
     */
    public function getSetDefinitionNames()
    {
        return array_keys($this->setDefinitions);
    }

    /**
     * @param string $name name of set
     *
     * @return array
     */
    private function getSetDefinition($name)
    {
        if (!isset($this->setDefinitions[$name])) {
            throw new \InvalidArgumentException(sprintf('Set "%s" does not exist.', $name));
        }

        return $this->setDefinitions[$name];
    }

    /**
     * Resolve input set into group of rules.
     *
     * @return $this
     */
    private function resolveSet()
    {
        $rules = $this->set;
        $resolvedRules = [];

        // expand sets
        foreach ($rules as $name => $value) {
            if ('@' === $name[0]) {
                if (!\is_bool($value)) {
                    throw new \UnexpectedValueException(sprintf('Nested rule set "%s" configuration must be a boolean.', $name));
                }

                $set = $this->resolveSubset($name, $value);
                $resolvedRules = array_merge($resolvedRules, $set);
            } else {
                $resolvedRules[$name] = $value;
            }
        }

        // filter out all resolvedRules that are off
        $resolvedRules = array_filter($resolvedRules);

        $this->rules = $resolvedRules;

        return $this;
    }

    /**
     * Resolve set rules as part of another set.
     *
     * If set value is false then disable all fixers in set,
     * if not then get value from set item.
     *
     * @param string $setName
     * @param bool   $setValue
     *
     * @return array
     */
    private function resolveSubset($setName, $setValue)
    {
        $rules = $this->getSetDefinition($setName);
        foreach ($rules as $name => $value) {
            if ('@' === $name[0]) {
                $set = $this->resolveSubset($name, $setValue);
                unset($rules[$name]);
                $rules = array_merge($rules, $set);
            } elseif (!$setValue) {
                $rules[$name] = false;
            } else {
                $rules[$name] = $value;
            }
        }

        return $rules;
    }
}


<?php

/*
 * 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\ControlStructure;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Eddilbert Macharia <edd.cowan@gmail.com>
 */
final class NoAlternativeSyntaxFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Replace control structure alternative syntax to use braces.',
            [
                new CodeSample(
                    "<?php\nif(true):echo 't';else:echo 'f';endif;\n"
                ),
                new CodeSample(
                    "<?php\nwhile(true):echo 'red';endwhile;\n"
                ),
                new CodeSample(
                    "<?php\nfor(;;):echo 'xc';endfor;\n"
                ),
                new CodeSample(
                    "<?php\nforeach(array('a') as \$item):echo 'xc';endforeach;\n"
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound(
            [
                T_ENDIF,
                T_ENDWHILE,
                T_ENDFOREACH,
                T_ENDFOR,
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // Should run before BracesFixer and ElseifFixer
        return 1;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
            $token = $tokens[$index];
            $this->fixElseif($index, $token, $tokens);
            $this->fixElse($index, $token, $tokens);
            $this->fixOpenCloseControls($index, $token, $tokens);
        }
    }

    private function findParenthesisEnd(Tokens $tokens, $structureTokenIndex)
    {
        $nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
        $nextToken = $tokens[$nextIndex];

        // return if next token is not opening parenthesis
        if (!$nextToken->equals('(')) {
            return $structureTokenIndex;
        }

        return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
    }

    /**
     * Handle both extremes of the control structures.
     * e.g. if(): or endif;.
     *
     * @param int    $index  the index of the token being processed
     * @param Token  $token  the token being processed
     * @param Tokens $tokens the collection of tokens
     */
    private function fixOpenCloseControls($index, Token $token, Tokens $tokens)
    {
        if ($token->isGivenKind([T_IF, T_FOREACH, T_WHILE, T_FOR])) {
            $openIndex = $tokens->getNextTokenOfKind($index, ['(']);
            $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openIndex);
            $afterParenthesisIndex = $tokens->getNextNonWhitespace($closeIndex);
            $afterParenthesis = $tokens[$afterParenthesisIndex];

            if (!$afterParenthesis->equals(':')) {
                return;
            }
            $items = [];
            if (!$tokens[$afterParenthesisIndex - 1]->isWhitespace()) {
                $items[] = new Token([T_WHITESPACE, ' ']);
            }
            $items[] = new Token('{');

            if (!$tokens[$afterParenthesisIndex + 1]->isWhitespace()) {
                $items[] = new Token([T_WHITESPACE, ' ']);
            }
            $tokens->clearAt($afterParenthesisIndex);
            $tokens->insertAt($afterParenthesisIndex, $items);
        }

        if (!$token->isGivenKind([T_ENDIF, T_ENDFOREACH, T_ENDWHILE, T_ENDFOR])) {
            return;
        }

        $nextTokenIndex = $tokens->getNextMeaningfulToken($index);
        $nextToken = $tokens[$nextTokenIndex];
        $tokens[$index] = new Token('}');
        if ($nextToken->equals(';')) {
            $tokens->clearAt($nextTokenIndex);
        }
    }

    /**
     * Handle the else:.
     *
     * @param int    $index  the index of the token being processed
     * @param Token  $token  the token being processed
     * @param Tokens $tokens the collection of tokens
     */
    private function fixElse($index, Token $token, Tokens $tokens)
    {
        if (!$token->isGivenKind(T_ELSE)) {
            return;
        }

        $tokenAfterElseIndex = $tokens->getNextMeaningfulToken($index);
        $tokenAfterElse = $tokens[$tokenAfterElseIndex];
        if (!$tokenAfterElse->equals(':')) {
            return;
        }

        $this->addBraces($tokens, new Token([T_ELSE, 'else']), $index, $tokenAfterElseIndex);
    }

    /**
     * Handle the elsif(): cases.
     *
     * @param int    $index  the index of the token being processed
     * @param Token  $token  the token being processed
     * @param Tokens $tokens the collection of tokens
     */
    private function fixElseif($index, Token $token, Tokens $tokens)
    {
        if (!$token->isGivenKind(T_ELSEIF)) {
            return;
        }
        $parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
        $tokenAfterParenthesisIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
        $tokenAfterParenthesis = $tokens[$tokenAfterParenthesisIndex];
        if (!$tokenAfterParenthesis->equals(':')) {
            return;
        }

        $this->addBraces($tokens, new Token([T_ELSEIF, 'elseif']), $index, $tokenAfterParenthesisIndex);
    }

    /**
     * Add opening and closing braces to the else: and elseif: .
     *
     * @param Tokens $tokens     the tokens collection
     * @param Token  $token      the current token
     * @param int    $index      the current token index
     * @param int    $colonIndex the index of the colon
     */
    private function addBraces(Tokens $tokens, Token $token, $index, $colonIndex)
    {
        $items = [
            new Token('}'),
            new Token([T_WHITESPACE, ' ']),
            $token,
        ];
        if (!$tokens[$index + 1]->isWhitespace()) {
            $items[] = new Token([T_WHITESPACE, ' ']);
        }
        $tokens->clearAt($index);
        $tokens->insertAt(
            $index,
            $items
        );

        // increment the position of the colon by number of items inserted
        $colonIndex += \count($items);

        $items = [new Token('{')];
        if (!$tokens[$colonIndex + 1]->isWhitespace()) {
            $items[] = new Token([T_WHITESPACE, ' ']);
        }

        $tokens->clearAt($colonIndex);
        $tokens->insertAt(
            $colonIndex,
            $items
        );
    }
}


<?php

/*
 * 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\Whitespace;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * Fixer for rules defined in PSR2 ¶2.4.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class IndentationTypeFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
    /**
     * @var string
     */
    private $indent;

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Code MUST use configured indentation type.',
            [
                new CodeSample("<?php\n\nif (true) {\n\techo 'Hello!';\n}\n"),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        return 50;
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound([T_COMMENT, T_DOC_COMMENT, T_WHITESPACE]);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $this->indent = $this->whitespacesConfig->getIndent();

        foreach ($tokens as $index => $token) {
            if ($token->isComment()) {
                $tokens[$index] = $this->fixIndentInComment($tokens, $index);

                continue;
            }

            if ($token->isWhitespace()) {
                $tokens[$index] = $this->fixIndentToken($tokens, $index);

                continue;
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return Token
     */
    private function fixIndentInComment(Tokens $tokens, $index)
    {
        $content = Preg::replace('/^(?:(?<! ) {1,3})?\t/m', '\1    ', $tokens[$index]->getContent(), -1, $count);

        // Also check for more tabs.
        while (0 !== $count) {
            $content = Preg::replace('/^(\ +)?\t/m', '\1    ', $content, -1, $count);
        }

        $indent = $this->indent;

        // change indent to expected one
        $content = Preg::replaceCallback('/^(?:    )+/m', static function ($matches) use ($indent) {
            return str_replace('    ', $indent, $matches[0]);
        }, $content);

        return new Token([$tokens[$index]->getId(), $content]);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return Token
     */
    private function fixIndentToken(Tokens $tokens, $index)
    {
        $content = $tokens[$index]->getContent();
        $previousTokenHasTrailingLinebreak = false;

        // @TODO 3.0 this can be removed when we have a transformer for "T_OPEN_TAG" to "T_OPEN_TAG + T_WHITESPACE"
        if (false !== strpos($tokens[$index - 1]->getContent(), "\n")) {
            $content = "\n".$content;
            $previousTokenHasTrailingLinebreak = true;
        }

        $indent = $this->indent;
        $newContent = Preg::replaceCallback(
            '/(\R)(\h+)/', // find indent
            static function (array $matches) use ($indent) {
                // normalize mixed indent
                $content = Preg::replace('/(?:(?<! ) {1,3})?\t/', '    ', $matches[2]);

                // change indent to expected one
                return $matches[1].str_replace('    ', $indent, $content);
            },
            $content
        );

        if ($previousTokenHasTrailingLinebreak) {
            $newContent = substr($newContent, 1);
        }

        return new Token([T_WHITESPACE, $newContent]);
    }
}


<?php

/*
 * 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;

use PhpCsFixer\DocBlock\Annotation;
use PhpCsFixer\DocBlock\DocBlock;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * This abstract fixer provides a base for fixers to fix types in PHPDoc.
 *
 * @author Graham Campbell <graham@alt-three.com>
 *
 * @internal
 */
abstract class AbstractPhpdocTypesFixer extends AbstractFixer
{
    /**
     * The annotation tags search inside.
     *
     * @var string[]
     */
    protected $tags;

    /**
     * {@inheritdoc}
     */
    public function __construct()
    {
        parent::__construct();

        $this->tags = Annotation::getTagsWithTypes();
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_DOC_COMMENT);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($tokens as $index => $token) {
            if (!$token->isGivenKind(T_DOC_COMMENT)) {
                continue;
            }

            $doc = new DocBlock($token->getContent());
            $annotations = $doc->getAnnotationsOfType($this->tags);

            if (empty($annotations)) {
                continue;
            }

            foreach ($annotations as $annotation) {
                $this->fixTypes($annotation);
            }

            $tokens[$index] = new Token([T_DOC_COMMENT, $doc->getContent()]);
        }
    }

    /**
     * Actually normalize the given type.
     *
     * @param string $type
     *
     * @return string
     */
    abstract protected function normalize($type);

    /**
     * Fix the types at the given line.
     *
     * We must be super careful not to modify parts of words.
     *
     * This will be nicely handled behind the scenes for us by the annotation class.
     *
     * @param Annotation $annotation
     */
    private function fixTypes(Annotation $annotation)
    {
        $types = $annotation->getTypes();

        $new = $this->normalizeTypes($types);

        if ($types !== $new) {
            $annotation->setTypes($new);
        }
    }

    /**
     * @param string[] $types
     *
     * @return string[]
     */
    private function normalizeTypes(array $types)
    {
        foreach ($types as $index => $type) {
            $types[$index] = $this->normalizeType($type);
        }

        return $types;
    }

    /**
     * Prepare the type and normalize it.
     *
     * @param string $type
     *
     * @return string
     */
    private function normalizeType($type)
    {
        if ('[]' === substr($type, -2)) {
            return $this->normalize(substr($type, 0, -2)).'[]';
        }

        return $this->normalize($type);
    }
}


<?php

/*
 * 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\NamespaceNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Bram Gotink <bram@gotink.me>
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class NoLeadingNamespaceWhitespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_NAMESPACE);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'The namespace declaration line shouldn\'t contain leading whitespace.',
            [
                new CodeSample(
                    '<?php
 namespace Test8a;
    namespace Test8b;
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        for ($index = \count($tokens) - 1; 0 <= $index; --$index) {
            $token = $tokens[$index];

            if (!$token->isGivenKind(T_NAMESPACE)) {
                continue;
            }

            $beforeNamespaceIndex = $index - 1;
            $beforeNamespace = $tokens[$beforeNamespaceIndex];

            if (!$beforeNamespace->isWhitespace()) {
                if (!self::endsWithWhitespace($beforeNamespace->getContent())) {
                    $tokens->insertAt($index, new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding()]));
                }

                continue;
            }

            $lastNewline = strrpos($beforeNamespace->getContent(), "\n");

            if (false === $lastNewline) {
                $beforeBeforeNamespace = $tokens[$index - 2];

                if (self::endsWithWhitespace($beforeBeforeNamespace->getContent())) {
                    $tokens->clearAt($beforeNamespaceIndex);
                } else {
                    $tokens[$beforeNamespaceIndex] = new Token([T_WHITESPACE, ' ']);
                }
            } else {
                $tokens[$beforeNamespaceIndex] = new Token([T_WHITESPACE, substr($beforeNamespace->getContent(), 0, $lastNewline + 1)]);
            }
        }
    }

    private static function endsWithWhitespace($str)
    {
        if ('' === $str) {
            return false;
        }

        return '' === trim(substr($str, -1));
    }
}


<?php

/*
 * 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\Console\Command;

use PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface;
use PhpCsFixer\PharCheckerInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\ToolInfoInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * @author Igor Wiedler <igor@wiedler.ch>
 * @author Stephane PY <py.stephane1@gmail.com>
 * @author Grégoire Pineau <lyrixx@lyrixx.info>
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author SpacePossum
 *
 * @internal
 */
final class SelfUpdateCommand extends Command
{
    const COMMAND_NAME = 'self-update';

    /**
     * @var NewVersionCheckerInterface
     */
    private $versionChecker;

    /**
     * @var ToolInfoInterface
     */
    private $toolInfo;

    /**
     * @var PharCheckerInterface
     */
    private $pharChecker;

    public function __construct(
        NewVersionCheckerInterface $versionChecker,
        ToolInfoInterface $toolInfo,
        PharCheckerInterface $pharChecker
    ) {
        parent::__construct();

        $this->versionChecker = $versionChecker;
        $this->toolInfo = $toolInfo;
        $this->pharChecker = $pharChecker;
    }

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setName(self::COMMAND_NAME)
            ->setAliases(['selfupdate'])
            ->setDefinition(
                [
                    new InputOption('--force', '-f', InputOption::VALUE_NONE, 'Force update to next major version if available.'),
                ]
            )
            ->setDescription('Update php-cs-fixer.phar to the latest stable version.')
            ->setHelp(
                <<<'EOT'
The <info>%command.name%</info> command replace your php-cs-fixer.phar by the
latest version released on:
<comment>https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases</comment>

<info>$ php php-cs-fixer.phar %command.name%</info>

EOT
            )
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        if (!$this->toolInfo->isInstalledAsPhar()) {
            $output->writeln('<error>Self-update is available only for PHAR version.</error>');

            return 1;
        }

        $currentVersion = $this->getApplication()->getVersion();
        Preg::match('/^v?(?<major>\d+)\./', $currentVersion, $matches);
        $currentMajor = (int) $matches['major'];

        try {
            $latestVersion = $this->versionChecker->getLatestVersion();
            $latestVersionOfCurrentMajor = $this->versionChecker->getLatestVersionOfMajor($currentMajor);
        } catch (\Exception $exception) {
            $output->writeln(sprintf(
                '<error>Unable to determine newest version: %s</error>',
                $exception->getMessage()
            ));

            return 1;
        }

        if (1 !== $this->versionChecker->compareVersions($latestVersion, $currentVersion)) {
            $output->writeln('<info>php-cs-fixer is already up to date.</info>');

            return 0;
        }

        $remoteTag = $latestVersion;

        if (
            0 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $latestVersion)
            && true !== $input->getOption('force')
        ) {
            $output->writeln(sprintf('<info>A new major version of php-cs-fixer is available</info> (<comment>%s</comment>)', $latestVersion));
            $output->writeln(sprintf('<info>Before upgrading please read</info> https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/%s/UPGRADE.md', $latestVersion));
            $output->writeln('<info>If you are ready to upgrade run this command with</info> <comment>-f</comment>');
            $output->writeln('<info>Checking for new minor/patch version...</info>');

            if (1 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $currentVersion)) {
                $output->writeln('<info>No minor update for php-cs-fixer.</info>');

                return 0;
            }

            $remoteTag = $latestVersionOfCurrentMajor;
        }

        $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];

        if (!is_writable($localFilename)) {
            $output->writeln(sprintf('<error>No permission to update %s file.</error>', $localFilename));

            return 1;
        }

        $tempFilename = \dirname($localFilename).'/'.basename($localFilename, '.phar').'-tmp.phar';
        $remoteFilename = $this->toolInfo->getPharDownloadUri($remoteTag);

        if (false === @copy($remoteFilename, $tempFilename)) {
            $output->writeln(sprintf('<error>Unable to download new version %s from the server.</error>', $remoteTag));

            return 1;
        }

        chmod($tempFilename, 0777 & ~umask());

        $pharInvalidityReason = $this->pharChecker->checkFileValidity($tempFilename);
        if (null !== $pharInvalidityReason) {
            unlink($tempFilename);
            $output->writeln(sprintf('<error>The download of %s is corrupt (%s).</error>', $remoteTag, $pharInvalidityReason));
            $output->writeln('<error>Please re-run the self-update command to try again.</error>');

            return 1;
        }

        rename($tempFilename, $localFilename);

        $output->writeln(sprintf('<info>php-cs-fixer updated</info> (<comment>%s</comment>)', $remoteTag));
    }
}


<?php

/*
 * 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\Tokenizer\Transformer;

use PhpCsFixer\Tokenizer\AbstractTransformer;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * Transform T_USE into:
 * - CT::T_USE_TRAIT for imports,
 * - CT::T_USE_LAMBDA for lambda variable uses.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * @internal
 */
final class UseTransformer extends AbstractTransformer
{
    /**
     * {@inheritdoc}
     */
    public function getCustomTokens()
    {
        return [CT::T_USE_TRAIT, CT::T_USE_LAMBDA];
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // Should run after CurlyBraceTransformer and before TypeColonTransformer
        return -5;
    }

    /**
     * {@inheritdoc}
     */
    public function getRequiredPhpVersionId()
    {
        return 50300;
    }

    /**
     * {@inheritdoc}
     */
    public function process(Tokens $tokens, Token $token, $index)
    {
        if ($token->isGivenKind(T_USE) && $this->isUseForLambda($tokens, $index)) {
            $tokens[$index] = new Token([CT::T_USE_LAMBDA, $token->getContent()]);

            return;
        }

        // Only search inside class/trait body for `T_USE` for traits.
        // Cannot import traits inside interfaces or anywhere else

        if (!$token->isGivenKind([T_CLASS, T_TRAIT])) {
            return;
        }

        if ($tokens[$tokens->getPrevMeaningfulToken($index)]->isGivenKind(T_DOUBLE_COLON)) {
            return;
        }

        $index = $tokens->getNextTokenOfKind($index, ['{']);
        $innerLimit = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);

        while ($index < $innerLimit) {
            $token = $tokens[++$index];

            if (!$token->isGivenKind(T_USE)) {
                continue;
            }

            if ($this->isUseForLambda($tokens, $index)) {
                $tokens[$index] = new Token([CT::T_USE_LAMBDA, $token->getContent()]);
            } else {
                $tokens[$index] = new Token([CT::T_USE_TRAIT, $token->getContent()]);
            }
        }
    }

    /**
     * Check if token under given index is `use` statement for lambda function.
     *
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return bool
     */
    private function isUseForLambda(Tokens $tokens, $index)
    {
        $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];

        // test `function () use ($foo) {}` case
        return $nextToken->equals('(');
    }
}


<?php

/*
 * 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\Alias;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Preg;
use PhpCsFixer\PregException;
use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Utils;

/**
 * @author Matteo Beccati <matteo@beccati.com>
 */
final class EregToPregFixer extends AbstractFixer
{
    /**
     * @var array the list of the ext/ereg function names, their preg equivalent and the preg modifier(s), if any
     *            all condensed in an array of arrays
     */
    private static $functions = [
        ['ereg', 'preg_match', ''],
        ['eregi', 'preg_match', 'i'],
        ['ereg_replace', 'preg_replace', ''],
        ['eregi_replace', 'preg_replace', 'i'],
        ['split', 'preg_split', ''],
        ['spliti', 'preg_split', 'i'],
    ];

    /**
     * @var array the list of preg delimiters, in order of preference
     */
    private static $delimiters = ['/', '#', '!'];

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Replace deprecated `ereg` regular expression functions with `preg`.',
            [new CodeSample("<?php \$x = ereg('[A-Z]');\n")],
            null,
            'Risky if the `ereg` function is overridden.'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_STRING);
    }

    /**
     * {@inheritdoc}
     */
    public function isRisky()
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $end = $tokens->count() - 1;
        $functionsAnalyzer = new FunctionsAnalyzer();

        foreach (self::$functions as $map) {
            // the sequence is the function name, followed by "(" and a quoted string
            $seq = [[T_STRING, $map[0]], '(', [T_CONSTANT_ENCAPSED_STRING]];

            $currIndex = 0;
            while (null !== $currIndex) {
                $match = $tokens->findSequence($seq, $currIndex, $end, false);

                // did we find a match?
                if (null === $match) {
                    break;
                }

                // findSequence also returns the tokens, but we're only interested in the indexes, i.e.:
                // 0 => function name,
                // 1 => bracket "("
                // 2 => quoted string passed as 1st parameter
                $match = array_keys($match);

                // advance tokenizer cursor
                $currIndex = $match[2];

                if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $match[0])) {
                    continue;
                }

                // ensure the first parameter is just a string (e.g. has nothing appended)
                $next = $tokens->getNextMeaningfulToken($match[2]);
                if (null === $next || !$tokens[$next]->equalsAny([',', ')'])) {
                    continue;
                }

                // convert to PCRE
                $regexTokenContent = $tokens[$match[2]]->getContent();
                $string = substr($regexTokenContent, 1, -1);
                $quote = $regexTokenContent[0];
                $delim = $this->getBestDelimiter($string);
                $preg = $delim.addcslashes($string, $delim).$delim.'D'.$map[2];

                // check if the preg is valid
                if (!$this->checkPreg($preg)) {
                    continue;
                }

                // modify function and argument
                $tokens[$match[0]] = new Token([T_STRING, $map[1]]);
                $tokens[$match[2]] = new Token([T_CONSTANT_ENCAPSED_STRING, $quote.$preg.$quote]);
            }
        }
    }

    /**
     * Check the validity of a PCRE.
     *
     * @param string $pattern the regular expression
     *
     * @return bool
     */
    private function checkPreg($pattern)
    {
        try {
            Preg::match($pattern, '');

            return true;
        } catch (PregException $e) {
            return false;
        }
    }

    /**
     * Get the delimiter that would require the least escaping in a regular expression.
     *
     * @param string $pattern the regular expression
     *
     * @return string the preg delimiter
     */
    private function getBestDelimiter($pattern)
    {
        // try do find something that's not used
        $delimiters = [];
        foreach (self::$delimiters as $k => $d) {
            if (false === strpos($pattern, $d)) {
                return $d;
            }

            $delimiters[$d] = [substr_count($pattern, $d), $k];
        }

        // return the least used delimiter, using the position in the list as a tie breaker
        uasort($delimiters, static function ($a, $b) {
            if ($a[0] === $b[0]) {
                return Utils::cmpInt($a, $b);
            }

            return $a[0] < $b[0] ? -1 : 1;
        });

        return key($delimiters);
    }
}


<?php

/*
 * 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\StringNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author ntzm
 */
final class NoBinaryStringFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_START_HEREDOC]);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There should not be a binary flag before strings.',
            [
                new CodeSample("<?php \$a = b'foo';\n"),
                new CodeSample("<?php \$a = b<<<EOT\nfoo\nEOT;\n"),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($tokens as $index => $token) {
            if (!$token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_START_HEREDOC])) {
                continue;
            }

            $content = $token->getContent();

            if ('b' === strtolower($content[0])) {
                $tokens[$index] = new Token([$token->getId(), substr($content, 1)]);
            }
        }
    }
}


<?php

/*
 * 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\Comment;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Filippo Tessarotto <zoeslam@gmail.com>
 */
final class SingleLineCommentStyleFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    /**
     * @var bool
     */
    private $asteriskEnabled;

    /**
     * @var bool
     */
    private $hashEnabled;

    /**
     * {@inheritdoc}
     */
    public function configure(array $configuration = null)
    {
        parent::configure($configuration);

        $this->asteriskEnabled = \in_array('asterisk', $this->configuration['comment_types'], true);
        $this->hashEnabled = \in_array('hash', $this->configuration['comment_types'], true);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax.',
            [
                new CodeSample(
                    '<?php
/* asterisk comment */
$a = 1;

# hash comment
$b = 2;

/*
 * multi-line
 * comment
 */
$c = 3;
'
                ),
                new CodeSample(
                    '<?php
/* first comment */
$a = 1;

/*
 * second comment
 */
$b = 2;

/*
 * third
 * comment
 */
$c = 3;
',
                    ['comment_types' => ['asterisk']]
                ),
                new CodeSample(
                    "<?php # comment\n",
                    ['comment_types' => ['hash']]
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_COMMENT);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($tokens as $index => $token) {
            if (!$token->isGivenKind(T_COMMENT)) {
                continue;
            }

            $content = $token->getContent();
            $commentContent = substr($content, 2, -2) ?: '';

            if ($this->hashEnabled && '#' === $content[0]) {
                $tokens[$index] = new Token([$token->getId(), '//'.substr($content, 1)]);

                continue;
            }

            if (
                !$this->asteriskEnabled
                || false !== strpos($commentContent, '?>')
                || '/*' !== substr($content, 0, 2)
                || 1 === Preg::match('/[^\s\*].*\R.*[^\s\*]/s', $commentContent)
            ) {
                continue;
            }

            $nextTokenIndex = $index + 1;
            if (isset($tokens[$nextTokenIndex])) {
                $nextToken = $tokens[$nextTokenIndex];
                if (!$nextToken->isWhitespace() || 1 !== Preg::match('/\R/', $nextToken->getContent())) {
                    continue;
                }

                $tokens[$nextTokenIndex] = new Token([$nextToken->getId(), ltrim($nextToken->getContent(), " \t")]);
            }

            $content = '//';
            if (1 === Preg::match('/[^\s\*]/', $commentContent)) {
                $content = '// '.Preg::replace('/[\s\*]*([^\s\*](?:.+[^\s\*])?)[\s\*]*/', '\1', $commentContent);
            }
            $tokens[$index] = new Token([$token->getId(), $content]);
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolver([
            (new FixerOptionBuilder('comment_types', 'List of comment types to fix'))
                ->setAllowedTypes(['array'])
                ->setAllowedValues([new AllowedValueSubset(['asterisk', 'hash'])])
                ->setDefault(['asterisk', 'hash'])
                ->getOption(),
        ]);
    }
}


<?php

/*
 * 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\ClassNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Ceeram <ceeram@cakephp.org>
 */
final class NoBlankLinesAfterClassOpeningFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There should be no empty lines after class opening brace.',
            [
                new CodeSample(
                    '<?php
final class Sample
{

    protected function foo()
    {
    }
}
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($tokens as $index => $token) {
            if (!$token->isClassy()) {
                continue;
            }

            $startBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
            if (!$tokens[$startBraceIndex + 1]->isWhitespace()) {
                continue;
            }

            $this->fixWhitespace($tokens, $startBraceIndex + 1);
        }
    }

    /**
     * Cleanup a whitespace token.
     *
     * @param Tokens $tokens
     * @param int    $index
     */
    private function fixWhitespace(Tokens $tokens, $index)
    {
        $content = $tokens[$index]->getContent();
        // if there is more than one new line in the whitespace, then we need to fix it
        if (substr_count($content, "\n") > 1) {
            // the final bit of the whitespace must be the next statement's indentation
            $tokens[$index] = new Token([T_WHITESPACE, $this->whitespacesConfig->getLineEnding().substr($content, strrpos($content, "\n") + 1)]);
        }
    }
}


<?php

/*
 * 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\Tokenizer;

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class CT
{
    const T_ARRAY_INDEX_CURLY_BRACE_CLOSE = 10001;
    const T_ARRAY_INDEX_CURLY_BRACE_OPEN = 10002;
    const T_ARRAY_SQUARE_BRACE_CLOSE = 10003;
    const T_ARRAY_SQUARE_BRACE_OPEN = 10004;
    const T_ARRAY_TYPEHINT = 10005;
    const T_BRACE_CLASS_INSTANTIATION_CLOSE = 10006;
    const T_BRACE_CLASS_INSTANTIATION_OPEN = 10007;
    const T_CLASS_CONSTANT = 10008;
    const T_CONST_IMPORT = 10009;
    const T_CURLY_CLOSE = 10010;
    const T_DESTRUCTURING_SQUARE_BRACE_CLOSE = 10011;
    const T_DESTRUCTURING_SQUARE_BRACE_OPEN = 10012;
    const T_DOLLAR_CLOSE_CURLY_BRACES = 10013;
    const T_DYNAMIC_PROP_BRACE_CLOSE = 10014;
    const T_DYNAMIC_PROP_BRACE_OPEN = 10015;
    const T_DYNAMIC_VAR_BRACE_CLOSE = 10016;
    const T_DYNAMIC_VAR_BRACE_OPEN = 10017;
    const T_FUNCTION_IMPORT = 10018;
    const T_GROUP_IMPORT_BRACE_CLOSE = 10019;
    const T_GROUP_IMPORT_BRACE_OPEN = 10020;
    const T_NAMESPACE_OPERATOR = 10021;
    const T_NULLABLE_TYPE = 10022;
    const T_RETURN_REF = 10023;
    const T_TYPE_ALTERNATION = 10024;
    const T_TYPE_COLON = 10025;
    const T_USE_LAMBDA = 10026;
    const T_USE_TRAIT = 10027;

    private function __construct()
    {
    }

    /**
     * Get name for custom token.
     *
     * @param int $value custom token value
     *
     * @return string
     */
    public static function getName($value)
    {
        if (!self::has($value)) {
            throw new \InvalidArgumentException(sprintf('No custom token was found for "%s".', $value));
        }

        $tokens = self::getMapById();

        return 'CT::'.$tokens[$value];
    }

    /**
     * Check if given custom token exists.
     *
     * @param int $value custom token value
     *
     * @return bool
     */
    public static function has($value)
    {
        $tokens = self::getMapById();

        return isset($tokens[$value]);
    }

    private static function getMapById()
    {
        static $constants;

        if (null === $constants) {
            $reflection = new \ReflectionClass(__CLASS__);
            $constants = array_flip($reflection->getConstants());
        }

        return $constants;
    }
}