mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Allow opt-in to strict return type checking
This commit is contained in:
parent
3483c59d9b
commit
1389dc6adf
@ -76,6 +76,7 @@
|
|||||||
<xs:attribute name="allowInternalNamedArgumentCalls" type="xs:boolean" default="true" />
|
<xs:attribute name="allowInternalNamedArgumentCalls" type="xs:boolean" default="true" />
|
||||||
<xs:attribute name="allowNamedArgumentCalls" type="xs:boolean" default="true" />
|
<xs:attribute name="allowNamedArgumentCalls" type="xs:boolean" default="true" />
|
||||||
<xs:attribute name="reportInfo" type="xs:boolean" default="true" />
|
<xs:attribute name="reportInfo" type="xs:boolean" default="true" />
|
||||||
|
<xs:attribute name="restrictReturnTypes" type="xs:boolean" default="false" />
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="ProjectFilesType">
|
<xs:complexType name="ProjectFilesType">
|
||||||
|
@ -433,6 +433,11 @@ class Config
|
|||||||
*/
|
*/
|
||||||
public $resolve_from_config_file = true;
|
public $resolve_from_config_file = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $restrict_return_types = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
@ -835,6 +840,7 @@ class Config
|
|||||||
'allowNamedArgumentCalls' => 'allow_named_arg_calls',
|
'allowNamedArgumentCalls' => 'allow_named_arg_calls',
|
||||||
'findUnusedPsalmSuppress' => 'find_unused_psalm_suppress',
|
'findUnusedPsalmSuppress' => 'find_unused_psalm_suppress',
|
||||||
'reportInfo' => 'report_info',
|
'reportInfo' => 'report_info',
|
||||||
|
'restrictReturnTypes' => 'restrict_return_types',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($booleanAttributes as $xmlName => $internalName) {
|
foreach ($booleanAttributes as $xmlName => $internalName) {
|
||||||
|
@ -525,63 +525,68 @@ class ReturnTypeAnalyzer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($codebase->alter_code
|
} elseif (!$inferred_return_type->hasMixed()
|
||||||
&& isset($project_analyzer->getIssuesToFix()['LessSpecificReturnType'])
|
&& !UnionTypeComparator::isContainedBy(
|
||||||
&& !in_array('LessSpecificReturnType', $suppressed_issues)
|
|
||||||
&& !($function_like_storage instanceof MethodStorage && $function_like_storage->inheritdoc)
|
|
||||||
) {
|
|
||||||
if (!UnionTypeComparator::isContainedBy(
|
|
||||||
$codebase,
|
$codebase,
|
||||||
$declared_return_type,
|
$declared_return_type,
|
||||||
$inferred_return_type,
|
$inferred_return_type,
|
||||||
false,
|
false,
|
||||||
false
|
false
|
||||||
)) {
|
)
|
||||||
self::addOrUpdateReturnType(
|
|
||||||
$function,
|
|
||||||
$project_analyzer,
|
|
||||||
$inferred_return_type,
|
|
||||||
$source,
|
|
||||||
$compatible_method_ids
|
|
||||||
|| (($project_analyzer->only_replace_php_types_with_non_docblock_types
|
|
||||||
|| $unsafe_return_type)
|
|
||||||
&& $inferred_return_type->from_docblock),
|
|
||||||
$function_like_storage
|
|
||||||
);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} elseif (!$inferred_return_type->hasMixed()
|
|
||||||
&& ((!$inferred_return_type->isNullable() && $declared_return_type->isNullable())
|
|
||||||
|| (!$inferred_return_type->isFalsable() && $declared_return_type->isFalsable()))
|
|
||||||
) {
|
) {
|
||||||
if ($function instanceof Function_
|
if ($codebase->alter_code) {
|
||||||
|| $function instanceof Closure
|
if (isset($project_analyzer->getIssuesToFix()['LessSpecificReturnType'])
|
||||||
|| $function instanceof ArrowFunction
|
&& !in_array('LessSpecificReturnType', $suppressed_issues)
|
||||||
|| $function->isPrivate()
|
&& !($function_like_storage instanceof MethodStorage && $function_like_storage->inheritdoc)
|
||||||
) {
|
) {
|
||||||
$check_for_less_specific_type = true;
|
self::addOrUpdateReturnType(
|
||||||
} elseif ($source instanceof StatementsAnalyzer) {
|
$function,
|
||||||
if ($function_like_storage instanceof MethodStorage) {
|
$project_analyzer,
|
||||||
$check_for_less_specific_type = !$function_like_storage->overridden_somewhere;
|
$inferred_return_type,
|
||||||
|
$source,
|
||||||
|
$compatible_method_ids
|
||||||
|
|| (($project_analyzer->only_replace_php_types_with_non_docblock_types
|
||||||
|
|| $unsafe_return_type)
|
||||||
|
&& $inferred_return_type->from_docblock),
|
||||||
|
$function_like_storage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($function instanceof Function_
|
||||||
|
|| $function instanceof Closure
|
||||||
|
|| $function instanceof ArrowFunction
|
||||||
|
|| $function->isPrivate()
|
||||||
|
) {
|
||||||
|
$check_for_less_specific_type = true;
|
||||||
|
} elseif ($source instanceof StatementsAnalyzer) {
|
||||||
|
if ($function_like_storage instanceof MethodStorage) {
|
||||||
|
$check_for_less_specific_type = !$function_like_storage->overridden_somewhere;
|
||||||
|
} else {
|
||||||
|
$check_for_less_specific_type = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$check_for_less_specific_type = false;
|
$check_for_less_specific_type = false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$check_for_less_specific_type = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($check_for_less_specific_type) {
|
if ($check_for_less_specific_type
|
||||||
if (IssueBuffer::accepts(
|
&& (\Psalm\Config::getInstance()->restrict_return_types
|
||||||
new LessSpecificReturnType(
|
|| (!$inferred_return_type->isNullable() && $declared_return_type->isNullable())
|
||||||
'The inferred return type \'' . $inferred_return_type . '\' for ' . $cased_method_id .
|
|| (!$inferred_return_type->isFalsable() && $declared_return_type->isFalsable()))
|
||||||
' is more specific than the declared return type \'' . $declared_return_type . '\'',
|
) {
|
||||||
$return_type_location
|
if (IssueBuffer::accepts(
|
||||||
),
|
new LessSpecificReturnType(
|
||||||
$suppressed_issues,
|
'The inferred return type \''
|
||||||
!($function_like_storage instanceof MethodStorage && $function_like_storage->inheritdoc)
|
. $inferred_return_type->getId()
|
||||||
)) {
|
. '\' for ' . $cased_method_id
|
||||||
return false;
|
. ' is more specific than the declared return type \''
|
||||||
|
. $declared_return_type->getId() . '\'',
|
||||||
|
$return_type_location
|
||||||
|
),
|
||||||
|
$suppressed_issues,
|
||||||
|
!($function_like_storage instanceof MethodStorage && $function_like_storage->inheritdoc)
|
||||||
|
)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -597,7 +597,6 @@ class ConditionalReturnTypeTest extends TestCase
|
|||||||
* @template T of mixed|false|null
|
* @template T of mixed|false|null
|
||||||
* @param T $i
|
* @param T $i
|
||||||
* @return (T is false ? no-return : T is null ? no-return : T)
|
* @return (T is false ? no-return : T is null ? no-return : T)
|
||||||
* @psalm-suppress LessSpecificReturnType
|
|
||||||
*/
|
*/
|
||||||
function orThrow($i) {
|
function orThrow($i) {
|
||||||
if ($i === false || $i === null) {
|
if ($i === false || $i === null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user