Skip to content

Commit c2fdcdf

Browse files
authored
Split ParamReturnAndVarTagMalformsFixer into single-task doc block rules (#86)
* split ParamReturnAndVarTagMalformsFixer into particular rules, each handling single job * README: drop deprecated rule mention from doc block section
1 parent 61675a1 commit c2fdcdf

72 files changed

Lines changed: 956 additions & 326 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ vendor/bin/ecs --fix
3838

3939
<br>
4040

41-
# 14 Rules to Keep Your Code Clean
41+
# 23 Rules to Keep Your Code Clean
4242

4343
## ArrayListItemNewlineFixer
4444

@@ -125,13 +125,17 @@ Each chain method call must be on own line
125125

126126
<br>
127127

128-
## ParamReturnAndVarTagMalformsFixer
128+
## Doc block malform rules
129129

130-
Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats. This single rule covers a wide range of docblock malforms:
130+
Single-task rules that each fix one kind of `@param`/`@return`/`@var` malform. They are registered together in the [`docblock` set](../config/sets/docblock.php) and all handle the `@phpstan-` and `@psalm-` prefixed variants of these tags.
131131

132-
- class: [`Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer`](../src/Fixer/Commenting/ParamReturnAndVarTagMalformsFixer.php)
132+
<br>
133+
134+
## AddMissingParamNameFixer
135+
136+
Add a missing variable name to a `@param` annotation
133137

134-
**Add a missing `@param` variable name**
138+
- class: [`Symplify\CodingStandard\Fixer\Commenting\AddMissingParamNameFixer`](../src/Fixer/Commenting/AddMissingParamNameFixer.php)
135139

136140
```diff
137141
/**
@@ -143,21 +147,60 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
143147
}
144148
```
145149

146-
**Reorder switched type and variable name**
150+
<br>
151+
152+
## AddMissingVarNameFixer
153+
154+
Add a missing variable name to an inline `@var` annotation
155+
156+
- class: [`Symplify\CodingStandard\Fixer\Commenting\AddMissingVarNameFixer`](../src/Fixer/Commenting/AddMissingVarNameFixer.php)
157+
158+
```diff
159+
-/** @var int */
160+
+/** @var int $value */
161+
$value = 1000;
162+
```
163+
164+
<br>
165+
166+
## DoubleAsteriskInlineVarFixer
167+
168+
Use a double asterisk `/**` doc block for an inline `@var` comment
169+
170+
- class: [`Symplify\CodingStandard\Fixer\Commenting\DoubleAsteriskInlineVarFixer`](../src/Fixer/Commenting/DoubleAsteriskInlineVarFixer.php)
171+
172+
```diff
173+
-/* @var int $variable */
174+
+/** @var int $variable */
175+
$variable = 5;
176+
```
177+
178+
<br>
179+
180+
## FixParamNameTypoFixer
181+
182+
Fix a typo in the `@param` variable name to match the real argument
183+
184+
- class: [`Symplify\CodingStandard\Fixer\Commenting\FixParamNameTypoFixer`](../src/Fixer/Commenting/FixParamNameTypoFixer.php)
147185

148186
```diff
149187
/**
150-
- * @param $a string
151-
- * @param $b string|null
152-
+ * @param string $a
153-
+ * @param string|null $b
188+
* @param string $one
189+
- * @param string $twoTypo
190+
+ * @param string $two
154191
*/
155-
function test($a, string $b = null): string
192+
function anotherFunction(string $one, string $two)
156193
{
157194
}
158195
```
159196

160-
**Remove a dead `@param` line that has only a name and no type**
197+
<br>
198+
199+
## RemoveDeadParamFixer
200+
201+
Remove a dead `@param` line that has only a name and no type
202+
203+
- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveDeadParamFixer`](../src/Fixer/Commenting/RemoveDeadParamFixer.php)
161204

162205
```diff
163206
/**
@@ -169,20 +212,13 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
169212
}
170213
```
171214

172-
**Fix a typo in the `@param` variable name to match the real argument**
215+
<br>
216+
217+
## RemoveParamNameReferenceFixer
173218

174-
```diff
175-
/**
176-
* @param string $one
177-
- * @param string $twoTypo
178-
+ * @param string $two
179-
*/
180-
function anotherFunction(string $one, string $two)
181-
{
182-
}
183-
```
219+
Remove the reference `&` from a `@param` variable name
184220

185-
**Remove the reference `&` from a `@param` name**
221+
- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveParamNameReferenceFixer`](../src/Fixer/Commenting/RemoveParamNameReferenceFixer.php)
186222

187223
```diff
188224
/**
@@ -194,7 +230,13 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
194230
}
195231
```
196232

