-
-
Notifications
You must be signed in to change notification settings - Fork 672
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
522 additions
and
0 deletions.
There are no files selected for viewing
163 changes: 163 additions & 0 deletions
163
packages/coding-style/src/Rector/ClassMethod/AnnotateThrowablesRector.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Rector\CodingStyle\Rector\ClassMethod; | ||
|
||
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; | ||
|
||
/** | ||
* 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); | ||
/** @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 ( | ||
strpos($throwClassName, '\\') === false && | ||
strpos($FQN, $throwClassName) !== false && | ||
$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); | ||
|
||
/** @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); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
...-style/tests/Rector/ClassMethod/AnnotateThrowablesRector/AnnotateThrowablesRectorTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
...r/ClassMethod/AnnotateThrowablesRector/Fixture/custom_exception_already_annotated.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture; | ||
|
||
class CustomExceptionAlreadyAnnotated | ||
{ | ||
/** | ||
* @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 CustomExceptionAlreadyAnnotated | ||
{ | ||
/** | ||
* @throws \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException | ||
*/ | ||
public function throwException() | ||
{ | ||
throw new \Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException(); | ||
} | ||
} | ||
|
||
?> |
38 changes: 38 additions & 0 deletions
38
...sMethod/AnnotateThrowablesRector/Fixture/custom_exception_in_method_with_docblock.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} | ||
|
||
?> |
30 changes: 30 additions & 0 deletions
30
...thod/AnnotateThrowablesRector/Fixture/custom_exception_in_method_without_docblock.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} | ||
|
||
?> |
37 changes: 37 additions & 0 deletions
37
...thod/AnnotateThrowablesRector/Fixture/custom_imported_exception_already_annotated.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<?php | ||
|
||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture; | ||
|
||
use Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Source\TheException; | ||
|
||
class CustomImportedExceptionAlreadyAnnotated | ||
{ | ||
/** | ||
* @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 CustomImportedExceptionAlreadyAnnotated | ||
{ | ||
/** | ||
* @throws TheException | ||
*/ | ||
public function throwException() | ||
{ | ||
throw new TheException(); | ||
} | ||
} | ||
|
||
?> |
33 changes: 33 additions & 0 deletions
33
...tor/ClassMethod/AnnotateThrowablesRector/Fixture/root_exception_already_annotated.php.inc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture; | ||
|
||
class RootExceptionAlreadyAnnotated | ||
{ | ||
/** | ||
* @throws \RuntimeException | ||
*/ | ||
public function throwException() | ||
{ | ||
throw new \RuntimeException(); | ||
} | ||
} | ||
|
||
?> | ||
----- | ||
<?php | ||
|
||
namespace Rector\CodingStyle\Tests\Rector\ClassMethod\AnnotateThrowables\Fixture; | ||
|
||
class RootExceptionAlreadyAnnotated | ||
{ | ||
/** | ||
* @throws \RuntimeException | ||
*/ | ||
public function throwException() | ||
{ | ||
throw new \RuntimeException(); | ||
} | ||
} | ||
|
||
?> |
Oops, something went wrong.