<?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\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Gregor Harlan <gharlan@web.de>
 */
final class OrderedClassElementsFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    /** @internal */
    const SORT_ALPHA = 'alpha';
    /** @internal */
    const SORT_NONE = 'none';

    /**
     * @var array Array containing all class element base types (keys) and their parent types (values)
     */
    private static $typeHierarchy = [
        'use_trait' => null,
        'public' => null,
        'protected' => null,
        'private' => null,
        'constant' => null,
        'constant_public' => ['constant', 'public'],
        'constant_protected' => ['constant', 'protected'],
        'constant_private' => ['constant', 'private'],
        'property' => null,
        'property_static' => ['property'],
        'property_public' => ['property', 'public'],
        'property_protected' => ['property', 'protected'],
        'property_private' => ['property', 'private'],
        'property_public_static' => ['property_static', 'property_public'],
        'property_protected_static' => ['property_static', 'property_protected'],
        'property_private_static' => ['property_static', 'property_private'],
        'method' => null,
        'method_static' => ['method'],
        'method_public' => ['method', 'public'],
        'method_protected' => ['method', 'protected'],
        'method_private' => ['method', 'private'],
        'method_public_static' => ['method_static', 'method_public'],
        'method_protected_static' => ['method_static', 'method_protected'],
        'method_private_static' => ['method_static', 'method_private'],
    ];

    /**
     * @var array Array containing special method types
     */
    private static $specialTypes = [
        'construct' => null,
        'destruct' => null,
        'magic' => null,
        'phpunit' => null,
    ];

    /**
     * Array of supported sort algorithms in configuration.
     *
     * @var string[]
     */
    private $supportedSortAlgorithms = [
        self::SORT_NONE,
        self::SORT_ALPHA,
    ];

    /**
     * @var array Resolved configuration array (type => position)
     */
    private $typePosition;

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

        $this->typePosition = [];
        $pos = 0;
        foreach ($this->configuration['order'] as $type) {
            $this->typePosition[$type] = $pos++;
        }

        foreach (self::$typeHierarchy as $type => $parents) {
            if (isset($this->typePosition[$type])) {
                continue;
            }

            if (!$parents) {
                $this->typePosition[$type] = null;

                continue;
            }

            foreach ($parents as $parent) {
                if (isset($this->typePosition[$parent])) {
                    $this->typePosition[$type] = $this->typePosition[$parent];

                    continue 2;
                }
            }

            $this->typePosition[$type] = null;
        }

        $lastPosition = \count($this->configuration['order']);
        foreach ($this->typePosition as &$pos) {
            if (null === $pos) {
                $pos = $lastPosition;
            }
            // last digit is used by phpunit method ordering
            $pos *= 10;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Orders the elements of classes/interfaces/traits.',
            [
                new CodeSample(
                    '<?php
final class Example
{
    use BarTrait;
    use BazTrait;
    const C1 = 1;
    const C2 = 2;
    protected static $protStatProp;
    public static $pubStatProp1;
    public $pubProp1;
    protected $protProp;
    var $pubProp2;
    private static $privStatProp;
    private $privProp;
    public static $pubStatProp2;
    public $pubProp3;
    protected function __construct() {}
    private static function privStatFunc() {}
    public function pubFunc1() {}
    public function __toString() {}
    protected function protFunc() {}
    function pubFunc2() {}
    public static function pubStatFunc1() {}
    public function pubFunc3() {}
    static function pubStatFunc2() {}
    private function privFunc() {}
    public static function pubStatFunc3() {}
    protected static function protStatFunc() {}
    public function __destruct() {}
}
'
                ),
                new CodeSample(
                    '<?php
class Example
{
    public function A(){}
    private function B(){}
}
',
                    ['order' => ['method_private', 'method_public']]
                ),
                new CodeSample(
                    '<?php
class Example
{
    public function D(){}
    public function B(){}
    public function A(){}
    public function C(){}
}
',
                    ['order' => ['method_public'], 'sortAlgorithm' => 'alpha']
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // must run before MethodSeparationFixer, NoBlankLinesAfterClassOpeningFixer and SpaceAfterSemicolonFixer.
        // must run after ProtectedToPrivateFixer.
        return 65;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        for ($i = 1, $count = $tokens->count(); $i < $count; ++$i) {
            if (!$tokens[$i]->isClassy()) {
                continue;
            }

            $i = $tokens->getNextTokenOfKind($i, ['{']);
            $elements = $this->getElements($tokens, $i);

            if (!$elements) {
                continue;
            }

            $sorted = $this->sortElements($elements);
            $endIndex = $elements[\count($elements) - 1]['end'];

            if ($sorted !== $elements) {
                $this->sortTokens($tokens, $i, $endIndex, $sorted);
            }

            $i = $endIndex;
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolverRootless('order', [
            (new FixerOptionBuilder('order', 'List of strings defining order of elements.'))
                ->setAllowedTypes(['array'])
                ->setAllowedValues([new AllowedValueSubset(array_keys(array_merge(self::$typeHierarchy, self::$specialTypes)))])
                ->setDefault([
                    'use_trait',
                    'constant_public',
                    'constant_protected',
                    'constant_private',
                    'property_public',
                    'property_protected',
                    'property_private',
                    'construct',
                    'destruct',
                    'magic',
                    'phpunit',
                    'method_public',
                    'method_protected',
                    'method_private',
                ])
                ->getOption(),
            (new FixerOptionBuilder('sortAlgorithm', 'How multiple occurrences of same type statements should be sorted'))
                ->setAllowedValues($this->supportedSortAlgorithms)
                ->setDefault(self::SORT_NONE)
                ->getOption(),
        ], $this->getName());
    }

    /**
     * @param Tokens $tokens
     * @param int    $startIndex
     *
     * @return array[]
     */
    private function getElements(Tokens $tokens, $startIndex)
    {
        static $elementTokenKinds = [CT::T_USE_TRAIT, T_CONST, T_VARIABLE, T_FUNCTION];

        ++$startIndex;
        $elements = [];

        while (true) {
            $element = [
                'start' => $startIndex,
                'visibility' => 'public',
                'static' => false,
            ];

            for ($i = $startIndex;; ++$i) {
                $token = $tokens[$i];

                // class end
                if ($token->equals('}')) {
                    return $elements;
                }

                if ($token->isGivenKind(T_STATIC)) {
                    $element['static'] = true;

                    continue;
                }

                if ($token->isGivenKind([T_PROTECTED, T_PRIVATE])) {
                    $element['visibility'] = strtolower($token->getContent());

                    continue;
                }

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

                $type = $this->detectElementType($tokens, $i);
                if (\is_array($type)) {
                    $element['type'] = $type[0];
                    $element['name'] = $type[1];
                } else {
                    $element['type'] = $type;
                }

                if ('property' === $element['type']) {
                    $element['name'] = $tokens[$i]->getContent();
                } elseif (\in_array($element['type'], ['use_trait', 'constant', 'method', 'magic'], true)) {
                    $element['name'] = $tokens[$tokens->getNextMeaningfulToken($i)]->getContent();
                }

                $element['end'] = $this->findElementEnd($tokens, $i);

                break;
            }

            $elements[] = $element;
            $startIndex = $element['end'] + 1;
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return array|string type or array of type and name
     */
    private function detectElementType(Tokens $tokens, $index)
    {
        $token = $tokens[$index];

        if ($token->isGivenKind(CT::T_USE_TRAIT)) {
            return 'use_trait';
        }

        if ($token->isGivenKind(T_CONST)) {
            return 'constant';
        }

        if ($token->isGivenKind(T_VARIABLE)) {
            return 'property';
        }

        $nameToken = $tokens[$tokens->getNextMeaningfulToken($index)];

        if ($nameToken->equals([T_STRING, '__construct'], false)) {
            return 'construct';
        }

        if ($nameToken->equals([T_STRING, '__destruct'], false)) {
            return 'destruct';
        }

        if (
            $nameToken->equalsAny([
                [T_STRING, 'setUpBeforeClass'],
                [T_STRING, 'tearDownAfterClass'],
                [T_STRING, 'setUp'],
                [T_STRING, 'tearDown'],
            ], false)
        ) {
            return ['phpunit', strtolower($nameToken->getContent())];
        }

        if ('__' === substr($nameToken->getContent(), 0, 2)) {
            return 'magic';
        }

        return 'method';
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return int
     */
    private function findElementEnd(Tokens $tokens, $index)
    {
        $index = $tokens->getNextTokenOfKind($index, ['{', ';']);

        if ($tokens[$index]->equals('{')) {
            $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
        }

        for (++$index; $tokens[$index]->isWhitespace(" \t") || $tokens[$index]->isComment(); ++$index);

        --$index;

        return $tokens[$index]->isWhitespace() ? $index - 1 : $index;
    }

    /**
     * @param array[] $elements
     *
     * @return array[]
     */
    private function sortElements(array $elements)
    {
        static $phpunitPositions = [
            'setupbeforeclass' => 1,
            'teardownafterclass' => 2,
            'setup' => 3,
            'teardown' => 4,
        ];

        foreach ($elements as &$element) {
            $type = $element['type'];

            if (\array_key_exists($type, self::$specialTypes)) {
                if (isset($this->typePosition[$type])) {
                    $element['position'] = $this->typePosition[$type];
                    if ('phpunit' === $type) {
                        $element['position'] += $phpunitPositions[$element['name']];
                    }

                    continue;
                }

                $type = 'method';
            }

            if (\in_array($type, ['constant', 'property', 'method'], true)) {
                $type .= '_'.$element['visibility'];
                if ($element['static']) {
                    $type .= '_static';
                }
            }

            $element['position'] = $this->typePosition[$type];
        }
        unset($element);

        usort($elements, function (array $a, array $b) {
            if ($a['position'] === $b['position']) {
                return $this->sortGroupElements($a, $b);
            }

            return $a['position'] > $b['position'] ? 1 : -1;
        });

        return $elements;
    }

    private function sortGroupElements(array $a, array $b)
    {
        $selectedSortAlgorithm = $this->configuration['sortAlgorithm'];

        if (self::SORT_ALPHA === $selectedSortAlgorithm) {
            return strcasecmp($a['name'], $b['name']);
        }

        return $a['start'] > $b['start'] ? 1 : -1;
    }

    /**
     * @param Tokens  $tokens
     * @param int     $startIndex
     * @param int     $endIndex
     * @param array[] $elements
     */
    private function sortTokens(Tokens $tokens, $startIndex, $endIndex, array $elements)
    {
        $replaceTokens = [];

        foreach ($elements as $element) {
            for ($i = $element['start']; $i <= $element['end']; ++$i) {
                $replaceTokens[] = clone $tokens[$i];
            }
        }

        $tokens->overrideRange($startIndex + 1, $endIndex, $replaceTokens);
    }
}


<?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;

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author SpacePossum
 *
 * @internal
 */
final class WordMatcher
{
    /**
     * @var string[]
     */
    private $candidates;

    /**
     * @param string[] $candidates
     */
    public function __construct(array $candidates)
    {
        $this->candidates = $candidates;
    }

    /**
     * @param string $needle
     *
     * @return null|string
     */
    public function match($needle)
    {
        $word = null;
        $distance = ceil(\strlen($needle) * 0.35);

        foreach ($this->candidates as $candidate) {
            $candidateDistance = levenshtein($needle, $candidate);

            if ($candidateDistance < $distance) {
                $word = $candidate;
                $distance = $candidateDistance;
            }
        }

        return $word;
    }
}


<?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;

/**
 * Fixer for part of rule defined in PSR5 ¶7.22.
 *
 * @author SpacePossum
 */
final class PhpdocSingleLineVarSpacingFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Single line `@var` PHPDoc should have proper spacing.',
            [new CodeSample("<?php /**@var   MyClass   \$a   */\n\$a = test();\n")]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run after PhpdocNoAliasTagFixer.
        return -10;
    }

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        /** @var Token $token */
        foreach ($tokens as $index => $token) {
            if ($token->isGivenKind(T_DOC_COMMENT)) {
                $tokens[$index] = new Token([T_DOC_COMMENT, $this->fixTokenContent($token->getContent())]);

                continue;
            }

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

            $content = $token->getContent();
            $fixedContent = $this->fixTokenContent($content);
            if ($content !== $fixedContent) {
                $tokens[$index] = new Token([T_DOC_COMMENT, $fixedContent]);
            }
        }
    }

    /**
     * @param string $content
     *
     * @return string
     */
    private function fixTokenContent($content)
    {
        return Preg::replaceCallback(
            '#^/\*\*[ \t]*@var[ \t]+(\S+)[ \t]*(\$\S+)?[ \t]*([^\n]*)\*/$#',
            static function (array $matches) {
                $content = '/** @var';
                for ($i = 1, $m = \count($matches); $i < $m; ++$i) {
                    if ('' !== $matches[$i]) {
                        $content .= ' '.$matches[$i];
                    }
                }

                $content = rtrim($content);

                return $content.' */';
            },
            $content
        );
    }
}


<?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 discriminate overloaded square braces tokens.
 *
 * Performed transformations:
 * - in `[1, 2, 3]` into CT::T_ARRAY_SQUARE_BRACE_OPEN and CT::T_ARRAY_SQUARE_BRACE_CLOSE,
 * - in `[$a, &$b, [$c]] = array(1, 2, array(3))` into CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN and CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author SpacePossum
 *
 * @internal
 */
final class SquareBraceTransformer extends AbstractTransformer
{
    /**
     * {@inheritdoc}
     */
    public function getCustomTokens()
    {
        return [
            CT::T_ARRAY_SQUARE_BRACE_OPEN,
            CT::T_ARRAY_SQUARE_BRACE_CLOSE,
            CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN,
            CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE,
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // must run after CurlyBraceTransformer
        return -1;
    }

    /**
     * {@inheritdoc}
     */
    public function getRequiredPhpVersionId()
    {
        // Short array syntax was introduced in PHP 5.4, but the fixer is smart
        // enough to handle it even before 5.4.
        // Same for array destructing syntax sugar `[` introduced in PHP 7.1.
        return 50000;
    }

    /**
     * {@inheritdoc}
     */
    public function process(Tokens $tokens, Token $token, $index)
    {
        if ($this->isArrayDestructing($tokens, $index)) {
            $this->transformIntoDestructuringSquareBrace($tokens, $index);

            return;
        }

        if ($this->isShortArray($tokens, $index)) {
            $this->transformIntoArraySquareBrace($tokens, $index);
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     */
    private function transformIntoArraySquareBrace(Tokens $tokens, $index)
    {
        $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);

        $tokens[$index] = new Token([CT::T_ARRAY_SQUARE_BRACE_OPEN, '[']);
        $tokens[$endIndex] = new Token([CT::T_ARRAY_SQUARE_BRACE_CLOSE, ']']);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     */
    private function transformIntoDestructuringSquareBrace(Tokens $tokens, $index)
    {
        $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index);

        $tokens[$index] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
        $tokens[$endIndex] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);

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

        while ($index < $endIndex) {
            if ($tokens[$index]->equals('[') && $tokens[$previousMeaningfulIndex]->equalsAny([[CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN], ','])) {
                $tokens[$tokens->findBlockEnd(Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE, $index)] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, ']']);
                $tokens[$index] = new Token([CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN, '[']);
            }

            $previousMeaningfulIndex = $index;
            $index = $tokens->getNextMeaningfulToken($index);
        }
    }

    /**
     * Check if token under given index is short array opening.
     *
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return bool
     */
    private function isShortArray(Tokens $tokens, $index)
    {
        if (!$tokens[$index]->equals('[')) {
            return false;
        }

        static $disallowedPrevTokens = [
            ')',
            ']',
            '}',
            '"',
            [T_CONSTANT_ENCAPSED_STRING],
            [T_STRING],
            [T_STRING_VARNAME],
            [T_VARIABLE],
            [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
            [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
            [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
            [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
        ];

        $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
        if ($prevToken->equalsAny($disallowedPrevTokens)) {
            return false;
        }

        $nextToken = $tokens[$tokens->getNextMeaningfulToken($index)];
        if ($nextToken->equals(']')) {
            return true;
        }

        return !$this->isArrayDestructing($tokens, $index);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return bool
     */
    private function isArrayDestructing(Tokens $tokens, $index)
    {
        if (\PHP_VERSION_ID < 70100 || !$tokens[$index]->equals('[')) {
            return false;
        }

        static $disallowedPrevTokens = [
            ')',
            ']',
            '"',
            [T_CONSTANT_ENCAPSED_STRING],
            [T_STRING],
            [T_STRING_VARNAME],
            [T_VARIABLE],
            [CT::T_ARRAY_SQUARE_BRACE_CLOSE],
            [CT::T_DYNAMIC_PROP_BRACE_CLOSE],
            [CT::T_DYNAMIC_VAR_BRACE_CLOSE],
            [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
        ];

        $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
        if ($prevToken->equalsAny($disallowedPrevTokens)) {
            return false;
        }

        $type = Tokens::detectBlockType($tokens[$index]);
        $end = $tokens->findBlockEnd($type['type'], $index);

        $nextToken = $tokens[$tokens->getNextMeaningfulToken($end)];

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

use PhpCsFixer\AbstractFopenFlagFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author SpacePossum
 */
final class FopenFlagOrderFixer extends AbstractFopenFlagFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Order the flags in `fopen` calls, `b` and `t` must be last.',
            [new CodeSample("<?php\n\$a = fopen(\$foo, 'br+');\n")],
            null,
            'Risky when the function `fopen` is overridden.'
        );
    }

    /**
     * @param Tokens $tokens
     * @param int    $argumentStartIndex
     * @param int    $argumentEndIndex
     */
    protected function fixFopenFlagToken(Tokens $tokens, $argumentStartIndex, $argumentEndIndex)
    {
        $argumentFlagIndex = null;

        for ($i = $argumentStartIndex; $i <= $argumentEndIndex; ++$i) {
            if ($tokens[$i]->isGivenKind([T_WHITESPACE, T_COMMENT, T_DOC_COMMENT])) {
                continue;
            }

            if (null !== $argumentFlagIndex) {
                return; // multiple meaningful tokens found, no candidate for fixing
            }

            $argumentFlagIndex = $i;
        }

        // check if second argument is candidate
        if (null === $argumentFlagIndex || !$tokens[$argumentFlagIndex]->isGivenKind(T_CONSTANT_ENCAPSED_STRING)) {
            return;
        }

        $content = $tokens[$argumentFlagIndex]->getContent();
        $contentQuote = $content[0]; // `'`, `"`, `b` or `B`

        if ('b' === $contentQuote || 'B' === $contentQuote) {
            $binPrefix = $contentQuote;
            $contentQuote = $content[1]; // `'` or `"`
            $mode = substr($content, 2, -1);
        } else {
            $binPrefix = '';
            $mode = substr($content, 1, -1);
        }

        $modeLength = \strlen($mode);
        if ($modeLength < 2) {
            return; // nothing to sort
        }

        if (false === $this->isValidModeString($mode)) {
            return;
        }

        $split = $this->sortFlags(Preg::split('#([^\+]\+?)#', $mode, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE));
        $newContent = $binPrefix.$contentQuote.implode('', $split).$contentQuote;

        if ($content !== $newContent) {
            $tokens[$argumentFlagIndex] = new Token([T_CONSTANT_ENCAPSED_STRING, $newContent]);
        }
    }

    /**
     * @param string[] $flags
     *
     * @return string[]
     */
    private function sortFlags(array $flags)
    {
        usort(
            $flags,
            static function ($flag1, $flag2) {
                if ($flag1 === $flag2) {
                    return 0;
                }

                if ('b' === $flag1) {
                    return 1;
                }

                if ('b' === $flag2) {
                    return -1;
                }

                if ('t' === $flag1) {
                    return 1;
                }

                if ('t' === $flag2) {
                    return -1;
                }

                return $flag1 < $flag2 ? -1 : 1;
            }
        );

        return $flags;
    }
}


<?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\Tokens;

/**
 * @author SpacePossum
 */
final class NoUnneededCurlyBracesFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Removes unneeded curly braces that are superfluous and aren\'t part of a control structure\'s body.',
            [
                new CodeSample(
                    '<?php {
    echo 1;
}

switch ($b) {
    case 1: {
        break;
    }
}
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // must be run before NoUselessElseFixer and NoUselessReturnFixer.
        return 26;
    }

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($this->findCurlyBraceOpen($tokens) as $index) {
            if ($this->isOverComplete($tokens, $index)) {
                $this->clearOverCompleteBraces($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $openIndex  index of `{` token
     * @param int    $closeIndex index of `}` token
     */
    private function clearOverCompleteBraces(Tokens $tokens, $openIndex, $closeIndex)
    {
        $tokens->clearTokenAndMergeSurroundingWhitespace($closeIndex);
        $tokens->clearTokenAndMergeSurroundingWhitespace($openIndex);
    }

    private function findCurlyBraceOpen(Tokens $tokens)
    {
        for ($i = \count($tokens) - 1; $i > 0; --$i) {
            if ($tokens[$i]->equals('{')) {
                yield $i;
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index  index of `{` token
     *
     * @return bool
     */
    private function isOverComplete(Tokens $tokens, $index)
    {
        static $whiteList = ['{', '}', [T_OPEN_TAG], ':', ';'];

        return $tokens[$tokens->getPrevMeaningfulToken($index)]->equalsAny($whiteList);
    }
}


<?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\ConfigurationException\InvalidFixerConfigurationException;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerConfiguration\AliasedFixerOptionBuilder;
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;
use Symfony\Component\OptionsResolver\Options;

/**
 * @author Antonio J. García Lagar <aj@garcialagar.es>
 * @author SpacePossum
 */
final class HeaderCommentFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface, WhitespacesAwareFixerInterface
{
    const HEADER_PHPDOC = 'PHPDoc';
    const HEADER_COMMENT = 'comment';

    /** @deprecated will be removed in 3.0 */
    const HEADER_LOCATION_AFTER_OPEN = 1;
    /** @deprecated will be removed in 3.0 */
    const HEADER_LOCATION_AFTER_DECLARE_STRICT = 2;

    /** @deprecated will be removed in 3.0 */
    const HEADER_LINE_SEPARATION_BOTH = 1;
    /** @deprecated will be removed in 3.0 */
    const HEADER_LINE_SEPARATION_TOP = 2;
    /** @deprecated will be removed in 3.0 */
    const HEADER_LINE_SEPARATION_BOTTOM = 3;
    /** @deprecated will be removed in 3.0 */
    const HEADER_LINE_SEPARATION_NONE = 4;

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Add, replace or remove header comment.',
            [
                new CodeSample(
                    '<?php
declare(strict_types=1);

namespace A\B;

echo 1;
',
                    [
                        'header' => 'Made with love.',
                    ]
                ),
                new CodeSample(
                    '<?php
declare(strict_types=1);

namespace A\B;

echo 1;
',
                    [
                        'header' => 'Made with love.',
                        'comment_type' => 'PHPDoc',
                        'location' => 'after_open',
                        'separate' => 'bottom',
                    ]
                ),
                new CodeSample(
                    '<?php
declare(strict_types=1);

namespace A\B;

echo 1;
',
                    [
                        'header' => 'Made with love.',
                        'comment_type' => 'comment',
                        'location' => 'after_declare_strict',
                    ]
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens[0]->isGivenKind(T_OPEN_TAG) && $tokens->isMonolithicPhp();
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run after the NoBlankLinesAfterPhpdocFixer.
        //
        // When this fixer is configured with ["separate" => "bottom", "commentType" => "PHPDoc"]
        // and the target file has no namespace or declare() construct,
        // the fixed header comment gets trimmed by NoBlankLinesAfterPhpdocFixer if we run before it.
        return -30;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        // figure out where the comment should be placed
        $headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens);

        // check if there is already a comment
        $headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerNewIndex - 1);

        if (null === $headerCurrentIndex) {
            if ('' === $this->configuration['header']) {
                return; // header not found and none should be set, return
            }

            $this->insertHeader($tokens, $headerNewIndex);
        } elseif ($this->getHeaderAsComment() !== $tokens[$headerCurrentIndex]->getContent()) {
            $tokens->clearTokenAndMergeSurroundingWhitespace($headerCurrentIndex);
            if ('' === $this->configuration['header']) {
                return; // header found and cleared, none should be set, return
            }

            $this->insertHeader($tokens, $headerNewIndex);
        } else {
            $headerNewIndex = $headerCurrentIndex;
        }

        $this->fixWhiteSpaceAroundHeader($tokens, $headerNewIndex);
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        $fixerName = $this->getName();

        return new FixerConfigurationResolver([
            (new FixerOptionBuilder('header', 'Proper header content.'))
                ->setAllowedTypes(['string'])
                ->setNormalizer(static function (Options $options, $value) use ($fixerName) {
                    if ('' === trim($value)) {
                        return '';
                    }

                    if (false !== strpos($value, '*/')) {
                        throw new InvalidFixerConfigurationException($fixerName, 'Cannot use \'*/\' in header.');
                    }

                    return $value;
                })
                ->getOption(),
            (new AliasedFixerOptionBuilder(
                new FixerOptionBuilder('comment_type', 'Comment syntax type.'),
                'commentType'
            ))
                ->setAllowedValues([self::HEADER_PHPDOC, self::HEADER_COMMENT])
                ->setDefault(self::HEADER_COMMENT)
                ->getOption(),
            (new FixerOptionBuilder('location', 'The location of the inserted header.'))
                ->setAllowedValues(['after_open', 'after_declare_strict'])
                ->setDefault('after_declare_strict')
                ->getOption(),
            (new FixerOptionBuilder('separate', 'Whether the header should be separated from the file content with a new line.'))
                ->setAllowedValues(['both', 'top', 'bottom', 'none'])
                ->setDefault('both')
                ->getOption(),
        ]);
    }

    /**
     * Enclose the given text in a comment block.
     *
     * @return string
     */
    private function getHeaderAsComment()
    {
        $lineEnding = $this->whitespacesConfig->getLineEnding();

        $comment = (self::HEADER_COMMENT === $this->configuration['comment_type'] ? '/*' : '/**').$lineEnding;
        $lines = explode("\n", str_replace("\r", '', $this->configuration['header']));

        foreach ($lines as $line) {
            $comment .= rtrim(' * '.$line).$lineEnding;
        }

        return $comment.' */';
    }

    /**
     * @param Tokens $tokens
     * @param int    $headerNewIndex
     *
     * @return null|int
     */
    private function findHeaderCommentCurrentIndex(Tokens $tokens, $headerNewIndex)
    {
        $index = $tokens->getNextNonWhitespace($headerNewIndex);

        return null === $index || !$tokens[$index]->isComment() ? null : $index;
    }

    /**
     * Find the index where the header comment must be inserted.
     *
     * @param Tokens $tokens
     *
     * @return int
     */
    private function findHeaderCommentInsertionIndex(Tokens $tokens)
    {
        if ('after_open' === $this->configuration['location']) {
            return 1;
        }

        $index = $tokens->getNextMeaningfulToken(0);
        if (null === $index) {
            // file without meaningful tokens but an open tag, comment should always be placed directly after the open tag
            return 1;
        }

        if (!$tokens[$index]->isGivenKind(T_DECLARE)) {
            return 1;
        }

        $next = $tokens->getNextMeaningfulToken($index);
        if (null === $next || !$tokens[$next]->equals('(')) {
            return 1;
        }

        $next = $tokens->getNextMeaningfulToken($next);
        if (null === $next || !$tokens[$next]->equals([T_STRING, 'strict_types'], false)) {
            return 1;
        }

        $next = $tokens->getNextMeaningfulToken($next);
        if (null === $next || !$tokens[$next]->equals('=')) {
            return 1;
        }

        $next = $tokens->getNextMeaningfulToken($next);
        if (null === $next || !$tokens[$next]->isGivenKind(T_LNUMBER)) {
            return 1;
        }

        $next = $tokens->getNextMeaningfulToken($next);
        if (null === $next || !$tokens[$next]->equals(')')) {
            return 1;
        }

        $next = $tokens->getNextMeaningfulToken($next);
        if (null === $next || !$tokens[$next]->equals(';')) { // don't insert after close tag
            return 1;
        }

        return $next + 1;
    }

    /**
     * @param Tokens $tokens
     * @param int    $headerIndex
     */
    private function fixWhiteSpaceAroundHeader(Tokens $tokens, $headerIndex)
    {
        $lineEnding = $this->whitespacesConfig->getLineEnding();

        // fix lines after header comment
        $expectedLineCount = 'both' === $this->configuration['separate'] || 'bottom' === $this->configuration['separate'] ? 2 : 1;
        if ($headerIndex === \count($tokens) - 1) {
            $tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount)]));
        } else {
            $afterCommentIndex = $tokens->getNextNonWhitespace($headerIndex);
            $lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex + 1, null === $afterCommentIndex ? \count($tokens) : $afterCommentIndex);
            if ($lineBreakCount < $expectedLineCount) {
                $missing = str_repeat($lineEnding, $expectedLineCount - $lineBreakCount);
                if ($tokens[$headerIndex + 1]->isWhitespace()) {
                    $tokens[$headerIndex + 1] = new Token([T_WHITESPACE, $missing.$tokens[$headerIndex + 1]->getContent()]);
                } else {
                    $tokens->insertAt($headerIndex + 1, new Token([T_WHITESPACE, $missing]));
                }
            } elseif ($lineBreakCount > 2) {
                // remove extra line endings
                if ($tokens[$headerIndex + 1]->isWhitespace()) {
                    $tokens[$headerIndex + 1] = new Token([T_WHITESPACE, $lineEnding.$lineEnding]);
                }
            }
        }

        // fix lines before header comment
        $expectedLineCount = 'both' === $this->configuration['separate'] || 'top' === $this->configuration['separate'] ? 2 : 1;
        $prev = $tokens->getPrevNonWhitespace($headerIndex);

        $regex = '/[\t ]$/';
        if ($tokens[$prev]->isGivenKind(T_OPEN_TAG) && Preg::match($regex, $tokens[$prev]->getContent())) {
            $tokens[$prev] = new Token([T_OPEN_TAG, Preg::replace($regex, $lineEnding, $tokens[$prev]->getContent())]);
        }

        $lineBreakCount = $this->getLineBreakCount($tokens, $prev, $headerIndex);
        if ($lineBreakCount < $expectedLineCount) {
            // because of the way the insert index was determined for header comment there cannot be an empty token here
            $tokens->insertAt($headerIndex, new Token([T_WHITESPACE, str_repeat($lineEnding, $expectedLineCount - $lineBreakCount)]));
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $indexStart
     * @param int    $indexEnd
     *
     * @return int
     */
    private function getLineBreakCount(Tokens $tokens, $indexStart, $indexEnd)
    {
        $lineCount = 0;
        for ($i = $indexStart; $i < $indexEnd; ++$i) {
            $lineCount += substr_count($tokens[$i]->getContent(), "\n");
        }

        return $lineCount;
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     */
    private function insertHeader(Tokens $tokens, $index)
    {
        $tokens->insertAt($index, new Token([self::HEADER_COMMENT === $this->configuration['comment_type'] ? T_COMMENT : T_DOC_COMMENT, $this->getHeaderAsComment()]));
    }
}


<?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\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Adam Marczuk <adam@marczuk.info>
 */
final class WhitespaceAfterCommaInArrayFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'In array declaration, there MUST be a whitespace after each comma.',
            [new CodeSample("<?php\n\$sample = array(1,'a',\$b,);\n")]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        for ($index = $tokens->count() - 1; $index >= 0; --$index) {
            if ($tokens[$index]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
                $this->fixSpacing($index, $tokens);
            }
        }
    }

    /**
     * Method to fix spacing in array declaration.
     *
     * @param int    $index
     * @param Tokens $tokens
     */
    private function fixSpacing($index, Tokens $tokens)
    {
        if ($tokens[$index]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
            $startIndex = $index;
            $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
        } else {
            $startIndex = $tokens->getNextTokenOfKind($index, ['(']);
            $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
        }

        for ($i = $endIndex - 1; $i > $startIndex; --$i) {
            $i = $this->skipNonArrayElements($i, $tokens);
            if ($tokens[$i]->equals(',') && !$tokens[$i + 1]->isWhitespace()) {
                $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));
            }
        }
    }

    /**
     * Method to move index over the non-array elements like function calls or function declarations.
     *
     * @param int    $index
     * @param Tokens $tokens
     *
     * @return int New index
     */
    private function skipNonArrayElements($index, Tokens $tokens)
    {
        if ($tokens[$index]->equals('}')) {
            return $tokens->findBlockStart(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);
        }

        if ($tokens[$index]->equals(')')) {
            $startIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index);
            $startIndex = $tokens->getPrevMeaningfulToken($startIndex);
            if (!$tokens[$startIndex]->isGivenKind([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN])) {
                return $startIndex;
            }
        }

        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\Fixer\LanguageConstruct;

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

/**
 * @author Vladimir Reznichenko <kalessil@gmail.com>
 */
final class DirConstantFixer extends AbstractFunctionReferenceFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant.',
            [new CodeSample("<?php\n\$a = dirname(__FILE__);\n")],
            null,
            'Risky when the function `dirname` is overridden.'
        );
    }

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

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should run before CombineNestedDirnameFixer
        return 4;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $currIndex = 0;
        while (null !== $currIndex) {
            $boundaries = $this->find('dirname', $tokens, $currIndex, $tokens->count() - 1);
            if (null === $boundaries) {
                return;
            }

            list($functionNameIndex, $openParenthesis, $closeParenthesis) = $boundaries;

            // analysing cursor shift, so nested expressions kept processed
            $currIndex = $openParenthesis;

            // ensure __FILE__ is in between (...)

            $fileCandidateRightIndex = $tokens->getPrevMeaningfulToken($closeParenthesis);
            $trailingCommaIndex = null;
            if ($tokens[$fileCandidateRightIndex]->equals(',')) {
                $trailingCommaIndex = $fileCandidateRightIndex;
                $fileCandidateRightIndex = $tokens->getPrevMeaningfulToken($fileCandidateRightIndex);
            }

            $fileCandidateRight = $tokens[$fileCandidateRightIndex];
            if (!$fileCandidateRight->isGivenKind(T_FILE)) {
                continue;
            }

            $fileCandidateLeftIndex = $tokens->getNextMeaningfulToken($openParenthesis);
            $fileCandidateLeft = $tokens[$fileCandidateLeftIndex];

            if (!$fileCandidateLeft->isGivenKind(T_FILE)) {
                continue;
            }

            // get rid of root namespace when it used
            $namespaceCandidateIndex = $tokens->getPrevMeaningfulToken($functionNameIndex);
            $namespaceCandidate = $tokens[$namespaceCandidateIndex];
            if ($namespaceCandidate->isGivenKind(T_NS_SEPARATOR)) {
                $tokens->removeTrailingWhitespace($namespaceCandidateIndex);
                $tokens->clearAt($namespaceCandidateIndex);
            }

            if (null !== $trailingCommaIndex) {
                if (!$tokens[$tokens->getNextNonWhitespace($trailingCommaIndex)]->isComment()) {
                    $tokens->removeTrailingWhitespace($trailingCommaIndex);
                }

                $tokens->clearTokenAndMergeSurroundingWhitespace($trailingCommaIndex);
            }

            // closing parenthesis removed with leading spaces
            if (!$tokens[$tokens->getNextNonWhitespace($closeParenthesis)]->isComment()) {
                $tokens->removeLeadingWhitespace($closeParenthesis);
            }

            $tokens->clearTokenAndMergeSurroundingWhitespace($closeParenthesis);

            // opening parenthesis removed with trailing and leading spaces
            if (!$tokens[$tokens->getNextNonWhitespace($openParenthesis)]->isComment()) {
                $tokens->removeLeadingWhitespace($openParenthesis);
            }

            $tokens->removeTrailingWhitespace($openParenthesis);
            $tokens->clearTokenAndMergeSurroundingWhitespace($openParenthesis);

            // replace constant and remove function name
            $tokens[$fileCandidateLeftIndex] = new Token([T_DIR, '__DIR__']);
            $tokens->clearTokenAndMergeSurroundingWhitespace($functionNameIndex);
        }
    }
}


<?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\PhpTag;

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 LinebreakAfterOpeningTagFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Ensure there is no code on the same line as the PHP open tag.',
            [new CodeSample("<?php \$a = 1;\n\$b = 3;\n")]
        );
    }

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        // ignore files with short open tag and ignore non-monolithic files
        if (!$tokens[0]->isGivenKind(T_OPEN_TAG) || !$tokens->isMonolithicPhp()) {
            return;
        }

        $newlineFound = false;
        foreach ($tokens as $token) {
            if ($token->isWhitespace() && false !== strpos($token->getContent(), "\n")) {
                $newlineFound = true;

                break;
            }
        }

        // ignore one-line files
        if (!$newlineFound) {
            return;
        }

        $token = $tokens[0];
        $tokens[0] = new Token([$token->getId(), rtrim($token->getContent()).$this->whitespacesConfig->getLineEnding()]);
    }
}


