Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DeclaredClassCasingFilter #3969

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.rst
Expand Up @@ -847,6 +847,10 @@ Choose from the list of available rules:
multi-line whitespace or move the semicolon to the new line for chained
calls; defaults to ``'no_multi_line'``

* **native_class_casing**

Classes should be referred to using the correct casing.

* **native_constant_invocation** [@Symfony:risky]

Add leading ``\`` before constant invocation of internal constant to speed
Expand Down
110 changes: 110 additions & 0 deletions src/Fixer/Casing/NativeClassCasingFixer.php
@@ -0,0 +1,110 @@
<?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\Casing;

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

/**
* @author siad007
*/
final class NativeClassCasingFixer extends AbstractFixer
{
private static $nativeClassNames;

public function __construct()
{
parent::__construct();

if (null === self::$nativeClassNames) {
foreach (get_declared_classes() as $class) {
SpacePossum marked this conversation as resolved.
Show resolved Hide resolved
self::$nativeClassNames[strtolower($class)] = $class;
}
}
}

/**
* {@inheritdoc}
*/
public function getDefinition()
{
return new FixerDefinition(
'Classes should be referred to using the correct casing.',
SpacePossum marked this conversation as resolved.
Show resolved Hide resolved
[new CodeSample("<?php\nnew STDCLASS();\n")]
);
}

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

/**
* @param \SplFileInfo $file
* @param Tokens $tokens
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens)
{
foreach ($tokens as $index => $token) {
if ($name = $this->nativeClass($index, $token, $tokens)) {
$tokens[$index] = new Token([T_STRING, self::$nativeClassNames[$name]]);
}
}
}

/**
* Get the lower case name of the native class or null.
*
* @param int $index
* @param Token $token
* @param Tokens $tokens
*
* @return null|string
*/
private function nativeClass($index, Token $token, Tokens $tokens)
{
$beforeClassName = $tokens->getPrevMeaningfulToken($index);
$lower = strtolower($token->getContent());

return array_key_exists($lower, self::$nativeClassNames)
&&
!$tokens[$beforeClassName]->isGivenKind(
[
T_CLASS,
T_AS,
T_DOUBLE_COLON,
T_OBJECT_OPERATOR,
T_FUNCTION,
T_CONST,
T_TRAIT,
T_USE,
CT::T_USE_TRAIT,
]
)
&&
!(
$tokens[$beforeClassName]->isGivenKind(T_NS_SEPARATOR)
&&
$tokens[$tokens->getPrevMeaningfulToken($beforeClassName)]->isGivenKind([T_STRING])
)
? $lower
: null;
SpacePossum marked this conversation as resolved.
Show resolved Hide resolved
}
}
123 changes: 123 additions & 0 deletions tests/Fixer/Casing/NativeClassCasingFixerTest.php
@@ -0,0 +1,123 @@
<?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\Tests\Fixer\Casing;

use PhpCsFixer\Tests\Test\AbstractFixerTestCase;

/**
* @author siad007
*
* @internal
*
* @covers \PhpCsFixer\Fixer\Casing\NativeClassCasingFixer
*/
final class NativeClassCasingFixerTest extends AbstractFixerTestCase
{
/**
* @param string $expected
* @param null|string $input
*
* @dataProvider provideFixCases
*/
public function testFix($expected, $input = null)
{
$this->doTest($expected, $input);
}

public function provideFixCases()
{
return [
[
'<?php
$stdclass = new \stdClass();
$stdclass = new stdClass();
',
'<?php
$stdclass = new \STDCLASS();
$stdclass = new STDCLASS();
',
],
[
'<?php

namespace Foo;

class exception extends \Exception
{
}
',
'<?php

namespace Foo;

class exception extends \EXCEPTION
{
}
',
],
[
'<?php

echo \Exception::class;
echo Exception::class;
',
'<?php

echo \ExCePTion::class;
echo ExCePTion::class;
',
],
[
'<?php

$a::exception();
',
],
[
'<?php

$a->exception();
',
],
[
'<?php

function exception() {};
',
],
[
'<?php

echo "This is an " . "exception";
',
],
[
'<?php

namespace Foo;

trait stdclass
{
}

use Foo\stdclass as exception;

class test
{
use exception;
}
',
],
];
}
}