From d52875dc860d8eb3bfad26a766af5d3a9c60272f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Wer=C5=82os?= Date: Wed, 5 May 2021 15:24:18 +0200 Subject: [PATCH] Fix constant invocation detection cases --- src/Tokenizer/TokensAnalyzer.php | 19 +++ .../NativeConstantInvocationFixerTest.php | 14 ++ tests/Tokenizer/TokensAnalyzerTest.php | 149 +++++++++++------- 3 files changed, 127 insertions(+), 55 deletions(-) diff --git a/src/Tokenizer/TokensAnalyzer.php b/src/Tokenizer/TokensAnalyzer.php index f8116077fac..b07250006a4 100644 --- a/src/Tokenizer/TokensAnalyzer.php +++ b/src/Tokenizer/TokensAnalyzer.php @@ -383,6 +383,14 @@ public function isConstantInvocation($index) } } + // check for attribute: `#[Foo]` + if ( + \defined('T_ATTRIBUTE') // @TODO: drop condition when PHP 8.0+ is required + && $this->tokens[$prevIndex]->isGivenKind(T_ATTRIBUTE) + ) { + return false; + } + // check for goto label if ($this->tokens[$nextIndex]->equals(':')) { if (null === $this->gotoLabelAnalyzer) { @@ -394,6 +402,17 @@ public function isConstantInvocation($index) } } + // check for non-capturing catches + while ($this->tokens[$prevIndex]->isGivenKind([CT::T_TYPE_ALTERNATION, T_STRING])) { + $prevIndex = $this->tokens->getPrevMeaningfulToken($prevIndex); + } + if ($this->tokens[$prevIndex]->equals('(')) { + $prevPrevIndex = $this->tokens->getPrevMeaningfulToken($prevIndex); + if ($this->tokens[$prevPrevIndex]->isGivenKind(T_CATCH)) { + return false; + } + } + return true; } diff --git a/tests/Fixer/ConstantNotation/NativeConstantInvocationFixerTest.php b/tests/Fixer/ConstantNotation/NativeConstantInvocationFixerTest.php index 26083955708..66ab3c25a4c 100644 --- a/tests/Fixer/ConstantNotation/NativeConstantInvocationFixerTest.php +++ b/tests/Fixer/ConstantNotation/NativeConstantInvocationFixerTest.php @@ -553,4 +553,18 @@ public function testFixPrePHP80() ' ); } + + /** + * @requires PHP 8.0 + */ + public function testFixPhp80() + { + $this->fixer->configure(['strict' => true]); + $this->doTest( + ' $expectedValue) { - static::assertSame($expectedValue, $tokensAnalyzer->isConstantInvocation($index), 'Token at index '.$index.' should match the expected value.'); - } + $this->doIsConstantInvocationTest($source, $expected); } public function provideIsConstantInvocationCases() @@ -813,7 +809,7 @@ public function provideIsConstantInvocationCases() ], [ ' true, 8 => true], + [1 => false, 3 => true, 6 => false, 8 => true], ], [ ' true, 11 => true], + [3 => true, 7 => false, 9 => false, 11 => true], ], [ ' BAR; }', - [11 => true, 16 => true, 20 => true], + [3 => false, 11 => true, 16 => true, 20 => true], ], [ ' false], + [3 => false, 8 => false], ], [ ' false], + [3 => false, 7 => false], ], [ ' false], + [3 => false, 7 => false], ], [ ' false, 10 => false, 13 => false], + [3 => false, 7 => false, 10 => false, 13 => false], ], [ ' false], + [3 => false, 9 => false], ], [ ' false], + [3 => false, 9 => false], ], [ ' false, 12 => false, 16 => false, 18 => false, 22 => false], + [3 => false, 9 => false, 12 => false, 16 => false, 18 => false, 22 => false], ], [ ' false, 11 => false, 17 => false], + [3 => false, 6 => false, 11 => false, 17 => false], ], [ ' false], + [1 => false, 3 => false], ], [ ' false], + [1 => false, 3 => false], ], [ ' true, 7 => true], + [1 => false, 3 => true, 7 => true], ], [ ' false, 10 => false, 13 => false], + [3 => false, 7 => false, 10 => false, 13 => false], ], [ ' $expectedValue) { - static::assertSame($expectedValue, $tokensAnalyzer->isConstantInvocation($index), 'Token at index '.$index.' should match the expected value.'); - } + $this->doIsConstantInvocationTest($source, $expected); } public function provideIsConstantInvocation70Cases() @@ -954,11 +946,11 @@ public function provideIsConstantInvocation70Cases() return [ [ ' false], + [3 => false, 8 => false], ], [ ' false, 11 => false, 15 => false, 18 => false], + [3 => false, 5 => false, 8 => false, 11 => false, 15 => false, 18 => false], ], ]; } @@ -971,11 +963,7 @@ public function provideIsConstantInvocation70Cases() */ public function testIsConstantInvocation71($source, array $expected) { - $tokensAnalyzer = new TokensAnalyzer(Tokens::fromCode($source)); - - foreach ($expected as $index => $expectedValue) { - static::assertSame($expectedValue, $tokensAnalyzer->isConstantInvocation($index), 'Token at index '.$index.' should match the expected value.'); - } + $this->doIsConstantInvocationTest($source, $expected); } public function provideIsConstantInvocation71Cases() @@ -983,11 +971,11 @@ public function provideIsConstantInvocation71Cases() return [ [ ' false], + [3 => false, 6 => false], ], [ ' false], + [3 => false, 9 => false], ], [ ' false], + [3 => false, 11 => false, 16 => false], ], [ ' false], + [3 => false, 11 => false, 17 => false], ], [ ' false], + [3 => false, 11 => false, 17 => false], ], [ ' false], + [3 => false, 11 => false, 18 => false], ], ]; } + /** + * @param string $source + * + * @dataProvider provideIsConstantInvocationPhp80Cases + * @requires PHP 8.0 + */ + public function testIsConstantInvocationPhp80($source, array $expected) + { + $this->doIsConstantInvocationTest($source, $expected); + } + + public function provideIsConstantInvocationPhp80Cases() + { + yield [ + 'b?->c;', + [3 => false, 5 => false], + ]; + + yield [ + ' false], + ]; + + yield [ + ' false], + ]; + + yield [ + ' false, 13 => false], + ]; + + yield [ + ' false, 7 => false], + ]; + + yield [ + ' false, 9 => false], + ]; + } + public function testIsConstantInvocationInvalid() { $this->expectException(\LogicException::class); @@ -1021,23 +1053,6 @@ public function testIsConstantInvocationInvalid() $tokensAnalyzer->isConstantInvocation(0); } - /** - * @requires PHP 8.0 - */ - public function testIsConstantInvocationForNullSafeObjectOperator() - { - $tokens = Tokens::fromCode('b?->c;'); - - $tokensAnalyzer = new TokensAnalyzer($tokens); - - foreach ($tokens as $index => $token) { - if (!$token->isGivenKind(T_STRING)) { - continue; - } - static::assertFalse($tokensAnalyzer->isConstantInvocation($index)); - } - } - /** * @param string $source * @@ -2071,4 +2086,28 @@ public function provideIsSuperGlobalCases() return $cases; } + + /** + * @param string $source + */ + private function doIsConstantInvocationTest($source, array $expected) + { + $tokens = Tokens::fromCode($source); + + static::assertCount( + $tokens->countTokenKind(T_STRING), + $expected, + 'All T_STRING tokens must be tested' + ); + + $tokensAnalyzer = new TokensAnalyzer($tokens); + + foreach ($expected as $index => $expectedValue) { + static::assertSame( + $expectedValue, + $tokensAnalyzer->isConstantInvocation($index), + sprintf('Token at index '.$index.' should match the expected value (%s).', $expectedValue ? 'true' : 'false') + ); + } + } }