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