Skip to content

Commit 46cd765

Browse files
committed
ReferencedNameHelper - search in complex annotations (e. g. \Foo|\Bar)
1 parent 1a53b21 commit 46cd765

File tree

7 files changed

+92
-23
lines changed

7 files changed

+92
-23
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace SlevomatCodingStandard\Helpers;
4+
5+
class ReferencedName
6+
{
7+
8+
/** @var string */
9+
private $nameAsReferencedInFile;
10+
11+
/** @var integer */
12+
private $pointer;
13+
14+
/**
15+
* @param string $nameAsReferencedInFile
16+
* @param integer $pointer
17+
*/
18+
public function __construct($nameAsReferencedInFile, $pointer)
19+
{
20+
$this->nameAsReferencedInFile = $nameAsReferencedInFile;
21+
$this->pointer = $pointer;
22+
}
23+
/**
24+
* @return string
25+
*/
26+
public function getNameAsReferencedInFile()
27+
{
28+
return $this->nameAsReferencedInFile;
29+
}
30+
31+
/**
32+
* @return integer
33+
*/
34+
public function getPointer()
35+
{
36+
return $this->pointer;
37+
}
38+
39+
}

SlevomatCodingStandard/Helpers/ReferencedNameHelper.php

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ReferencedNameHelper
2929
* @param \PHP_CodeSniffer_File $phpcsFile
3030
* @param integer $openTagPointer
3131
* @param boolean $searchAnnotations
32-
* @return string[] referenced names, pointer(integer) => name(string)
32+
* @return \SlevomatCodingStandard\Helpers\ReferencedName[] referenced names
3333
*/
3434
public static function getAllReferencedNames(PHP_CodeSniffer_File $phpcsFile, $openTagPointer, $searchAnnotations = false)
3535
{
@@ -45,7 +45,7 @@ public static function getAllReferencedNames(PHP_CodeSniffer_File $phpcsFile, $o
4545
* @param \PHP_CodeSniffer_File $phpcsFile
4646
* @param integer $openTagPointer
4747
* @param boolean $searchAnnotations
48-
* @return string[] referenced names, pointer(integer) => name(string)
48+
* @return \SlevomatCodingStandard\Helpers\ReferencedName[] referenced names
4949
*/
5050
private static function createAllReferencedNames(PHP_CodeSniffer_File $phpcsFile, $openTagPointer, $searchAnnotations)
5151
{
@@ -61,17 +61,33 @@ private static function createAllReferencedNames(PHP_CodeSniffer_File $phpcsFile
6161
$searchTypes = array_merge($phpDocTypes, $searchTypes);
6262
}
6363

64-
$matchTypeInAnnotation = function ($annotation) {
64+
$types = [];
65+
66+
$matchTypesInAnnotation = function ($annotation, $nameStartPointer) use (&$types) {
6567
$annotation = trim($annotation, '@ ');
66-
if (preg_match('#^([a-zA-Z0-9\\\]+)#', $annotation, $matches) === 1) {
67-
return $matches[1];
68+
if (preg_match('#([a-zA-Z0-9|\[\]\\\]+)#', $annotation, $matches) > 0) {
69+
$referencedNames = array_filter(array_map(function ($name) {
70+
return trim($name, '[]');
71+
}, explode('|', $matches[1])), function ($match) {
72+
return !in_array($match, [
73+
'null',
74+
'self',
75+
'static',
76+
'mixed',
77+
'array',
78+
'string',
79+
'int',
80+
'integer',
81+
'bool',
82+
'boolean',
83+
], true);
84+
});
85+
foreach ($referencedNames as $name) {
86+
$types[] = new ReferencedName($name, $nameStartPointer);
87+
}
6888
}
69-
70-
return null;
7189
};
7290

73-
$types = [];
74-
7591
while (true) {
7692
$nameStartPointer = $phpcsFile->findNext($searchTypes, $beginSearchAtPointer);
7793
if ($nameStartPointer === false) {
@@ -89,16 +105,10 @@ private static function createAllReferencedNames(PHP_CodeSniffer_File $phpcsFile
89105
&& !StringHelper::startsWith($nameStartToken['content'], '@link')
90106
&& !StringHelper::startsWith($nameStartToken['content'], '@inherit')
91107
) {
92-
$matched = $matchTypeInAnnotation($nameStartToken['content']);
93-
if ($matched !== null) {
94-
$types[$nameStartPointer] = $matched;
95-
}
108+
$matchTypesInAnnotation($nameStartToken['content'], $nameStartPointer);
96109
}
97110
} elseif ($nameStartToken['code'] === T_DOC_COMMENT_STRING) {
98-
$matched = $matchTypeInAnnotation($nameStartToken['content']);
99-
if ($matched !== null) {
100-
$types[$nameStartPointer] = $matched;
101-
}
111+
$matchTypesInAnnotation($nameStartToken['content'], $nameStartPointer);
102112
}
103113

104114
$beginSearchAtPointer = $nameStartPointer + 1;
@@ -113,7 +123,7 @@ private static function createAllReferencedNames(PHP_CodeSniffer_File $phpcsFile
113123
);
114124
continue;
115125
}
116-
$types[$nameStartPointer] = TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer);
126+
$types[] = new ReferencedName(TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer), $nameStartPointer);
117127
$beginSearchAtPointer = $nameEndPointer + 1;
118128
}
119129
return $types;

SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedExceptionsSniff.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $openTagPointer)
5151
{
5252
$referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer);
5353
$useStatements = UseStatementHelper::getUseStatements($phpcsFile, $openTagPointer);
54-
foreach ($referencedNames as $pointer => $name) {
54+
foreach ($referencedNames as $referencedName) {
55+
$pointer = $referencedName->getPointer();
56+
$name = $referencedName->getNameAsReferencedInFile();
5557
$normalizedName = UseStatement::normalizedNameAsReferencedInFile($name);
5658
if (isset($useStatements[$normalizedName])) {
5759
$useStatement = $useStatements[$normalizedName];

SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $openTagPointer)
105105
{
106106
$tokens = $phpcsFile->getTokens();
107107
$referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer);
108-
foreach ($referencedNames as $pointer => $name) {
108+
foreach ($referencedNames as $referencedName) {
109+
$name = $referencedName->getNameAsReferencedInFile();
110+
$pointer = $referencedName->getPointer();
109111
if (NamespaceHelper::isFullyQualifiedName($name)) {
110112
if (
111113
(

SlevomatCodingStandard/Sniffs/Namespaces/UnusedUsesSniff.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ public function register()
3434
public function process(PHP_CodeSniffer_File $phpcsFile, $openTagPointer)
3535
{
3636
$unusedNames = UseStatementHelper::getUseStatements($phpcsFile, $openTagPointer);
37-
$types = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer, $this->searchAnnotations);
37+
$referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer, $this->searchAnnotations);
3838

39-
foreach ($types as $pointer => $name) {
39+
foreach ($referencedNames as $referencedName) {
40+
$name = $referencedName->getNameAsReferencedInFile();
41+
$pointer = $referencedName->getPointer();
4042
$nameParts = NamespaceHelper::getNameParts($name);
4143
$nameAsReferencedInFile = $nameParts[0];
4244
$normalizedNameAsReferencedInFile = UseStatement::normalizedNameAsReferencedInFile($nameAsReferencedInFile);

tests/Helpers/ReferencedNameHelperTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public function dataGetAllReferencedNames()
2626
'\ImplementedInterface',
2727
'ORM\Column',
2828
'Bar',
29+
'Lorem',
30+
'Ipsum',
31+
'Rasmus',
32+
'Lerdorf',
33+
'\Foo\BarBaz',
2934
'TypehintedName',
3035
'AnotherTypehintedName',
3136
'ClassInstance',
@@ -48,8 +53,11 @@ public function testGetAllReferencedNames(array $foundTypes, $searchAnnotations)
4853
$codeSnifferFile = $this->getCodeSnifferFile(
4954
__DIR__ . '/data/lotsOfReferencedNames.php'
5055
);
56+
5157
$names = ReferencedNameHelper::getAllReferencedNames($codeSnifferFile, 0, $searchAnnotations);
52-
$this->assertSame($foundTypes, array_values(array_unique($names)));
58+
$this->assertSame($foundTypes, array_values(array_unique(array_map(function (ReferencedName $name) {
59+
return $name->getNameAsReferencedInFile();
60+
}, $names))));
5361
}
5462

5563
public function testFindReferencedNameEndPointerOnNonReferencedName()

tests/Helpers/data/lotsOfReferencedNames.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ class FooClass extends \ExtendedClass implements \ImplementedInterface
1414
/** @var Bar */
1515
private $bar;
1616

17+
/** @var Lorem[]|Ipsum|null */
18+
private $baz;
19+
20+
/** @var Rasmus|Lerdorf[]|null|string|self|\Foo\BarBaz */
21+
private $barz;
22+
1723
/**
1824
* @param TypehintedName $foo
1925
* @param AnotherTypehintedName[] $bar

0 commit comments

Comments
 (0)