Skip to content

Commit de148ae

Browse files
AIlkivkukulich
authored andcommitted
Appended logic in ReferencedNameHelper for find names of class inside double quotes
1 parent db0f06a commit de148ae

File tree

5 files changed

+83
-1
lines changed

5 files changed

+83
-1
lines changed

SlevomatCodingStandard/Helpers/ReferencedNameHelper.php

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
use function array_values;
1010
use function count;
1111
use function in_array;
12+
use function is_array;
13+
use function token_get_all;
1214
use const T_ANON_CLASS;
1315
use const T_ARRAY;
1416
use const T_AS;
@@ -23,21 +25,25 @@
2325
use const T_CONST;
2426
use const T_DECLARE;
2527
use const T_DOUBLE_COLON;
28+
use const T_DOUBLE_QUOTED_STRING;
2629
use const T_ELLIPSIS;
2730
use const T_EXTENDS;
2831
use const T_FUNCTION;
2932
use const T_GOTO;
33+
use const T_HEREDOC;
3034
use const T_IMPLEMENTS;
3135
use const T_INSTANCEOF;
3236
use const T_NAMESPACE;
3337
use const T_NEW;
38+
use const T_NS_SEPARATOR;
3439
use const T_NULLABLE;
3540
use const T_NULLSAFE_OBJECT_OPERATOR;
3641
use const T_OBJECT_OPERATOR;
3742
use const T_OPEN_PARENTHESIS;
3843
use const T_OPEN_SHORT_ARRAY;
3944
use const T_OPEN_TAG;
4045
use const T_PARAM_NAME;
46+
use const T_STRING;
4147
use const T_TRAIT;
4248
use const T_TYPE_UNION;
4349
use const T_USE;
@@ -128,14 +134,32 @@ private static function createAllReferencedNames(File $phpcsFile, int $openTagPo
128134

129135
$beginSearchAtPointer = $openTagPointer + 1;
130136
$nameTokenCodes = TokenHelper::getNameTokenCodes();
131-
$tokens = $phpcsFile->getTokens();
137+
$nameTokenCodes[] = T_DOUBLE_QUOTED_STRING;
132138

139+
$tokens = $phpcsFile->getTokens();
133140
while (true) {
134141
$nameStartPointer = TokenHelper::findNext($phpcsFile, $nameTokenCodes, $beginSearchAtPointer);
135142
if ($nameStartPointer === null) {
136143
break;
137144
}
138145

146+
// Find referenced names inside double quotes string
147+
if (self::isNeedParsedContent($tokens[$nameStartPointer]['code'])) {
148+
$content = $tokens[$nameStartPointer]['content'];
149+
if (self::isNeedParsedContent($tokens[$nameStartPointer - 1]['code'])) {
150+
$content = '"' . $content;
151+
}
152+
if (self::isNeedParsedContent($tokens[$nameStartPointer + 1]['code'])) {
153+
$content .= '"';
154+
}
155+
$names = self::getReferencedNamesFromString($content);
156+
foreach ($names as $name) {
157+
$referencedNames[] = new ReferencedName($name, $nameStartPointer, $nameStartPointer, ReferencedName::TYPE_CLASS);
158+
}
159+
$beginSearchAtPointer = $nameStartPointer + 1;
160+
continue;
161+
}
162+
139163
// Attributes are parsed in specific method
140164
$attributeStartPointerBefore = TokenHelper::findPrevious($phpcsFile, T_ATTRIBUTE, $nameStartPointer - 1, $beginSearchAtPointer);
141165
if ($attributeStartPointerBefore !== null) {
@@ -435,4 +459,42 @@ private static function createAllReferencedNamesInAttributes(File $phpcsFile, in
435459
return $referencedNames;
436460
}
437461

462+
/**
463+
* @param int|string $code
464+
* @return bool
465+
*/
466+
private static function isNeedParsedContent($code): bool
467+
{
468+
return in_array($code, [T_DOUBLE_QUOTED_STRING, T_HEREDOC], true);
469+
}
470+
471+
/**
472+
* @param string $content
473+
* @return string[]
474+
*/
475+
private static function getReferencedNamesFromString(string $content): array
476+
{
477+
$referencedNames = [];
478+
$subTokens = token_get_all('<?php ' . $content);
479+
480+
foreach ($subTokens as $position => $token) {
481+
if (is_array($token) && $token[0] === T_DOUBLE_COLON) {
482+
$referencedName = '';
483+
$tmpPosition = $position - 1;
484+
while (true) {
485+
if (!is_array($subTokens[$tmpPosition]) || !in_array($subTokens[$tmpPosition][0], [T_NS_SEPARATOR, T_STRING], true)) {
486+
break;
487+
}
488+
489+
$referencedName = $subTokens[$tmpPosition][1] . $referencedName;
490+
$tmpPosition--;
491+
}
492+
493+
$referencedNames[] = $referencedName;
494+
}
495+
}
496+
497+
return $referencedNames;
498+
}
499+
438500
}

tests/Helpers/ReferencedNameHelperTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public function testGetAllReferencedNames(): void
6767
['STR_PAD_RIGHT', false, true],
6868
['EnumType', false, false],
6969
['UrlGeneratorInterface', false, false],
70+
['ClassInDoubleQuote', false, false],
7071
];
7172

7273
$names = ReferencedNameHelper::getAllReferencedNames($phpcsFile, 0);

tests/Helpers/data/lotsOfReferencedNames.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,17 @@ public function generateRoute($router): string
176176
], referenceType: UrlGeneratorInterface::RELATIVE_PATH);
177177
}
178178
}
179+
180+
"foo {$db->quote(ClassInDoubleQuote::SOME_CONSTANT)}";
181+
"foo $db->quote(FakeClassInDoubleQuote::SOME_CONSTANT)";
182+
183+
$script .= "// @see \Foo\Bar::func()
184+
\$hasDefaultValue = $hasDefaultValue;
185+
/** @var \Foo\Test\Bla\Whatever */
186+
";
187+
return "
188+
/** @var \\Generated\\Test\\Ide\\AutoCompletion \$locator */
189+
\$locator = \\Foo\\Test\\Kernel\\Locator::getInstance();
190+
$objName = \$locator->"
191+
. '()->entity'
192+
. $this->getObjectClassName() . '();';

tests/Sniffs/Namespaces/UnusedUsesSniffTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ public function testUnusedUse(): void
6666

6767
// Used class with static variable
6868
self::assertNoSniffError($report, 29);
69+
70+
self::assertNoSniffError($report, 30);
6971
}
7072

7173
public function testUnusedUseWithMultipleNamespaces(): void

tests/Sniffs/Namespaces/data/unusedUses.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use EnumClass;
2828
use ReferenceClass;
2929
use ClassWithStaticVariable;
30+
use ClassWithConstant;
3031

3132
class TestClass implements FirstInterface, SecondInterface
3233
{
@@ -56,6 +57,8 @@ enum_type: EnumClass::VALUE(),
5657
reference_type: ReferenceClass::SOME_CONSTANT
5758
);
5859

60+
echo "test {$wrapper->escape(ClassWithConstant::FOO)}";
61+
5962
return new NewObject();
6063
}
6164

0 commit comments

Comments
 (0)