Skip to content
Permalink
Browse files

Merge pull request #194 from kubawerlos/add_PhpdocTypesTrimFixer

Add PhpdocTypesTrimFixer
  • Loading branch information
kubawerlos committed Nov 25, 2019
2 parents 552f3bf + f57b145 commit 0c9929bea076c268d8b40060a7fb87dee3acc44b
Showing with 240 additions and 2 deletions.
  1. +12 −1 README.md
  2. +1 −1 composer.json
  3. +108 −0 src/Fixer/PhpdocTypesTrimFixer.php
  4. +119 −0 tests/Fixer/PhpdocTypesTrimFixerTest.php
@@ -8,7 +8,7 @@

[![Build status](https://img.shields.io/travis/kubawerlos/php-cs-fixer-custom-fixers/master.svg)](https://travis-ci.org/kubawerlos/php-cs-fixer-custom-fixers)
[![Code coverage](https://img.shields.io/coveralls/github/kubawerlos/php-cs-fixer-custom-fixers/master.svg)](https://coveralls.io/github/kubawerlos/php-cs-fixer-custom-fixers?branch=master)
![Tests](https://img.shields.io/badge/tests-1552-brightgreen.svg)
![Tests](https://img.shields.io/badge/tests-1576-brightgreen.svg)
[![Mutation testing badge](https://badge.stryker-mutator.io/github.com/kubawerlos/php-cs-fixer-custom-fixers/master)](https://stryker-mutator.github.io)
[![Psalm type coverage](https://shepherd.dev/github/kubawerlos/php-cs-fixer-custom-fixers/coverage.svg)](https://shepherd.dev/github/kubawerlos/php-cs-fixer-custom-fixers)

@@ -426,6 +426,17 @@ In PHPDoc inside class or interface element `self` should be preferred over the
}
```

#### PhpdocTypesTrimFixer
PHPDoc must be trimmed.
```diff
<?php
/**
- * @param null | string $x
+ * @param null|string $x
*/
function foo($x) {}
```

#### PhpdocVarAnnotationCorrectOrderFixer
`@var` and `@type` annotations must have type and name in the correct order.
DEPRECATED: use `phpdoc_var_annotation_correct_order` instead.
@@ -40,7 +40,7 @@
"./dev-tools/readme > README.md"
],
"infection": [
"./dev-tools/vendor/bin/infection run --ansi --min-msi=100 --only-covered --threads=16"
"./dev-tools/vendor/bin/infection run --ansi --min-msi=100 --threads=16"
],
"test": [
"./dev-tools/vendor/bin/phpunit"
@@ -0,0 +1,108 @@
<?php

declare(strict_types = 1);

namespace PhpCsFixerCustomFixers\Fixer;

use PhpCsFixer\DocBlock\DocBlock;
use PhpCsFixer\DocBlock\Line;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

final class PhpdocTypesTrimFixer extends AbstractFixer
{
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'PHPDoc must be trimmed.',
[new CodeSample('<?php
/**
* @param null | string $x
*/
function foo($x) {}
')]
);
}

public function getPriority(): int
{
return 0;
}

public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(T_DOC_COMMENT);
}

public function isRisky(): bool
{
return false;
}

public function fix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = $tokens->count() - 1; $index > 0; $index--) {
$token = $tokens[$index];

if (!$token->isGivenKind([T_DOC_COMMENT])) {
continue;
}

$docBlock = new DocBlock($token->getContent());

foreach ($docBlock->getAnnotations() as $annotation) {
if (!$annotation->supportTypes()) {
continue;
}

$content = $annotation->getContent();

$variableStartPosition = \strpos($content, '$');

if ($variableStartPosition === false) {
$variableStartPosition = \strlen($content);
}

$types = $this->trimTypes(\substr($content, 0, $variableStartPosition));

$newContent = $types . \substr($content, $variableStartPosition);

/** @var Line $line */
$line = $docBlock->getLine($annotation->getStart());
$line->setContent($newContent);
}

$newContent = $docBlock->getContent();
if ($newContent === $token->getContent()) {
continue;
}

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

private function trimTypes(string $typesContent): string
{
$types = \explode('|', $typesContent);

if (\count($types) < 2) {
return $typesContent;
}
$lastIndex = \count($types) - 1;

foreach ($types as $key => $type) {
if ($key === 0) {
$types[$key] = \rtrim($type);
} elseif ($key === $lastIndex) {
$types[$key] = \ltrim($type);
} else {
$types[$key] = \trim($type);
}
}

return \implode('|', $types);
}
}
@@ -0,0 +1,119 @@
<?php

declare(strict_types = 1);

namespace Tests\Fixer;

/**
* @internal
*
* @covers \PhpCsFixerCustomFixers\Fixer\PhpdocTypesTrimFixer
*/
final class PhpdocTypesTrimFixerTest extends AbstractFixerTestCase
{
public function testIsRisky(): void
{
static::assertFalse($this->fixer->isRisky());
}

/**
* @dataProvider provideFixCases
*/
public function testFix(string $expected, ?string $input = null): void
{
$this->doTest($expected, $input);
}

public static function provideFixCases(): iterable
{
yield [
'<?php
/**
* @customAnnotation Foo | Bar ($x) Bar | Foo
*/
',
];

yield [
'<?php
/**
* @param Foo $x
*
* @return Bar
*/
',
];

yield [
'<?php
/**
* @param Foo|Bar $x
*/
',
'<?php
/**
* @param Foo | Bar $x
*/
',
];

yield [
'<?php
/**
* @return Foo|Bar
*/
',
'<?php
/**
* @return Foo | Bar
*/
',
];

yield [
'<?php
/**
* @param ClassA|ClassB|ClassC|ClassD|ClassE|ClassF|ClassG|ClassH $x should be 0 | 1
*/
',
'<?php
/**
* @param ClassA | ClassB | ClassC | ClassD | ClassE | ClassF | ClassG | ClassH $x should be 0 | 1
*/
',
];

yield [
'<?php
/**
* @notParam Foo | Bar $x
* @param Foo|Bar $x
* @param Foo|Bar $y
*
* @notReturn Foo | Bar
* @return Foo|Bar
*/
function fooBar($x, $y) {}
/**
* @return Baz
*/
function baz() {}
',
'<?php
/**
* @notParam Foo | Bar $x
* @param Foo | Bar $x
* @param Foo|Bar $y
*
* @notReturn Foo | Bar
* @return Foo | Bar
*/
function fooBar($x, $y) {}
/**
* @return Baz
*/
function baz() {}
',
];
}
}

0 comments on commit 0c9929b

Please sign in to comment.
You can’t perform that action at this time.