Skip to content

Commit 8dcb596

Browse files
authored
Merge pull request #46 from zalnora/master
Fix StaticMethodsFixer to align with PhpBasic convention: Static methods
2 parents 2471ac6 + d9ece7c commit 8dcb596

File tree

3 files changed

+312
-134
lines changed

3 files changed

+312
-134
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ Semantic Versioning is maintained only for the following:
1111
The fixers themselves can change their behavior on any update.
1212
New fixers could be added with minor releases, this would require changes in configuration if migration mode is used.
1313

14+
## 3.0.3
15+
16+
### Fixed
17+
- StaticMethodsFixer to align with PhpBasic convention "Static methods".
18+
1419
## 3.0.2
1520

1621
### Changed

src/Fixer/PhpBasic/Feature/StaticMethodsFixer.php

Lines changed: 72 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,43 +14,28 @@
1414

1515
final class StaticMethodsFixer extends AbstractFixer
1616
{
17-
public const CONVENTION = 'PhpBasic convention 3.11: Static function must return only "self" or "static" constants';
18-
19-
private array $validTokens;
20-
21-
public function __construct()
22-
{
23-
parent::__construct();
24-
25-
$this->validTokens = [
26-
T_COMMENT,
27-
T_STATIC,
28-
T_STRING,
29-
T_DOUBLE_COLON,
30-
T_RETURN,
31-
T_DOUBLE_ARROW,
32-
T_WHITESPACE,
33-
T_VARIABLE,
34-
];
35-
}
17+
public const CONVENTION = 'PhpBasic convention: Static methods, https://github.com/paysera/php-style-guide?tab=readme-ov-file#static-methods';
3618

3719
public function getDefinition(): FixerDefinitionInterface
3820
{
3921
return new FixerDefinition(
40-
<<<'TEXT'
41-
We do use static methods only in these cases:
42-
* to create an entity for fluent interface, if PHP version in the project is lower than 5.4.
43-
We use (new Entity())->set(\'a\') in 5.4 or above
44-
* to give available values for some field of an entity, used in validation.
45-
TEXT,
22+
self::CONVENTION . ' .',
4623
[
4724
new CodeSample(
4825
<<<'PHP'
4926
<?php
50-
class Sample {
51-
public static function someFunction()
27+
class MyTest {
28+
/**
29+
* @dataProvider getCases
30+
*/
31+
public function test(): void
32+
{
33+
$this->assertTrue(true);
34+
}
35+
36+
public function getCases(): array
5237
{
53-
return SomeClass::get("something");
38+
return [['data']];
5439
}
5540
}
5641

@@ -87,55 +72,71 @@ public function isCandidate(Tokens $tokens): bool
8772
protected function applyFix(SplFileInfo $file, Tokens $tokens): void
8873
{
8974
foreach ($tokens as $key => $token) {
90-
$functionIndex = $tokens->getNextMeaningfulToken($key);
91-
$functionNameIndex = $functionIndex ? $tokens->getNextMeaningfulToken($functionIndex) : null;
92-
93-
if (
94-
$token->isGivenKind(T_STATIC)
95-
&& $tokens[$functionIndex]->isGivenKind(T_FUNCTION)
96-
&& $tokens[$functionNameIndex]->isGivenKind(T_STRING)
97-
) {
98-
$curlyBraceStartIndex = $tokens->getNextTokenOfKind($key, ['{']);
99-
$curlyBraceEndIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $curlyBraceStartIndex);
100-
if (
101-
!$this->isStaticMethodValid($tokens, $curlyBraceStartIndex, $curlyBraceEndIndex)
102-
&& !$tokens[$curlyBraceStartIndex - 2]->isGivenKind(T_COMMENT)
103-
) {
104-
$tokens->insertSlices([
105-
($curlyBraceStartIndex - 1) => [
106-
new Token([T_WHITESPACE, ' ']),
107-
new Token([
108-
T_COMMENT,
109-
'// TODO: "' . $tokens[$functionNameIndex]->getContent() . '" - ' . self::CONVENTION,
110-
]),
111-
],
112-
]);
75+
if (!$token->isGivenKind(T_FUNCTION)) {
76+
continue;
77+
}
78+
79+
$functionNameIndex = $tokens->getNextMeaningfulToken($key);
80+
if (!$functionNameIndex || !$tokens[$functionNameIndex]->isGivenKind(T_STRING)) {
81+
continue;
82+
}
83+
84+
$functionName = $tokens[$functionNameIndex]->getContent();
85+
86+
// Check if this method is referenced as a data provider
87+
$isDataProvider = false;
88+
for ($i = 0; $i < count($tokens); $i++) {
89+
if ($tokens[$i]->isGivenKind(T_DOC_COMMENT)) {
90+
$docComment = $tokens[$i]->getContent();
91+
if (strpos($docComment, '@dataProvider ' . $functionName) !== false) {
92+
$isDataProvider = true;
93+
break;
94+
}
95+
}
96+
97+
// Check for PHP 8 attributes if available
98+
if (PHP_VERSION_ID >= 80000 && defined('T_ATTRIBUTE')) {
99+
if ($tokens[$i]->isGivenKind(T_ATTRIBUTE)) {
100+
$attributeEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ATTRIBUTE, $i);
101+
$attributeContent = $tokens->generatePartialCode($i, $attributeEnd);
102+
103+
// Match DataProvider('methodName') or DataProvider("methodName")
104+
if (preg_match('/DataProvider\([\'"]' . preg_quote($functionName, '/') . '[\'"]\)/', $attributeContent)) {
105+
$isDataProvider = true;
106+
break;
107+
}
108+
}
113109
}
114110
}
115-
}
116-
}
117111

118-
/**
119-
* @param Tokens $tokens
120-
* @param int $startIndex
121-
* @param int $endIndex
122-
* @return bool
123-
*/
124-
private function isStaticMethodValid(Tokens $tokens, $startIndex, $endIndex): bool
125-
{
126-
for ($i = $startIndex + 1; $i < $endIndex; $i++) {
127-
if (
128-
$tokens[$i]->isGivenKind($this->validTokens)
129-
|| $tokens[$i]->equalsAny([',', ';'])
130-
|| $tokens[$i]->getContent() === '['
131-
|| $tokens[$i]->getContent() === ']'
132-
) {
112+
if (!$isDataProvider) {
133113
continue;
134114
}
135115

136-
return false;
137-
}
116+
// Check if method is static
117+
$prevIndex = $tokens->getPrevMeaningfulToken($key);
118+
if ($prevIndex && $tokens[$prevIndex]->isGivenKind(T_STATIC)) {
119+
continue;
120+
}
138121

139-
return true;
122+
$nextTokenIndex = $tokens->getNextTokenOfKind($key, ['{']);
123+
if ($nextTokenIndex === null) {
124+
continue;
125+
}
126+
127+
// Add comment if not already present
128+
if (!$tokens[$nextTokenIndex - 2]->isGivenKind(T_COMMENT)) {
129+
$tokens->insertSlices([
130+
($nextTokenIndex - 1) => [
131+
new Token([T_WHITESPACE, ' ']),
132+
new Token([
133+
T_COMMENT,
134+
'// TODO: "' . $functionName . '" - ' . self::CONVENTION,
135+
]),
136+
],
137+
]);
138+
}
139+
}
140140
}
141+
141142
}

0 commit comments

Comments
 (0)