Skip to content

Commit 6f57667

Browse files
committed
Fixed FQN resolving for partial uses
1 parent 8c99293 commit 6f57667

File tree

8 files changed

+325
-100
lines changed

8 files changed

+325
-100
lines changed

SlevomatCodingStandard/Helpers/NamespaceHelper.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,28 @@ public static function resolveName(
9292
int $currentPointer
9393
): string
9494
{
95-
if (!self::isFullyQualifiedName($nameAsReferencedInFile)) {
96-
$normalizedName = UseStatement::normalizedNameAsReferencedInFile(self::normalizeToCanonicalName($nameAsReferencedInFile));
95+
if (self::isFullyQualifiedName($nameAsReferencedInFile)) {
96+
return $nameAsReferencedInFile;
97+
}
98+
99+
$normalizedName = UseStatement::normalizedNameAsReferencedInFile(self::normalizeToCanonicalName($nameAsReferencedInFile));
97100

98-
if (isset($useStatements[$normalizedName])) {
99-
return sprintf('%s%s', self::NAMESPACE_SEPARATOR, $useStatements[$normalizedName]->getFullyQualifiedTypeName());
100-
}
101+
if (isset($useStatements[$normalizedName])) {
102+
return sprintf('%s%s', self::NAMESPACE_SEPARATOR, $useStatements[$normalizedName]->getFullyQualifiedTypeName());
103+
}
101104

102-
$namespaceName = self::findCurrentNamespaceName($phpcsFile, $currentPointer);
103-
return sprintf('%s%s%s', $namespaceName ?? '', self::NAMESPACE_SEPARATOR, $nameAsReferencedInFile);
105+
$nameParts = self::getNameParts($nameAsReferencedInFile);
106+
$normalizedNameFirstPart = UseStatement::normalizedNameAsReferencedInFile($nameParts[0]);
107+
if (count($nameParts) > 1 && isset($useStatements[$normalizedNameFirstPart])) {
108+
return sprintf('%s%s%s%s', self::NAMESPACE_SEPARATOR, $useStatements[$normalizedNameFirstPart]->getFullyQualifiedTypeName(), self::NAMESPACE_SEPARATOR, implode(self::NAMESPACE_SEPARATOR, array_slice($nameParts, 1)));
104109
}
105110

106-
return $nameAsReferencedInFile;
111+
$name = sprintf('%s%s', self::NAMESPACE_SEPARATOR, $nameAsReferencedInFile);
112+
$namespaceName = self::findCurrentNamespaceName($phpcsFile, $currentPointer);
113+
if ($namespaceName !== null) {
114+
$name = sprintf('%s%s%s', self::NAMESPACE_SEPARATOR, $namespaceName, $name);
115+
}
116+
return $name;
107117
}
108118

109119
}

SlevomatCodingStandard/Helpers/TypeHintHelper.php

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,25 +61,10 @@ public static function getFullyQualifiedTypeHint(\PHP_CodeSniffer_File $phpcsFil
6161
{
6262
if (self::isSimpleTypeHint($typeHint)) {
6363
return self::convertLongSimpleTypeHintToShort($typeHint);
64-
} elseif (NamespaceHelper::isFullyQualifiedName($typeHint)) {
65-
return $typeHint;
6664
}
6765

68-
$canonicalQualifiedTypeHint = $typeHint;
69-
7066
$useStatements = UseStatementHelper::getUseStatements($phpcsFile, $phpcsFile->findPrevious(T_OPEN_TAG, $pointer));
71-
$normalizedTypeHint = UseStatement::normalizedNameAsReferencedInFile($typeHint);
72-
if (isset($useStatements[$normalizedTypeHint])) {
73-
$useStatement = $useStatements[$normalizedTypeHint];
74-
$canonicalQualifiedTypeHint = $useStatement->getFullyQualifiedTypeName();
75-
} else {
76-
$fileNamespace = NamespaceHelper::findCurrentNamespaceName($phpcsFile, $pointer);
77-
if ($fileNamespace !== null) {
78-
$canonicalQualifiedTypeHint = sprintf('%s%s%s', $fileNamespace, NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint);
79-
}
80-
}
81-
82-
return sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $canonicalQualifiedTypeHint);
67+
return NamespaceHelper::resolveName($phpcsFile, $typeHint, $useStatements, $pointer);
8368
}
8469

8570
}

tests/Helpers/TypeHintHelperTest.php

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ public function testConvertLongSimpleTypeHintToShort(string $long, string $short
9191
$this->assertSame($short, TypeHintHelper::convertLongSimpleTypeHintToShort($long));
9292
}
9393

