mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Improve checks to prevent breaking existing typehints when running psalter
This commit is contained in:
parent
06e850867d
commit
f5ef864168
@ -830,6 +830,14 @@ class ClassChecker extends ClassLikeChecker
|
||||
|
||||
$return_type = $codebase->methods->getMethodReturnType($analyzed_method_id, $self_class);
|
||||
|
||||
$overridden_method_ids = isset($class_storage->overridden_method_ids[strtolower($stmt->name)])
|
||||
? $class_storage->overridden_method_ids[strtolower($stmt->name)]
|
||||
: [];
|
||||
|
||||
if ($actual_method_storage->overridden_downstream) {
|
||||
$overridden_method_ids[] = 'overridden::downstream';
|
||||
}
|
||||
|
||||
if (!$return_type && isset($class_storage->interface_method_ids[strtolower($stmt->name)])) {
|
||||
foreach ($class_storage->interface_method_ids[strtolower($stmt->name)] as $interface_method_id) {
|
||||
list($interface_class) = explode('::', $interface_method_id);
|
||||
@ -849,7 +857,8 @@ class ClassChecker extends ClassLikeChecker
|
||||
$method_checker,
|
||||
$interface_return_type,
|
||||
$interface_class,
|
||||
$interface_return_type_location
|
||||
$interface_return_type_location,
|
||||
[$analyzed_method_id]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -860,7 +869,8 @@ class ClassChecker extends ClassLikeChecker
|
||||
$method_checker,
|
||||
$return_type,
|
||||
$self_class,
|
||||
$return_type_location
|
||||
$return_type_location,
|
||||
$overridden_method_ids
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ class ReturnTypeChecker
|
||||
* @param Type\Union|null $return_type
|
||||
* @param string $fq_class_name
|
||||
* @param CodeLocation|null $return_type_location
|
||||
* @param string[] $compatible_method_ids
|
||||
*
|
||||
* @return false|null
|
||||
*/
|
||||
@ -48,7 +49,8 @@ class ReturnTypeChecker
|
||||
FunctionLikeChecker $function_like_checker,
|
||||
Type\Union $return_type = null,
|
||||
$fq_class_name = null,
|
||||
CodeLocation $return_type_location = null
|
||||
CodeLocation $return_type_location = null,
|
||||
array $compatible_method_ids = []
|
||||
) {
|
||||
$suppressed_issues = $function_like_checker->getSuppressedIssues();
|
||||
$project_checker = $source->getFileChecker()->project_checker;
|
||||
@ -230,9 +232,10 @@ class ReturnTypeChecker
|
||||
$inferred_return_type,
|
||||
$source,
|
||||
$function_like_checker,
|
||||
($project_checker->only_replace_php_types_with_non_docblock_types
|
||||
|| $unsafe_return_type)
|
||||
&& $inferred_return_type->from_docblock
|
||||
$compatible_method_ids
|
||||
|| (($project_checker->only_replace_php_types_with_non_docblock_types
|
||||
|| $unsafe_return_type)
|
||||
&& $inferred_return_type->from_docblock)
|
||||
);
|
||||
|
||||
return null;
|
||||
@ -387,9 +390,10 @@ class ReturnTypeChecker
|
||||
$inferred_return_type,
|
||||
$source,
|
||||
$function_like_checker,
|
||||
($project_checker->only_replace_php_types_with_non_docblock_types
|
||||
$compatible_method_ids
|
||||
|| (($project_checker->only_replace_php_types_with_non_docblock_types
|
||||
|| $unsafe_return_type)
|
||||
&& $inferred_return_type->from_docblock
|
||||
&& $inferred_return_type->from_docblock)
|
||||
);
|
||||
|
||||
return null;
|
||||
|
@ -514,6 +514,18 @@ class Populator
|
||||
$storage->inheritable_method_ids[$aliased_method_name] = $declaring_method_id;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($storage->methods as $method_name => $_) {
|
||||
if (isset($storage->overridden_method_ids[$method_name])) {
|
||||
foreach ($storage->overridden_method_ids[$method_name] as $declaring_method_id) {
|
||||
list($declaring_class, $declaring_method_name) = explode('::', $declaring_method_id);
|
||||
$declaring_class_storage = $this->classlike_storage_provider->get($declaring_class);
|
||||
|
||||
// tell the declaring class it's overridden downstream
|
||||
$declaring_class_storage->methods[strtolower($declaring_method_name)]->overridden_downstream = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,4 +34,9 @@ class MethodStorage extends FunctionLikeStorage
|
||||
* @var array<int, bool>
|
||||
*/
|
||||
public $used_params = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $overridden_downstream = false;
|
||||
}
|
||||
|
@ -576,6 +576,128 @@ class FileManipulationTest extends TestCase
|
||||
['MissingReturnType'],
|
||||
true,
|
||||
],
|
||||
'dontAddMissingVoidReturnTypehintForSubclass71' => [
|
||||
'<?php
|
||||
class A {
|
||||
public function foo() {}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public function foo() {}
|
||||
}',
|
||||
'<?php
|
||||
class A {
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function foo() {}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function foo() {}
|
||||
}',
|
||||
'7.1',
|
||||
['MissingReturnType'],
|
||||
true,
|
||||
],
|
||||
'dontAddMissingVoidReturnTypehintForPrivateMethodInSubclass71' => [
|
||||
'<?php
|
||||
class A {
|
||||
private function foo() {}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
private function foo() {}
|
||||
}',
|
||||
'<?php
|
||||
class A {
|
||||
private function foo(): void {}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
private function foo(): void {}
|
||||
}',
|
||||
'7.1',
|
||||
['MissingReturnType'],
|
||||
true,
|
||||
],
|
||||
'dontAddMissingClassReturnTypehintForSubclass71' => [
|
||||
'<?php
|
||||
class A {
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}',
|
||||
'<?php
|
||||
class A {
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}',
|
||||
'7.1',
|
||||
['MissingReturnType'],
|
||||
true,
|
||||
],
|
||||
'dontAddMissingClassReturnTypehintForSubSubclass71' => [
|
||||
'<?php
|
||||
class A {
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
class C extends B {
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}',
|
||||
'<?php
|
||||
class A {
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
class C extends B {
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function foo() {
|
||||
return $this;
|
||||
}
|
||||
}',
|
||||
'7.1',
|
||||
['MissingReturnType'],
|
||||
true,
|
||||
],
|
||||
'fixInvalidIntReturnType56' => [
|
||||
'<?php
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user