diff --git a/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/AddParenthesesTest.php b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/AddParenthesesTest.php new file mode 100644 index 00000000000..c45b8d257b1 --- /dev/null +++ b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/AddParenthesesTest.php @@ -0,0 +1,27 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/FixtureAdd'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/add_parentheses.php'; + } +} diff --git a/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/FixtureAdd/fixture.php.inc b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/FixtureAdd/fixture.php.inc new file mode 100644 index 00000000000..8963517c938 --- /dev/null +++ b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/FixtureAdd/fixture.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/FixtureRemove/fixture.php.inc b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/FixtureRemove/fixture.php.inc new file mode 100644 index 00000000000..a790e2b681a --- /dev/null +++ b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/FixtureRemove/fixture.php.inc @@ -0,0 +1,11 @@ + +----- + diff --git a/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/RemoveParenthesesTest.php b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/RemoveParenthesesTest.php new file mode 100644 index 00000000000..3598addac65 --- /dev/null +++ b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/RemoveParenthesesTest.php @@ -0,0 +1,27 @@ +doTestFile($filePath); + } + + public static function provideData(): \Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/FixtureRemove'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/remove_parentheses.php'; + } +} diff --git a/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/config/add_parentheses.php b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/config/add_parentheses.php new file mode 100644 index 00000000000..789e74962d6 --- /dev/null +++ b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/config/add_parentheses.php @@ -0,0 +1,12 @@ +ruleWithConfiguration(ParenthesizeNegatedInstanceofRector::class, [ + 'mode' => ParenthesizeNegatedInstanceofRector::ADD_PARENTHESES, + ]); +}; diff --git a/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/config/remove_parentheses.php b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/config/remove_parentheses.php new file mode 100644 index 00000000000..5e6e6d6b873 --- /dev/null +++ b/rules-tests/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector/config/remove_parentheses.php @@ -0,0 +1,12 @@ +ruleWithConfiguration(ParenthesizeNegatedInstanceofRector::class, [ + 'mode' => ParenthesizeNegatedInstanceofRector::REMOVE_PARENTHESES, + ]); +}; diff --git a/rules/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector.php b/rules/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector.php new file mode 100644 index 00000000000..dd626dbf217 --- /dev/null +++ b/rules/Instanceof_/Rector/BooleanNot/ParenthesizeNegatedInstanceofRector.php @@ -0,0 +1,119 @@ + self::ADD_PARENTHESES, + ], + ), + new ConfiguredCodeSample( + <<<'CODE_SAMPLE' +if (!($foo instanceof Foo)) {} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +if (!$foo instanceof Foo) {} +CODE_SAMPLE + , + [ + 'mode' => self::REMOVE_PARENTHESES, + ], + ), + ], + ); + } + + public function configure(array $configuration): void + { + if ($configuration !== []) { + Assert::keyExists($configuration, 'mode'); + Assert::oneOf($configuration['mode'], [self::ADD_PARENTHESES, self::REMOVE_PARENTHESES]); + } + + $this->mode = $configuration['mode'] ?? $this->mode; + } + + public function getNodeTypes(): array + { + return [BooleanNot::class]; + } + + /** + * @param BooleanNot $node + */ + public function refactor(Node $node): ?BooleanNot + { + if (! $node->expr instanceof Instanceof_) { + return null; + } + + $oldTokens = $this->file->getOldTokens(); + + $tokensStartWithOpeningParens = ((string) $oldTokens[$node->getStartTokenPos() + 1]) === '('; + $tokensEndWithClosingParens = ((string) $oldTokens[$node->getEndTokenPos()]) === ')'; + + $alreadyWrapped = $tokensStartWithOpeningParens && $tokensEndWithClosingParens; + + if ($this->mode === self::ADD_PARENTHESES && $alreadyWrapped === true) { + return null; + } + + if ($this->mode === self::ADD_PARENTHESES) { + $node->expr->setAttribute(AttributeKey::WRAPPED_IN_PARENTHESES, true); + return $node; + } + + if ($alreadyWrapped === false) { + return null; + } + + return new BooleanNot($node->expr); + } +}