|
14 | 14 |
|
15 | 15 | final class StaticMethodsFixer extends AbstractFixer |
16 | 16 | { |
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'; |
36 | 18 |
|
37 | 19 | public function getDefinition(): FixerDefinitionInterface |
38 | 20 | { |
39 | 21 | 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 . ' .', |
46 | 23 | [ |
47 | 24 | new CodeSample( |
48 | 25 | <<<'PHP' |
49 | 26 | <?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 |
52 | 37 | { |
53 | | - return SomeClass::get("something"); |
| 38 | + return [['data']]; |
54 | 39 | } |
55 | 40 | } |
56 | 41 |
|
@@ -87,55 +72,71 @@ public function isCandidate(Tokens $tokens): bool |
87 | 72 | protected function applyFix(SplFileInfo $file, Tokens $tokens): void |
88 | 73 | { |
89 | 74 | 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 | + } |
113 | 109 | } |
114 | 110 | } |
115 | | - } |
116 | | - } |
117 | 111 |
|
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) { |
133 | 113 | continue; |
134 | 114 | } |
135 | 115 |
|
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 | + } |
138 | 121 |
|
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 | + } |
140 | 140 | } |
| 141 | + |
141 | 142 | } |
0 commit comments