diff --git a/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php b/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php index 1a91a6e06..1e215f13f 100644 --- a/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php +++ b/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php @@ -35,6 +35,9 @@ use const T_HEREDOC; use const T_IMPLEMENTS; use const T_INSTANCEOF; +use const T_NAME_FULLY_QUALIFIED; +use const T_NAME_QUALIFIED; +use const T_NAME_RELATIVE; use const T_NAMESPACE; use const T_NEW; use const T_NS_SEPARATOR; @@ -51,6 +54,7 @@ use const T_TYPE_UNION; use const T_USE; use const T_VARIABLE; +use const T_WHITESPACE; /** * @internal @@ -494,6 +498,31 @@ private static function getReferencedNamesFromString(string $content): array } $referencedNames[] = $referencedName; + } elseif (is_array($token) && $token[0] === T_NEW) { + $referencedName = ''; + $tmpPosition = $position + 1; + while (true) { + if (!is_array($subTokens[$tmpPosition])) { + break; + } + if ($subTokens[$tmpPosition][0] === T_WHITESPACE) { + $tmpPosition++; + continue; + } + if (!in_array( + $subTokens[$tmpPosition][0], + [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED, T_NAME_RELATIVE], + true + )) { + break; + } + + $referencedName .= $subTokens[$tmpPosition][1]; + $tmpPosition++; + } + if ($referencedName !== '') { + $referencedNames[] = $referencedName; + } } } diff --git a/tests/Helpers/ReferencedNameHelperTest.php b/tests/Helpers/ReferencedNameHelperTest.php index e2d304831..5880cdfad 100644 --- a/tests/Helpers/ReferencedNameHelperTest.php +++ b/tests/Helpers/ReferencedNameHelperTest.php @@ -76,7 +76,9 @@ public function testGetAllReferencedNames(): void ['EnumType', false, false], ['UrlGeneratorInterface', false, false], ['ClassInHeredoc', false, false], + ['\Some\OtherClassInHeredoc', false, false], ['ClassInDoubleQuote', false, false], + ['\Some\OtherClassInDoubleQuote', false, false], ['object', true, false], ['DateTime', false, false], ['DateTimeImmutable', false, false], diff --git a/tests/Helpers/data/lotsOfReferencedNames.php b/tests/Helpers/data/lotsOfReferencedNames.php index 6579fd2eb..41619be15 100644 --- a/tests/Helpers/data/lotsOfReferencedNames.php +++ b/tests/Helpers/data/lotsOfReferencedNames.php @@ -196,10 +196,12 @@ public function generateRoute($router): string <<Hello world and {$this->wrap(ClassInHeredoc::EXAMPLE)} + {$_(new \Some\OtherClassInHeredoc())} XML; "foo {$db->quote(ClassInDoubleQuote::SOME_CONSTANT)}"; "foo $db->quote(FakeClassInDoubleQuote::SOME_CONSTANT)"; +"{$_(new \Some\OtherClassInDoubleQuote ?? "")}"; $script .= "// @see \Foo\Bar::func() \$hasDefaultValue = $hasDefaultValue; diff --git a/tests/Sniffs/Namespaces/UnusedUsesSniffTest.php b/tests/Sniffs/Namespaces/UnusedUsesSniffTest.php index 147a926a5..78250fddd 100644 --- a/tests/Sniffs/Namespaces/UnusedUsesSniffTest.php +++ b/tests/Sniffs/Namespaces/UnusedUsesSniffTest.php @@ -70,6 +70,10 @@ public function testUnusedUse(): void self::assertNoSniffError($report, 30); self::assertNoSniffError($report, 31); + // Used class inside a string or heredoc + self::assertNoSniffError($report, 31); + self::assertNoSniffError($report, 32); + self::assertNoSniffError($report, 91); } diff --git a/tests/Sniffs/Namespaces/data/unusedUses.php b/tests/Sniffs/Namespaces/data/unusedUses.php index 9f8fbcd51..4e100eaf9 100644 --- a/tests/Sniffs/Namespaces/data/unusedUses.php +++ b/tests/Sniffs/Namespaces/data/unusedUses.php @@ -29,6 +29,8 @@ use ClassWithStaticVariable; use ClassWithConstant; use function Psl\Type\null; +use InstantiableClass1; +use InstantiableClass2; class TestClass implements FirstInterface, SecondInterface { @@ -60,6 +62,11 @@ enum_type: EnumClass::VALUE(), echo "test {$wrapper->escape(ClassWithConstant::FOO)}"; + echo "{$_(new InstantiableClass1())}"; + echo <<