94-
public function testFunctionAnnotationTypeHintWithNamespace()
94+
public function testFunctionReturnAnnotationWithNamespace()
9595
{
9696
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithNamespace.php');
9797

98-
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithAnnotation');
98+
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithReturnAnnotation');
9999
$returnAnnotation = FunctionHelper::findReturnAnnotation($codeSnifferFile, $functionPointer);
100100
$this->assertSame('void', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $returnAnnotation->getContent()));
101101
}
@@ -109,11 +109,30 @@ public function testFunctionReturnTypeHintWithNamespace()
109109
$this->assertSame('\FooNamespace\FooClass', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $returnTypeHint->getTypeHint()));
110110
}
111111

112-
public function testMethodAnnotationTypeHintWithNamespace()
112+
public function testFunctionParameterAnnotationWithNamespace()
113113
{
114114
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithNamespace.php');
115115

116-
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithAnnotation');
116+
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithParameterAnnotation');
117+
$parameterAnnotation = FunctionHelper::getParametersAnnotations($codeSnifferFile, $functionPointer)[0];
118+
$parameterTypeHint = preg_split('~\\s+~', $parameterAnnotation->getContent())[0];
119+
$this->assertSame('\Doctrine\Common\Collections\ArrayCollection', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $parameterTypeHint));
120+
}
121+
122+
public function testFunctionParameterTypeHintWithNamespace()
123+
{
124+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithNamespace.php');
125+
126+
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithParameterTypeHint');
127+
$parameterTypeHint = FunctionHelper::getParametersTypeHints($codeSnifferFile, $functionPointer)['$parameter'];
128+
$this->assertSame('\Doctrine\Common\Collections\ArrayCollection', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $parameterTypeHint->getTypeHint()));
129+
}
130+
131+
public function testMethodReturnAnnotationWithNamespace()
132+
{
133+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithNamespace.php');
134+
135+
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithReturnAnnotation');
117136
$returnAnnotation = FunctionHelper::findReturnAnnotation($codeSnifferFile, $methodPointer);
118137
$this->assertSame('\FooNamespace\FooClass', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $returnAnnotation->getContent()));
119138
}
@@ -127,11 +146,30 @@ public function testMethodReturnTypeHintWithNamespace()
127146
$this->assertSame('bool', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $returnTypeHint->getTypeHint()));
128147
}
129148

130-
public function testFunctionAnnotationTypeHintWithoutNamespace()
149+
public function testMethodParameterAnnotationWithNamespace()
150+
{
151+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithNamespace.php');
152+
153+
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithParameterAnnotation');
154+
$parameterAnnotation = FunctionHelper::getParametersAnnotations($codeSnifferFile, $methodPointer)[0];
155+
$parameterTypeHint = preg_split('~\\s+~', $parameterAnnotation->getContent())[0];
156+
$this->assertSame('\Doctrine\ORM\Mapping\Id', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $parameterTypeHint));
157+
}
158+
159+
public function testMethodParameterTypeHintWithNamespace()
160+
{
161+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithNamespace.php');
162+
163+
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithParameterTypeHint');
164+
$parameterTypeHint = FunctionHelper::getParametersTypeHints($codeSnifferFile, $methodPointer)['$parameter'];
165+
$this->assertSame('\Doctrine\ORM\Mapping\Id', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $parameterTypeHint->getTypeHint()));
166+
}
167+
168+
public function testFunctionReturnAnnotationWithoutNamespace()
131169
{
132170
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithoutNamespace.php');
133171

134-
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithAnnotation');
172+
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithReturnAnnotation');
135173
$returnAnnotation = FunctionHelper::findReturnAnnotation($codeSnifferFile, $functionPointer);
136174
$this->assertSame('void', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $returnAnnotation->getContent()));
137175
}
@@ -145,11 +183,30 @@ public function testFunctionReturnTypeHintWithoutNamespace()
145183
$this->assertSame('\FooClass', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $returnTypeHint->getTypeHint()));
146184
}
147185

148-
public function testMethodAnnotationTypeHintWithoutNamespace()
186+
public function testFunctionParameterAnnotationWithoutNamespace()
149187
{
150188
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithoutNamespace.php');
151189

152-
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithAnnotation');
190+
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithParameterAnnotation');
191+
$parameterAnnotation = FunctionHelper::getParametersAnnotations($codeSnifferFile, $functionPointer)[0];
192+
$parameterTypeHint = preg_split('~\\s+~', $parameterAnnotation->getContent())[0];
193+
$this->assertSame('\Doctrine\Common\Collections\ArrayCollection', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $parameterTypeHint));
194+
}
195+
196+
public function testFunctionParameterTypeHintWithoutNamespace()
197+
{
198+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithoutNamespace.php');
199+
200+
$functionPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooFunctionWithParameterTypeHint');
201+
$parameterTypeHint = FunctionHelper::getParametersTypeHints($codeSnifferFile, $functionPointer)['$parameter'];
202+
$this->assertSame('\Doctrine\Common\Collections\ArrayCollection', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $functionPointer, $parameterTypeHint->getTypeHint()));
203+
}
204+
205+
public function testMethodReturnAnnotationWithoutNamespace()
206+
{
207+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithoutNamespace.php');
208+
209+
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithReturnAnnotation');
153210
$returnAnnotation = FunctionHelper::findReturnAnnotation($codeSnifferFile, $methodPointer);
154211
$this->assertSame('\FooClass', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $returnAnnotation->getContent()));
155212
}
@@ -163,4 +220,23 @@ public function testMethodReturnTypeHintWithoutNamespace()
163220
$this->assertSame('bool', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $returnTypeHint->getTypeHint()));
164221
}
165222