<?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\DocBlock;

use PhpCsFixer\Preg;

/**
 * This represents a line of a docblock.
 *
 * @author Graham Campbell <graham@alt-three.com>
 */
class Line
{
    /**
     * The content of this line.
     *
     * @var string
     */
    private $content;

    /**
     * Create a new line instance.
     *
     * @param string $content
     */
    public function __construct($content)
    {
        $this->content = $content;
    }

    /**
     * Get the string representation of object.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->content;
    }

    /**
     * Get the content of this line.
     *
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * Does this line contain useful content?
     *
     * If the line contains text or tags, then this is true.
     *
     * @return bool
     */
    public function containsUsefulContent()
    {
        return 0 !== Preg::match('/\\*\s*\S+/', $this->content) && !$this->isTheStart() && !$this->isTheEnd();
    }

    /**
     * Does the line contain a tag?
     *
     * If this is true, then it must be the first line of an annotation.
     *
     * @return bool
     */
    public function containsATag()
    {
        return 0 !== Preg::match('/\\*\s*@/', $this->content);
    }

    /**
     * Is the line the start of a docblock?
     *
     * @return bool
     */
    public function isTheStart()
    {
        return false !== strpos($this->content, '/**');
    }

    /**
     * Is the line the end of a docblock?
     *
     * @return bool
     */
    public function isTheEnd()
    {
        return false !== strpos($this->content, '*/');
    }

