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 MagicMethodCasingFixer #3739

Merged
merged 1 commit into from Aug 22, 2018
Merged

Add MagicMethodCasingFixer #3739

merged 1 commit into from Aug 22, 2018

Conversation

SpacePossum
Copy link
Contributor

$ php php-cs-fixer describe magic_method_casing
Description of magic_method_casing rule.
Magic method definitions and calls must be using the correct casing.

Fixing examples:
 * Example #1.
   ---------- begin diff ----------
   --- Original
   +++ New
   @@ -1,7 +1,7 @@
    <?php
    class Foo
    {
   -    public function __Sleep()
   +    public function __sleep()
        {
        }
    }
   
   ----------- end diff -----------

 * Example #2.
   ---------- begin diff ----------
   --- Original
   +++ New
   @@ -1,2 +1,2 @@
    <?php
   -$foo->__INVOKE(1);
   +$foo->__invoke(1);
   
   ----------- end diff -----------

README.rst Outdated
@@ -743,6 +743,10 @@ Choose from the list of available rules:

Magic constants should be referred to using the correct casing.

* **magic_method_casing**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add to .php_cs.dist

],
'__callstatic' => [
'name' => '__callStatic',
'argumentsRange' => [2, 2],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is casing related to number of params ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the number of arguments do not match the signature as defined as magic PHP method it does not get fixed as it assumed as overridden, to be a safe-ish side, you think we could do without? happy to remove

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all magic methods are in fact overriden.
I assume you are talking about overloading methods, but that doesn't work in PHP and PHP will still treat them as magic methods. IMO, casing shall be respected even if one provides wrong number of params.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that simplifies things :D
will update soon :)

@keradus
Copy link
Member

keradus commented May 15, 2018

idea is good, can you fix travis before we would review PR ?

@SpacePossum
Copy link
Contributor Author

the failures do not seem related to this PR, I'm looking into those nevertheless in another PR (not sure about a time frame though)

@keradus
Copy link
Member

keradus commented May 15, 2018

  1. PhpCsFixer\Tests\Fixer\Casing\MagicMethodCasingFixerTest::testFix with data set UnusedUseStatementsFixer does not support 'as' keyword #2 ('<?php class Foo {public funct...l(){}}', '<?php class Foo {public funct...L(){}}')
    Failed asserting that 'PHP Fatal error: Method Foo::__call() must take exactly 2 arguments in /home/travis/build/FriendsOfPHP/PHP-CS-Fixer/cs_fixer_tmp_2vUrqF on line 1

looks pretty much related to this PR

@SpacePossum
Copy link
Contributor Author

