diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php index dcde0859b..7c4ace3d8 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallAnalyzer.php @@ -209,6 +209,10 @@ class FunctionCallAnalyzer extends CallAnalyzer $statements_analyzer->node_data->setType($real_stmt, $stmt_type); + if ($stmt_type->isNever()) { + $context->has_returned = true; + } + $event = new AfterEveryFunctionCallAnalysisEvent( $stmt, $function_call_info->function_id, diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php index d3b4b034c..1b3d005f1 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/MethodCallAnalyzer.php @@ -362,6 +362,10 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\ if ($stmt_type) { $statements_analyzer->node_data->setType($stmt, $stmt_type); + + if ($stmt_type->isNever()) { + $context->has_returned = true; + } } if ($result->returns_by_ref) { diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php index a9cf6f617..f9f80a8b6 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php @@ -139,6 +139,8 @@ class ExitAnalyzer $statements_analyzer->node_data->setType($stmt, Type::getEmpty()); + $context->has_returned = true; + return true; } } diff --git a/tests/BinaryOperationTest.php b/tests/BinaryOperationTest.php index 3750adb9b..19928ac02 100644 --- a/tests/BinaryOperationTest.php +++ b/tests/BinaryOperationTest.php @@ -17,8 +17,6 @@ class BinaryOperationTest extends TestCase { if (class_exists('GMP') === false) { $this->markTestSkipped('Cannot run test, base class "GMP" does not exist!'); - - return; } $this->addFile( diff --git a/tests/ClassTest.php b/tests/ClassTest.php index 227e50c4c..7ea1f0595 100644 --- a/tests/ClassTest.php +++ b/tests/ClassTest.php @@ -15,8 +15,6 @@ class ClassTest extends TestCase { if (class_exists('mysqli') === false) { $this->markTestSkipped('Cannot run test, base class "mysqli" does not exist!'); - - return; } $this->addFile( diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 14048db22..3c5050a92 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -161,8 +161,6 @@ class ConfigTest extends \Psalm\Tests\TestCase if (is_array($last_error) && $no_symlinking_error === $last_error['message']) { $this->markTestSkipped($no_symlinking_error); - - return; } } diff --git a/tests/EndToEnd/DestructiveAutoloaderTest.php b/tests/EndToEnd/DestructiveAutoloaderTest.php index a4c392e97..a396ce663 100644 --- a/tests/EndToEnd/DestructiveAutoloaderTest.php +++ b/tests/EndToEnd/DestructiveAutoloaderTest.php @@ -11,8 +11,6 @@ class DestructiveAutoloaderTest extends TestCase { if (\version_compare(\PHP_VERSION, '7.2.0', '<')) { $this->markTestSkipped('Test case requires PHP 7.2.'); - - return; } $this->runPsalm(['--no-cache'], __DIR__ . '/' . '../fixtures/DestructiveAutoloader/', true); diff --git a/tests/EndToEnd/SuicidalAutoloaderTest.php b/tests/EndToEnd/SuicidalAutoloaderTest.php index 6ce439b71..ef18e2b2d 100644 --- a/tests/EndToEnd/SuicidalAutoloaderTest.php +++ b/tests/EndToEnd/SuicidalAutoloaderTest.php @@ -11,8 +11,6 @@ class SuicidalAutoloaderTest extends TestCase { if (\version_compare(\PHP_VERSION, '7.2.0', '<')) { $this->markTestSkipped('Test case requires PHP 7.2.'); - - return; } $this->runPsalm(['--no-cache'], __DIR__ . '/' . '../fixtures/SuicidalAutoloader/'); diff --git a/tests/MethodCallTest.php b/tests/MethodCallTest.php index 334d3bde9..deab0ad35 100644 --- a/tests/MethodCallTest.php +++ b/tests/MethodCallTest.php @@ -17,8 +17,6 @@ class MethodCallTest extends TestCase { if (class_exists('SoapClient') === false) { $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); - - return; } $this->addFile( diff --git a/tests/MethodSignatureTest.php b/tests/MethodSignatureTest.php index 5c222481d..13b700fa0 100644 --- a/tests/MethodSignatureTest.php +++ b/tests/MethodSignatureTest.php @@ -19,8 +19,6 @@ class MethodSignatureTest extends TestCase { if (class_exists('SoapClient') === false) { $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); - - return; } $this->addFile( @@ -58,8 +56,6 @@ class MethodSignatureTest extends TestCase { if (class_exists('SoapClient') === false) { $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); - - return; } $this->addFile( @@ -89,8 +85,6 @@ class MethodSignatureTest extends TestCase { if (class_exists('SoapClient') === false) { $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); - - return; } $this->addFile( @@ -265,8 +259,6 @@ class MethodSignatureTest extends TestCase $this->expectException(\Psalm\Exception\CodeException::class); if (class_exists('SoapClient') === false) { $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); - - return; } $this->addFile( @@ -304,8 +296,6 @@ class MethodSignatureTest extends TestCase if (class_exists('SoapClient') === false) { $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); - - return; } $this->addFile( diff --git a/tests/Traits/InvalidCodeAnalysisTestTrait.php b/tests/Traits/InvalidCodeAnalysisTestTrait.php index 63965af80..6a744ae14 100644 --- a/tests/Traits/InvalidCodeAnalysisTestTrait.php +++ b/tests/Traits/InvalidCodeAnalysisTestTrait.php @@ -40,14 +40,10 @@ trait InvalidCodeAnalysisTestTrait if (strpos($test_name, 'PHP71-') !== false) { if (version_compare(PHP_VERSION, '7.1.0', '<')) { $this->markTestSkipped('Test case requires PHP 7.1.'); - - return; } } elseif (strpos($test_name, 'PHP80-') !== false) { if (version_compare(PHP_VERSION, '8.0.0', '<')) { $this->markTestSkipped('Test case requires PHP 8.0.'); - - return; } } elseif (strpos($test_name, 'SKIPPED-') !== false) { $this->markTestSkipped('Skipped due to a bug.'); diff --git a/tests/Traits/ValidCodeAnalysisTestTrait.php b/tests/Traits/ValidCodeAnalysisTestTrait.php index 077eec281..64be3b4a1 100644 --- a/tests/Traits/ValidCodeAnalysisTestTrait.php +++ b/tests/Traits/ValidCodeAnalysisTestTrait.php @@ -40,20 +40,14 @@ trait ValidCodeAnalysisTestTrait if (strpos($test_name, 'PHP73-') !== false) { if (version_compare(PHP_VERSION, '7.3.0', '<')) { $this->markTestSkipped('Test case requires PHP 7.3.'); - - return; } } elseif (strpos($test_name, 'PHP71-') !== false) { if (version_compare(PHP_VERSION, '7.1.0', '<')) { $this->markTestSkipped('Test case requires PHP 7.1.'); - - return; } } elseif (strpos($test_name, 'PHP80-') !== false) { if (version_compare(PHP_VERSION, '8.0.0', '<')) { $this->markTestSkipped('Test case requires PHP 8.0.'); - - return; } } elseif (strpos($test_name, 'SKIPPED-') !== false) { $this->markTestSkipped('Skipped due to a bug.'); diff --git a/tests/UnusedCodeTest.php b/tests/UnusedCodeTest.php index d8f48c4ed..1f46d3f92 100644 --- a/tests/UnusedCodeTest.php +++ b/tests/UnusedCodeTest.php @@ -1491,6 +1491,45 @@ class UnusedCodeTest extends TestCase ', 'error_message' => 'UnusedFunctionCall', ], + 'functionNeverUnevaluatedCode' => [ + ' 'UnevaluatedCode', + ], + 'methodNeverUnevaluatedCode' => [ + 'neverReturns(); + echo "hello"; + } + } + ', + 'error_message' => 'UnevaluatedCode', + ], + 'exitNeverUnevaluatedCode' => [ + ' 'UnevaluatedCode', + ], ]; } }