    /**
     * Set the content of this line.
     *
     * @param string $content
     */
    public function setContent($content)
    {
        $this->content = $content;
    }

    /**
     * Remove this line by clearing its contents.
     *
     * Note that this method technically brakes the internal state of the
     * docblock, but is useful when we need to retain the indexes of lines
     * during the execution of an algorithm.
     */
    public function remove()
    {
        $this->content = '';
    }

    /**
     * Append a blank docblock line to this line's contents.
     *
     * Note that this method technically brakes the internal state of the
     * docblock, but is useful when we need to retain the indexes of lines
     * during the execution of an algorithm.
     */
    public function addBlank()
    {
        $matched = Preg::match('/^([ \t]*\*)[^\r\n]*(\r?\n)$/', $this->content, $matches);

        if (1 !== $matched) {
            return;
        }

        $this->content .= $matches[1].$matches[2];
    }
}


<?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\FixerConfiguration;

/**
 * @internal
 *
 * @deprecated will be removed in 3.0
 */
final class FixerConfigurationResolverRootless implements FixerConfigurationResolverInterface
{
    /**
     * @var FixerConfigurationResolverInterface
     */
    private $resolver;

    /**
     * @var string
     */
    private $root;

    /**
     * @var string
     */
    private $fixerName;

    /**
     * @param string                         $root
     * @param iterable<FixerOptionInterface> $options
     * @param string                         $fixerName
     */
    public function __construct($root, $options, $fixerName)
    {
        $this->resolver = new FixerConfigurationResolver($options);
        $this->fixerName = $fixerName;

        $names = array_map(
            static function (FixerOptionInterface $option) {
                return $option->getName();
            },
            $this->resolver->getOptions()
        );

        if (!\in_array($root, $names, true)) {
            throw new \LogicException(sprintf('The "%s" option is not defined.', $root));
        }

        $this->root = $root;
    }

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

