1
0
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:
Matt Brown 2018-03-23 16:34:45 -04:00
parent 06e850867d
commit f5ef864168
5 changed files with 161 additions and 8 deletions

View File

@ -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
);
}
}

View File

@ -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;

View File

@ -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;
}
}
}
}
/**

View File

@ -34,4 +34,9 @@ class MethodStorage extends FunctionLikeStorage
* @var array<int, bool>
*/
public $used_params = [];
/**
* @var bool
*/
public $overridden_downstream = false;
}

View File

@ -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
/**