223+
public function testMethodParameterAnnotationWithoutNamespace()
224+
{
225+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithoutNamespace.php');
226+
227+
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithParameterAnnotation');
228+
$parameterAnnotation = FunctionHelper::getParametersAnnotations($codeSnifferFile, $methodPointer)[0];
229+
$parameterTypeHint = preg_split('~\\s+~', $parameterAnnotation->getContent())[0];
230+
$this->assertSame('\Doctrine\ORM\Mapping\Id', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $parameterTypeHint));
231+
}
232+
233+
public function testMethodParameterTypeHintWithoutNamespace()
234+
{
235+
$codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/typeHintWithoutNamespace.php');
236+
237+
$methodPointer = $this->findFunctionPointerByName($codeSnifferFile, 'fooMethodWithParameterTypeHint');
238+
$parameterTypeHint = FunctionHelper::getParametersTypeHints($codeSnifferFile, $methodPointer)['$parameter'];
239+
$this->assertSame('\Doctrine\ORM\Mapping\Id', TypeHintHelper::getFullyQualifiedTypeHint($codeSnifferFile, $methodPointer, $parameterTypeHint->getTypeHint()));
240+
}
241+
166242
}

tests/Helpers/data/typeHintWithNamespace.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
namespace FooNamespace;
44

5+
use Doctrine;
6+
use Doctrine\ORM\Mapping as ORM;
7+
58
/**
69
* @return void
710
*/
8-
function fooFunctionWithAnnotation()
11+
function fooFunctionWithReturnAnnotation()
912
{
1013

1114
}
@@ -15,13 +18,26 @@ function fooFunctionWithReturnTypeHint(): FooClass
1518
return new FooClass();
1619
}
1720

21+
/**
22+
* @param Doctrine\Common\Collections\ArrayCollection $parameter
23+
*/
24+
function fooFunctionWithParameterAnnotation($parameter)
25+
{
26+
27+
}
28+
29+
function fooFunctionWithParameterTypeHint(Doctrine\Common\Collections\ArrayCollection $parameter)
30+
{
31+
32+
}
33+
1834
class FooClass
1935
{
2036

2137
/**
2238
* @return FooClass
2339
*/
24-
public function fooMethodWithAnnotation()
40+
public function fooMethodWithReturnAnnotation()
2541
{
2642
return new self();
2743
}
@@ -32,4 +48,17 @@ public function fooMethodWithReturnTypeHint(): bool
3248
return true;
3349
}
3450

51+
/**
52+
* @param ORM\Id $parameter
53+
*/
54+
public function fooMethodWithParameterAnnotation($parameter)
55+
{
56+
57+
}
58+
59+
public function fooMethodWithParameterTypeHint(ORM\Id $parameter)
60+
{
61+
62+
}
63+
3564
}

tests/Helpers/data/typeHintWithoutNamespace.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
<?php
22

3+
use Doctrine;
4+
use Doctrine\ORM\Mapping as ORM;
5+
36
/**
47
* @return void
58
*/
6-
function fooFunctionWithAnnotation()
9+
function fooFunctionWithReturnAnnotation()
710
{
811

912
}
@@ -13,13 +16,26 @@ function fooFunctionWithReturnTypeHint(): FooClass
1316
return new FooClass();
1417
}
1518

19+
/**
20+
* @param Doctrine\Common\Collections\ArrayCollection $parameter
21+
*/
22+
function fooFunctionWithParameterAnnotation($parameter)
23+
{
24+
25+
}
26+
27+
function fooFunctionWithParameterTypeHint(Doctrine\Common\Collections\ArrayCollection $parameter)
28+
{
29+
30+
}
31+
1632
class FooClass
1733
{
1834

1935
/**
2036
* @return FooClass
2137
*/
22-
public function fooMethodWithAnnotation()
38+
public function fooMethodWithReturnAnnotation()
2339
{
2440
return new self();
2541
}
@@ -30,4 +46,17 @@ public function fooMethodWithReturnTypeHint(): bool
3046
return true;
3147
}
3248

49+
/**
50+
* @param ORM\Id $parameter
51+
*/
52+
public function fooMethodWithParameterAnnotation($parameter)
53+
{
54+
55+
}
56+
57+
public function fooMethodWithParameterTypeHint(ORM\Id $parameter)
58+
{
59+
60+
}
61+
3362
}

0 commit comments

Comments
 (0)