    /**
     * {@inheritdoc}
     */
    public function resolve(array $options)
    {
        if (!empty($options) && !\array_key_exists($this->root, $options)) {
            $names = array_map(
                function (FixerOptionInterface $option) {
                    return $option->getName();
                },
                $this->resolver->getOptions()
            );

            $passedNames = array_keys($options);

            if (!empty(array_diff($passedNames, $names))) {
                $message = "Passing \"{$this->root}\" at the root of the configuration for rule \"{$this->fixerName}\" is deprecated and will not be supported in 3.0, use \"{$this->root}\" => array(...) option instead.";

                if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
                    throw new \RuntimeException("{$message}. This check was performed as `PHP_CS_FIXER_FUTURE_MODE` env var is set.");
                }

                @trigger_error($message, E_USER_DEPRECATED);

                $options = [$this->root => $options];
            }
        }

        return $this->resolver->resolve($options);
    }
}


<?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\Report;

use Symfony\Component\Console\Formatter\OutputFormatter;

/**
 * @author Boris Gorbylev <ekho@ekho.name>
 *
 * @internal
 */
final class XmlReporter implements ReporterInterface
{
    /**
     * {@inheritdoc}
     */
    public function getFormat()
    {
        return 'xml';
    }

    /**
     * {@inheritdoc}
     */
    public function generate(ReportSummary $reportSummary)
    {
        if (!\extension_loaded('dom')) {
            throw new \RuntimeException('Cannot generate report! `ext-dom` is not available!');
        }

        $dom = new \DOMDocument('1.0', 'UTF-8');
        // new nodes should be added to this or existing children
        $root = $dom->createElement('report');
        $dom->appendChild($root);

        $filesXML = $dom->createElement('files');
        $root->appendChild($filesXML);

        $i = 1;
        foreach ($reportSummary->getChanged() as $file => $fixResult) {
            $fileXML = $dom->createElement('file');
            $fileXML->setAttribute('id', (string) $i++);
            $fileXML->setAttribute('name', $file);
            $filesXML->appendChild($fileXML);

            if ($reportSummary->shouldAddAppliedFixers()) {
                $fileXML->appendChild($this->createAppliedFixersElement($dom, $fixResult));
            }

            if (!empty($fixResult['diff'])) {
                $fileXML->appendChild($this->createDiffElement($dom, $fixResult));
            }
        }

        if (0 !== $reportSummary->getTime()) {
            $root->appendChild($this->createTimeElement($reportSummary->getTime(), $dom));
        }

        if (0 !== $reportSummary->getMemory()) {
            $root->appendChild($this->createMemoryElement($reportSummary->getMemory(), $dom));
        }

        $dom->formatOutput = true;

        return $reportSummary->isDecoratedOutput() ? OutputFormatter::escape($dom->saveXML()) : $dom->saveXML();
    }

