Merge pull request #3009 from Aerendir/AnnotateThrowables-support-this-same-class

[ReadyToBeMerged][AnnotateThrowables] Support `$this` calling a method of the same class
This commit is contained in:
Tomas Votruba 2020-03-09 16:17:19 +01:00 committed by GitHub
commit 59cf0665cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 133 additions and 29 deletions

View File

@ -15,7 +15,7 @@ class ThisA
}
}
class UseOfThis extends ThisA
class UseOfThisInherited extends ThisA
{
public function thisMethodUsesAThisThatThrowsAnException()
{
@ -42,7 +42,7 @@ class ThisA
}
}
class UseOfThis extends ThisA
class UseOfThisInherited extends ThisA
{
/**
* @throws \Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException

View File

@ -0,0 +1,50 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Fixture;
use Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException;
class UseOfThisSameClass
{
/**
* @throws TheException
*/
public function thisMethodThrowsAnException():string
{
throw new TheException('');
}
public function thisMethodUsesAThisThatThrowsAnException()
{
$this->thisMethodThrowsAnException();
}
}
?>
-----
<?php
namespace Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Fixture;
use Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException;
class UseOfThisSameClass
{
/**
* @throws TheException
*/
public function thisMethodThrowsAnException():string
{
throw new TheException('');
}
/**
* @throws \Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException
*/
public function thisMethodUsesAThisThatThrowsAnException()
{
$this->thisMethodThrowsAnException();
}
}
?>

View File

@ -0,0 +1,50 @@
<?php
namespace Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Fixture;
use Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException;
class UseOfThisSameClassWithAssignment
{
/**
* @throws TheException
*/
public function thisMethodThrowsAnException():string
{
throw new TheException('');
}
public function thisMethodUsesAThisThatThrowsAnException()
{
$assign = $this->thisMethodThrowsAnException();
}
}
?>
-----
<?php
namespace Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Fixture;
use Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException;
class UseOfThisSameClassWithAssignment
{
/**
* @throws TheException
*/
public function thisMethodThrowsAnException():string
{
throw new TheException('');
}
/**
* @throws \Rector\CodingStyle\Tests\Rector\Throw_\AnnotateThrowablesRector\Source\Exceptions\TheException
*/
public function thisMethodUsesAThisThatThrowsAnException()
{
$assign = $this->thisMethodThrowsAnException();
}
}
?>

View File

@ -8,15 +8,26 @@ use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\NodeNameResolver\NodeNameResolver;
final class ClassResolver
{
/**
* @var NodeNameResolver
*/
private $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
}
public function getClassFromMethodCall(MethodCall $methodCall): ?FullyQualified
{
$class = null;
@ -53,32 +64,25 @@ final class ClassResolver
private function resolveFromClassMethod(ClassMethod $classMethod, MethodCall $methodCall): ?FullyQualified
{
$class = $this->tryToResolveClassMethodStmts($classMethod);
if ($class === null) {
$class = $this->tryToResolveClassMethodParams($classMethod, $methodCall);
}
return $class;
}
private function tryToResolveClassMethodStmts(ClassMethod $classMethod): ?FullyQualified
{
// $ this -> method();
$stmts = $classMethod->stmts;
if ($stmts === null) {
$var = $methodCall->var;
if (! $var instanceof Variable) {
return null;
}
/** @var Stmt $stmt */
foreach ($stmts as $stmt) {
if ($stmt->expr->var->name === 'this') {
$class = $classMethod->name->getAttribute(ClassLike::class)->extends;
return $class instanceof FullyQualified ? $class : null;
}
return $this->nodeNameResolver->isName($var, 'this')
? $this->tryToResolveClassMethodFromThis($classMethod)
: $this->tryToResolveClassMethodParams($classMethod, $methodCall);
}
private function tryToResolveClassMethodFromThis(ClassMethod $classMethod): ?FullyQualified
{
$class = $classMethod->name->getAttribute(ClassLike::class)->name;
if (! $class instanceof Identifier) {
return null;
}
return null;
return new FullyQualified($class->getAttribute('className'));
}
private function tryToResolveClassMethodParams(ClassMethod $classMethod, MethodCall $methodCall): ?FullyQualified

View File

@ -41,13 +41,13 @@ final class ClassMethodReflectionHelper
return [];
}
$returnTags = $this->phpDocTagsFinder->extractTagsFromStringedDocblock($methodDocblock, $tag);
$extractedTags = $this->phpDocTagsFinder->extractTagsFromStringedDocblock($methodDocblock, $tag);
$returnClasses = [];
foreach ($returnTags as $returnTag) {
$returnClasses[] = Reflection::expandClassName($returnTag, $reflectedMethod->getDeclaringClass());
$classes = [];
foreach ($extractedTags as $returnTag) {
$classes[] = Reflection::expandClassName($returnTag, $reflectedMethod->getDeclaringClass());
}
return $returnClasses;
return $classes;
}
}