Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 100 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ vendor/bin/ecs --fix

<br>

# 14 Rules to Keep Your Code Clean
# 23 Rules to Keep Your Code Clean

## ArrayListItemNewlineFixer

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

<br>

## ParamReturnAndVarTagMalformsFixer
## Doc block malform rules

Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats. This single rule covers a wide range of docblock malforms:
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.

- class: [`Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer`](../src/Fixer/Commenting/ParamReturnAndVarTagMalformsFixer.php)
<br>

## AddMissingParamNameFixer

Add a missing variable name to a `@param` annotation

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

```diff
/**
Expand All @@ -143,21 +147,60 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
}
```

**Reorder switched type and variable name**
<br>

## AddMissingVarNameFixer

Add a missing variable name to an inline `@var` annotation

- class: [`Symplify\CodingStandard\Fixer\Commenting\AddMissingVarNameFixer`](../src/Fixer/Commenting/AddMissingVarNameFixer.php)

```diff
-/** @var int */
+/** @var int $value */
$value = 1000;
```

<br>

## DoubleAsteriskInlineVarFixer

Use a double asterisk `/**` doc block for an inline `@var` comment

- class: [`Symplify\CodingStandard\Fixer\Commenting\DoubleAsteriskInlineVarFixer`](../src/Fixer/Commenting/DoubleAsteriskInlineVarFixer.php)

```diff
-/* @var int $variable */
+/** @var int $variable */
$variable = 5;
```

<br>

## FixParamNameTypoFixer

Fix a typo in the `@param` variable name to match the real argument

- class: [`Symplify\CodingStandard\Fixer\Commenting\FixParamNameTypoFixer`](../src/Fixer/Commenting/FixParamNameTypoFixer.php)

```diff
/**
- * @param $a string
- * @param $b string|null
+ * @param string $a
+ * @param string|null $b
* @param string $one
- * @param string $twoTypo
+ * @param string $two
*/
function test($a, string $b = null): string
function anotherFunction(string $one, string $two)
{
}
```

**Remove a dead `@param` line that has only a name and no type**
<br>

## RemoveDeadParamFixer

Remove a dead `@param` line that has only a name and no type

- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveDeadParamFixer`](../src/Fixer/Commenting/RemoveDeadParamFixer.php)

```diff
/**
Expand All @@ -169,20 +212,13 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
}
```

**Fix a typo in the `@param` variable name to match the real argument**
<br>

## RemoveParamNameReferenceFixer

```diff
/**
* @param string $one
- * @param string $twoTypo
+ * @param string $two
*/
function anotherFunction(string $one, string $two)
{
}
```
Remove the reference `&` from a `@param` variable name

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

```diff
/**
Expand All @@ -194,7 +230,13 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
}
```

**Remove a superfluous variable name from `@return`**
<br>

## RemoveSuperfluousReturnNameFixer

Remove a superfluous variable name from a `@return` annotation

- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousReturnNameFixer`](../src/Fixer/Commenting/RemoveSuperfluousReturnNameFixer.php)

```diff
/**
Expand All @@ -206,7 +248,13 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
}
```

**Remove a superfluous variable name from a property `@var`**
<br>

## RemoveSuperfluousVarNameFixer

Remove a superfluous variable name from a property `@var` annotation

- class: [`Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousVarNameFixer`](../src/Fixer/Commenting/RemoveSuperfluousVarNameFixer.php)

```diff
/**
Expand All @@ -216,24 +264,42 @@ Fixes `@param`, `@return`, `@var` and inline `@var` annotations broken formats.
private $property;
```

**Add a missing variable name to an inline `@var`**
<br>

## SingleLineInlineVarDocBlockFixer

Collapse a multi-line inline `@var` doc block into a single line

- class: [`Symplify\CodingStandard\Fixer\Commenting\SingleLineInlineVarDocBlockFixer`](../src/Fixer/Commenting/SingleLineInlineVarDocBlockFixer.php)

```diff
-/** @var int */
-/**
- * @var int $value
- */
+/** @var int $value */
$value = 1000;
```

**Normalize a malformed inline `@var` (single asterisk, switched name/type)**
<br>

## SwitchedTypeAndNameFixer

Reorder switched type and variable name in `@param`/`@var` annotation

- class: [`Symplify\CodingStandard\Fixer\Commenting\SwitchedTypeAndNameFixer`](../src/Fixer/Commenting/SwitchedTypeAndNameFixer.php)

```diff
-/* @var $variable int */
+/** @var int $variable */
$variable = 5;
/**
- * @param $a string
- * @param $b string|null
+ * @param string $a
+ * @param string|null $b
*/
function test($a, string $b = null): string
{
}
```

It also handles the `@phpstan-` and `@psalm-` prefixed variants of these tags.

<br>

## RemovePropertyVariableNameDescriptionFixer
Expand Down
37 changes: 37 additions & 0 deletions config/sets/docblock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

use Symplify\CodingStandard\Fixer\Commenting\AddMissingParamNameFixer;
use Symplify\CodingStandard\Fixer\Commenting\AddMissingVarNameFixer;
use Symplify\CodingStandard\Fixer\Commenting\DoubleAsteriskInlineVarFixer;
use Symplify\CodingStandard\Fixer\Commenting\FixParamNameTypoFixer;
use Symplify\CodingStandard\Fixer\Commenting\RemoveDeadParamFixer;
use Symplify\CodingStandard\Fixer\Commenting\RemoveParamNameReferenceFixer;
use Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousReturnNameFixer;
use Symplify\CodingStandard\Fixer\Commenting\RemoveSuperfluousVarNameFixer;
use Symplify\CodingStandard\Fixer\Commenting\SingleLineInlineVarDocBlockFixer;
use Symplify\CodingStandard\Fixer\Commenting\SwitchedTypeAndNameFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;

return static function (ECSConfig $ecsConfig): void {
$ecsConfig->rules([
// inline @var
DoubleAsteriskInlineVarFixer::class,
SingleLineInlineVarDocBlockFixer::class,
AddMissingVarNameFixer::class,

// @param
AddMissingParamNameFixer::class,
FixParamNameTypoFixer::class,
RemoveParamNameReferenceFixer::class,
RemoveDeadParamFixer::class,

// superfluous names
RemoveSuperfluousReturnNameFixer::class,
RemoveSuperfluousVarNameFixer::class,

// switched type/name order
SwitchedTypeAndNameFixer::class,
]);
};
5 changes: 3 additions & 2 deletions config/symplify.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Symplify\CodingStandard\Fixer\ArrayNotation\ArrayListItemNewlineFixer;
use Symplify\CodingStandard\Fixer\ArrayNotation\ArrayOpenerAndCloserNewlineFixer;
use Symplify\CodingStandard\Fixer\ArrayNotation\StandaloneLineInMultilineArrayFixer;
use Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer;
use Symplify\CodingStandard\Fixer\Commenting\RemoveUselessDefaultCommentFixer;
use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
use Symplify\CodingStandard\Fixer\Spacing\MethodChainingNewlineFixer;
Expand All @@ -20,10 +19,12 @@
use Symplify\EasyCodingStandard\Config\ECSConfig;

return static function (ECSConfig $ecsConfig): void {
// split @param/@return/@var malform rules
$ecsConfig->sets([__DIR__ . '/sets/docblock.php']);

$ecsConfig->rules([
// docblocks and comments
RemovePHPStormAnnotationFixer::class,
ParamReturnAndVarTagMalformsFixer::class,
RemoveUselessDefaultCommentFixer::class,
RemoveMethodNameDuplicateDescriptionFixer::class,
RemovePropertyVariableNameDescriptionFixer::class,
Expand Down
114 changes: 114 additions & 0 deletions src/Fixer/Commenting/AbstractDocBlockFixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

namespace Symplify\CodingStandard\Fixer\Commenting;

use Override;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use SplFileInfo;
use Symplify\CodingStandard\Fixer\AbstractSymplifyFixer;
use Symplify\CodingStandard\TokenRunner\Traverser\TokenReverser;
use Symplify\CodingStandard\Utils\Regex;

/**
* Base for single-task @param/@return/@var doc block fixers. Handles the shared token traversal,
* leaving the actual doc block transformation to the child via processDocContent().
*/
abstract class AbstractDocBlockFixer extends AbstractSymplifyFixer
{
/**
* @see https://regex101.com/r/Nlxkd9/1
*/
private const string TYPE_ANNOTATION_REGEX = '#@(psalm-|phpstan-)?(param|return|var)#';

public function __construct(
protected readonly TokenReverser $tokenReverser
) {
}

/**
* @param Tokens<Token> $tokens
*/
public function isCandidate(Tokens $tokens): bool
{
if (! $tokens->isAnyTokenKindsFound([T_DOC_COMMENT, T_COMMENT])) {
return false;
}

$reversedTokens = $this->tokenReverser->reverse($tokens);

foreach ($reversedTokens as $index => $token) {
if (! $token->isGivenKind([T_CALLABLE])) {
continue;
}

if (! (isset($tokens[$index + 3]) && $tokens[$index + 3]->getContent() === ')')) {
continue;
}

return false;
}

return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_VARIABLE]);
}

/**
* @param Tokens<Token> $tokens
*/
public function fix(SplFileInfo $fileInfo, Tokens $tokens): void
{
$reversedTokens = $this->tokenReverser->reverse($tokens);

foreach ($reversedTokens as $index => $token) {
if (! $token->isGivenKind([T_DOC_COMMENT, T_COMMENT])) {
continue;
}

$docContent = $token->getContent();
if (! Regex::match($docContent, self::TYPE_ANNOTATION_REGEX)) {
continue;
}

$newDocContent = $this->processDocContent($docContent, $tokens, $index);
if ($newDocContent === $docContent) {
continue;
}

// doc block became empty after removing dead lines → remove it completely,
// including the whitespace that followed it, to avoid leaving a blank line
if ($this->isEmptyDocBlock($newDocContent)) {
$tokens->clearAt($index);
if (isset($tokens[$index + 1]) && $tokens[$index + 1]->isWhitespace()) {
$tokens->clearAt($index + 1);
}

continue;
}

$tokens[$index] = new Token([T_DOC_COMMENT, $newDocContent]);
}
}

/**
* Must run before
*
* @see \PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer::getPriority()
*/
#[Override]
public function getPriority(): int
{
return -37;
}

/**
* @param Tokens<Token> $tokens
*/
abstract protected function processDocContent(string $docContent, Tokens $tokens, int $position): string;

private function isEmptyDocBlock(string $docContent): bool
{
return Regex::replace($docContent, '#/\*\*|\*/|\*|\s#', '') === '';
}
}
Loading
Loading