197-
**Remove a superfluous variable name from `@return`**
233+
<br>
234+
235+
## RemoveSuperfluousReturnNameFixer
236+
237+
Remove a superfluous variable name from a `@return` annotation
238+
239+
- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousReturnNameFixer`](../src/Fixer/Commenting/RemoveSuperfluousReturnNameFixer.php)
198240

199241
```diff
200242
/**
@@ -206,7 +248,13 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
206248
}
207249
```
208250

209-
**Remove a superfluous variable name from a property `@var`**
251+
<br>
252+
253+
## RemoveSuperfluousVarNameFixer
254+
255+
Remove a superfluous variable name from a property `@var` annotation
256+
257+
- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousVarNameFixer`](../src/Fixer/Commenting/RemoveSuperfluousVarNameFixer.php)
210258

211259
```diff
212260
/**
@@ -216,24 +264,42 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
216264
private $property;
217265
```
218266

219-
**Add a missing variable name to an inline `@var`**
267+
<br>
268+
269+
## SingleLineInlineVarDocBlockFixer
270+
271+
Collapse a multi-line inline `@var` doc block into a single line
272+
273+
- class: [`Symplify\CodingStandard\Fixer\Commenting\SingleLineInlineVarDocBlockFixer`](../src/Fixer/Commenting/SingleLineInlineVarDocBlockFixer.php)
220274

221275
```diff
222-
-/** @var int */
276+
-/**
277+
- * @var int $value
278+
- */
223279
+/** @var int $value */
224280
$value = 1000;
225281
```
226282

227-
**Normalize a malformed inline `@var` (single asterisk, switched name/type)**
283+
<br>
284+
285+
## SwitchedTypeAndNameFixer
286+
287+
Reorder switched type and variable name in `@param`/`@var` annotation
288+
289+
- class: [`Symplify\CodingStandard\Fixer\Commenting\SwitchedTypeAndNameFixer`](../src/Fixer/Commenting/SwitchedTypeAndNameFixer.php)
228290

229291
```diff
230-
-/* @var $variable int */
231-
+/** @var int $variable */
232-
$variable = 5;
292+
/**
293+
- * @param $a string
294+
- * @param $b string|null
295+
+ * @param string $a
296+
+ * @param string|null $b
297+
*/
298+
function test($a, string $b = null): string
299+
{
300+
}
233301
```
234302

235-
It also handles the `@phpstan-` and `@psalm-` prefixed variants of these tags.
236-
237303
<br>
238304

239305
## RemovePropertyVariableNameDescriptionFixer

config/sets/docblock.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Symplify\CodingStandard\Fixer\Commenting\AddMissingParamNameFixer;
6+
use Symplify\CodingStandard\Fixer\Commenting\AddMissingVarNameFixer;
7+
use Symplify\CodingStandard\Fixer\Commenting\DoubleAsteriskInlineVarFixer;
8+
use Symplify\CodingStandard\Fixer\Commenting\FixParamNameTypoFixer;
9+
use Symplify\CodingStandard\Fixer\Commenting\RemoveDeadParamFixer;
10+
use Symplify\CodingStandard\Fixer\Commenting\RemoveParamNameReferenceFixer;
11+
use Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousReturnNameFixer;
12+
use Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousVarNameFixer;
13+
use Symplify\CodingStandard\Fixer\Commenting\SingleLineInlineVarDocBlockFixer;
14+
use Symplify\CodingStandard\Fixer\Commenting\SwitchedTypeAndNameFixer;
15+
use Symplify\EasyCodingStandard\Config\ECSConfig;
16+
17+
return static function (ECSConfig $ecsConfig): void {
18+
$ecsConfig->rules([
19+
// inline @var
20+
DoubleAsteriskInlineVarFixer::class,
21+
SingleLineInlineVarDocBlockFixer::class,
22+
AddMissingVarNameFixer::class,
23+
24+
// @param
25+
AddMissingParamNameFixer::class,
26+
FixParamNameTypoFixer::class,
27+
RemoveParamNameReferenceFixer::class,
28+
RemoveDeadParamFixer::class,
29+
30+
// superfluous names
31+
RemoveSuperfluousReturnNameFixer::class,
32+
RemoveSuperfluousVarNameFixer::class,
33+
34+
// switched type/name order
35+
SwitchedTypeAndNameFixer::class,
36+
]);
37+
};

config/symplify.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use Symplify\CodingStandard\Fixer\ArrayNotation\ArrayListItemNewlineFixer;
1010
use Symplify\CodingStandard\Fixer\ArrayNotation\ArrayOpenerAndCloserNewlineFixer;
1111
use Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer;
12-
use Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer;
1312
use Symplify\CodingStandard\Fixer\Commenting\RemoveUselessDefaultCommentFixer;
1413
use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
1514
use Symplify\CodingStandard\Fixer\Spacing\MethodChainingNewlineFixer;
@@ -20,10 +19,12 @@
2019
use Symplify\EasyCodingStandard\Config\ECSConfig;
2120

2221
return static function (ECSConfig $ecsConfig): void {
22+
// split @param/@return/@var malform rules
23+
$ecsConfig->sets([__DIR__ . '/sets/docblock.php']);
24+
2325
$ecsConfig->rules([
2426
// docblocks and comments
2527
RemovePHPStormAnnotationFixer::class,
26-
ParamReturnAndVarTagMalformsFixer::class,
2728
RemoveUselessDefaultCommentFixer::class,
2829
RemoveMethodNameDuplicateDescriptionFixer::class,
2930
RemovePropertyVariableNameDescriptionFixer::class,
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Symplify\CodingStandard\Fixer\Commenting;
6+
7+
use Override;
8+
use PhpCsFixer\Tokenizer\Token;
9+
use PhpCsFixer\Tokenizer\Tokens;
10+
use SplFileInfo;
11+
use Symplify\CodingStandard\Fixer\AbstractSymplifyFixer;
12+
use Symplify\CodingStandard\TokenRunner\Traverser\TokenReverser;
13+
use Symplify\CodingStandard\Utils\Regex;
14+
15+
/**
16+
* Base for single-task @param/@return/@var doc block fixers. Handles the shared token traversal,
17+
* leaving the actual doc block transformation to the child via processDocContent().
18+
*/
19+
abstract class AbstractDocBlockFixer extends AbstractSymplifyFixer
20+
{
21+
/**
22+
* @see https://regex101.com/r/Nlxkd9/1
23+
*/
24+
private const string TYPE_ANNOTATION_REGEX = '#@(psalm-|phpstan-)?(param|return|var)#';
25+
26+
public function __construct(
27+
protected readonly TokenReverser $tokenReverser
28+
) {
29+
}
30+
31+
/**
32+
* @param Tokens<Token> $tokens
33+
*/
34+
public function isCandidate(Tokens $tokens): bool
35+
{
36+
if (! $tokens->isAnyTokenKindsFound([T_DOC_COMMENT, T_COMMENT])) {
37+
return false;
38+
}
39+
40+
$reversedTokens = $this->tokenReverser->reverse($tokens);
41+
42+
foreach ($reversedTokens as $index => $token) {
43+
if (! $token->isGivenKind([T_CALLABLE])) {
44+
continue;
45+
}
46+
47+
if (! (isset($tokens[$index + 3]) && $tokens[$index + 3]->getContent() === ')')) {
48+
continue;
49+
}
50+
51+
return false;
52+
}
53+
54+
return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_VARIABLE]);
55+
}
56+
57+
/**
58+
* @param Tokens<Token> $tokens
59+
*/
60+
public function fix(SplFileInfo $fileInfo, Tokens $tokens): void
61+
{
62+
$reversedTokens = $this->tokenReverser->reverse($tokens);
63+
64+
foreach ($reversedTokens as $index => $token) {
65+
if (! $token->isGivenKind([T_DOC_COMMENT, T_COMMENT])) {
66+
continue;
67+
}
68+
69+
$docContent = $token->getContent();
70+
if (! Regex::match($docContent, self::TYPE_ANNOTATION_REGEX)) {
71+
continue;
72+
}
73+
74+
$newDocContent = $this->processDocContent($docContent, $tokens, $index);
75+
if ($newDocContent === $docContent) {
76+
continue;
77+
}
78+
79+
// doc block became empty after removing dead lines → remove it completely,
80+
// including the whitespace that followed it, to avoid leaving a blank line
81+
if ($this->isEmptyDocBlock($newDocContent)) {
82+
$tokens->clearAt($index);
83+
if (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) {
84+
$tokens->clearAt($index + 1);
85+
}
86+
87+
continue;
88+
}
89+
90+
$tokens[$index] = new Token([T_DOC_COMMENT, $newDocContent]);
91+
}
92+
}
93+
94+
/**
95+
* Must run before
96+
*
97+
* @see \PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer::getPriority()
98+
*/
99+
#[Override]
100+
public function getPriority(): int
101+
{
102+
return -37;
103+
}
104+
105+
/**
106+
* @param Tokens<Token> $tokens
107+
*/
108+
abstract protected function processDocContent(string $docContent, Tokens $tokens, int $position): string;
109+
110+
private function isEmptyDocBlock(string $docContent): bool
111+
{
112+
return Regex::replace($docContent, '#/\*\*|\*/|\*|\s#', '') === '';
113+
}
114+
}

0 commit comments

Comments
 (0)