Skip to content

Commit

Permalink
Prevent some internal errors with methods by using the current node c…
Browse files Browse the repository at this point in the history
…lass reflection
  • Loading branch information
ondrejmirtes committed Jun 10, 2020
1 parent c60e7ae commit af0c64b
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 56 deletions.
18 changes: 7 additions & 11 deletions src/Dependency/DependencyResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Function_;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ParametersAcceptorWithPhpDocs;
use PHPStan\Reflection\Php\PhpMethodReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Reflection\ReflectionWithFilename;
use PHPStan\Type\ClosureType;
Expand Down Expand Up @@ -49,16 +48,13 @@ public function resolveDependencies(\PhpParser\Node $node, Scope $scope): array
$this->addClassToDependencies($className->toString(), $dependenciesReflections);
}
}
} elseif ($node instanceof ClassMethod) {
if (!$scope->isInClass()) {
throw new \PHPStan\ShouldNotHappenException();
}
$nativeMethod = $scope->getClassReflection()->getNativeMethod($node->name->name);
if ($nativeMethod instanceof PhpMethodReflection) {
/** @var \PHPStan\Reflection\ParametersAcceptorWithPhpDocs $parametersAcceptor */
} elseif ($node instanceof InClassMethodNode) {
$nativeMethod = $scope->getFunction();
if ($nativeMethod !== null) {
$parametersAcceptor = ParametersAcceptorSelector::selectSingle($nativeMethod->getVariants());

$this->extractFromParametersAcceptor($parametersAcceptor, $dependenciesReflections);
if ($parametersAcceptor instanceof \PHPStan\Reflection\ParametersAcceptorWithPhpDocs) {
$this->extractFromParametersAcceptor($parametersAcceptor, $dependenciesReflections);
}
}
} elseif ($node instanceof Function_) {
$functionName = $node->name->name;
Expand Down
4 changes: 0 additions & 4 deletions src/PhpDoc/StubValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
use PHPStan\Rules\Generics\TraitTemplateTypeRule;
use PHPStan\Rules\Generics\VarianceCheck;
use PHPStan\Rules\Methods\ExistingClassesInTypehintsRule;
use PHPStan\Rules\Methods\MissingMethodParameterTypehintRule;
use PHPStan\Rules\Methods\MissingMethodReturnTypehintRule;
use PHPStan\Rules\MissingTypehintCheck;
use PHPStan\Rules\PhpDoc\IncompatiblePhpDocTypeRule;
use PHPStan\Rules\PhpDoc\IncompatiblePropertyPhpDocTypeRule;
Expand Down Expand Up @@ -150,8 +148,6 @@ private function getRuleRegistry(Container $container): Registry
// level 6
new MissingFunctionParameterTypehintRule($missingTypehintCheck),
new MissingFunctionReturnTypehintRule($missingTypehintCheck),
new MissingMethodParameterTypehintRule($missingTypehintCheck),
new MissingMethodReturnTypehintRule($missingTypehintCheck),
new MissingPropertyTypehintRule($missingTypehintCheck),
]);
}
Expand Down
22 changes: 10 additions & 12 deletions src/Rules/Generics/MethodSignatureVarianceRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Rules\Rule;

