<?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\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class PhpUnitNamespacedFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    /**
     * @var string
     */
    private $originalClassRegEx;

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'PHPUnit classes MUST be used in namespaced version, e.g. `\PHPUnit\Framework\TestCase` instead of `\PHPUnit_Framework_TestCase`.',
            [
                new CodeSample(
                    '<?php
final class MyTest extends \PHPUnit_Framework_TestCase
{
}
'
                ),
            ],
            "PHPUnit v6 has finally fully switched to namespaces.\n"
            ."You could start preparing the upgrade by switching from non-namespaced TestCase to namespaced one.\n"
            .'Forward compatibility layer (`\PHPUnit\Framework\TestCase` class) was backported to PHPUnit v4.8.35 and PHPUnit v5.4.0.'."\n"
            .'Extended forward compatibility layer (`PHPUnit\Framework\Assert`, `PHPUnit\Framework\BaseTestListener`, `PHPUnit\Framework\TestListener` classes) was introduced in v5.7.0.'."\n",
            'Risky when PHPUnit classes are overridden or not accessible, or when project has PHPUnit incompatibilities.'
        );
    }

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

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

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

        if (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_6_0)) {
            $this->originalClassRegEx = '/^PHPUnit_\w+$/i';
        } elseif (PhpUnitTargetVersion::fulfills($this->configuration['target'], PhpUnitTargetVersion::VERSION_5_7)) {
            $this->originalClassRegEx = '/^PHPUnit_Framework_TestCase|PHPUnit_Framework_Assert|PHPUnit_Framework_BaseTestListener|PHPUnit_Framework_TestListener$/i';
        } else {
            $this->originalClassRegEx = '/^PHPUnit_Framework_TestCase$/i';
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $importedOriginalClassesMap = [];
        $currIndex = 0;

        while (null !== $currIndex) {
            $currIndex = $tokens->getNextTokenOfKind($currIndex, [[T_STRING]]);

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

            $originalClass = $tokens[$currIndex]->getContent();

            if (1 !== Preg::match($this->originalClassRegEx, $originalClass)) {
                ++$currIndex;

                continue;
            }

            $substituteTokens = $this->generateReplacement($originalClass);

            $tokens->clearAt($currIndex);
            $tokens->insertAt(
                $currIndex,
                isset($importedOriginalClassesMap[$originalClass]) ? $substituteTokens[$substituteTokens->getSize() - 1] : $substituteTokens
            );

            $prevIndex = $tokens->getPrevMeaningfulToken($currIndex);
            if ($tokens[$prevIndex]->isGivenKind(T_USE)) {
                $importedOriginalClassesMap[$originalClass] = true;
            } elseif ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
                $prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);

                if ($tokens[$prevIndex]->isGivenKind(T_USE)) {
                    $importedOriginalClassesMap[$originalClass] = true;
                }
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolver([
            (new FixerOptionBuilder('target', 'Target version of PHPUnit.'))
                ->setAllowedTypes(['string'])
                ->setAllowedValues([PhpUnitTargetVersion::VERSION_4_8, PhpUnitTargetVersion::VERSION_5_7, PhpUnitTargetVersion::VERSION_6_0, PhpUnitTargetVersion::VERSION_NEWEST])
                ->setDefault(PhpUnitTargetVersion::VERSION_NEWEST)
                ->getOption(),
        ]);
    }

    /**
     * @param string $originalClassName
     *
     * @return Tokens
     */
    private function generateReplacement($originalClassName)
    {
        $parts = explode('_', $originalClassName);

        $tokensArray = [];
        while (!empty($parts)) {
            $tokensArray[] = new Token([T_STRING, array_shift($parts)]);
            if (!empty($parts)) {
                $tokensArray[] = new Token([T_NS_SEPARATOR, '\\']);
            }
        }

        return Tokens::fromArray($tokensArray);
    }
}


<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer;

use PhpCsFixer\Fixer\FixerInterface;
use PhpCsFixer\Tokenizer\Token;

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author Graham Campbell <graham@alt-three.com>
 * @author Odín del Río <odin.drp@gmail.com>
 *
 * @internal
 */
final class Utils
{
    /**
     * Calculate a bitmask for given constant names.
     *
     * @param string[] $options constant names
     *
     * @return int
     */
    public static function calculateBitmask(array $options)
    {
        $bitmask = 0;

        foreach ($options as $optionName) {
            if (\defined($optionName)) {
                $bitmask |= \constant($optionName);
            }
        }

        return $bitmask;
    }

    /**
     * Converts a camel cased string to an snake cased string.
     *
     * @param string $string
     *
     * @return string
     */
    public static function camelCaseToUnderscore($string)
    {
        return Preg::replaceCallback(
            '/(^|[a-z0-9])([A-Z])/',
            static function (array $matches) {
                return strtolower('' !== $matches[1] ? $matches[1].'_'.$matches[2] : $matches[2]);
            },
            $string
        );
    }

    /**
     * Compare two integers for equality.
     *
     * We'll return 0 if they're equal, 1 if the first is bigger than the
     * second, and -1 if the second is bigger than the first.
     *
     * @param int $a
     * @param int $b
     *
     * @return int
     */
    public static function cmpInt($a, $b)
    {
        if ($a === $b) {
            return 0;
        }

        return $a < $b ? -1 : 1;
    }

    /**
     * Calculate the trailing whitespace.
     *
     * What we're doing here is grabbing everything after the final newline.
     *
     * @param Token $token
     *
     * @return string
     */
    public static function calculateTrailingWhitespaceIndent(Token $token)
    {
        if (!$token->isWhitespace()) {
            throw new \InvalidArgumentException(sprintf('The given token must be whitespace, got "%s".', $token->getName()));
        }

        $str = strrchr(
            str_replace(["\r\n", "\r"], "\n", $token->getContent()),
            "\n"
        );

        if (false === $str) {
            return '';
        }

        return ltrim($str, "\n");
    }

    /**
     * Perform stable sorting using provided comparison function.
     *
     * Stability is ensured by using Schwartzian transform.
     *
     * @param mixed[]  $elements
     * @param callable $getComparedValue a callable that takes a single element and returns the value to compare
     * @param callable $compareValues    a callable that compares two values
     *
     * @return mixed[]
     */
    public static function stableSort(array $elements, callable $getComparedValue, callable $compareValues)
    {
        array_walk($elements, static function (&$element, $index) use ($getComparedValue) {
            $element = [$element, $index, $getComparedValue($element)];
        });

        usort($elements, static function ($a, $b) use ($compareValues) {
            $comparison = $compareValues($a[2], $b[2]);

            if (0 !== $comparison) {
                return $comparison;
            }

            return self::cmpInt($a[1], $b[1]);
        });

        return array_map(static function (array $item) {
            return $item[0];
        }, $elements);
    }

    /**
     * Sort fixers by their priorities.
     *
     * @param FixerInterface[] $fixers
     *
     * @return FixerInterface[]
     */
    public static function sortFixers(array $fixers)
    {
        // Schwartzian transform is used to improve the efficiency and avoid
        // `usort(): Array was modified by the user comparison function` warning for mocked objects.
        return self::stableSort(
            $fixers,
            static function (FixerInterface $fixer) {
                return $fixer->getPriority();
            },
            static function ($a, $b) {
                return self::cmpInt($b, $a);
            }
        );
    }

    /**
     * Join names in natural language wrapped in backticks, e.g. `a`, `b` and `c`.
     *
     * @param string[] $names
     *
     * @throws \InvalidArgumentException
     *
     * @return string
     */
    public static function naturalLanguageJoinWithBackticks(array $names)
    {
        if (empty($names)) {
            throw new \InvalidArgumentException('Array of names cannot be empty');
        }

        $names = array_map(static function ($name) {
            return sprintf('`%s`', $name);
        }, $names);

        $last = array_pop($names);

        if ($names) {
            return implode(', ', $names).' and '.$last;
        }

        return $last;
    }
}


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

/**
 * This class represents a short description (aka summary) of a docblock.
 *
 * @internal
 */
final class ShortDescription
{
    /**
     * The docblock containing the short description.
     *
     * @var DocBlock
     */
    private $doc;

    public function __construct(DocBlock $doc)
    {
        $this->doc = $doc;
    }

    /**
     * Get the line index of the line containing the end of the short
     * description, if present.
     *
     * @return null|int
     */
    public function getEnd()
    {
        $reachedContent = false;

        foreach ($this->doc->getLines() as $index => $line) {
            // we went past a description, then hit a tag or blank line, so
            // the last line of the description must be the one before this one
            if ($reachedContent && ($line->containsATag() || !$line->containsUsefulContent())) {
                return $index - 1;
            }

            // no short description was found
            if ($line->containsATag()) {
                return null;
            }

            // we've reached content, but need to check the next lines too
            // in case the short description is multi-line
            if ($line->containsUsefulContent()) {
                $reachedContent = true;
            }
        }
    }
}