There were 12 errors:
1) PhpCsFixer\Tests\Fixer\Basic\BracesFixerTest::testFixMissingBracesAndIndent with data set #44 ('<?php if (true) {\n    echo "...n} ?>x', '<?php if (true) echo "s" ?>x')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Basic/BracesFixer.php:769
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Basic/BracesFixer.php:617
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Basic/BracesFixer.php:147
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Basic/BracesFixerTest.php:827
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
2) PhpCsFixer\Tests\Fixer\Basic\BracesFixerTest::testFixMissingBracesAndIndent with data set #110 ('<?php if (true) {\n    echo "...n} ?>x', '<?php if (true) echo "s" ?>x', array('same'))
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Basic/BracesFixer.php:769
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Basic/BracesFixer.php:617
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Basic/BracesFixer.php:147
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Basic/BracesFixerTest.php:827
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
3) PhpCsFixer\Tests\Fixer\ControlStructure\YodaStyleFixerTest::testFixInverse with data set #63 ('<?php return 2 == ($a)?>', '<?php return ($a) == 2?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/ControlStructure/YodaStyleFixer.php:352
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/ControlStructure/YodaStyleFixer.php:238
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/ControlStructure/YodaStyleFixer.php:96
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/ControlStructure/YodaStyleFixerTest.php:54
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
4) PhpCsFixer\Tests\Fixer\ControlStructure\YodaStyleFixerTest::testFixInverse with data set #77 ('<?php $a = 1 == $$a?>', '<?php $a = $$a == 1?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/ControlStructure/YodaStyleFixer.php:352
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/ControlStructure/YodaStyleFixer.php:238
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/ControlStructure/YodaStyleFixer.php:96
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/ControlStructure/YodaStyleFixerTest.php:54
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
5) PhpCsFixer\Tests\Fixer\Import\NoUnusedImportsFixerTest::testFix with data set "close_tag_1" ('<?php\n?>inline content<?php ?>', '<?php\n     use A\AA;\n     u...E\F ?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/NoUnusedImportsFixer.php:170
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/NoUnusedImportsFixer.php:109
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Import/NoUnusedImportsFixerTest.php:32
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
6) PhpCsFixer\Tests\Fixer\Import\NoUnusedImportsFixerTest::testFix with data set "close_tag_3" ('<?php ?>', '<?php use A\B?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/NoUnusedImportsFixer.php:170
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/NoUnusedImportsFixer.php:109
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Import/NoUnusedImportsFixerTest.php:32
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
7) PhpCsFixer\Tests\Fixer\Import\OrderedImportsFixerTest::testCodeWithCloseTag
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/OrderedImportsFixer.php:338
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/OrderedImportsFixer.php:189
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Import/OrderedImportsFixerTest.php:595
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
8) PhpCsFixer\Tests\Fixer\Import\SingleImportPerStatementFixerTest::testFix with data set #4 ('<?php use FooA;\nuse FooB?>', '<?php use FooA, FooB?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/SingleImportPerStatementFixer.php:69
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Import/SingleImportPerStatementFixerTest.php:36
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
9) PhpCsFixer\Tests\Fixer\Import\SingleLineAfterImportsFixerTest::testFix with data set #23 ('<?php use A\B;\n\n?>', '<?php use A\B?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/SingleLineAfterImportsFixer.php:99
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Import/SingleLineAfterImportsFixerTest.php:35
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
10) PhpCsFixer\Tests\Fixer\Import\SingleLineAfterImportsFixerTest::testFix70 with data set #0 ('<?php\nuse some\test\{ClassA,... 123\n', '<?php\nuse some\test\{ClassA,... 123\n')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Import/SingleLineAfterImportsFixer.php:99
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Import/SingleLineAfterImportsFixerTest.php:368
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
11) PhpCsFixer\Tests\Fixer\NamespaceNotation\BlankLineAfterNamespaceFixerTest::testFix with data set #1 ('<?php namespace A\B?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/NamespaceNotation/BlankLineAfterNamespaceFixer.php:76
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:159
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/NamespaceNotation/BlankLineAfterNamespaceFixerTest.php:35
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39
12) PhpCsFixer\Tests\Fixer\Operator\NewWithBracesFixerTest::testFix with data set #24 ('<?php $b = new \StdClass() /**/?>', '<?php $b = new \StdClass /**/?>')
RuntimeException: Index invalid or out of range
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/Fixer/Operator/NewWithBracesFixer.php:111
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/src/AbstractFixer.php:75
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Test/AbstractFixerTestCase.php:127
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/tests/Fixer/Operator/NewWithBracesFixerTest.php:34
/home/travis/build/FriendsOfPHP/PHP-CS-Fixer/vendor/phpunitgoodpractices/traits/src/ExpectationViaCodeOverAnnotationTrait7.php:39

doesn't look much related though

@keradus
Copy link
Member

keradus commented May 15, 2018

you are talking about nightly build which is allowed to failed and that we have meta 7.3 ticket that mentions this issue already

I'm talking about 5.6 build that must not fail

errors on those builds are different

@SpacePossum
Copy link
Contributor Author

just listing all failures to look into about this PR so I can work on those, not stating these have the same weight or priority

@keradus
Copy link
Member

keradus commented May 15, 2018

