mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-26 12:52:36 +00:00
#2824: Automatically add to DocBlock comments the thrown \Throwables
.
This commit is contained in:
parent
a8a9886c26
commit
12670ed9df
|
@ -1,4 +1,4 @@
|
|||
# All 447 Rectors Overview
|
||||
# All 448 Rectors Overview
|
||||
|
||||
- [Projects](#projects)
|
||||
- [General](#general)
|
||||
|
@ -1631,6 +1631,30 @@ Adds array default value to property to prevent foreach over null error
|
|||
|
||||
<br>
|
||||
|
||||
### `AnnotateThrowablesRector`
|
||||
|
||||
- class: `Rector\CodingStyle\Rector\ClassMethod\AnnotateThrowablesRector`
|
||||
|
||||
Adds @throws DocBlock comments to methods that thrwo \Throwables.
|
||||
|
||||
```diff
|
||||
class RootExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
+ * @throws \RuntimeException
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \RuntimeException('', $code);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### `BinarySwitchToIfElseRector`
|
||||
|
||||
- class: `Rector\CodingStyle\Rector\Switch_\BinarySwitchToIfElseRector`
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Rector\ClassMethod;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Throw_;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwareGenericTagValueNode;
|
||||
use Rector\AttributeAwarePhpDoc\Ast\PhpDoc\AttributeAwarePhpDocTagNode;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\RectorDefinition\CodeSample;
|
||||
use Rector\Core\RectorDefinition\RectorDefinition;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Adds "throws" DocBlock to methods.
|
||||
*/
|
||||
final class AnnotateThrowablesRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [Throw_::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* From this method documentation is generated.
|
||||
*/
|
||||
public function getDefinition(): RectorDefinition
|
||||
{
|
||||
return new RectorDefinition(
|
||||
'Adds @throws DocBlock comments to methods that thrwo \Throwables.', [
|
||||
new CodeSample(
|
||||
// code before
|
||||
<<<'PHP'
|
||||
class RootExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \RuntimeException('', $code);
|
||||
}
|
||||
}
|
||||
PHP
|
||||
,
|
||||
// code after
|
||||
<<<'PHP'
|
||||
class RootExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \RuntimeException('', $code);
|
||||
}
|
||||
}
|
||||
PHP
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throw_ $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if ($this->isThrowableAnnotated($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->annotateMethod($node);
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function isThrowableAnnotated(Throw_ $node): bool
|
||||
{
|
||||
$method = $node->getAttribute(AttributeKey::METHOD_NODE);
|
||||
|
||||
if ($method === null) {
|
||||
throw new RuntimeException('This should not happen and is probably a bug. Please report it.');
|
||||
}
|
||||
|
||||
/** @var PhpDocInfo $phpDocInfo */
|
||||
$phpDocInfo = $method->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
$throwTags = $phpDocInfo->getTagsByName('throws');
|
||||
$FQN = $this->buildFQN($node);
|
||||
|
||||
if (empty($throwTags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var AttributeAwarePhpDocTagNode $throwTag */
|
||||
foreach ($throwTags as $throwTag) {
|
||||
$throwClassName = $throwTag->value->type->name;
|
||||
if ($throwClassName === $FQN) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
! Strings::contains($throwClassName, '\\') &&
|
||||
Strings::contains($FQN, $throwClassName) &&
|
||||
$this->isThrowableImported($node)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isThrowableImported(Throw_ $node): bool
|
||||
{
|
||||
$throwClassName = $this->getName($node->expr->class);
|
||||
$useNodes = $node->getAttribute(AttributeKey::USE_NODES);
|
||||
|
||||
if ($useNodes === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Use_ $useNode */
|
||||
foreach ($useNodes as $useNode) {
|
||||
/** @var UseUse $useStmt */
|
||||
foreach ($useNode->uses as $useStmt) {
|
||||
if ($this->getName($useStmt) === $throwClassName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function annotateMethod(Throw_ $node): void
|
||||
{
|
||||
/** @var ClassMethod $method */
|
||||
$method = $node->getAttribute(AttributeKey::METHOD_NODE);
|
||||
$FQN = $this->buildFQN($node);
|
||||
$docComment = $this->buildThrowsDocComment($FQN);
|
||||
|
||||
/** @var PhpDocInfo $methodPhpDocInfo */
|
||||
$methodPhpDocInfo = $method->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
$methodPhpDocInfo->addPhpDocTagNode($docComment);
|
||||
}
|
||||
|
||||
private function buildThrowsDocComment(string $FQNOrThrowableName): AttributeAwarePhpDocTagNode
|
||||
{
|
||||
$value = new AttributeAwareGenericTagValueNode($FQNOrThrowableName);
|
||||
return new AttributeAwarePhpDocTagNode('@throws', $value);
|
||||
}
|
||||
|
||||
private function buildFQN(Throw_ $node): string
|
||||
{
|
||||
return '\\' . $this->getName($node->expr->class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowablesRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\CodingStyle\Rector\ClassMethod\AnnotateThrowablesRector;
|
||||
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
|
||||
final class AnnotateThrowablesRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideDataForTest()
|
||||
*/
|
||||
public function test(string $file): void
|
||||
{
|
||||
$this->doTestFile($file);
|
||||
}
|
||||
|
||||
public function provideDataForTest(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return AnnotateThrowablesRector::class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException('', $code);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException('', $code);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionInMethodWithoutDocblock
|
||||
{
|
||||
public function throwException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionInMethodWithoutDocblock
|
||||
{
|
||||
/**
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionThrownInTwoMethods
|
||||
{
|
||||
/**
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
|
||||
public function anotherThrowException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class CustomExceptionThrownInTwoMethods
|
||||
{
|
||||
/**
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException
|
||||
*/
|
||||
public function anotherThrowException()
|
||||
{
|
||||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
use Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException;
|
||||
|
||||
class CustomImportedExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
use Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException;
|
||||
|
||||
class CustomImportedExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws TheException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new TheException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \RuntimeException('', $code);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionInMethodWithDocblock
|
||||
{
|
||||
/**
|
||||
* This is a comment.
|
||||
*
|
||||
* @param int $code
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException(int $code)
|
||||
{
|
||||
throw new \RuntimeException('', $code);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionInMethodWithoutDocblock
|
||||
{
|
||||
public function throwException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionInMethodWithoutDocblock
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionThrownInTwoMethods
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
|
||||
public function anotherThrowException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
class RootExceptionThrownInTwoMethods
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function anotherThrowException()
|
||||
{
|
||||
throw new \RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
use \RuntimeException;
|
||||
|
||||
class RootImportedExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture;
|
||||
|
||||
use \RuntimeException;
|
||||
|
||||
class RootImportedExceptionAlreadyAnnotatedInMethod
|
||||
{
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function throwException()
|
||||
{
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source;
|
||||
|
||||
class TheException extends \RuntimeException {}
|
Loading…
Reference in New Issue
Block a user