    /**
     * @param \DOMDocument $dom
     * @param array        $fixResult
     *
     * @return \DOMElement
     */
    private function createAppliedFixersElement($dom, array $fixResult)
    {
        $appliedFixersXML = $dom->createElement('applied_fixers');

        foreach ($fixResult['appliedFixers'] as $appliedFixer) {
            $appliedFixerXML = $dom->createElement('applied_fixer');
            $appliedFixerXML->setAttribute('name', $appliedFixer);
            $appliedFixersXML->appendChild($appliedFixerXML);
        }

        return $appliedFixersXML;
    }

    /**
     * @param \DOMDocument $dom
     * @param array        $fixResult
     *
     * @return \DOMElement
     */
    private function createDiffElement(\DOMDocument $dom, array $fixResult)
    {
        $diffXML = $dom->createElement('diff');
        $diffXML->appendChild($dom->createCDATASection($fixResult['diff']));

        return $diffXML;
    }

    /**
     * @param float        $time
     * @param \DOMDocument $dom
     *
     * @return \DOMElement
     */
    private function createTimeElement($time, \DOMDocument $dom)
    {
        $time = round($time / 1000, 3);

        $timeXML = $dom->createElement('time');
        $timeXML->setAttribute('unit', 's');
        $timeTotalXML = $dom->createElement('total');
        $timeTotalXML->setAttribute('value', (string) $time);
        $timeXML->appendChild($timeTotalXML);

        return $timeXML;
    }

