From 39c992c255ecaa065ba02aa25b9d4b9408d98a0d Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Tue, 14 Feb 2023 02:25:46 -0400 Subject: [PATCH] Emit issues for calls to `is_a(string, class-string, false)` Fixes vimeo/psalm#4092 --- .../Call/NamedFunctionCallHandler.php | 36 ++++++++++++++ tests/FunctionCallTest.php | 48 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php index 79196cc1d..39cf5dd95 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php @@ -514,6 +514,42 @@ class NamedFunctionCallHandler } } } + + if ($first_arg + && $function_id === 'is_a' + // assertion reconsiler already emits relevant (but different) issues + && !$context->inside_conditional + ) { + $first_arg_type = $statements_analyzer->node_data->getType($first_arg->value); + + if ($first_arg_type && $first_arg_type->isString()) { + $third_arg = $stmt->getArgs()[2] ?? null; + if ($third_arg) { + $third_arg_type = $statements_analyzer->node_data->getType($third_arg->value); + } else { + $third_arg_type = Type::getFalse(); + } + + if ($third_arg_type + && $third_arg_type->isSingle() + && $third_arg_type->isFalse() + ) { + if ($first_arg_type->from_docblock) { + IssueBuffer::maybeAdd(new RedundantFunctionCallGivenDocblockType( + 'Call to is_a always return false when first argument is string ' + . 'unless third argument is true', + new CodeLocation($statements_analyzer, $function_name), + )); + } else { + IssueBuffer::maybeAdd(new RedundantFunctionCall( + 'Call to is_a always return false when first argument is string ' + . 'unless third argument is true', + new CodeLocation($statements_analyzer, $function_name), + )); + } + } + } + } } private static function handleDependentTypeFunction( diff --git a/tests/FunctionCallTest.php b/tests/FunctionCallTest.php index 41916337e..6c0a4f8a6 100644 --- a/tests/FunctionCallTest.php +++ b/tests/FunctionCallTest.php @@ -2693,6 +2693,54 @@ class FunctionCallTest extends TestCase ', 'error_message' => 'InvalidArgument', ], + 'is_a_withAStringAndNoThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAStringAndFalseThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAUnionOfStringsAndNoThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAUnionOfStringsAndFalseThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAClassStringAndNoThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAClassStringAndFalseThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAUnionOfClassStringsAndNoThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], + 'is_a_withAUnionOfClassStringsAndFalseThirdArg' => [ + 'code' => ' 'RedundantFunctionCall', + ], ]; }