diff --git a/config.xsd b/config.xsd index ab37ca2dcd3..9f8676ce823 100644 --- a/config.xsd +++ b/config.xsd @@ -424,6 +424,8 @@ + + diff --git a/docs/running_psalm/error_levels.md b/docs/running_psalm/error_levels.md index 39f6d46e5c5..3babb92488a 100644 --- a/docs/running_psalm/error_levels.md +++ b/docs/running_psalm/error_levels.md @@ -140,6 +140,7 @@ These issues are treated as errors at level 2 and below. - [PropertyNotSetInConstructor](issues/PropertyNotSetInConstructor.md) - [RawObjectIteration](issues/RawObjectIteration.md) - [RedundantConditionGivenDocblockType](issues/RedundantConditionGivenDocblockType.md) + - [RedundantFunctionCallGivenDocblockType](issues/RedundantFunctionCallGivenDocblockType.md) - [ReferenceConstraintViolation](issues/ReferenceConstraintViolation.md) - [UndefinedTrace](issues/UndefinedTrace.md) - [UnresolvableInclude](issues/UnresolvableInclude.md) @@ -209,6 +210,7 @@ These issues are treated as errors at level 4 and below. - [NoInterfaceProperties](issues/NoInterfaceProperties.md) - [PossibleRawObjectIteration](issues/PossibleRawObjectIteration.md) - [RedundantCondition](issues/RedundantCondition.md) + - [RedundantFunctionCall](issues/RedundantFunctionCall.md) - [RedundantPropertyInitializationCheck](issues/RedundantPropertyInitializationCheck.md) - [StringIncrement](issues/StringIncrement.md) - [TooManyArguments](issues/TooManyArguments.md) diff --git a/docs/running_psalm/issues.md b/docs/running_psalm/issues.md index 43838dafcae..3982858cb49 100644 --- a/docs/running_psalm/issues.md +++ b/docs/running_psalm/issues.md @@ -200,6 +200,8 @@ - [RedundantCastGivenDocblockType](issues/RedundantCastGivenDocblockType.md) - [RedundantCondition](issues/RedundantCondition.md) - [RedundantConditionGivenDocblockType](issues/RedundantConditionGivenDocblockType.md) + - [RedundantFunctionCall](issues/RedundantFunctionCall.md) + - [RedundantFunctionCallGivenDocblockType](issues/RedundantFunctionCallGivenDocblockType.md) - [RedundantIdentityWithTrue](issues/RedundantIdentityWithTrue.md) - [RedundantPropertyInitializationCheck](issues/RedundantPropertyInitializationCheck.md) - [ReferenceConstraintViolation](issues/ReferenceConstraintViolation.md) diff --git a/docs/running_psalm/issues/RedundantFunctionCall.md b/docs/running_psalm/issues/RedundantFunctionCall.md new file mode 100644 index 00000000000..e9fdd48496e --- /dev/null +++ b/docs/running_psalm/issues/RedundantFunctionCall.md @@ -0,0 +1,12 @@ +# RedundantFunctionCall + +Emitted when a function call (`array_values`, `strtolower`, `ksort` etc.) is redundant. + +```php +} $s + * + * @return lowercase-string + */ +function foo($s): string { + $redundantList = array_values($s); + $redundantSubList = array_values($s[1]); + $redundantLowercase = strtolower($redundantSubList[0]); + return $redundantLowercase; +} +``` diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index f0e4ff28299..9584302113e 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -1679,6 +1679,10 @@ public static function getParentIssueType(string $issue_type): ?string return 'RedundantCondition'; } + if ($issue_type === 'RedundantFunctionCallGivenDocblockType') { + return 'RedundantFunctionCall'; + } + if ($issue_type === 'RedundantCastGivenDocblockType') { return 'RedundantCast'; } diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php index 3fb74057c14..cb9143412dc 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php @@ -18,8 +18,8 @@ use Psalm\Issue\ForbiddenCode; use Psalm\Issue\PossibleRawObjectIteration; use Psalm\Issue\RawObjectIteration; -use Psalm\Issue\RedundantCast; -use Psalm\Issue\RedundantCastGivenDocblockType; +use Psalm\Issue\RedundantFunctionCall; +use Psalm\Issue\RedundantFunctionCallGivenDocblockType; use Psalm\IssueBuffer; use Psalm\Node\Expr\VirtualArray; use Psalm\Node\Expr\VirtualArrayItem; @@ -389,7 +389,7 @@ function (array $_): bool { return; } - if ($first_arg && $function_id === 'array_values') { + if ($first_arg && ($function_id === 'array_values' || $function_id === 'ksort')) { $first_arg_type = $statements_analyzer->node_data->getType($first_arg->value); if ($first_arg_type @@ -401,16 +401,16 @@ function (array $_): bool { ) { if ($first_arg_type->from_docblock) { IssueBuffer::maybeAdd( - new RedundantCastGivenDocblockType( - 'The call to array_values is unnecessary given the list docblock type '.$first_arg_type, + new RedundantFunctionCallGivenDocblockType( + "The call to $function_id is unnecessary given the list docblock type $first_arg_type", new CodeLocation($statements_analyzer, $function_name) ), $statements_analyzer->getSuppressedIssues() ); } else { IssueBuffer::maybeAdd( - new RedundantCast( - 'The call to array_values is unnecessary, '.$first_arg_type.' is already a list', + new RedundantFunctionCall( + "The call to $function_id is unnecessary, $first_arg_type is already a list", new CodeLocation($statements_analyzer, $function_name) ), $statements_analyzer->getSuppressedIssues() @@ -430,7 +430,7 @@ function (array $_): bool { ) { if ($first_arg_type->from_docblock) { IssueBuffer::maybeAdd( - new RedundantCastGivenDocblockType( + new RedundantFunctionCallGivenDocblockType( 'The call to strtolower is unnecessary given the docblock type', new CodeLocation($statements_analyzer, $function_name) ), @@ -438,7 +438,7 @@ function (array $_): bool { ); } else { IssueBuffer::maybeAdd( - new RedundantCast( + new RedundantFunctionCall( 'The call to strtolower is unnecessary', new CodeLocation($statements_analyzer, $function_name) ), diff --git a/src/Psalm/Issue/RedundantFunctionCall.php b/src/Psalm/Issue/RedundantFunctionCall.php new file mode 100644 index 00000000000..d84d0a4f826 --- /dev/null +++ b/src/Psalm/Issue/RedundantFunctionCall.php @@ -0,0 +1,9 @@ + [ ' [ @@ -2062,7 +2062,7 @@ function baz(array $bar) : void { function foo(array $a) : array { return array_values($a); }', - 'error_message' => 'RedundantCast', + 'error_message' => 'RedundantFunctionCall', ], 'assignToListWithUpdatedForeachKey' => [ ' */ public function map(callable $callback) { - /** @psalm-suppress RedundantCast */ + /** @psalm-suppress RedundantFunctionCall */ return new static(array_values(array_map($callback, $this->elements))); } }