    /**
     * @param float        $memory
     * @param \DOMDocument $dom
     *
     * @return \DOMElement
     */
    private function createMemoryElement($memory, \DOMDocument $dom)
    {
        $memory = round($memory / 1024 / 1024, 3);

        $memoryXML = $dom->createElement('memory');
        $memoryXML->setAttribute('value', (string) $memory);
        $memoryXML->setAttribute('unit', 'MB');

        return $memoryXML;
    }
}


<?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 discriminate overloaded curly braces tokens.
 *
 * Performed transformations:
 * - closing `}` for T_CURLY_OPEN into CT::T_CURLY_CLOSE,
 * - closing `}` for T_DOLLAR_OPEN_CURLY_BRACES into CT::T_DOLLAR_CLOSE_CURLY_BRACES,
 * - in `$foo->{$bar}` into CT::T_DYNAMIC_PROP_BRACE_OPEN and CT::T_DYNAMIC_PROP_BRACE_CLOSE,
 * - in `${$foo}` into CT::T_DYNAMIC_VAR_BRACE_OPEN and CT::T_DYNAMIC_VAR_BRACE_CLOSE,
 * - in `$array{$index}` into CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN and CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
 * - in `use some\a\{ClassA, ClassB, ClassC as C}` into CT::T_GROUP_IMPORT_BRACE_OPEN, CT::T_GROUP_IMPORT_BRACE_CLOSE.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * @internal
 */
final class CurlyBraceTransformer extends AbstractTransformer
{
    /**
     * {@inheritdoc}
     */
    public function getCustomTokens()
    {
        return [
            CT::T_CURLY_CLOSE,
            CT::T_DOLLAR_CLOSE_CURLY_BRACES,
            CT::T_DYNAMIC_PROP_BRACE_OPEN,
            CT::T_DYNAMIC_PROP_BRACE_CLOSE,
            CT::T_DYNAMIC_VAR_BRACE_OPEN,
            CT::T_DYNAMIC_VAR_BRACE_CLOSE,
            CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN,
            CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE,
            CT::T_GROUP_IMPORT_BRACE_OPEN,
            CT::T_GROUP_IMPORT_BRACE_CLOSE,
        ];
    }

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

    /**
     * {@inheritdoc}
     */
    public function process(Tokens $tokens, Token $token, $index)
    {
        $this->transformIntoCurlyCloseBrace($tokens, $token, $index);
        $this->transformIntoDollarCloseBrace($tokens, $token, $index);
        $this->transformIntoDynamicPropBraces($tokens, $token, $index);
        $this->transformIntoDynamicVarBraces($tokens, $token, $index);
        $this->transformIntoCurlyIndexBraces($tokens, $token, $index);

        if (\PHP_VERSION_ID >= 70000) {
            $this->transformIntoGroupUseBraces($tokens, $token, $index);
        }
    }

    /**
     * Transform closing `}` for T_CURLY_OPEN into CT::T_CURLY_CLOSE.
     *
     * This should be done at very beginning of curly braces transformations.
     *
     * @param Tokens $tokens
     * @param Token  $token
     * @param int    $index
     */
    private function transformIntoCurlyCloseBrace(Tokens $tokens, Token $token, $index)
    {
        if (!$token->isGivenKind(T_CURLY_OPEN)) {
            return;
        }

        $level = 1;
        $nestIndex = $index;

        while (0 < $level) {
            ++$nestIndex;

            // we count all kind of {
            if ($tokens[$nestIndex]->equals('{')) {
                ++$level;

                continue;
            }

            // we count all kind of }
            if ($tokens[$nestIndex]->equals('}')) {
                --$level;
            }
        }

        $tokens[$nestIndex] = new Token([CT::T_CURLY_CLOSE, '}']);
    }

    private function transformIntoDollarCloseBrace(Tokens $tokens, Token $token, $index)
    {
        if ($token->isGivenKind(T_DOLLAR_OPEN_CURLY_BRACES)) {
            $nextIndex = $tokens->getNextTokenOfKind($index, ['}']);
            $tokens[$nextIndex] = new Token([CT::T_DOLLAR_CLOSE_CURLY_BRACES, '}']);
        }
    }

    private function transformIntoDynamicPropBraces(Tokens $tokens, Token $token, $index)
    {
        if (!$token->isGivenKind(T_OBJECT_OPERATOR)) {
            return;
        }

        if (!$tokens[$index + 1]->equals('{')) {
            return;
        }

        $openIndex = $index + 1;
        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openIndex);

        $tokens[$openIndex] = new Token([CT::T_DYNAMIC_PROP_BRACE_OPEN, '{']);
        $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_PROP_BRACE_CLOSE, '}']);
    }

    private function transformIntoDynamicVarBraces(Tokens $tokens, Token $token, $index)
    {
        if (!$token->equals('$')) {
            return;
        }

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

        if (null === $openIndex) {
            return;
        }

        $openToken = $tokens[$openIndex];

        if (!$openToken->equals('{')) {
            return;
        }

        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openIndex);

        $tokens[$openIndex] = new Token([CT::T_DYNAMIC_VAR_BRACE_OPEN, '{']);
        $tokens[$closeIndex] = new Token([CT::T_DYNAMIC_VAR_BRACE_CLOSE, '}']);
    }

    private function transformIntoCurlyIndexBraces(Tokens $tokens, Token $token, $index)
    {
        if (!$token->equals('{')) {
            return;
        }

        $prevIndex = $tokens->getPrevMeaningfulToken($index);

        if (!$tokens[$prevIndex]->equalsAny([
            [T_STRING],
            [T_VARIABLE],
            [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE],
            ']',
            ')',
        ])) {
            return;
        }

        if (
            $tokens[$prevIndex]->isGivenKind(T_STRING)
            && !$tokens[$tokens->getPrevMeaningfulToken($prevIndex)]->isGivenKind(T_OBJECT_OPERATOR)
        ) {
            return;
        }

        if (
            $tokens[$prevIndex]->equals(')')
            && !$tokens[$tokens->getPrevMeaningfulToken(
                $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $prevIndex)
            )]->isGivenKind(T_ARRAY)
        ) {
            return;
        }

        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);

        $tokens[$index] = new Token([CT::T_ARRAY_INDEX_CURLY_BRACE_OPEN, '{']);
        $tokens[$closeIndex] = new Token([CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE, '}']);
    }

    private function transformIntoGroupUseBraces(Tokens $tokens, Token $token, $index)
    {
        if (!$token->equals('{')) {
            return;
        }

        $prevIndex = $tokens->getPrevMeaningfulToken($index);

        if (!$tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
            return;
        }

        $closeIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);

        $tokens[$index] = new Token([CT::T_GROUP_IMPORT_BRACE_OPEN, '{']);
        $tokens[$closeIndex] = new Token([CT::T_GROUP_IMPORT_BRACE_CLOSE, '}']);
    }
}


