Missing dependancies

This commit is contained in:
tokslaw7
2023-06-21 12:19:22 +00:00
parent fbf3f180c2
commit 421f25c80d
2356 changed files with 342670 additions and 4743 deletions
@@ -0,0 +1,175 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Analyzer\Analysis\NamespaceAnalysis;
use PhpCsFixer\Tokenizer\Analyzer\NamespacesAnalyzer;
use PhpCsFixer\Tokenizer\Analyzer\NamespaceUsesAnalyzer;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
final class ClassReferenceNameCasingFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'When referencing an internal class it must be written using the correct casing.',
[
new CodeSample("<?php\nthrow new \\exception();\n"),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_STRING);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$namespacesAnalyzer = new NamespacesAnalyzer();
$namespaceUsesAnalyzer = new NamespaceUsesAnalyzer();
$classNames = $this->getClassNames();
foreach ($namespacesAnalyzer->getDeclarations($tokens) as $namespace) {
$uses = [];
foreach ($namespaceUsesAnalyzer->getDeclarationsInNamespace($tokens, $namespace) as $use) {
$uses[strtolower($use->getShortName())] = true;
}
foreach ($this->getClassReference($tokens, $namespace) as $reference) {
$currentContent = $tokens[$reference]->getContent();
$lowerCurrentContent = strtolower($currentContent);
if (isset($classNames[$lowerCurrentContent]) && $currentContent !== $classNames[$lowerCurrentContent] && !isset($uses[$lowerCurrentContent])) {
$tokens[$reference] = new Token([T_STRING, $classNames[$lowerCurrentContent]]);
}
}
}
}
private function getClassReference(Tokens $tokens, NamespaceAnalysis $namespace): \Generator
{
static $notBeforeKinds;
static $blockKinds;
if (null === $notBeforeKinds) {
$notBeforeKinds = [
CT::T_USE_TRAIT,
T_AS,
T_CASE, // PHP 8.1 trait enum-case
T_CLASS,
T_CONST,
T_DOUBLE_ARROW,
T_DOUBLE_COLON,
T_FUNCTION,
T_INTERFACE,
T_OBJECT_OPERATOR,
T_TRAIT,
];
if (\defined('T_ENUM')) { // @TODO: drop condition when PHP 8.1+ is required
$notBeforeKinds[] = T_ENUM;
}
}
if (null === $blockKinds) {
$blockKinds = ['before' => [','], 'after' => [',']];
foreach (Tokens::getBlockEdgeDefinitions() as $definition) {
$blockKinds['before'][] = $definition['start'];
$blockKinds['after'][] = $definition['end'];
}
}
$namespaceIsGlobal = $namespace->isGlobalNamespace();
for ($index = $namespace->getScopeStartIndex(); $index < $namespace->getScopeEndIndex(); ++$index) {
if (!$tokens[$index]->isGivenKind(T_STRING)) {
continue;
}
$nextIndex = $tokens->getNextMeaningfulToken($index);
if ($tokens[$nextIndex]->isGivenKind(T_NS_SEPARATOR)) {
continue;
}
$prevIndex = $tokens->getPrevMeaningfulToken($index);
$nextIndex = $tokens->getNextMeaningfulToken($index);
$isNamespaceSeparator = $tokens[$prevIndex]->isGivenKind(T_NS_SEPARATOR);
if (!$isNamespaceSeparator && !$namespaceIsGlobal) {
continue;
}
if ($isNamespaceSeparator) {
$prevIndex = $tokens->getPrevMeaningfulToken($prevIndex);
if ($tokens[$prevIndex]->isGivenKind(T_STRING)) {
continue;
}
} elseif ($tokens[$prevIndex]->isGivenKind($notBeforeKinds)) {
continue;
}
if ($tokens[$prevIndex]->equalsAny($blockKinds['before']) && $tokens[$nextIndex]->equalsAny($blockKinds['after'])) {
continue;
}
if (!$tokens[$prevIndex]->isGivenKind(T_NEW) && $tokens[$nextIndex]->equalsAny(['(', ';', [T_CLOSE_TAG]])) {
continue;
}
yield $index;
}
}
/**
* @return array<string, string>
*/
private function getClassNames(): array
{
static $classes = null;
if (null === $classes) {
$classes = [];
foreach (get_declared_classes() as $class) {
if ((new \ReflectionClass($class))->isInternal()) {
$classes[strtolower($class)] = $class;
}
}
}
return $classes;
}
}
@@ -0,0 +1,176 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Fixer for constants case.
*
* @author Pol Dellaiera <pol.dellaiera@protonmail.com>
*/
final class ConstantCaseFixer extends AbstractFixer implements ConfigurableFixerInterface
{
/**
* Hold the function that will be used to convert the constants.
*
* @var callable
*/
private $fixFunction;
/**
* {@inheritdoc}
*/
public function configure(array $configuration): void
{
parent::configure($configuration);
if ('lower' === $this->configuration['case']) {
$this->fixFunction = static function (string $content): string {
return strtolower($content);
};
}
if ('upper' === $this->configuration['case']) {
$this->fixFunction = static function (string $content): string {
return strtoupper($content);
};
}
}
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'The PHP constants `true`, `false`, and `null` MUST be written using the correct casing.',
[
new CodeSample("<?php\n\$a = FALSE;\n\$b = True;\n\$c = nuLL;\n"),
new CodeSample("<?php\n\$a = FALSE;\n\$b = True;\n\$c = nuLL;\n", ['case' => 'upper']),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_STRING);
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('case', 'Whether to use the `upper` or `lower` case syntax.'))
->setAllowedValues(['upper', 'lower'])
->setDefault('lower')
->getOption(),
]);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$fixFunction = $this->fixFunction;
foreach ($tokens as $index => $token) {
if (!$token->isNativeConstant()) {
continue;
}
if (
$this->isNeighbourAccepted($tokens, $tokens->getPrevMeaningfulToken($index))
&& $this->isNeighbourAccepted($tokens, $tokens->getNextMeaningfulToken($index))
&& !$this->isEnumCaseName($tokens, $index)
) {
$tokens[$index] = new Token([$token->getId(), $fixFunction($token->getContent())]);
}
}
}
private function isNeighbourAccepted(Tokens $tokens, int $index): bool
{
static $forbiddenTokens = null;
if (null === $forbiddenTokens) {
$forbiddenTokens = array_merge(
[
T_AS,
T_CLASS,
T_CONST,
T_EXTENDS,
T_IMPLEMENTS,
T_INSTANCEOF,
T_INSTEADOF,
T_INTERFACE,
T_NEW,
T_NS_SEPARATOR,
T_PAAMAYIM_NEKUDOTAYIM,
T_TRAIT,
T_USE,
CT::T_USE_TRAIT,
CT::T_USE_LAMBDA,
],
Token::getObjectOperatorKinds()
);
}
$token = $tokens[$index];
if ($token->equalsAny(['{', '}'])) {
return false;
}
return !$token->isGivenKind($forbiddenTokens);
}
private function isEnumCaseName(Tokens $tokens, int $index): bool
{
if (!\defined('T_ENUM') || !$tokens->isTokenKindFound(T_ENUM)) { // @TODO: drop condition when PHP 8.1+ is required
return false;
}
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if (null === $prevIndex || !$tokens[$prevIndex]->isGivenKind(T_CASE)) {
return false;
}
if (!$tokens->isTokenKindFound(T_SWITCH)) {
return true;
}
$prevIndex = $tokens->getPrevTokenOfKind($prevIndex, [[T_ENUM], [T_SWITCH]]);
return null !== $prevIndex && $tokens[$prevIndex]->isGivenKind(T_ENUM);
}
}
@@ -0,0 +1,69 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
final class IntegerLiteralCaseFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Integer literals must be in correct case.',
[
new CodeSample(
"<?php\n\$foo = 0Xff;\n\$bar = 0B11111111;\n"
),
]
);
}
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_LNUMBER);
}
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
foreach ($tokens as $index => $token) {
if (!$token->isGivenKind(T_LNUMBER)) {
continue;
}
$content = $token->getContent();
if (1 !== Preg::match('#^0[bxoBXO][0-9a-fA-F]+$#', $content)) {
continue;
}
$newContent = '0'.strtolower($content[1]).strtoupper(substr($content, 2));
if ($content === $newContent) {
continue;
}
$tokens[$index] = new Token([T_LNUMBER, $newContent]);
}
}
}
@@ -0,0 +1,81 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Fixer for rules defined in PSR2 ¶2.5.
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
final class LowercaseKeywordsFixer extends AbstractFixer
{
/**
* @var int[]
*/
private static array $excludedTokens = [T_HALT_COMPILER];
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'PHP keywords MUST be in lower case.',
[
new CodeSample(
'<?php
FOREACH($a AS $B) {
TRY {
NEW $C($a, ISSET($B));
WHILE($B) {
INCLUDE "test.php";
}
} CATCH(\Exception $e) {
EXIT(1);
}
}
'
),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound(Token::getKeywords());
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
foreach ($tokens as $index => $token) {
if ($token->isKeyword() && !$token->isGivenKind(self::$excludedTokens)) {
$tokens[$index] = new Token([$token->getId(), strtolower($token->getContent())]);
}
}
}
}
@@ -0,0 +1,106 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* @author Kuba Werłos <werlos@gmail.com>
*/
final class LowercaseStaticReferenceFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Class static references `self`, `static` and `parent` MUST be in lower case.',
[
new CodeSample('<?php
class Foo extends Bar
{
public function baz1()
{
return STATIC::baz2();
}
public function baz2($x)
{
return $x instanceof Self;
}
public function baz3(PaRent $x)
{
return true;
}
}
'),
new CodeSample(
'<?php
class Foo extends Bar
{
public function baz(?self $x) : SELF
{
return false;
}
}
'
),
]
);
}
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound([T_STATIC, T_STRING]);
}
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
foreach ($tokens as $index => $token) {
if (!$token->equalsAny([[T_STRING, 'self'], [T_STATIC, 'static'], [T_STRING, 'parent']], false)) {
continue;
}
$newContent = strtolower($token->getContent());
if ($token->getContent() === $newContent) {
continue; // case is already correct
}
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if ($tokens[$prevIndex]->isGivenKind([T_CONST, T_DOUBLE_COLON, T_FUNCTION, T_NAMESPACE, T_NS_SEPARATOR]) || $tokens[$prevIndex]->isObjectOperator()) {
continue;
}
$nextIndex = $tokens->getNextMeaningfulToken($index);
if ($tokens[$nextIndex]->isGivenKind([T_FUNCTION, T_NS_SEPARATOR, T_PRIVATE, T_PROTECTED, T_PUBLIC, T_STRING, CT::T_NULLABLE_TYPE])) {
continue;
}
if ('static' === $newContent && $tokens[$nextIndex]->isGivenKind(T_VARIABLE)) {
continue;
}
$tokens[$index] = new Token([$token->getId(), $newContent]);
}
}
}
@@ -0,0 +1,101 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* @author ntzm
*/
final class MagicConstantCasingFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Magic constants should be referred to using the correct casing.',
[new CodeSample("<?php\necho __dir__;\n")]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound($this->getMagicConstantTokens());
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$magicConstants = $this->getMagicConstants();
$magicConstantTokens = $this->getMagicConstantTokens();
foreach ($tokens as $index => $token) {
if ($token->isGivenKind($magicConstantTokens)) {
$tokens[$index] = new Token([$token->getId(), $magicConstants[$token->getId()]]);
}
}
}
/**
* @return array<int, string>
*/
private function getMagicConstants(): array
{
static $magicConstants = null;
if (null === $magicConstants) {
$magicConstants = [
T_LINE => '__LINE__',
T_FILE => '__FILE__',
T_DIR => '__DIR__',
T_FUNC_C => '__FUNCTION__',
T_CLASS_C => '__CLASS__',
T_METHOD_C => '__METHOD__',
T_NS_C => '__NAMESPACE__',
CT::T_CLASS_CONSTANT => 'class',
T_TRAIT_C => '__TRAIT__',
];
}
return $magicConstants;
}
/**
* @return array<int>
*/
private function getMagicConstantTokens(): array
{
static $magicConstantTokens = null;
if (null === $magicConstantTokens) {
$magicConstantTokens = array_keys($this->getMagicConstants());
}
return $magicConstantTokens;
}
}
@@ -0,0 +1,206 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
final class MagicMethodCasingFixer extends AbstractFixer
{
/**
* @var array<string,string>
*/
private static array $magicNames = [
'__call' => '__call',
'__callstatic' => '__callStatic',
'__clone' => '__clone',
'__construct' => '__construct',
'__debuginfo' => '__debugInfo',
'__destruct' => '__destruct',
'__get' => '__get',
'__invoke' => '__invoke',
'__isset' => '__isset',
'__serialize' => '__serialize',
'__set' => '__set',
'__set_state' => '__set_state',
'__sleep' => '__sleep',
'__tostring' => '__toString',
'__unserialize' => '__unserialize',
'__unset' => '__unset',
'__wakeup' => '__wakeup',
];
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Magic method definitions and calls must be using the correct casing.',
[
new CodeSample(
'<?php
class Foo
{
public function __Sleep()
{
}
}
'
),
new CodeSample(
'<?php
$foo->__INVOKE(1);
'
),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_STRING) && $tokens->isAnyTokenKindsFound(array_merge([T_FUNCTION, T_DOUBLE_COLON], Token::getObjectOperatorKinds()));
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$inClass = 0;
$tokenCount = \count($tokens);
for ($index = 1; $index < $tokenCount - 2; ++$index) {
if (0 === $inClass && $tokens[$index]->isClassy()) {
$inClass = 1;
$index = $tokens->getNextTokenOfKind($index, ['{']);
continue;
}
if (0 !== $inClass) {
if ($tokens[$index]->equals('{')) {
++$inClass;
continue;
}
if ($tokens[$index]->equals('}')) {
--$inClass;
continue;
}
}
if (!$tokens[$index]->isGivenKind(T_STRING)) {
continue; // wrong type
}
$content = $tokens[$index]->getContent();
if (!str_starts_with($content, '__')) {
continue; // cheap look ahead
}
$name = strtolower($content);
if (!$this->isMagicMethodName($name)) {
continue; // method name is not one of the magic ones we can fix
}
$nameInCorrectCasing = $this->getMagicMethodNameInCorrectCasing($name);
if ($nameInCorrectCasing === $content) {
continue; // method name is already in the correct casing, no fix needed
}
if ($this->isFunctionSignature($tokens, $index)) {
if (0 !== $inClass) {
// this is a method definition we want to fix
$this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
}
continue;
}
if ($this->isMethodCall($tokens, $index)) {
$this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
continue;
}
if (
('__callstatic' === $name || '__set_state' === $name)
&& $this->isStaticMethodCall($tokens, $index)
) {
$this->setTokenToCorrectCasing($tokens, $index, $nameInCorrectCasing);
}
}
}
private function isFunctionSignature(Tokens $tokens, int $index): bool
{
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if (!$tokens[$prevIndex]->isGivenKind(T_FUNCTION)) {
return false; // not a method signature
}
return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
}
private function isMethodCall(Tokens $tokens, int $index): bool
{
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if (!$tokens[$prevIndex]->isObjectOperator()) {
return false; // not a "simple" method call
}
return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
}
private function isStaticMethodCall(Tokens $tokens, int $index): bool
{
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if (!$tokens[$prevIndex]->isGivenKind(T_DOUBLE_COLON)) {
return false; // not a "simple" static method call
}
return $tokens[$tokens->getNextMeaningfulToken($index)]->equals('(');
}
private function isMagicMethodName(string $name): bool
{
return isset(self::$magicNames[$name]);
}
/**
* @param string $name name of a magic method
*/
private function getMagicMethodNameInCorrectCasing(string $name): string
{
return self::$magicNames[$name];
}
private function setTokenToCorrectCasing(Tokens $tokens, int $index, string $nameInCorrectCasing): void
{
$tokens[$index] = new Token([T_STRING, $nameInCorrectCasing]);
}
}
@@ -0,0 +1,98 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
final class NativeFunctionCasingFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Function defined by PHP should be called using the correct casing.',
[new CodeSample("<?php\nSTRLEN(\$str);\n")]
);
}
/**
* {@inheritdoc}
*
* Must run after FunctionToConstantFixer, NoUselessSprintfFixer, PowToExponentiationFixer.
*/
public function getPriority(): int
{
return 0;
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_STRING);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$functionsAnalyzer = new FunctionsAnalyzer();
static $nativeFunctionNames = null;
if (null === $nativeFunctionNames) {
$nativeFunctionNames = $this->getNativeFunctionNames();
}
for ($index = 0, $count = $tokens->count(); $index < $count; ++$index) {
// test if we are at a function all
if (!$functionsAnalyzer->isGlobalFunctionCall($tokens, $index)) {
continue;
}
// test if the function call is to a native PHP function
$lower = strtolower($tokens[$index]->getContent());
if (!\array_key_exists($lower, $nativeFunctionNames)) {
continue;
}
$tokens[$index] = new Token([T_STRING, $nativeFunctionNames[$lower]]);
}
}
/**
* @return array<string, string>
*/
private function getNativeFunctionNames(): array
{
$allFunctions = get_defined_functions();
$functions = [];
foreach ($allFunctions['internal'] as $function) {
$functions[strtolower($function)] = $function;
}
return $functions;
}
}
@@ -0,0 +1,169 @@
<?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\Casing;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\FixerDefinition\VersionSpecification;
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
use PhpCsFixer\Tokenizer\Analyzer\Analysis\TypeAnalysis;
use PhpCsFixer\Tokenizer\Analyzer\FunctionsAnalyzer;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
final class NativeFunctionTypeDeclarationCasingFixer extends AbstractFixer
{
/**
* https://secure.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration.
*
* self PHP 5.0
* array PHP 5.1
* callable PHP 5.4
* bool PHP 7.0
* float PHP 7.0
* int PHP 7.0
* string PHP 7.0
* iterable PHP 7.1
* void PHP 7.1
* object PHP 7.2
* static PHP 8.0 (return type only)
* mixed PHP 8.0
* false PHP 8.0 (union return type only)
* null PHP 8.0 (union return type only)
* never PHP 8.1 (return type only)
* true PHP 8.2 (standalone type: https://wiki.php.net/rfc/true-type)
* false PHP 8.2 (standalone type: https://wiki.php.net/rfc/null-false-standalone-types)
* null PHP 8.2 (standalone type: https://wiki.php.net/rfc/null-false-standalone-types)
*
* @var array<string, true>
*/
private array $hints;
private FunctionsAnalyzer $functionsAnalyzer;
public function __construct()
{
parent::__construct();
$this->hints = [
'array' => true,
'bool' => true,
'callable' => true,
'float' => true,
'int' => true,
'iterable' => true,
'object' => true,
'self' => true,
'string' => true,
'void' => true,
];
if (\PHP_VERSION_ID >= 80000) {
$this->hints['false'] = true;
$this->hints['mixed'] = true;
$this->hints['null'] = true;
$this->hints['static'] = true;
}
if (\PHP_VERSION_ID >= 80100) {
$this->hints['never'] = true;
}
if (\PHP_VERSION_ID >= 80200) {
$this->hints['true'] = true;
}
$this->functionsAnalyzer = new FunctionsAnalyzer();
}
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Native type hints for functions should use the correct case.',
[
new CodeSample("<?php\nclass Bar {\n public function Foo(CALLABLE \$bar)\n {\n return 1;\n }\n}\n"),
new CodeSample(
"<?php\nfunction Foo(INT \$a): Bool\n{\n return true;\n}\n"
),
new CodeSample(
"<?php\nfunction Foo(Iterable \$a): VOID\n{\n echo 'Hello world';\n}\n"
),
new VersionSpecificCodeSample(
"<?php\nfunction Foo(Object \$a)\n{\n return 'hi!';\n}\n",
new VersionSpecification(70200)
),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAllTokenKindsFound([T_FUNCTION, T_STRING]);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = $tokens->count() - 1; $index >= 0; --$index) {
if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
$this->fixFunctionReturnType($tokens, $index);
$this->fixFunctionArgumentTypes($tokens, $index);
}
}
}
private function fixFunctionArgumentTypes(Tokens $tokens, int $index): void
{
foreach ($this->functionsAnalyzer->getFunctionArguments($tokens, $index) as $argument) {
$this->fixArgumentType($tokens, $argument->getTypeAnalysis());
}
}
private function fixFunctionReturnType(Tokens $tokens, int $index): void
{
$this->fixArgumentType($tokens, $this->functionsAnalyzer->getFunctionReturnType($tokens, $index));
}
private function fixArgumentType(Tokens $tokens, ?TypeAnalysis $type = null): void
{
if (null === $type) {
return;
}
for ($index = $type->getStartIndex(); $index <= $type->getEndIndex(); ++$index) {
if ($tokens[$tokens->getNextMeaningfulToken($index)]->isGivenKind(T_NS_SEPARATOR)) {
continue;
}
$lowerCasedName = strtolower($tokens[$index]->getContent());
if (!isset($this->hints[$lowerCasedName])) {
continue;
}
$tokens[$index] = new Token([$tokens[$index]->getId(), $lowerCasedName]);
}
}
}