File "PhpdocNoUselessInheritdocFixer.php"
Full Path: /var/www/html/back/vendor/friendsofphp/php-cs-fixer/src/Fixer/Phpdoc/PhpdocNoUselessInheritdocFixer.php
File size: 5.26 KB
MIME-type: text/x-php
Charset: utf-8
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz RumiĆski <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Phpdoc;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Remove inheritdoc tags from classy that does not inherit.
*
* @no-named-arguments Parameter names are not covered by the backward compatibility promise.
*/
final class PhpdocNoUselessInheritdocFixer extends AbstractFixer
{
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Classy that does not inherit must not have `@inheritdoc` tags.',
[
new CodeSample("<?php\n/** {@inheritdoc} */\nclass Sample\n{\n}\n"),
new CodeSample("<?php\nclass Sample\n{\n /**\n * @inheritdoc\n */\n public function Test()\n {\n }\n}\n"),
],
);
}
/**
* {@inheritdoc}
*
* Must run before NoEmptyPhpdocFixer, NoTrailingWhitespaceInCommentFixer, PhpdocAlignFixer.
* Must run after AlignMultilineCommentFixer, CommentToPhpdocFixer, PhpdocIndentFixer, PhpdocScalarFixer, PhpdocToCommentFixer, PhpdocTypesFixer.
*/
public function getPriority(): int
{
return 6;
}
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(\T_DOC_COMMENT) && $tokens->isAnyTokenKindsFound([\T_CLASS, \T_INTERFACE]);
}
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
// min. offset 4 as minimal candidate is @: <?php\n/** @inheritdoc */class min{}
for ($index = 1, $count = \count($tokens) - 4; $index < $count; ++$index) {
if ($tokens[$index]->isGivenKind([\T_CLASS, \T_INTERFACE])) {
$index = $this->fixClassy($tokens, $index);
}
}
}
private function fixClassy(Tokens $tokens, int $index): int
{
// figure out where the classy starts
$classOpenIndex = $tokens->getNextTokenOfKind($index, ['{']);
// figure out where the classy ends
$classEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classOpenIndex);
// is classy extending or implementing some interface
$extendingOrImplementing = $this->isExtendingOrImplementing($tokens, $index, $classOpenIndex);
if (!$extendingOrImplementing) {
// PHPDoc of classy should not have inherit tag even when using traits as Traits cannot provide this information
$this->fixClassyOutside($tokens, $index);
}
// figure out if the classy uses a trait
if (!$extendingOrImplementing && $this->isUsingTrait($tokens, $index, $classOpenIndex, $classEndIndex)) {
$extendingOrImplementing = true;
}
$this->fixClassyInside($tokens, $classOpenIndex, $classEndIndex, !$extendingOrImplementing);
return $classEndIndex;
}
private function fixClassyInside(Tokens $tokens, int $classOpenIndex, int $classEndIndex, bool $fixThisLevel): void
{
for ($i = $classOpenIndex; $i < $classEndIndex; ++$i) {
if ($tokens[$i]->isGivenKind(\T_CLASS)) {
$i = $this->fixClassy($tokens, $i);
} elseif ($fixThisLevel && $tokens[$i]->isGivenKind(\T_DOC_COMMENT)) {
$this->fixToken($tokens, $i);
}
}
}
private function fixClassyOutside(Tokens $tokens, int $classIndex): void
{
$previousIndex = $tokens->getPrevNonWhitespace($classIndex);
if ($tokens[$previousIndex]->isGivenKind(\T_DOC_COMMENT)) {
$this->fixToken($tokens, $previousIndex);
}
}
private function fixToken(Tokens $tokens, int $tokenIndex): void
{
$count = 0;
$content = Preg::replaceCallback(
'#(\h*(?:@{*|{*\h*@)\h*inheritdoc\h*)([^}]*)((?:}*)\h*)#i',
static fn (array $matches): string => ' '.$matches[2],
$tokens[$tokenIndex]->getContent(),
-1,
$count,
);
if ($count > 0) {
$tokens[$tokenIndex] = new Token([\T_DOC_COMMENT, $content]);
}
}
private function isExtendingOrImplementing(Tokens $tokens, int $classIndex, int $classOpenIndex): bool
{
for ($index = $classIndex; $index < $classOpenIndex; ++$index) {
if ($tokens[$index]->isGivenKind([\T_EXTENDS, \T_IMPLEMENTS])) {
return true;
}
}
return false;
}
private function isUsingTrait(Tokens $tokens, int $classIndex, int $classOpenIndex, int $classCloseIndex): bool
{
if ($tokens[$classIndex]->isGivenKind(\T_INTERFACE)) {
// cannot use Trait inside an interface
return false;
}
$useIndex = $tokens->getNextTokenOfKind($classOpenIndex, [[CT::T_USE_TRAIT]]);
return null !== $useIndex && $useIndex < $classCloseIndex;
}
}