<?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\PhpUnit;

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

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class PhpUnitConstructFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    private static $assertionFixers = [
        'assertSame' => 'fixAssertPositive',
        'assertEquals' => 'fixAssertPositive',
        'assertNotEquals' => 'fixAssertNegative',
        'assertNotSame' => 'fixAssertNegative',
    ];

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

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

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'PHPUnit assertion method calls like `->assertSame(true, $foo)` should be written with dedicated method like `->assertTrue($foo)`.',
            [
                new CodeSample(
                    '<?php
$this->assertEquals(false, $b);
$this->assertSame(true, $a);
$this->assertNotEquals(null, $c);
$this->assertNotSame(null, $d);
'
                ),
                new CodeSample(
                    '<?php
$this->assertEquals(false, $b);
$this->assertSame(true, $a);
$this->assertNotEquals(null, $c);
$this->assertNotSame(null, $d);
',
                    ['assertions' => ['assertSame', 'assertNotSame']]
                ),
            ],
            null,
            'Fixer could be risky if one is overriding PHPUnit\'s native methods.'
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run after the PhpUnitStrictFixer and before PhpUnitDedicateAssertFixer.
        return -10;
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        // no assertions to be fixed - fast return
        if (empty($this->configuration['assertions'])) {
            return;
        }

        foreach ($this->configuration['assertions'] as $assertionMethod) {
            $assertionFixer = self::$assertionFixers[$assertionMethod];

            for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
                $index = $this->{$assertionFixer}($tokens, $index, $assertionMethod);

                if (null === $index) {
                    break;
                }
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolverRootless('assertions', [
            (new FixerOptionBuilder('assertions', 'List of assertion methods to fix.'))
                ->setAllowedTypes(['array'])
                ->setAllowedValues([new AllowedValueSubset(array_keys(self::$assertionFixers))])
                ->setDefault([
                    'assertEquals',
                    'assertSame',
                    'assertNotEquals',
                    'assertNotSame',
                ])
                ->getOption(),
        ], $this->getName());
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     * @param string $method
     *
     * @return null|int
     */
    private function fixAssertNegative(Tokens $tokens, $index, $method)
    {
        static $map = [
            'false' => 'assertNotFalse',
            'null' => 'assertNotNull',
            'true' => 'assertNotTrue',
        ];

        return $this->fixAssert($map, $tokens, $index, $method);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     * @param string $method
     *
     * @return null|int
     */
    private function fixAssertPositive(Tokens $tokens, $index, $method)
    {
        static $map = [
            'false' => 'assertFalse',
            'null' => 'assertNull',
            'true' => 'assertTrue',
        ];

        return $this->fixAssert($map, $tokens, $index, $method);
    }

    /**
     * @param array<string, string> $map
     * @param Tokens                $tokens
     * @param int                   $index
     * @param string                $method
     *
     * @return null|int
     */
    private function fixAssert(array $map, Tokens $tokens, $index, $method)
    {
        $sequence = $tokens->findSequence(
            [
                [T_STRING, $method],
                '(',
            ],
            $index
        );

        if (null === $sequence) {
            return null;
        }

        $sequenceIndexes = array_keys($sequence);
        $operatorIndex = $tokens->getPrevMeaningfulToken($sequenceIndexes[0]);
        $referenceIndex = $tokens->getPrevMeaningfulToken($operatorIndex);
        if (
            !($tokens[$operatorIndex]->equals([T_OBJECT_OPERATOR, '->']) && $tokens[$referenceIndex]->equals([T_VARIABLE, '$this']))
            && !($tokens[$operatorIndex]->equals([T_DOUBLE_COLON, '::']) && $tokens[$referenceIndex]->equals([T_STRING, 'self']))
            && !($tokens[$operatorIndex]->equals([T_DOUBLE_COLON, '::']) && $tokens[$referenceIndex]->equals([T_STATIC, 'static']))
        ) {
            return null;
        }

        $sequenceIndexes[2] = $tokens->getNextMeaningfulToken($sequenceIndexes[1]);
        $firstParameterToken = $tokens[$sequenceIndexes[2]];

        if (!$firstParameterToken->isNativeConstant()) {
            return $sequenceIndexes[2];
        }

        $sequenceIndexes[3] = $tokens->getNextMeaningfulToken($sequenceIndexes[2]);

        // return if first method argument is an expression, not value
        if (!$tokens[$sequenceIndexes[3]]->equals(',')) {
            return $sequenceIndexes[3];
        }

        $tokens[$sequenceIndexes[0]] = new Token([T_STRING, $map[strtolower($firstParameterToken->getContent())]]);
        $tokens->clearRange($sequenceIndexes[2], $tokens->getNextNonWhitespace($sequenceIndexes[3]) - 1);

        return $sequenceIndexes[3];
    }
}


<?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\ReturnNotation;

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

/**
 * @author SpacePossum
 */
final class NoUselessReturnFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAllTokenKindsFound([T_FUNCTION, T_RETURN]);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There should not be an empty `return` statement at the end of a function.',
            [
                new CodeSample(
                    '<?php
function example($b) {
    if ($b) {
        return;
    }
    return;
}
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run before BlankLineBeforeReturnFixer, NoExtraBlankLinesFixer, NoWhitespaceInBlankLineFixer and after SimplifiedNullReturnFixer and NoEmptyStatementFixer.
        return -18;
    }

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

            $index = $tokens->getNextTokenOfKind($index, [';', '{']);
            if ($tokens[$index]->equals('{')) {
                $this->fixFunction($tokens, $index, $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index));
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $start  Token index of the opening brace token of the function
     * @param int    $end    Token index of the closing brace token of the function
     */
    private function fixFunction(Tokens $tokens, $start, $end)
    {
        for ($index = $end; $index > $start; --$index) {
            if (!$tokens[$index]->isGivenKind(T_RETURN)) {
                continue;
            }

            $nextAt = $tokens->getNextMeaningfulToken($index);
            if (!$tokens[$nextAt]->equals(';')) {
                continue;
            }

            if ($tokens->getNextMeaningfulToken($nextAt) !== $end) {
                continue;
            }

            $previous = $tokens->getPrevMeaningfulToken($index);
            if ($tokens[$previous]->equalsAny([[T_ELSE], ')'])) {
                continue;
            }

            $tokens->clearTokenAndMergeSurroundingWhitespace($index);
            $tokens->clearTokenAndMergeSurroundingWhitespace($nextAt);
        }
    }
}


<?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\AbstractFunctionReferenceFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverRootless;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;

/**
 * @author Vladimir Reznichenko <kalessil@gmail.com>
 */
final class RandomApiMigrationFixer extends AbstractFunctionReferenceFixer implements ConfigurationDefinitionFixerInterface
{
    /**
     * @var array
     */
    private static $argumentCounts = [
        'getrandmax' => [0],
        'mt_rand' => [1, 2],
        'rand' => [0, 2],
        'srand' => [0, 1],
    ];

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

        foreach ($this->configuration['replacements'] as $functionName => $replacement) {
            $this->configuration['replacements'][$functionName] = [
                'alternativeName' => $replacement,
                'argumentCount' => self::$argumentCounts[$functionName],
            ];
        }
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Replaces `rand`, `srand`, `getrandmax` functions calls with their `mt_*` analogs.',
            [
                new CodeSample("<?php\n\$a = getrandmax();\n\$a = rand(\$b, \$c);\n\$a = srand();\n"),
                new CodeSample(
                    "<?php\n\$a = getrandmax();\n\$a = rand(\$b, \$c);\n\$a = srand();\n",
                    ['replacements' => ['getrandmax' => 'mt_getrandmax']]
                ),
            ],
            null,
            'Risky when the configured functions are overridden.'
        );
    }

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

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

        foreach ($this->configuration['replacements'] as $functionIdentity => $functionReplacement) {
            if ($functionIdentity === $functionReplacement['alternativeName']) {
                continue;
            }

            $currIndex = 0;
            while (null !== $currIndex) {
                // try getting function reference and translate boundaries for humans
                $boundaries = $this->find($functionIdentity, $tokens, $currIndex, $tokens->count() - 1);
                if (null === $boundaries) {
                    // next function search, as current one not found
                    continue 2;
                }

                list($functionName, $openParenthesis, $closeParenthesis) = $boundaries;
                $count = $argumentsAnalyzer->countArguments($tokens, $openParenthesis, $closeParenthesis);
                if (!\in_array($count, $functionReplacement['argumentCount'], true)) {
                    continue 2;
                }

                // analysing cursor shift, so nested calls could be processed
                $currIndex = $openParenthesis;

                $tokens[$functionName] = new Token([T_STRING, $functionReplacement['alternativeName']]);

                if (0 === $count && 'random_int' === $functionReplacement['alternativeName']) {
                    $tokens->insertAt($currIndex + 1, [
                        new Token([T_LNUMBER, '0']),
                        new Token(','),
                        new Token([T_WHITESPACE, ' ']),
                        new Token([T_STRING, 'getrandmax']),
                        new Token('('),
                        new Token(')'),
                    ]);

                    $currIndex += 6;
                }
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolverRootless('replacements', [
            (new FixerOptionBuilder('replacements', 'Mapping between replaced functions with the new ones.'))
                ->setAllowedTypes(['array'])
                ->setAllowedValues([static function ($value) {
                    foreach ($value as $functionName => $replacement) {
                        if (!\array_key_exists($functionName, self::$argumentCounts)) {
                            throw new InvalidOptionsException(sprintf(
                                'Function "%s" is not handled by the fixer.',
                                $functionName
                            ));
                        }

                        if (!\is_string($replacement)) {
                            throw new InvalidOptionsException(sprintf(
                                'Replacement for function "%s" must be a string, "%s" given.',
                                $functionName,
                                \is_object($replacement) ? \get_class($replacement) : \gettype($replacement)
                            ));
                        }
                    }

                    return true;
                }])
                ->setDefault([
                    'getrandmax' => 'mt_getrandmax',
                    'rand' => 'mt_rand',
                    'srand' => 'mt_srand',
                ])
                ->getOption(),
        ], $this->getName());
    }
}