/**
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\ClassMethod>
* @implements \PHPStan\Rules\Rule<InClassMethodNode>
*/
class MethodSignatureVarianceRule implements Rule
{
Expand All @@ -22,25 +24,21 @@ public function __construct(VarianceCheck $varianceCheck)

public function getNodeType(): string
{
return Node\Stmt\ClassMethod::class;
return InClassMethodNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
if (!$scope->isInClass()) {
throw new \PHPStan\ShouldNotHappenException();
$method = $scope->getFunction();
if (!$method instanceof MethodReflection) {
return [];
}

$classReflection = $scope->getClassReflection();
$className = $classReflection->getDisplayName();
$methodName = $node->name->toString();
$method = $classReflection->getNativeMethod($methodName);

return $this->varianceCheck->checkParametersAcceptor(
ParametersAcceptorSelector::selectSingle($method->getVariants()),
sprintf('in parameter %%s of method %s::%s()', $className, $methodName),
sprintf('in return type of method %s::%s()', $className, $methodName),
$methodName === '__construct' || $method->isStatic()
sprintf('in parameter %%s of method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()),
sprintf('in return type of method %s::%s()', $method->getDeclaringClass()->getDisplayName(), $method->getName()),
$method->getName() === '__construct' || $method->isStatic()
);
}

Expand Down
21 changes: 10 additions & 11 deletions src/Rules/Methods/MethodSignatureRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
namespace PHPStan\Rules\Methods;

use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Rules\RuleErrorBuilder;
Expand All @@ -16,7 +17,7 @@
use PHPStan\Type\VoidType;

/**
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\ClassMethod>
* @implements \PHPStan\Rules\Rule<InClassMethodNode>
*/
class MethodSignatureRule implements \PHPStan\Rules\Rule
{
Expand All @@ -36,22 +37,20 @@ public function __construct(

public function getNodeType(): string
{
return ClassMethod::class;
return InClassMethodNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
$methodName = (string) $node->name;

if ($methodName === '__construct') {
$method = $scope->getFunction();
if (!$method instanceof MethodReflection) {
return [];
}

$class = $scope->getClassReflection();
if ($class === null) {
throw new \PHPStan\ShouldNotHappenException();
$methodName = $method->getName();
if ($methodName === '__construct') {
return [];
}
$method = $class->getNativeMethod($methodName);
if (!$this->reportStatic && $method->isStatic()) {
return [];
}
Expand All @@ -61,7 +60,7 @@ public function processNode(Node $node, Scope $scope): array
$parameters = ParametersAcceptorSelector::selectSingle($method->getVariants());

$errors = [];
foreach ($this->collectParentMethods($methodName, $class, $scope) as $parentMethod) {
foreach ($this->collectParentMethods($methodName, $method->getDeclaringClass(), $scope) as $parentMethod) {
$parentParameters = ParametersAcceptorSelector::selectFromTypes(array_map(static function (ParameterReflection $parameter): Type {
return $parameter->getType();
}, $parameters->getParameters()), $parentMethod->getVariants(), false);
Expand Down
12 changes: 6 additions & 6 deletions src/Rules/Methods/MissingMethodParameterTypehintRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
Expand All @@ -13,7 +14,7 @@
use PHPStan\Type\VerbosityLevel;

/**
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\ClassMethod>
* @implements \PHPStan\Rules\Rule<InClassMethodNode>
*/
final class MissingMethodParameterTypehintRule implements \PHPStan\Rules\Rule
{
Expand All @@ -27,17 +28,16 @@ public function __construct(MissingTypehintCheck $missingTypehintCheck)

public function getNodeType(): string
{
return \PhpParser\Node\Stmt\ClassMethod::class;
return InClassMethodNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
if (!$scope->isInClass()) {
throw new \PHPStan\ShouldNotHappenException();
$methodReflection = $scope->getFunction();
if (!$methodReflection instanceof MethodReflection) {
return [];
}

$methodReflection = $scope->getClassReflection()->getNativeMethod($node->name->name);

$messages = [];

foreach (ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getParameters() as $parameterReflection) {
Expand Down
13 changes: 7 additions & 6 deletions src/Rules/Methods/MissingMethodReturnTypehintRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Rules\MissingTypehintCheck;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\MixedType;
use PHPStan\Type\VerbosityLevel;

/**
* @implements \PHPStan\Rules\Rule<\PhpParser\Node\Stmt\ClassMethod>
* @implements \PHPStan\Rules\Rule<InClassMethodNode>
*/
final class MissingMethodReturnTypehintRule implements \PHPStan\Rules\Rule
{
Expand All @@ -25,17 +27,16 @@ public function __construct(MissingTypehintCheck $missingTypehintCheck)

public function getNodeType(): string
{
return \PhpParser\Node\Stmt\ClassMethod::class;
return InClassMethodNode::class;
}

public function processNode(Node $node, Scope $scope): array
{
if (!$scope->isInClass()) {
throw new \PHPStan\ShouldNotHappenException();
$methodReflection = $scope->getFunction();
if (!$methodReflection instanceof MethodReflection) {
return [];
}

$methodReflection = $scope->getClassReflection()->getNativeMethod($node->name->name);

$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();

if ($returnType instanceof MixedType && !$returnType->isExplicitMixed()) {
Expand Down
12 changes: 6 additions & 6 deletions src/Rules/Methods/OverridingMethodRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ public function processNode(Node $node, Scope $scope): array
$parent->getDisplayName(),
$parentConstructor->getName()
))->nonIgnorable()->build(),
], $node->getOriginalNode(), $scope);
], $node, $scope);
}
}
if (!$prototype->isAbstract()) {
return $this->addErrors($messages, $node->getOriginalNode(), $scope);
return $this->addErrors($messages, $node, $scope);
}
}

Expand All @@ -140,7 +140,7 @@ public function processNode(Node $node, Scope $scope): array

$prototypeVariants = $prototype->getVariants();
if (count($prototypeVariants) !== 1) {
return $this->addErrors($messages, $node->getOriginalNode(), $scope);
return $this->addErrors($messages, $node, $scope);
}

$prototypeVariant = $prototypeVariants[0];
Expand Down Expand Up @@ -303,7 +303,7 @@ public function processNode(Node $node, Scope $scope): array
$methodReturnType = $methodVariant->getNativeReturnType();

if (!$prototypeVariant instanceof FunctionVariantWithPhpDocs) {
return $this->addErrors($messages, $node->getOriginalNode(), $scope);
return $this->addErrors($messages, $node, $scope);
}

$prototypeReturnType = $prototypeVariant->getNativeReturnType();
Expand Down Expand Up @@ -332,7 +332,7 @@ public function processNode(Node $node, Scope $scope): array
}
}

return $this->addErrors($messages, $node->getOriginalNode(), $scope);
return $this->addErrors($messages, $node, $scope);
}

private function isTypeCompatible(Type $methodParameterType, Type $prototypeParameterType, bool $supportsContravariance): bool
Expand Down Expand Up @@ -371,7 +371,7 @@ private function isTypeCompatible(Type $methodParameterType, Type $prototypePara
*/
private function addErrors(
array $errors,
Node\Stmt\ClassMethod $classMethod,
InClassMethodNode $classMethod,
Scope $scope
): array
{
Expand Down

0 comments on commit af0c64b

Please sign in to comment.