<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer;

use PhpCsFixer\Fixer\FixerInterface;

/**
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Katsuhiro Ogawa <ko.fivestar@gmail.com>
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
class Config implements ConfigInterface
{
    private $cacheFile = '.php_cs.cache';
    private $customFixers = [];
    private $finder;
    private $format = 'txt';
    private $hideProgress = false;
    private $indent = '    ';
    private $isRiskyAllowed = false;
    private $lineEnding = "\n";
    private $name;
    private $phpExecutable;
    private $rules = ['@PSR2' => true];
    private $usingCache = true;

    public function __construct($name = 'default')
    {
        $this->name = $name;
    }

    /**
     * @return static
     */
    public static function create()
    {
        return new static();
    }

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

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

    /**
     * {@inheritdoc}
     */
    public function getFinder()
    {
        if (null === $this->finder) {
            $this->finder = new Finder();
        }

        return $this->finder;
    }

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

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

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

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

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

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

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

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

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

    /**
     * {@inheritdoc}
     */
    public function registerCustomFixers($fixers)
    {
        if (false === \is_array($fixers) && false === $fixers instanceof \Traversable) {
            throw new \InvalidArgumentException(sprintf(
                'Argument must be an array or a Traversable, got "%s".',
                \is_object($fixers) ? \get_class($fixers) : \gettype($fixers)
            ));
        }

        foreach ($fixers as $fixer) {
            $this->addCustomFixer($fixer);
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setCacheFile($cacheFile)
    {
        $this->cacheFile = $cacheFile;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setFinder($finder)
    {
        if (false === \is_array($finder) && false === $finder instanceof \Traversable) {
            throw new \InvalidArgumentException(sprintf(
                'Argument must be an array or a Traversable, got "%s".',
                \is_object($finder) ? \get_class($finder) : \gettype($finder)
            ));
        }

        $this->finder = $finder;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setFormat($format)
    {
        $this->format = $format;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setHideProgress($hideProgress)
    {
        $this->hideProgress = $hideProgress;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setIndent($indent)
    {
        $this->indent = $indent;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setLineEnding($lineEnding)
    {
        $this->lineEnding = $lineEnding;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setPhpExecutable($phpExecutable)
    {
        $this->phpExecutable = $phpExecutable;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setRiskyAllowed($isRiskyAllowed)
    {
        $this->isRiskyAllowed = $isRiskyAllowed;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setRules(array $rules)
    {
        $this->rules = $rules;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setUsingCache($usingCache)
    {
        $this->usingCache = $usingCache;

        return $this;
    }

    private function addCustomFixer(FixerInterface $fixer)
    {
        $this->customFixers[] = $fixer;
    }
}


<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer;

use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Carlos Cirello <carlos.cirello.nl@gmail.com>
 *
 * @internal
 *
 * @deprecated
 */
abstract class AbstractAlignFixerHelper
{
    /**
     * @const Placeholder used as anchor for right alignment.
     */
    const ALIGNABLE_PLACEHOLDER = "\x2 ALIGNABLE%d \x3";

    /**
     * Keep track of the deepest level ever achieved while
     * parsing the code. Used later to replace alignment
     * placeholders with spaces.
     *
     * @var int
     */
    protected $deepestLevel = 0;

    public function fix(Tokens $tokens)
    {
        // This fixer works partially on Tokens and partially on string representation of code.
        // During the process of fixing internal state of single Token may be affected by injecting ALIGNABLE_PLACEHOLDER to its content.
        // The placeholder will be resolved by `replacePlaceholder` method by removing placeholder or changing it into spaces.
        // That way of fixing the code causes disturbances in marking Token as changed - if code is perfectly valid then placeholder
        // still be injected and removed, which will cause the `changed` flag to be set.
        // To handle that unwanted behavior we work on clone of Tokens collection and then override original collection with fixed collection.
        $tokensClone = clone $tokens;

        $this->injectAlignmentPlaceholders($tokensClone, 0, \count($tokens));
        $content = $this->replacePlaceholder($tokensClone);

        $tokens->setCode($content);
    }

    /**
     * Inject into the text placeholders of candidates of vertical alignment.
     *
     * @param Tokens $tokens
     * @param int    $startAt
     * @param int    $endAt
     */
    abstract protected function injectAlignmentPlaceholders(Tokens $tokens, $startAt, $endAt);

    /**
     * Look for group of placeholders, and provide vertical alignment.
     *
     * @param Tokens $tokens
     *
     * @return string
     */
    protected function replacePlaceholder(Tokens $tokens)
    {
        $tmpCode = $tokens->generateCode();

        for ($j = 0; $j <= $this->deepestLevel; ++$j) {
            $placeholder = sprintf(self::ALIGNABLE_PLACEHOLDER, $j);

            if (false === strpos($tmpCode, $placeholder)) {
                continue;
            }

            $lines = explode("\n", $tmpCode);
            $linesWithPlaceholder = [];
            $blockSize = 0;

            $linesWithPlaceholder[$blockSize] = [];

            foreach ($lines as $index => $line) {
                if (substr_count($line, $placeholder) > 0) {
                    $linesWithPlaceholder[$blockSize][] = $index;
                } else {
                    ++$blockSize;
                    $linesWithPlaceholder[$blockSize] = [];
                }
            }

            foreach ($linesWithPlaceholder as $group) {
                if (\count($group) < 1) {
                    continue;
                }

                $rightmostSymbol = 0;
                foreach ($group as $index) {
                    $rightmostSymbol = max($rightmostSymbol, strpos(utf8_decode($lines[$index]), $placeholder));
                }

                foreach ($group as $index) {
                    $line = $lines[$index];
                    $currentSymbol = strpos(utf8_decode($line), $placeholder);
                    $delta = abs($rightmostSymbol - $currentSymbol);

                    if ($delta > 0) {
                        $line = str_replace($placeholder, str_repeat(' ', $delta).$placeholder, $line);
                        $lines[$index] = $line;
                    }
                }
            }

            $tmpCode = str_replace($placeholder, '', implode("\n", $lines));
        }

        return $tmpCode;
    }
}


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

/**
 * @author Graham Campbell <graham@alt-three.com>
 */
final class PhpdocTrimFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'PHPDoc should start and end with content, excluding the very first and last line of the docblocks.',
            [new CodeSample('<?php
/**
 *
 * Foo must be final class.
 *
 *
 */
final class Foo {}
')]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        /*
         * Should be run after all phpdoc fixers that add or remove tags, or
         * alter descriptions. This is so that they don't leave behind blank
         * lines this fixer would have otherwise cleaned up.
         */
        return -5;
    }

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

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

            $content = $token->getContent();
            $content = $this->fixStart($content);
            // we need re-parse the docblock after fixing the start before
            // fixing the end in order for the lines to be correctly indexed
            $content = $this->fixEnd($content);
            $tokens[$index] = new Token([T_DOC_COMMENT, $content]);
        }
    }

    /**
     * Make sure the first useful line starts immediately after the first line.
     *
     * @param string $content
     *
     * @return string
     */
    private function fixStart($content)
    {
        return Preg::replace(
            '~
                (^/\*\*)                  # DocComment begin
                (?:
                    \R[ \t]*(?:\*[ \t]*)? # lines without useful content
                    (?!\R[ \t]*\*/)       # not followed by a DocComment end
                )+
                (\R[ \t]*(?:\*[ \t]*)?\S) # first line with useful content
            ~x',
            '$1$2',
            $content
        );
    }

    /**
     * Make sure the last useful line is immediately before the final line.
     *
     * @param string $content
     *
     * @return string
     */
    private function fixEnd($content)
    {
        return Preg::replace(
            '~
                (\R[ \t]*(?:\*[ \t]*)?\S.*?) # last line with useful content
                (?:
                    (?<!/\*\*)               # not preceded by a DocComment start
                    \R[ \t]*(?:\*[ \t]*)?    # lines without useful content
                )+
                (\R[ \t]*\*/$)               # DocComment end
            ~xu',
            '$1$2',
            $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\Fixer\Phpdoc;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\DocBlock\Annotation;
use PhpCsFixer\DocBlock\DocBlock;
use PhpCsFixer\DocBlock\TagComparator;
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 PhpdocSeparationFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other, and annotations of a different type are separated by a single blank line.',
            [
                new CodeSample(
                    '<?php
/**
 * Description.
 * @param string $foo
 *
 *
 * @param bool   $bar Bar
 * @throws Exception|RuntimeException
 * @return bool
 */
function fnc($foo, $bar) {}
'
                ),
            ]
        );
    }

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

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

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

            $doc = new DocBlock($token->getContent());
            $this->fixDescription($doc);
            $this->fixAnnotations($doc);

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

    /**
     * Make sure the description is separated from the annotations.
     *
     * @param DocBlock $doc
     */
    private function fixDescription(DocBlock $doc)
    {
        foreach ($doc->getLines() as $index => $line) {
            if ($line->containsATag()) {
                break;
            }

            if ($line->containsUsefulContent()) {
                $next = $doc->getLine($index + 1);

                if ($next->containsATag()) {
                    $line->addBlank();

                    break;
                }
            }
        }
    }

    /**
     * Make sure the annotations are correctly separated.
     *
     * @param DocBlock $doc
     *
     * @return string
     */
    private function fixAnnotations(DocBlock $doc)
    {
        foreach ($doc->getAnnotations() as $index => $annotation) {
            $next = $doc->getAnnotation($index + 1);

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

            if (true === $next->getTag()->valid()) {
                if (TagComparator::shouldBeTogether($annotation->getTag(), $next->getTag())) {
                    $this->ensureAreTogether($doc, $annotation, $next);
                } else {
                    $this->ensureAreSeparate($doc, $annotation, $next);
                }
            }
        }

        return $doc->getContent();
    }

    /**
     * Force the given annotations to immediately follow each other.
     *
     * @param DocBlock   $doc
     * @param Annotation $first
     * @param Annotation $second
     */
    private function ensureAreTogether(DocBlock $doc, Annotation $first, Annotation $second)
    {
        $pos = $first->getEnd();
        $final = $second->getStart();

        for ($pos = $pos + 1; $pos < $final; ++$pos) {
            $doc->getLine($pos)->remove();
        }
    }

    /**
     * Force the given annotations to have one empty line between each other.
     *
     * @param DocBlock   $doc
     * @param Annotation $first
     * @param Annotation $second
     */
    private function ensureAreSeparate(DocBlock $doc, Annotation $first, Annotation $second)
    {
        $pos = $first->getEnd();
        $final = $second->getStart() - 1;

        // check if we need to add a line, or need to remove one or more lines
        if ($pos === $final) {
            $doc->getLine($pos)->addBlank();

            return;
        }

        for ($pos = $pos + 1; $pos < $final; ++$pos) {
            $doc->getLine($pos)->remove();
        }
    }
}


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

/**
 * Manager of errors that occur during fixing.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * @internal
 */
final class ErrorsManager
{
    /**
     * @var Error[]
     */
    private $errors = [];

    /**
     * Returns errors reported during linting before fixing.
     *
     * @return Error[]
     */
    public function getInvalidErrors()
    {
        return array_filter($this->errors, static function (Error $error) {
            return Error::TYPE_INVALID === $error->getType();
        });
    }

    /**
     * Returns errors reported during fixing.
     *
     * @return Error[]
     */
    public function getExceptionErrors()
    {
        return array_filter($this->errors, static function (Error $error) {
            return Error::TYPE_EXCEPTION === $error->getType();
        });
    }

    /**
     * Returns errors reported during linting after fixing.
     *
     * @return Error[]
     */
    public function getLintErrors()
    {
        return array_filter($this->errors, static function (Error $error) {
            return Error::TYPE_LINT === $error->getType();
        });
    }

    /**
     * Returns true if no errors were reported.
     *
     * @return bool
     */
    public function isEmpty()
    {
        return empty($this->errors);
    }

    /**
     * @param Error $error
     */
    public function report(Error $error)
    {
        $this->errors[] = $error;
    }
}


<?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\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Jules Pietri <jules@heahprod.com>
 * @author Kuba Werłos <werlos@gmail.com>
 */
final class ErrorSuppressionFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    const OPTION_MUTE_DEPRECATION_ERROR = 'mute_deprecation_error';
    const OPTION_NOISE_REMAINING_USAGES = 'noise_remaining_usages';
    const OPTION_NOISE_REMAINING_USAGES_EXCLUDE = 'noise_remaining_usages_exclude';

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Error control operator should be added to deprecation notices and/or removed from other cases.',
            [
                new CodeSample("<?php\ntrigger_error('Warning.', E_USER_DEPRECATED);\n"),
                new CodeSample(
                    "<?php\n@mkdir(\$dir);\n@unlink(\$path);\n",
                    [self::OPTION_NOISE_REMAINING_USAGES => true]
                ),
                new CodeSample(
                    "<?php\n@mkdir(\$dir);\n@unlink(\$path);\n",
                    [
                        self::OPTION_NOISE_REMAINING_USAGES => true,
                        self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE => ['unlink'],
                    ]
                ),
            ],
            null,
            'Risky because adding/removing `@` might cause changes to code behaviour or if `trigger_error` function is overridden.'
        );
    }

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

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

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        return new FixerConfigurationResolver([
            (new FixerOptionBuilder(self::OPTION_MUTE_DEPRECATION_ERROR, 'Whether to add `@` in deprecation notices.'))
                ->setAllowedTypes(['bool'])
                ->setDefault(true)
                ->getOption(),
            (new FixerOptionBuilder(self::OPTION_NOISE_REMAINING_USAGES, 'Whether to remove `@` in remaining usages.'))
                ->setAllowedTypes(['bool'])
                ->setDefault(false)
                ->getOption(),
            (new FixerOptionBuilder(self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE, 'List of global functions to exclude from removing `@`'))
                ->setAllowedTypes(['array'])
                ->setDefault([])
                ->getOption(),
        ]);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $functionsAnalyzer = new FunctionsAnalyzer();
        $excludedFunctions = array_map(function ($function) {
            return strtolower($function);
        }, $this->configuration[self::OPTION_NOISE_REMAINING_USAGES_EXCLUDE]);

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

            if ($this->configuration[self::OPTION_NOISE_REMAINING_USAGES] && $token->equals('@')) {
                $tokens->clearAt($index);

                continue;
            }

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

            $functionIndex = $index;
            $startIndex = $index;
            $prevIndex = $tokens->getPrevMeaningfulToken($index);
            if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
                $startIndex = $prevIndex;
                $prevIndex = $tokens->getPrevMeaningfulToken($startIndex);
            }

            $index = $prevIndex;

            if ($this->isDeprecationErrorCall($tokens, $functionIndex)) {
                if (!$this->configuration[self::OPTION_MUTE_DEPRECATION_ERROR]) {
                    continue;
                }

                if ($tokens[$prevIndex]->equals('@')) {
                    continue;
                }

                $tokens->insertAt($startIndex, new Token('@'));

                continue;
            }

            if (!$tokens[$prevIndex]->equals('@')) {
                continue;
            }

            if ($this->configuration[self::OPTION_NOISE_REMAINING_USAGES] && !\in_array($tokens[$functionIndex]->getContent(), $excludedFunctions, true)) {
                $tokens->clearAt($index);
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return bool
     */
    private function isDeprecationErrorCall(Tokens $tokens, $index)
    {
        if ('trigger_error' !== strtolower($tokens[$index]->getContent())) {
            return false;
        }

        $endBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $tokens->getNextTokenOfKind($index, [T_STRING, '(']));

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

        return $tokens[$prevIndex]->equals([T_STRING, 'E_USER_DEPRECATED']);
    }
}


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

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;

/**
 * @author Filippo Tessarotto <zoeslam@gmail.com>
 */
final class NativeConstantInvocationFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    /**
     * @var array<string, true>
     */
    private $constantsToEscape = [];

    /**
     * @var array<string, true>
     */
    private $caseInsensitiveConstantsToEscape = [];

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Add leading `\` before constant invocation of internal constant to speed up resolving. Constant name match is case-sensitive, except for `null`, `false` and `true`.',
            [
                new CodeSample('<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);'.PHP_EOL),
                new CodeSample(
                    '<?php
namespace space1 {
    echo PHP_VERSION;
}
namespace {
    echo M_PI;
}
',
                    ['scope' => 'namespaced']
                ),
                new CodeSample(
                    '<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);'.PHP_EOL,
                    [
                        'include' => [
                            'MY_CUSTOM_PI',
                        ],
                    ]
                ),
                new CodeSample(
                    '<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);'.PHP_EOL,
                    [
                        'fix_built_in' => false,
                        'include' => [
                            'MY_CUSTOM_PI',
                        ],
                    ]
                ),
                new CodeSample(
                    '<?php var_dump(PHP_VERSION, M_PI, MY_CUSTOM_PI);'.PHP_EOL,
                    [
                        'exclude' => [
                            'M_PI',
                        ],
                    ]
                ),
            ],
            null,
            'Risky when any of the constants are namespaced or overridden.'
        );
    }

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

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

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

        $uniqueConfiguredExclude = array_unique($this->configuration['exclude']);

        // Case sensitive constants handling
        $constantsToEscape = array_values($this->configuration['include']);
        if (true === $this->configuration['fix_built_in']) {
            $getDefinedConstants = get_defined_constants(true);
            unset($getDefinedConstants['user']);
            foreach ($getDefinedConstants as $constants) {
                $constantsToEscape = array_merge($constantsToEscape, array_keys($constants));
            }
        }
        $constantsToEscape = array_diff(
            array_unique($constantsToEscape),
            $uniqueConfiguredExclude
        );

        // Case insensitive constants handling
        static $caseInsensitiveConstants = ['null', 'false', 'true'];
        $caseInsensitiveConstantsToEscape = [];
        foreach ($constantsToEscape as $constantIndex => $constant) {
            $loweredConstant = strtolower($constant);
            if (\in_array($loweredConstant, $caseInsensitiveConstants, true)) {
                $caseInsensitiveConstantsToEscape[] = $loweredConstant;
                unset($constantsToEscape[$constantIndex]);
            }
        }

        $caseInsensitiveConstantsToEscape = array_diff(
            array_unique($caseInsensitiveConstantsToEscape),
            array_map(function ($function) { return strtolower($function); }, $uniqueConfiguredExclude)
        );

        // Store the cache
        $this->constantsToEscape = array_fill_keys($constantsToEscape, true);
        ksort($this->constantsToEscape);

        $this->caseInsensitiveConstantsToEscape = array_fill_keys($caseInsensitiveConstantsToEscape, true);
        ksort($this->caseInsensitiveConstantsToEscape);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        if ('all' === $this->configuration['scope']) {
            $this->fixConstantInvocations($tokens, 0, \count($tokens) - 1);

            return;
        }

        $namespaces = (new NamespacesAnalyzer())->getDeclarations($tokens);

        // 'scope' is 'namespaced' here
        /** @var NamespaceAnalysis $namespace */
        foreach (array_reverse($namespaces) as $namespace) {
            if ('' === $namespace->getFullName()) {
                continue;
            }

            $this->fixConstantInvocations($tokens, $namespace->getScopeStartIndex(), $namespace->getScopeEndIndex());
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function createConfigurationDefinition()
    {
        $constantChecker = static function ($value) {
            foreach ($value as $constantName) {
                if (!\is_string($constantName) || '' === trim($constantName) || trim($constantName) !== $constantName) {
                    throw new InvalidOptionsException(sprintf(
                        'Each element must be a non-empty, trimmed string, got "%s" instead.',
                        \is_object($constantName) ? \get_class($constantName) : \gettype($constantName)
                    ));
                }
            }

            return true;
        };

        return new FixerConfigurationResolver([
            (new FixerOptionBuilder('fix_built_in', 'Whether to fix constants returned by `get_defined_constants`. User constants are not accounted in this list and must be specified in the include one.'))
                ->setAllowedTypes(['bool'])
                ->setDefault(true)
                ->getOption(),
            (new FixerOptionBuilder('include', 'List of additional constants to fix.'))
                ->setAllowedTypes(['array'])
                ->setAllowedValues([$constantChecker])
                ->setDefault([])
                ->getOption(),
            (new FixerOptionBuilder('exclude', 'List of constants to ignore.'))
                ->setAllowedTypes(['array'])
                ->setAllowedValues([$constantChecker])
                ->setDefault(['null', 'false', 'true'])
                ->getOption(),
            (new FixerOptionBuilder('scope', 'Only fix constant invocations that are made within a namespace or fix all.'))
                ->setAllowedValues(['all', 'namespaced'])
                ->setDefault('all')
                ->getOption(),
        ]);
    }

    /**
     * @param Tokens $tokens
     * @param int    $start
     * @param int    $end
     */
    private function fixConstantInvocations(Tokens $tokens, $start, $end)
    {
        $useDeclarations = (new NamespaceUsesAnalyzer())->getDeclarationsFromTokens($tokens);
        $useConstantDeclarations = [];
        foreach ($useDeclarations as $use) {
            if ($use->isConstant()) {
                $useConstantDeclarations[$use->getShortName()] = true;
            }
        }

        $tokenAnalyzer = new TokensAnalyzer($tokens);

        $indexes = [];
        for ($index = $start; $index < $end; ++$index) {
            $token = $tokens[$index];

            // test if we are at a constant call
            if (!$token->isGivenKind(T_STRING)) {
                continue;
            }

            $tokenContent = $token->getContent();

            if (!isset($this->constantsToEscape[$tokenContent]) && !isset($this->caseInsensitiveConstantsToEscape[strtolower($tokenContent)])) {
                continue;
            }

            if (isset($useConstantDeclarations[$tokenContent])) {
                continue;
            }

            $prevIndex = $tokens->getPrevMeaningfulToken($index);
            if ($tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR)) {
                continue;
            }

            if (!$tokenAnalyzer->isConstantInvocation($index)) {
                continue;
            }

            $indexes[] = $index;
        }

        $indexes = array_reverse($indexes);
        foreach ($indexes as $index) {
            $tokens->insertAt($index, new Token([T_NS_SEPARATOR, '\\']));
        }
    }
}


<?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\Analyzer\ArgumentsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class PhpUnitStrictFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
{
    private static $assertionMap = [
        'assertAttributeEquals' => 'assertAttributeSame',
        'assertAttributeNotEquals' => 'assertAttributeNotSame',
        'assertEquals' => 'assertSame',
        'assertNotEquals' => 'assertNotSame',
    ];

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'PHPUnit methods like `assertSame` should be used instead of `assertEquals`.',
            [
                new CodeSample(
                    '<?php
final class MyTest extends \PHPUnit_Framework_TestCase
{
    public function testSomeTest()
    {
        $this->assertAttributeEquals(a(), b());
        $this->assertAttributeNotEquals(a(), b());
        $this->assertEquals(a(), b());
        $this->assertNotEquals(a(), b());
    }
}
'
                ),
                new CodeSample(
                    '<?php
final class MyTest extends \PHPUnit_Framework_TestCase
{
    public function testSomeTest()
    {
        $this->assertAttributeEquals(a(), b());
        $this->assertAttributeNotEquals(a(), b());
        $this->assertEquals(a(), b());
        $this->assertNotEquals(a(), b());
    }
}
',
                    ['assertions' => ['assertEquals']]
                ),
            ],
            null,
            'Risky when any of the functions are overridden or when testing object equality.'
        );
    }

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

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

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

        foreach ($this->configuration['assertions'] as $methodBefore) {
            $methodAfter = self::$assertionMap[$methodBefore];

            for ($index = 0, $limit = $tokens->count(); $index < $limit; ++$index) {
                $methodIndex = $tokens->getNextTokenOfKind($index, [[T_STRING, $methodBefore]]);

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

                $operatorIndex = $tokens->getPrevMeaningfulToken($methodIndex);
                $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']))
                ) {
                    continue;
                }

                $openingParenthesisIndex = $tokens->getNextMeaningfulToken($methodIndex);
                $argumentsCount = $argumentsAnalyzer->countArguments(
                    $tokens,
                    $openingParenthesisIndex,
                    $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openingParenthesisIndex)
                );

                if (2 === $argumentsCount || 3 === $argumentsCount) {
                    $tokens[$methodIndex] = new Token([T_STRING, $methodAfter]);
                }

                $index = $methodIndex;
            }
        }
    }

    /**
     * {@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::$assertionMap))])
                ->setDefault([
                    'assertAttributeEquals',
                    'assertAttributeNotEquals',
                    'assertEquals',
                    'assertNotEquals',
                ])
                ->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\Import;

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

/**
 * Fixer for rules defined in PSR2 ¶3.
 *
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 * @author SpacePossum
 */
final class SingleImportPerStatementFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There MUST be one use keyword per declaration.',
            [new CodeSample("<?php\nuse Foo, Sample, Sample\\Sample as Sample2;\n")]
        );
    }

    public function getPriority()
    {
        // must be run before NoLeadingImportSlashFixer, NoSinglelineWhitespaceBeforeSemicolonsFixer, SpaceAfterSemicolonFixer, MultilineWhitespaceBeforeSemicolonsFixer, NoLeadingImportSlashFixer.
        return 1;
    }

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

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

        foreach ($uses as $index) {
            $endIndex = $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]);
            $groupClose = $tokens->getPrevMeaningfulToken($endIndex);

            if ($tokens[$groupClose]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_CLOSE)) {
                $this->fixGroupUse($tokens, $index, $endIndex);
            } else {
                $this->fixMultipleUse($tokens, $index, $endIndex);
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return string
     */
    private function detectIndent(Tokens $tokens, $index)
    {
        if (!$tokens[$index - 1]->isWhitespace()) {
            return ''; // cannot detect indent
        }

        $explodedContent = explode("\n", $tokens[$index - 1]->getContent());

        return end($explodedContent);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     *
     * @return array
     */
    private function getGroupDeclaration(Tokens $tokens, $index)
    {
        $groupPrefix = '';
        $comment = '';
        for ($i = $index + 1;; ++$i) {
            if ($tokens[$i]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
                $groupOpenIndex = $i;

                break;
            }

            if ($tokens[$i]->isComment()) {
                $comment .= $tokens[$i]->getContent();
                if (!$tokens[$i - 1]->isWhitespace() && !$tokens[$i + 1]->isWhitespace()) {
                    $groupPrefix .= ' ';
                }

                continue;
            }

            if ($tokens[$i]->isWhitespace()) {
                $groupPrefix .= ' ';

                continue;
            }

            $groupPrefix .= $tokens[$i]->getContent();
        }

        return [
            rtrim($groupPrefix),
            $groupOpenIndex,
            $tokens->findBlockEnd(Tokens::BLOCK_TYPE_GROUP_IMPORT_BRACE, $groupOpenIndex),
            $comment,
        ];
    }

    /**
     * @param Tokens $tokens
     * @param string $groupPrefix
     * @param int    $groupOpenIndex
     * @param int    $groupCloseIndex
     * @param string $comment
     *
     * @return string[]
     */
    private function getGroupStatements(Tokens $tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment)
    {
        $statements = [];
        $statement = $groupPrefix;

        for ($i = $groupOpenIndex + 1; $i <= $groupCloseIndex; ++$i) {
            $token = $tokens[$i];

            if ($token->equals(',') && $tokens[$tokens->getNextMeaningfulToken($i)]->equals([CT::T_GROUP_IMPORT_BRACE_CLOSE])) {
                continue;
            }

            if ($token->equalsAny([',', [CT::T_GROUP_IMPORT_BRACE_CLOSE]])) {
                $statements[] = 'use'.$statement.';';
                $statement = $groupPrefix;

                continue;
            }

            if ($token->isWhitespace()) {
                $j = $tokens->getNextMeaningfulToken($i);

                if ($tokens[$j]->equals([T_AS])) {
                    $statement .= ' as ';
                    $i += 2;
                } elseif ($tokens[$j]->equals([T_FUNCTION])) {
                    $statement = ' function'.$statement;
                    $i += 2;
                } elseif ($tokens[$j]->equals([T_CONST])) {
                    $statement = ' const'.$statement;
                    $i += 2;
                }

                if ($token->isWhitespace(" \t") || '//' !== substr($tokens[$i - 1]->getContent(), 0, 2)) {
                    continue;
                }
            }

            $statement .= $token->getContent();
        }

        if ('' !== $comment) {
            $statements[0] .= ' '.$comment;
        }

        return $statements;
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     * @param int    $endIndex
     */
    private function fixGroupUse(Tokens $tokens, $index, $endIndex)
    {
        list($groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment) = $this->getGroupDeclaration($tokens, $index);
        $statements = $this->getGroupStatements($tokens, $groupPrefix, $groupOpenIndex, $groupCloseIndex, $comment);

        if (\count($statements) < 2) {
            return;
        }

        $tokens->clearRange($index, $groupCloseIndex);
        if ($tokens[$endIndex]->equals(';')) {
            $tokens->clearAt($endIndex);
        }

        $ending = $this->whitespacesConfig->getLineEnding();
        $importTokens = Tokens::fromCode('<?php '.implode($ending, $statements));
        $importTokens->clearAt(0);
        $importTokens->clearEmptyTokens();

        $tokens->insertAt($index, $importTokens);
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     * @param int    $endIndex
     */
    private function fixMultipleUse(Tokens $tokens, $index, $endIndex)
    {
        $ending = $this->whitespacesConfig->getLineEnding();

        for ($i = $endIndex - 1; $i > $index; --$i) {
            if (!$tokens[$i]->equals(',')) {
                continue;
            }

            $tokens[$i] = new Token(';');
            $i = $tokens->getNextMeaningfulToken($i);
            $tokens->insertAt($i, new Token([T_USE, 'use']));
            $tokens->insertAt($i + 1, new Token([T_WHITESPACE, ' ']));

            $indent = $this->detectIndent($tokens, $index);
            if ($tokens[$i - 1]->isWhitespace()) {
                $tokens[$i - 1] = new Token([T_WHITESPACE, $ending.$indent]);

                continue;
            }

            if (false === strpos($tokens[$i - 1]->getContent(), "\n")) {
                $tokens->insertAt($i, new Token([T_WHITESPACE, $ending.$indent]));
            }
        }
    }
}


<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer\Fixer\ReturnNotation;

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

/**
 * @author SpacePossum
 */
final class ReturnAssignmentFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Local, dynamic and directly referenced variables should not be assigned and directly returned by a function or method.',
            [new CodeSample("<?php\nfunction a() {\n    \$a = 1;\n    return \$a;\n}\n")]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // must run after the NoEmptyStatementFixer
        // must run before BlankLineBeforeStatementFixer
        return -15;
    }

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

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

        for ($index = 1; $index < $tokenCount; ++$index) {
            if (!$tokens[$index]->isGivenKind(T_FUNCTION)) {
                continue;
            }

            $functionOpenIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
            if ($tokens[$functionOpenIndex]->equals(';')) { // abstract function
                $index = $functionOpenIndex - 1;

                continue;
            }

            $functionCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $functionOpenIndex);

            $tokensAdded = $this->fixFunction(
                $tokens,
                $index,
                $functionOpenIndex,
                $functionCloseIndex
            );

            $index = $functionCloseIndex + $tokensAdded;
            $tokenCount += $tokensAdded;
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $functionIndex      token index of T_FUNCTION
     * @param int    $functionOpenIndex  token index of the opening brace token of the function
     * @param int    $functionCloseIndex token index of the closing brace token of the function
     *
     * @return int >= 0 number of tokens inserted into the Tokens collection
     */
    private function fixFunction(Tokens $tokens, $functionIndex, $functionOpenIndex, $functionCloseIndex)
    {
        static $riskyKinds = [
            CT::T_DYNAMIC_VAR_BRACE_OPEN, // "$h = ${$g};" case
            T_EVAL,                       // "$c = eval('return $this;');" case
            T_GLOBAL,
            T_INCLUDE,                    // loading additional symbols we cannot analyze here
            T_INCLUDE_ONCE,               // "
            T_REQUIRE,                    // "
            T_REQUIRE_ONCE,               // "
            T_STATIC,
        ];

        $inserted = 0;
        $candidates = [];
        $isRisky = false;

        // go through the function declaration and check if references are passed
        // - check if it will be risky to fix return statements of this function
        for ($index = $functionIndex + 1; $index < $functionOpenIndex; ++$index) {
            if ($tokens[$index]->equals('&')) {
                $isRisky = true;

                break;
            }
        }

        // go through all the tokens of the body of the function:
        // - check if it will be risky to fix return statements of this function
        // - check nested functions; fix when found and update the upper limit + number of inserted token
        // - check for return statements that might be fixed (based on if fixing will be risky, which is only know after analyzing the whole function)

        for ($index = $functionOpenIndex + 1; $index < $functionCloseIndex; ++$index) {
            if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
                $nestedFunctionOpenIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
                if ($tokens[$nestedFunctionOpenIndex]->equals(';')) { // abstract function
                    $index = $nestedFunctionOpenIndex - 1;

                    continue;
                }

                $nestedFunctionCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $nestedFunctionOpenIndex);

                $tokensAdded = $this->fixFunction(
                    $tokens,
                    $index,
                    $nestedFunctionOpenIndex,
                    $nestedFunctionCloseIndex
                );

                $index = $nestedFunctionCloseIndex + $tokensAdded;
                $functionCloseIndex += $tokensAdded;
                $inserted += $tokensAdded;
            }

            if ($isRisky) {
                continue; // don't bother to look into anything else than nested functions as the current is risky already
            }

            if ($tokens[$index]->equals('&')) {
                $isRisky = true;

                continue;
            }

            if ($tokens[$index]->isGivenKind(T_RETURN)) {
                $candidates[] = $index;

                continue;
            }

            // test if there this is anything in the function body that might
            // change global state or indirect changes (like through references, eval, etc.)

            if ($tokens[$index]->isGivenKind($riskyKinds)) {
                $isRisky = true;

                continue;
            }

            if ($tokens[$index]->equals('$')) {
                $nextIndex = $tokens->getNextMeaningfulToken($index);
                if ($tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
                    $isRisky = true; // "$$a" case

                    continue;
                }
            }

            if ($this->isSuperGlobal($tokens[$index])) {
                $isRisky = true;

                continue;
            }
        }

        if ($isRisky) {
            return $inserted;
        }

        // fix the candidates in reverse order when applicable
        for ($i = \count($candidates) - 1; $i >= 0; --$i) {
            $index = $candidates[$i];

            // Check if returning only a variable (i.e. not the result of an expression, function call etc.)
            $returnVarIndex = $tokens->getNextMeaningfulToken($index);
            if (!$tokens[$returnVarIndex]->isGivenKind(T_VARIABLE)) {
                continue; // example: "return 1;"
            }

            $endReturnVarIndex = $tokens->getNextMeaningfulToken($returnVarIndex);
            if (!$tokens[$endReturnVarIndex]->equalsAny([';', [T_CLOSE_TAG]])) {
                continue; // example: "return $a + 1;"
            }

            // Check that the variable is assigned just before it is returned
            $assignVarEndIndex = $tokens->getPrevMeaningfulToken($index);
            if (!$tokens[$assignVarEndIndex]->equals(';')) {
                continue; // example: "? return $a;"
            }

            // Note: here we are @ "; return $a;" (or "; return $a ? >")
            $assignVarOperatorIndex = $tokens->getPrevTokenOfKind(
                $assignVarEndIndex,
                ['=', ';', '{', [T_OPEN_TAG], [T_OPEN_TAG_WITH_ECHO]]
            );

            if (null === $assignVarOperatorIndex || !$tokens[$assignVarOperatorIndex]->equals('=')) {
                continue;
            }

            // Note: here we are @ "= [^;{<? ? >] ; return $a;"
            $assignVarIndex = $tokens->getPrevMeaningfulToken($assignVarOperatorIndex);
            if (!$tokens[$assignVarIndex]->equals($tokens[$returnVarIndex], false)) {
                continue;
            }

            // Note: here we are @ "$a = [^;{<? ? >] ; return $a;"
            $beforeAssignVarIndex = $tokens->getPrevMeaningfulToken($assignVarIndex);
            if (!$tokens[$beforeAssignVarIndex]->equalsAny([';', '{', '}'])) {
                continue;
            }

            // Note: here we are @ "[;{}] $a = [^;{<? ? >] ; return $a;"
            $inserted += $this->simplifyReturnStatement(
                $tokens,
                $assignVarIndex,
                $assignVarOperatorIndex,
                $index,
                $endReturnVarIndex
            );
        }

        return $inserted;
    }

    /**
     * @param Tokens $tokens
     * @param int    $assignVarIndex
     * @param int    $assignVarOperatorIndex
     * @param int    $returnIndex
     * @param int    $returnVarEndIndex
     *
     * @return int >= 0 number of tokens inserted into the Tokens collection
     */
    private function simplifyReturnStatement(
        Tokens $tokens,
        $assignVarIndex,
        $assignVarOperatorIndex,
        $returnIndex,
        $returnVarEndIndex
    ) {
        $inserted = 0;
        $originalIndent = $tokens[$assignVarIndex - 1]->isWhitespace()
            ? $tokens[$assignVarIndex - 1]->getContent()
            : null
        ;

        // remove the return statement
        if ($tokens[$returnVarEndIndex]->equals(';')) { // do not remove PHP close tags
            $tokens->clearTokenAndMergeSurroundingWhitespace($returnVarEndIndex);
        }

        for ($i = $returnIndex; $i <= $returnVarEndIndex - 1; ++$i) {
            $this->clearIfSave($tokens, $i);
        }

        // remove no longer needed indentation of the old/remove return statement
        if ($tokens[$returnIndex - 1]->isWhitespace()) {
            $content = $tokens[$returnIndex - 1]->getContent();
            $fistLinebreakPos = strrpos($content, "\n");
            $content = false === $fistLinebreakPos
                ? ' '
                : substr($content, $fistLinebreakPos)
            ;

            $tokens[$returnIndex - 1] = new Token([T_WHITESPACE, $content]);
        }

        // remove the variable and the assignment
        for ($i = $assignVarIndex; $i <= $assignVarOperatorIndex; ++$i) {
            $this->clearIfSave($tokens, $i);
        }

        // insert new return statement
        $tokens->insertAt($assignVarIndex, new Token([T_RETURN, 'return']));
        ++$inserted;

        // use the original indent of the var assignment for the new return statement
        if (
            null !== $originalIndent
            && $tokens[$assignVarIndex - 1]->isWhitespace()
            && $originalIndent !== $tokens[$assignVarIndex - 1]->getContent()
        ) {
            $tokens[$assignVarIndex - 1] = new Token([T_WHITESPACE, $originalIndent]);
        }

        // remove trailing space after the new return statement which might be added during the clean up process
        $nextIndex = $tokens->getNonEmptySibling($assignVarIndex, 1);
        if (!$tokens[$nextIndex]->isWhitespace()) {
            $tokens->insertAt($nextIndex, new Token([T_WHITESPACE, ' ']));
            ++$inserted;
        }

        return $inserted;
    }

    private function clearIfSave(Tokens $tokens, $index)
    {
        if ($tokens[$index]->isComment()) {
            return;
        }

        if ($tokens[$index]->isWhitespace() && $tokens[$tokens->getPrevNonWhitespace($index)]->isComment()) {
            return;
        }

        $tokens->clearTokenAndMergeSurroundingWhitespace($index);
    }

    /**
     * @param Token $token
     *
     * @return bool
     */
    private function isSuperGlobal(Token $token)
    {
        static $superNames = [
            '$_COOKIE' => true,
            '$_ENV' => true,
            '$_FILES' => true,
            '$_GET' => true,
            '$_POST' => true,
            '$_REQUEST' => true,
            '$_SERVER' => true,
            '$_SESSION' => true,
            '$GLOBALS' => true,
        ];

        if (!$token->isGivenKind(T_VARIABLE)) {
            return false;
        }

        return isset($superNames[strtoupper($token->getContent())]);
    }
}


<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer;

use PhpCsFixer\Tokenizer\Analyzer\ArgumentsAnalyzer;
use PhpCsFixer\Tokenizer\Tokens;

/**
 * @internal
 *
 * @author SpacePossum
 */
abstract class AbstractFopenFlagFixer extends AbstractFunctionReferenceFixer
{
    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAllTokenKindsFound([T_STRING, T_CONSTANT_ENCAPSED_STRING]);
    }

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

        $index = 0;
        $end = $tokens->count() - 1;
        while (true) {
            $candidate = $this->find('fopen', $tokens, $index, $end);

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

            $index = $candidate[1]; // proceed to '(' of `fopen`

            // fetch arguments
            $arguments = $argumentsAnalyzer->getArguments(
                $tokens,
                $index,
                $candidate[2]
            );

            $argumentsCount = \count($arguments); // argument count sanity check

            if ($argumentsCount < 2 || $argumentsCount > 4) {
                continue;
            }

            $argumentStartIndex = array_keys($arguments)[1]; // get second argument index

            $this->fixFopenFlagToken(
                $tokens,
                $argumentStartIndex,
                $arguments[$argumentStartIndex]
            );
        }
    }

    abstract protected function fixFopenFlagToken(Tokens $tokens, $argumentStartIndex, $argumentEndIndex);

    /**
     * @param string $mode
     *
     * @return bool
     */
    protected function isValidModeString($mode)
    {
        $modeLength = \strlen($mode);
        if ($modeLength < 1 || $modeLength > 13) { // 13 === length 'r+w+a+x+c+etb'
            return false;
        }

        $validFlags = [
            'a' => true,
            'b' => true,
            'c' => true,
            'e' => true,
            'r' => true,
            't' => true,
            'w' => true,
            'x' => true,
        ];

        if (!isset($validFlags[$mode[0]])) {
            return false;
        }

        unset($validFlags[$mode[0]]);

        for ($i = 1; $i < $modeLength; ++$i) {
            if (isset($validFlags[$mode[$i]])) {
                unset($validFlags[$mode[$i]]);

                continue;
            }

            if ('+' !== $mode[$i]
                || (
                    'a' !== $mode[$i - 1] // 'a+','c+','r+','w+','x+'
                    && 'c' !== $mode[$i - 1]
                    && 'r' !== $mode[$i - 1]
                    && 'w' !== $mode[$i - 1]
                    && 'x' !== $mode[$i - 1]
                )
            ) {
                return false;
            }
        }

        return true;
    }
}


<?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\Preg;
use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;

/**
 * @author Gregor Harlan <gharlan@web.de>
 */
final class SelfAccessorFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Inside class or interface element `self` should be preferred to the class name itself.',
            [
                new CodeSample(
                    '<?php
class Sample
{
    const BAZ = 1;
    const BAR = Sample::BAZ;

    public function getBar()
    {
        return Sample::BAR;
    }
}
'
                ),
            ],
            null,
            'Risky when using dynamic calls like get_called_class() or late static binding.'
        );
    }

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

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

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

        foreach ((new NamespacesAnalyzer())->getDeclarations($tokens) as $namespace) {
            for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) {
                if (!$tokens[$index]->isGivenKind([T_CLASS, T_INTERFACE]) || $tokensAnalyzer->isAnonymousClass($index)) {
                    continue;
                }

                $nameIndex = $tokens->getNextTokenOfKind($index, [[T_STRING]]);
                $startIndex = $tokens->getNextTokenOfKind($nameIndex, ['{']);
                $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);

                $name = $tokens[$nameIndex]->getContent();

                $this->replaceNameOccurrences($tokens, $namespace->getFullName(), $name, $startIndex, $endIndex);

                $index = $endIndex;
            }
        }
    }

    /**
     * Replace occurrences of the name of the classy element by "self" (if possible).
     *
     * @param Tokens $tokens
     * @param string $namespace
     * @param string $name
     * @param int    $startIndex
     * @param int    $endIndex
     */
    private function replaceNameOccurrences(Tokens $tokens, $namespace, $name, $startIndex, $endIndex)
    {
        $tokensAnalyzer = new TokensAnalyzer($tokens);
        $insideMethodSignatureUntil = null;

        for ($i = $startIndex; $i < $endIndex; ++$i) {
            if ($i === $insideMethodSignatureUntil) {
                $insideMethodSignatureUntil = null;
            }

            $token = $tokens[$i];

            // skip anonymous classes
            if ($token->isGivenKind(T_CLASS) && $tokensAnalyzer->isAnonymousClass($i)) {
                $i = $tokens->getNextTokenOfKind($i, ['{']);
                $i = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $i);

                continue;
            }

            if ($token->isGivenKind(T_FUNCTION)) {
                $i = $tokens->getNextTokenOfKind($i, ['(']);
                $insideMethodSignatureUntil = $tokens->getNextTokenOfKind($i, ['{', ';']);

                continue;
            }

            if (!$token->equals([T_STRING, $name], false)) {
                continue;
            }

            $nextToken = $tokens[$tokens->getNextMeaningfulToken($i)];
            if ($nextToken->isGivenKind(T_NS_SEPARATOR)) {
                continue;
            }

            $classStartIndex = $i;
            $prevToken = $tokens[$tokens->getPrevMeaningfulToken($i)];
            if ($prevToken->isGivenKind(T_NS_SEPARATOR)) {
                $classStartIndex = $this->getClassStart($tokens, $i, $namespace);
                if (null === $classStartIndex) {
                    continue;
                }
                $prevToken = $tokens[$tokens->getPrevMeaningfulToken($classStartIndex)];
            }
            if ($prevToken->isGivenKind([T_OBJECT_OPERATOR, T_STRING])) {
                continue;
            }

            if (
                $prevToken->isGivenKind([T_INSTANCEOF, T_NEW])
                || $nextToken->isGivenKind(T_PAAMAYIM_NEKUDOTAYIM)
                || (
                    null !== $insideMethodSignatureUntil
                    && $i < $insideMethodSignatureUntil
                    && $prevToken->equalsAny(['(', ',', [CT::T_TYPE_COLON], [CT::T_NULLABLE_TYPE]])
                )
            ) {
                for ($j = $classStartIndex; $j < $i; ++$j) {
                    $tokens->clearTokenAndMergeSurroundingWhitespace($j);
                }
                $tokens[$i] = new Token([T_STRING, 'self']);
            }
        }
    }

    private function getClassStart(Tokens $tokens, $index, $namespace)
    {
        $namespace = ('' !== $namespace ? '\\'.$namespace : '').'\\';

        foreach (array_reverse(Preg::split('/(\\\\)/', $namespace, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE)) as $piece) {
            $index = $tokens->getPrevMeaningfulToken($index);
            if ('\\' === $piece) {
                if (!$tokens[$index]->isGivenKind([T_NS_SEPARATOR])) {
                    return null;
                }
            } else {
                if (!$tokens[$index]->equals([T_STRING, $piece], false)) {
                    return null;
                }
            }
        }

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

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

/**
 * @author Haralan Dobrev <hkdobrev@gmail.com>
 */
final class LogicalOperatorsFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Use `&&` and `||` logical operators instead of `and` and `or`.',
            [
                new CodeSample(
                    '<?php

if ($a == "foo" and ($b == "bar" or $c == "baz")) {
}
'
                ),
            ],
            null,
            'Risky, because you must double-check if using and/or with lower precedence was intentional.'
        );
    }

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

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        foreach ($tokens as $index => $token) {
            if ($token->isGivenKind(T_LOGICAL_AND)) {
                $tokens[$index] = new Token([T_BOOLEAN_AND, '&&']);
            } elseif ($token->isGivenKind(T_LOGICAL_OR)) {
                $tokens[$index] = new Token([T_BOOLEAN_OR, '||']);
            }
        }
    }
}


<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer\Fixer\ControlStructure;

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

/**
 * @author Sebastiaan Stok <s.stok@rollerscapes.net>
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
 */
final class IncludeFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Include/Require and file path should be divided with a single space. File path should not be placed under brackets.',
            [
                new CodeSample(
                    '<?php
require ("sample1.php");
require_once  "sample2.php";
include       "sample3.php";
include_once("sample4.php");
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound([T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE]);
    }

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $this->clearIncludies($tokens, $this->findIncludies($tokens));
    }

    private function clearIncludies(Tokens $tokens, array $includies)
    {
        foreach ($includies as $includy) {
            if ($includy['end'] && !$tokens[$includy['end']]->isGivenKind(T_CLOSE_TAG)) {
                $afterEndIndex = $tokens->getNextNonWhitespace($includy['end']);
                if (null === $afterEndIndex || !$tokens[$afterEndIndex]->isComment()) {
                    $tokens->removeLeadingWhitespace($includy['end']);
                }
            }

            $braces = $includy['braces'];

            if ($braces) {
                $nextToken = $tokens[$tokens->getNextMeaningfulToken($braces['close'])];

                if ($nextToken->equalsAny([';', [T_CLOSE_TAG]])) {
                    $this->removeWhitespaceAroundIfPossible($tokens, $braces['open']);
                    $this->removeWhitespaceAroundIfPossible($tokens, $braces['close']);
                    $tokens->clearTokenAndMergeSurroundingWhitespace($braces['open']);
                    $tokens->clearTokenAndMergeSurroundingWhitespace($braces['close']);
                }
            }

            $nextIndex = $tokens->getNonEmptySibling($includy['begin'], 1);

            if ($tokens[$nextIndex]->isWhitespace()) {
                $tokens[$nextIndex] = new Token([T_WHITESPACE, ' ']);
            } elseif ($braces || $tokens[$nextIndex]->isGivenKind([T_VARIABLE, T_CONSTANT_ENCAPSED_STRING, T_COMMENT])) {
                $tokens->insertAt($includy['begin'] + 1, new Token([T_WHITESPACE, ' ']));
            }
        }
    }

    private function findIncludies(Tokens $tokens)
    {
        static $includyTokenKinds = [T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE];

        $includies = [];

        foreach ($tokens->findGivenKind($includyTokenKinds) as $includyTokens) {
            foreach ($includyTokens as $index => $token) {
                $includy = [
                    'begin' => $index,
                    'braces' => null,
                    'end' => $tokens->getNextTokenOfKind($index, [';', [T_CLOSE_TAG]]),
                ];

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

                if ($nextToken->equals('(')) {
                    // Don't remove braces when the statement is wrapped.
                    // Include is also legal as function parameter or condition statement but requires being wrapped then.
                    $braceCloseIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextTokenIndex);

                    if ($tokens[$tokens->getNextMeaningfulToken($braceCloseIndex)]->equalsAny([';', [T_CLOSE_TAG]])) {
                        $includy['braces'] = [
                            'open' => $nextTokenIndex,
                            'close' => $braceCloseIndex,
                        ];
                    }
                }

                $includies[$index] = $includy;
            }
        }

        krsort($includies);

        return $includies;
    }

    /**
     * @param Tokens $tokens
     * @param int    $index
     */
    private function removeWhitespaceAroundIfPossible(Tokens $tokens, $index)
    {
        $nextIndex = $tokens->getNextNonWhitespace($index);
        if (null === $nextIndex || !$tokens[$nextIndex]->isComment()) {
            $tokens->removeLeadingWhitespace($index);
        }

        $prevIndex = $tokens->getPrevNonWhitespace($index);
        if (null === $prevIndex || !$tokens[$prevIndex]->isComment()) {
            $tokens->removeTrailingWhitespace($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\Comment;

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

/**
 * @author SpacePossum
 */
final class NoEmptyCommentFixer extends AbstractFixer
{
    const TYPE_HASH = 1;
    const TYPE_DOUBLE_SLASH = 2;
    const TYPE_SLASH_ASTERISK = 3;

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run after PhpdocToCommentFixer and before NoExtraBlankLinesFixer, NoTrailingWhitespaceFixer and NoWhitespaceInBlankLineFixer.
        return 2;
    }

    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'There should not be any empty comments.',
            [new CodeSample("<?php\n//\n#\n/* */\n")]
        );
    }

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

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

            list($blockStart, $index, $isEmpty) = $this->getCommentBlock($tokens, $index);
            if (false === $isEmpty) {
                continue;
            }

            for ($i = $blockStart; $i <= $index; ++$i) {
                $tokens->clearTokenAndMergeSurroundingWhitespace($i);
            }
        }
    }

    /**
     * Return the start index, end index and a flag stating if the comment block is empty.
     *
     * @param Tokens $tokens
     * @param int    $index  T_COMMENT index
     *
     * @return array
     */
    private function getCommentBlock(Tokens $tokens, $index)
    {
        $commentType = $this->getCommentType($tokens[$index]->getContent());
        $empty = $this->isEmptyComment($tokens[$index]->getContent());
        $start = $index;
        $count = \count($tokens);
        ++$index;

        for (; $index < $count; ++$index) {
            if ($tokens[$index]->isComment()) {
                if ($commentType !== $this->getCommentType($tokens[$index]->getContent())) {
                    break;
                }

                if ($empty) { // don't retest if already known the block not being empty
                    $empty = $this->isEmptyComment($tokens[$index]->getContent());
                }

                continue;
            }

            if (!$tokens[$index]->isWhitespace() || $this->getLineBreakCount($tokens, $index, $index + 1) > 1) {
                break;
            }
        }

        return [$start, $index - 1, $empty];
    }

    /**
     * @param string $content
     *
     * @return int
     */
    private function getCommentType($content)
    {
        if ('#' === $content[0]) {
            return self::TYPE_HASH;
        }

        if ('*' === $content[1]) {
            return self::TYPE_SLASH_ASTERISK;
        }

        return self::TYPE_DOUBLE_SLASH;
    }

    /**
     * @param Tokens $tokens
     * @param int    $whiteStart
     * @param int    $whiteEnd
     *
     * @return int
     */
    private function getLineBreakCount(Tokens $tokens, $whiteStart, $whiteEnd)
    {
        $lineCount = 0;
        for ($i = $whiteStart; $i < $whiteEnd; ++$i) {
            $lineCount += Preg::matchAll('/\R/u', $tokens[$i]->getContent(), $matches);
        }

        return $lineCount;
    }

    /**
     * @param string $content
     *
     * @return bool
     */
    private function isEmptyComment($content)
    {
        static $mapper = [
            self::TYPE_HASH => '|^#\s*$|', // single line comment starting with '#'
            self::TYPE_SLASH_ASTERISK => '|^/\*\s*\*/$|', // comment starting with '/*' and ending with '*/' (but not a PHPDoc)
            self::TYPE_DOUBLE_SLASH => '|^//\s*$|', // single line comment starting with '//'
        ];

        $type = $this->getCommentType($content);

        return 1 === Preg::match($mapper[$type], $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\Fixer\ClassNotation;

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

/**
 * @author ntzm
 */
final class NoNullPropertyInitializationFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Properties MUST not be explicitly initialized with `null`.',
            [
                new CodeSample(
                    '<?php
class Foo {
    public $foo = null;
}
'
                ),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function isCandidate(Tokens $tokens)
    {
        return $tokens->isAnyTokenKindsFound([T_CLASS, T_TRAIT]) && $tokens->isAnyTokenKindsFound([T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR]);
    }

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

            while (true) {
                $varTokenIndex = $index = $tokens->getNextMeaningfulToken($index);

                if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
                    break;
                }

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

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

                    if ($tokens[$index]->isGivenKind(T_NS_SEPARATOR)) {
                        $index = $tokens->getNextMeaningfulToken($index);
                    }

                    if ($tokens[$index]->equals([T_STRING, 'null'], false)) {
                        for ($i = $varTokenIndex + 1; $i <= $index; ++$i) {
                            if (
                                !($tokens[$i]->isWhitespace() && false !== strpos($tokens[$i]->getContent(), "\n"))
                                && !$tokens[$i]->isComment()
                            ) {
                                $tokens->clearAt($i);
                            }
                        }
                    }

                    ++$index;
                }

                if (!$tokens[$index]->equals(',')) {
                    break;
                }
            }
        }
    }
}


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

/**
 * @author SpacePossum
 */
final class CombineConsecutiveIssetsFixer extends AbstractFixer
{
    /**
     * {@inheritdoc}
     */
    public function getDefinition()
    {
        return new FixerDefinition(
            'Using `isset($var) &&` multiple times should be done in one call.',
            [new CodeSample("<?php\n\$a = isset(\$a) && isset(\$b);\n")]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getPriority()
    {
        // should be run before MultilineWhitespaceBeforeSemicolonsFixer, NoTrailingWhitespaceFixer, NoWhitespaceInBlankLineFixer and NoSpacesInsideParenthesisFixer.
        return 3;
    }

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

    /**
     * {@inheritdoc}
     */
    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
    {
        $tokenCount = $tokens->count();

        for ($index = 1; $index < $tokenCount; ++$index) {
            if (!$tokens[$index]->isGivenKind(T_ISSET) || $tokens[$tokens->getPrevMeaningfulToken($index)]->equals('!')) {
                continue;
            }

            $issetInfo = $this->getIssetInfo($tokens, $index);
            $issetCloseBraceIndex = end($issetInfo); // ')' token
            $insertLocation = prev($issetInfo) + 1; // one index after the previous meaningful of ')'

            $booleanAndTokenIndex = $tokens->getNextMeaningfulToken($issetCloseBraceIndex);

            while ($tokens[$booleanAndTokenIndex]->isGivenKind(T_BOOLEAN_AND)) {
                $issetIndex = $tokens->getNextMeaningfulToken($booleanAndTokenIndex);
                if (!$tokens[$issetIndex]->isGivenKind(T_ISSET)) {
                    $index = $issetIndex;

                    break;
                }

                // fetch info about the 'isset' statement that we're merging
                $nextIssetInfo = $this->getIssetInfo($tokens, $issetIndex);

                // clone what we want to move, do not clone '(' and ')' of the 'isset' statement we're merging
                $clones = $this->getTokenClones($tokens, \array_slice($nextIssetInfo, 1, -1));

                // clean up no the tokens of the 'isset' statement we're merging
                $this->clearTokens($tokens, array_merge($nextIssetInfo, [$issetIndex, $booleanAndTokenIndex]));

                // insert the tokens to create the new statement
                array_unshift($clones, new Token(','), new Token([T_WHITESPACE, ' ']));
                $tokens->insertAt($insertLocation, $clones);

                // correct some counts and offset based on # of tokens inserted
                $numberOfTokensInserted = \count($clones);
                $tokenCount += $numberOfTokensInserted;
                $issetCloseBraceIndex += $numberOfTokensInserted;
                $insertLocation += $numberOfTokensInserted;

                $booleanAndTokenIndex = $tokens->getNextMeaningfulToken($issetCloseBraceIndex);
            }
        }
    }

    /**
     * @param Tokens $tokens
     * @param int[]  $indexes
     */
    private function clearTokens(Tokens $tokens, array $indexes)
    {
        foreach ($indexes as $index) {
            $tokens->clearTokenAndMergeSurroundingWhitespace($index);
        }
    }

    /**
     * @param Tokens $tokens
     * @param int    $index  of T_ISSET
     *
     * @return int[] indexes of meaningful tokens belonging to the isset statement
     */
    private function getIssetInfo(Tokens $tokens, $index)
    {
        $openIndex = $tokens->getNextMeaningfulToken($index);

        $braceOpenCount = 1;
        $meaningfulTokenIndexes = [$openIndex];

        for ($i = $openIndex + 1;; ++$i) {
            if ($tokens[$i]->isWhitespace() || $tokens[$i]->isComment()) {
                continue;
            }

            $meaningfulTokenIndexes[] = $i;

            if ($tokens[$i]->equals(')')) {
                --$braceOpenCount;
                if (0 === $braceOpenCount) {
                    break;
                }
            } elseif ($tokens[$i]->equals('(')) {
                ++$braceOpenCount;
            }
        }

        return $meaningfulTokenIndexes;
    }

    /**
     * @param Tokens $tokens
     * @param int[]  $indexes
     *
     * @return Token[]
     */
    private function getTokenClones(Tokens $tokens, array $indexes)
    {
        $clones = [];

        foreach ($indexes as $i) {
            $clones[] = clone $tokens[$i];
        }

        return $clones;
    }
}