Skip to content

Commit 9b83481

Browse files
authored
StringableInterfaceFixer - fix for imported from global namespace (#783)
1 parent f698e08 commit 9b83481

File tree

3 files changed

+77
-8
lines changed

3 files changed

+77
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Latest stable version](https://img.shields.io/packagist/v/kubawerlos/php-cs-fixer-custom-fixers.svg?label=current%20version)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers)
44
[![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net)
55
[![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE)
6-
![Tests](https://img.shields.io/badge/tests-3413-brightgreen.svg)
6+
![Tests](https://img.shields.io/badge/tests-3417-brightgreen.svg)
77
[![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers)
88

99
[![CI Status](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/workflows/CI/badge.svg?branch=main)](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions)

src/Fixer/StringableInterfaceFixer.php

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public function isRisky(): bool
5555

5656
public function fix(\SplFileInfo $file, Tokens $tokens): void
5757
{
58-
$isNamespaced = false;
58+
$namespaceStartIndex = null;
5959

6060
for ($index = 1; $index < $tokens->count(); $index++) {
6161
if ($tokens[$index]->isGivenKind(\T_NAMESPACE)) {
62-
$isNamespaced = true;
62+
$namespaceStartIndex = $index;
6363
continue;
6464
}
6565

@@ -76,7 +76,7 @@ public function fix(\SplFileInfo $file, Tokens $tokens): void
7676
continue;
7777
}
7878

79-
$this->addStringableInterface($tokens, $index, $isNamespaced);
79+
$this->addStringableInterface($tokens, $index, $namespaceStartIndex);
8080
}
8181
}
8282

@@ -101,7 +101,7 @@ private function doesHaveToStringMethod(Tokens $tokens, int $classStartIndex, in
101101
return false;
102102
}
103103

104-
private function addStringableInterface(Tokens $tokens, int $classIndex, bool $isNamespaced): void
104+
private function addStringableInterface(Tokens $tokens, int $classIndex, ?int $namespaceStartIndex): void
105105
{
106106
$implementsIndex = $tokens->getNextTokenOfKind($classIndex, ['{', [\T_IMPLEMENTS]]);
107107
\assert(\is_int($implementsIndex));
@@ -126,7 +126,7 @@ private function addStringableInterface(Tokens $tokens, int $classIndex, bool $i
126126

127127
$implementsEndIndex = $tokens->getNextTokenOfKind($implementsIndex, ['{']);
128128
\assert(\is_int($implementsEndIndex));
129-
if ($this->isStringableAlreadyUsed($tokens, $implementsIndex + 1, $implementsEndIndex - 1, $isNamespaced)) {
129+
if ($this->isStringableAlreadyUsed($tokens, $implementsIndex + 1, $implementsEndIndex - 1, $namespaceStartIndex)) {
130130
return;
131131
}
132132

@@ -144,7 +144,7 @@ private function addStringableInterface(Tokens $tokens, int $classIndex, bool $i
144144
);
145145
}
146146

147-
private function isStringableAlreadyUsed(Tokens $tokens, int $implementsStartIndex, int $implementsEndIndex, bool $isNamespaced): bool
147+
private function isStringableAlreadyUsed(Tokens $tokens, int $implementsStartIndex, int $implementsEndIndex, ?int $namespaceStartIndex): bool
148148
{
149149
for ($index = $implementsStartIndex; $index < $implementsEndIndex; $index++) {
150150
if (!$tokens[$index]->equals([\T_STRING, 'Stringable'], false)) {
@@ -162,9 +162,35 @@ private function isStringableAlreadyUsed(Tokens $tokens, int $implementsStartInd
162162
return true;
163163
}
164164
} else {
165-
if (!$isNamespaced) {
165+
if ($namespaceStartIndex === null) {
166166
return true;
167167
}
168+
if ($this->isStringableImported($tokens, $namespaceStartIndex, $index)) {
169+
return true;
170+
}
171+
}
172+
}
173+
174+
return false;
175+
}
176+
177+
private function isStringableImported(Tokens $tokens, int $startIndex, int $endIndex): bool
178+
{
179+
for ($index = $startIndex; $index < $endIndex; $index++) {
180+
if (!$tokens[$index]->equals([\T_STRING, 'Stringable'], false)) {
181+
continue;
182+
}
183+
184+
$useIndex = $tokens->getPrevMeaningfulToken($index);
185+
\assert(\is_int($useIndex));
186+
187+
if ($tokens[$useIndex]->isGivenKind(\T_NS_SEPARATOR)) {
188+
$useIndex = $tokens->getPrevMeaningfulToken($useIndex);
189+
\assert(\is_int($useIndex));
190+
}
191+
192+
if ($tokens[$useIndex]->isGivenKind(\T_USE)) {
193+
return true;
168194
}
169195
}
170196

tests/Fixer/StringableInterfaceFixerTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,32 @@ public static function provideFixCases(): iterable
4444
yield ['<?php class Foo implements Stringable { public function __toString() { return "Foo"; } }'];
4545
yield ['<?php class Foo implements \Stringable { public function __toString() { return "Foo"; } }'];
4646

47+
yield ['<?php
48+
namespace Foo;
49+
use Stringable;
50+
class Bar implements Stringable {
51+
public function __toString() { return ""; }
52+
}
53+
'];
54+
55+
yield ['<?php
56+
namespace Foo;
57+
use \Stringable;
58+
class Bar implements Stringable {
59+
public function __toString() { return ""; }
60+
}
61+
'];
62+
63+
yield ['<?php
64+
namespace Foo;
65+
use Bar;
66+
use STRINGABLE;
67+
use Baz;
68+
class Qux implements Stringable {
69+
public function __toString() { return ""; }
70+
}
71+
'];
72+
4773
yield ['<?php class Foo {
4874
public function toString() {
4975
function () { return 0; };
@@ -155,6 +181,23 @@ public function __TOSTRING() { return "Foo"; }
155181
',
156182
];
157183

184+
yield [
185+
'<?php
186+
namespace Foo;
187+
use Bar;
188+
class Baz implements Stringable, \Stringable {
189+
public function __toString() { return ""; }
190+
}
191+
',
192+
'<?php
193+
namespace Foo;
194+
use Bar;
195+
class Baz implements Stringable {
196+
public function __toString() { return ""; }
197+
}
198+
',
199+
];
200+
158201
yield [
159202
'<?php new class implements \Stringable {
160203
public function __construct() {}

0 commit comments

Comments
 (0)