Skip to content

Commit 72566b6

Browse files
grongorondrejmirtes
authored andcommitted
Fix "incorrect case" error when using trait aliases
This fixes a bug in the PHP scripting engine, which causes Reflection API to return the incorrect case for aliased methods when traits are nested.
1 parent 768b459 commit 72566b6

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

src/Reflection/Php/PhpMethodReflection.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,43 @@ public function isStatic(): bool
106106

107107
public function getName(): string
108108
{
109-
return $this->reflection->getName();
109+
$name = $this->reflection->getName();
110+
$lowercaseName = strtolower($name);
111+
if ($lowercaseName === $name) {
112+
// fix for https://bugs.php.net/bug.php?id=74939
113+
foreach ($this->getDeclaringClass()->getNativeReflection()->getTraitAliases() as $traitTarget) {
114+
$correctName = $this->getMethodNameWithCorrectCase($name, $traitTarget);
115+
if ($correctName !== null) {
116+
$name = $correctName;
117+
break;
118+
}
119+
}
120+
}
121+
122+
return $name;
123+
}
124+
125+
/**
126+
* @param string $lowercaseMethodName
127+
* @param string $traitTarget
128+
* @return string|null
129+
*/
130+
private function getMethodNameWithCorrectCase(string $lowercaseMethodName, string $traitTarget)
131+
{
132+
list ($trait, $method) = explode('::', $traitTarget);
133+
$traitReflection = $this->broker->getClass($trait)->getNativeReflection();
134+
foreach ($traitReflection->getTraitAliases() as $methodAlias => $traitTarget) {
135+
if ($lowercaseMethodName === strtolower($methodAlias)) {
136+
return $methodAlias;
137+
}
138+
139+
$correctName = $this->getMethodNameWithCorrectCase($lowercaseMethodName, $traitTarget);
140+
if ($correctName !== null) {
141+
return $correctName;
142+
}
143+
}
144+
145+
return null;
110146
}
111147

112148
/**

tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ public function testCallTraitMethods()
259259
]);
260260
}
261261

262+
public function testCallTraitOverridenMethods()
263+
{
264+
$this->checkThisOnly = false;
265+
$this->checkNullables = true;
266+
$this->analyse([__DIR__ . '/data/call-trait-overridden-methods.php'], []);
267+
}
268+
262269
public function testCallInterfaceMethods()
263270
{
264271
$this->checkThisOnly = false;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace CallTraitOverriddenMethods;
4+
5+
trait TraitA {
6+
function sameName() {}
7+
}
8+
9+
trait TraitB {
10+
use TraitA {
11+
sameName as someOtherName;
12+
}
13+
function sameName() {
14+
$this->someOtherName();
15+
}
16+
}
17+
18+
trait TraitC {
19+
use TraitB {
20+
sameName as YetAnotherName;
21+
}
22+
function sameName()
23+
{
24+
$this->YetAnotherName();
25+
}
26+
}
27+
28+
class SomeClass {
29+
use TraitC {
30+
sameName as wowSoManyNames;
31+
}
32+
33+
function sameName()
34+
{
35+
$this->wowSoManyNames();
36+
}
37+
}

0 commit comments

Comments
 (0)