<?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\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Filippo Tessarotto <zoeslam@gmail.com>
 */
final class NoUnneededFinalMethodFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'A final class must not have final methods.',
            [
                new CodeSample(
                    '<?php
final class Foo {
    final public function foo() {}
    final protected function bar() {}
    final private function baz() {}
}
'
                ),
                new CodeSample(
                    '<?php
class Foo {
    final private function bar() {}
}
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAllTokenKindsFound([T_CLASS, T_FINAL]);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $tokensCount = \count($tokens);
        for ($index = 0; $index < $tokensCount; ++$index) {
            if (!$tokens[$index]->isGivenKind(T_CLASS)) {
                continue;
            }

            $classOpen = $tokens->getNextTokenOfKind($index, ['{']);
            $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
            $classIsFinal = $prevToken->isGivenKind(T_FINAL);

            $this->fixClass($tokens, $classOpen, $classIsFinal);
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $classOpenIndex
     * @param bool   $classIsFinal
     */
    private function fixClass(Tokens $tokens, $classOpenIndex, $classIsFinal)
    {
        $tokensCount = \count($tokens);
        for ($index = $classOpenIndex + 1; $index < $tokensCount; ++$index) {
            // Class end
            if ($tokens[$index]->equals('}')) {
                return;
            }

            // Skip method content
            if ($tokens[$index]->equals('{')) {
                $index = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $index);

                continue;
            }

            if (!$tokens[$index]->isGivenKind(T_FINAL)) {
                continue;
            }

            if (!$classIsFinal && !$this->isPrivateMethod($tokens, $index, $classOpenIndex)) {
                continue;
            }

            $tokens->clearAt($index);

            $nextTokenIndex = $index + 1;
            if ($tokens[$nextTokenIndex]->isWhitespace()) {
                $tokens->clearAt($nextTokenIndex);
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     * @param int    $classOpenIndex
     *
     * @return bool
     */
    private function isPrivateMethod(Tokens $tokens, $index, $classOpenIndex)
    {
        $index = max($classOpenIndex + 1, $tokens->getPrevTokenOfKind($index, [';', '{', '}']));

        while (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
            if ($tokens[$index]->isGivenKind(T_PRIVATE)) {
                return true;
            }

            ++$index;
        }

        return false;
    }
}


<?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\DocBlock\DocBlock;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Graham Campbell <graham@alt-three.com>
 */
final class PhpdocOrderFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isTokenKindFound(T_DOC_COMMENT);
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations.',
            [
                new CodeSample(
                    '<?php
/**
 * Hello there!
 *
 * @throws Exception|RuntimeException foo
 * @custom Test!
 * @return int  Return the number of changes.
 * @param string $foo
 * @param bool   $bar Bar
 */
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // must be run before the PhpdocSeparationFixer

        /*
         * Should be run before the php_doc_separation fixer so that if we
         * create incorrect annotation grouping while moving the annotations
         * about, we're still ok.
         */
        return -2;
    }

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

            $content = $token->getContent();
            // move param to start, return to end, leave throws in the middle
            $content = $this->moveParamAnnotations($content);
            // we're parsing the content again to make sure the internal
            // state of the dockblock is correct after the modifications
            $content = $this->moveReturnAnnotations($content);
            // persist the content at the end
            $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
        }
    }

    /**
     * Move all param annotations in before throws and return annotations.
     *
     * @param string $content
     *
     * @return string
     */
    private function moveParamAnnotations($content)
    {
        $doc = new DocBlock($content);
        $params = $doc->getAnnotationsOfType('param');

        // nothing to do if there are no param annotations
        if (empty($params)) {
            return $content;
        }

        $others = $doc->getAnnotationsOfType(['throws', 'return']);

        if (empty($others)) {
            return $content;
        }

        // get the index of the final line of the final param annotation
        $end = end($params)->getEnd();

        $line = $doc->getLine($end);

        // move stuff about if required
        foreach ($others as $other) {
            if ($other->getStart() < $end) {
                // we're doing this to maintain the original line indexes
                $line->setContent($line->getContent().$other->getContent());
                $other->remove();
            }
        }

        return $doc->getContent();
    }

    /**
     * Move all return annotations after param and throws annotations.
     *
     * @param string $content
     *
     * @return string
     */
    private function moveReturnAnnotations($content)
    {
        $doc = new DocBlock($content);
        $returns = $doc->getAnnotationsOfType('return');

        // nothing to do if there are no return annotations
        if (empty($returns)) {
            return $content;
        }

        $others = $doc->getAnnotationsOfType(['param', 'throws']);

        // nothing to do if there are no other annotations
        if (empty($others)) {
            return $content;
        }

        // get the index of the first line of the first return annotation
        $start = $returns[0]->getStart();
        $line = $doc->getLine($start);

        // move stuff about if required
        foreach (array_reverse($others) as $other) {
            if ($other->getEnd() > $start) {
                // we're doing this to maintain the original line indexes
                $line->setContent($other->getContent().$line->getContent());
                $other->remove();
            }
        }

        return $doc->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\Console\Command;

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * @internal
 */
final class FixCommandExitStatusCalculator
{
    // Exit status 1 is reserved for environment constraints not matched.
    const EXIT_STATUS_FLAG_HAS_INVALID_FILES = 4;
    const EXIT_STATUS_FLAG_HAS_CHANGED_FILES = 8;
    const EXIT_STATUS_FLAG_HAS_INVALID_CONFIG = 16;
    const EXIT_STATUS_FLAG_HAS_INVALID_FIXER_CONFIG = 32;
    const EXIT_STATUS_FLAG_EXCEPTION_IN_APP = 64;

    /**
     * @param bool $isDryRun
     * @param bool $hasChangedFiles
     * @param bool $hasInvalidErrors
     * @param bool $hasExceptionErrors
     *
     * @return int
     */
    public function calculate($isDryRun, $hasChangedFiles, $hasInvalidErrors, $hasExceptionErrors)
    {
        $exitStatus = 0;

        if ($isDryRun) {
            if ($hasChangedFiles) {
                $exitStatus |= self::EXIT_STATUS_FLAG_HAS_CHANGED_FILES;
            }

            if ($hasInvalidErrors) {
                $exitStatus |= self::EXIT_STATUS_FLAG_HAS_INVALID_FILES;
            }
        }

        if ($hasExceptionErrors) {
            $exitStatus |= self::EXIT_STATUS_FLAG_EXCEPTION_IN_APP;
        }

        return $exitStatus;
    }
}


<?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;

/**
 * Fixer for rules defined in PSR2 ¶3.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class BlankLineAfterNamespaceFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There MUST be one blank line after the namespace declaration.',
            [
                new CodeSample("<?php\nnamespace Sample\\Sample;\n\n\n\$a;\n"),
                new CodeSample("<?php\nnamespace Sample\\Sample;\nClass Test{}\n"),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run after the NoUnusedImportsFixer
        return -20;
    }

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $ending = $this->whitespacesConfig->getLineEnding();
        $lastIndex = $tokens->count() - 1;

        for ($index = $lastIndex; $index >= 0; --$index) {
            $token = $tokens[$index];

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

            $semicolonIndex = $tokens->getNextTokenOfKind($index, [';', '{', [T_CLOSE_TAG]]);
            $semicolonToken = $tokens[$semicolonIndex];

            if (!isset($tokens[$semicolonIndex + 1]) || !$semicolonToken->equals(';')) {
                continue;
            }

            $nextIndex = $semicolonIndex + 1;
            $nextToken = $tokens[$nextIndex];

            if (!$nextToken->isWhitespace()) {
                $tokens->insertAt($semicolonIndex + 1, new Token([T_WHITESPACE, $ending.$ending]));
            } else {
                $tokens[$nextIndex] = new Token([
                    T_WHITESPACE,
                    ($nextIndex === $lastIndex ? $ending : $ending.$ending).ltrim($nextToken->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\Operator;

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

/**
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class ObjectOperatorWithoutWhitespaceFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There should not be space before or after object `T_OBJECT_OPERATOR` `->`.',
            [new CodeSample("<?php \$a  ->  b;\n")]
        );
    }

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        // [Structure] there should not be space before or after T_OBJECT_OPERATOR
        foreach ($tokens as $index => $token) {
            if (!$token->isGivenKind(T_OBJECT_OPERATOR)) {
                continue;
            }

            // clear whitespace before ->
            if ($tokens[$index - 1]->isWhitespace(" \t") && !$tokens[$index - 2]->isComment()) {
                $tokens->clearAt($index - 1);
            }

            // clear whitespace after ->
            if ($tokens[$index + 1]->isWhitespace(" \t") && !$tokens[$index + 2]->isComment()) {
                $tokens->clearAt($index + 1);
            }
        }
    }
}