5.6 build. all
5.6 build is working on master branch, it fails on your PR.

@SpacePossum
Copy link
Contributor Author

rebased, I need Travis to see the 5.6 failures because only on that version the linter checks to much

@SpacePossum SpacePossum added this to the 2.12.0 milestone May 17, 2018
private function isMagicMethodCallInWrongCasing(Tokens $tokens, $index)
{
$prevIndex = $tokens->getPrevMeaningfulToken($index);
if (!$tokens[$prevIndex]->equals([T_OBJECT_OPERATOR, '->'])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about static calls? e.g. for __callStatic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:'(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one will not call Foo::__callStatic() but Foo::undefinedMethod(), so nothing to detect here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed for this case nevertheless

@keradus
Copy link
Member

keradus commented May 27, 2018

@SpacePossum , is there anything missing in this PR ?

@SpacePossum
Copy link
Contributor Author

SpacePossum commented May 28, 2018

there is this very theoretical missed opportunity case, but I'm happy with this PR as it is now and therefore I think it is ready to go :)

*
* @return bool
*/
private function isMagicMethodSignatureInWrongCasing(Tokens $tokens, $index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name is misleading IMO: it doesn't check if the tokens are a magic method with wrong casing, it only checks if they are a function definition.

}

$nextIndex = $tokens->getNextMeaningfulToken($index);
if (!$tokens[$nextIndex]->equals('(')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be simplified:

return $tokens[$nextIndex]->equals('(');

}

$nextIndex = $tokens->getNextMeaningfulToken($index);
if (!$tokens[$nextIndex]->equals('(')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be simplified:

return $tokens[$nextIndex]->equals('(');

*
* @return bool
*/
private function isMagicMethodCallInWrongCasing(Tokens $tokens, $index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name is misleading IMO: it doesn't check if the tokens are a magic method call with wrong casing, it only checks if they are a method call.

{
return [
[
'<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would split this case in several smaller ones to ease debugging if needed.


echo $a->__sleep;
',
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the following cases:

<?php
function __Tostring() {}
<?php
__Tostring();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<?php
function __Tostring() {}

can we note this as a false-fixing and move on, like anyone who creates functions with magic method names is not likely to use this tool anyway ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the one who will inherit codebase after him would ;P

agree, edge case...

@SpacePossum SpacePossum removed this from the 2.12.0 milestone May 28, 2018
@SpacePossum SpacePossum removed the WIP label Jun 7, 2018
@SpacePossum
Copy link
Contributor Author

I fixed both edge cases and all tests are green. @julienfalque can I bother you with asking for another review?

continue;
}

if ('__callstatic' === $name && $this->isStaticMethodCall($tokens, $index)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about __set_state?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about it?

Copy link
Contributor

@ntzm ntzm Jun 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it handled by this fixer? e.g. Foo::__sEt_State([]);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it isn't I think... hmmm


for ($index = 1; $index < $tokenCount - 2; ++$index) {
if (0 === $inClass && $tokens[$index]->isClassy()) {
$inClass = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be easier to make this variable be null by default and then store the result of $tokens->findBlockEnd() so that you just compare it to the current index instead of counting { and } tokens? The variable name could become e.g. $inClassUntil.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would require scanning from the classy open { till the end and than go back scanning all the tokens again for candidates, which is not very efficient.

}

if ($this->isMethodSignature($tokens, $index)) {
if (0 !== $inClass) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is misleading: the current index is a method signature, as just checked before, so the current index is in a class. The method name is actually wrong and should be isFunctionSignature IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this works well ATM

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this can be misleading when you don't know what the code does yet. The more the code is clear about that, the easier to understand it and maintain it. The first thing I asked myself was why is the second "are we in a class" check required? Then I remembered the previous condition actually doesn't check that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more the code is clear about that, the easier to understand it and maintain it.

I understand that concept

why is the second "are we in a class" check required?

It isn't, however if we don't do that global functions named the same a magic methods get fixed as well ( even though it would change code behavior) and you asked me to update the fixer not to do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed the method and added a comment in the code, lemme know if this is sufficient.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, thanks :) Just a small typo: an method => a method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks :)

$fixerReflection = new \ReflectionClass(MagicMethodCasingFixer::class);
$property = $fixerReflection->getProperty('magicNames');
$property->setAccessible(true);
$allMethodNames = $property->getValue();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid relying on such internal properties to generate test cases: if one removes values from it, tests won't fail as they won't run at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so you prefer listing all in test as well, so if one is added to the fixer but not to tests, the test won't fail?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. When removing code, if tests don't fail, one might think the removed code was not used or some other change replaced it, which is not true. A missing test when adding code is easily spotted during review.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me adding or removing is the same type of operation, so;
current: if one removes an entry from the fixer the test still passes
suggested: if one adds an entry to the fixer the test still passes

the only diff is the list was copyed to the test, but the coverage remains the same.

A missing test when adding code is easily spotted during review.

I don't see why this would be different for when removing code over adding code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In both cases this will have to be spotted during review. But it is different when nobody spots it. When removing code and test, you probably break something for users. When adding new code without test, you just add something that (probably) works as expected, or at least doesn't break existing tests.

In general, tests should be as much decoupled from the code itself as possible. The point is to be defensive. This is similar to Symfony doc's advice regarding hardcoded URLs in tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well this is one pattern against another; decoupled test or DRY: maintaining the same list of static values at two spots in the code.
I understand the arguments; I just out weight the value of not having two list + generating tests cases so I don't forget one, over the more theoretical decoupling of test argument.

*/
public function isCandidate(Tokens $tokens)
{
return $tokens->isTokenKindFound(T_STRING);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add && $tokens->isAnyTokenKindsFound([T_FUNCTION, T_OBJECT_OPERATOR, T_PAAMAYIM_NEKUDOTAYIM]);?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think T_PAAMAYIM_NEKUDOTAYIM should be T_DOUBLE_COLON here? sounds like a good idea to me :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@SpacePossum SpacePossum added this to the 2.13.0 milestone Jun 22, 2018
@SpacePossum
Copy link
Contributor Author

anything left here? I would like to move on ;)

*/
final class MagicMethodCasingFixer extends AbstractFixer
{
private static $magicNames = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constant? Or is the private more important?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pick scoping over constant, when we bump PHP requirement we can use scoped const, till than I prefer this one

@keradus keradus changed the title MagicMethodCasingFixer - introduction Add MagicMethodCasingFixer Aug 22, 2018
@keradus keradus added the RTM Ready To Merge label Aug 22, 2018
@keradus keradus removed the RTM Ready To Merge label Aug 22, 2018
@keradus
Copy link
Member

keradus commented Aug 22, 2018

Thank you @SpacePossum.

@keradus keradus merged commit e45919f into PHP-CS-Fixer:master Aug 22, 2018
keradus added a commit that referenced this pull request Aug 22, 2018
This PR was merged into the 2.13-dev branch.

Discussion
----------

Add MagicMethodCasingFixer

```
$ php php-cs-fixer describe magic_method_casing
Description of magic_method_casing rule.
Magic method definitions and calls must be using the correct casing.

Fixing examples:
 * Example #1.
   ---------- begin diff ----------
   --- Original
   +++ New
   @@ -1,7 +1,7 @@
    <?php
    class Foo
    {
   -    public function __Sleep()
   +    public function __sleep()
        {
        }
    }

   ----------- end diff -----------

 * Example #2.
   ---------- begin diff ----------
   --- Original
   +++ New
   @@ -1,2 +1,2 @@
    <?php
   -$foo->__INVOKE(1);
   +$foo->__invoke(1);

   ----------- end diff -----------

```

Commits
-------

e45919f Add MagicMethodCasingFixer
@SpacePossum SpacePossum deleted the master_MagicMethodCasingFixer branch August 23, 2018 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants