1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 12:55:26 +01:00

Merge pull request #6793 from orklah/unevaluatedCode

emit UnevaluatedCode after exit or never returning functionlike
This commit is contained in:
orklah 2021-11-01 23:41:36 +01:00 committed by GitHub
commit 96ae8e7600
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 49 additions and 32 deletions

View File

@ -209,6 +209,10 @@ class FunctionCallAnalyzer extends CallAnalyzer
$statements_analyzer->node_data->setType($real_stmt, $stmt_type); $statements_analyzer->node_data->setType($real_stmt, $stmt_type);
if ($stmt_type->isNever()) {
$context->has_returned = true;
}
$event = new AfterEveryFunctionCallAnalysisEvent( $event = new AfterEveryFunctionCallAnalysisEvent(
$stmt, $stmt,
$function_call_info->function_id, $function_call_info->function_id,

View File

@ -362,6 +362,10 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
if ($stmt_type) { if ($stmt_type) {
$statements_analyzer->node_data->setType($stmt, $stmt_type); $statements_analyzer->node_data->setType($stmt, $stmt_type);
if ($stmt_type->isNever()) {
$context->has_returned = true;
}
} }
if ($result->returns_by_ref) { if ($result->returns_by_ref) {

View File

@ -139,6 +139,8 @@ class ExitAnalyzer
$statements_analyzer->node_data->setType($stmt, Type::getEmpty()); $statements_analyzer->node_data->setType($stmt, Type::getEmpty());
$context->has_returned = true;
return true; return true;
} }
} }

View File

@ -17,8 +17,6 @@ class BinaryOperationTest extends TestCase
{ {
if (class_exists('GMP') === false) { if (class_exists('GMP') === false) {
$this->markTestSkipped('Cannot run test, base class "GMP" does not exist!'); $this->markTestSkipped('Cannot run test, base class "GMP" does not exist!');
return;
} }
$this->addFile( $this->addFile(

View File

@ -15,8 +15,6 @@ class ClassTest extends TestCase
{ {
if (class_exists('mysqli') === false) { if (class_exists('mysqli') === false) {
$this->markTestSkipped('Cannot run test, base class "mysqli" does not exist!'); $this->markTestSkipped('Cannot run test, base class "mysqli" does not exist!');
return;
} }
$this->addFile( $this->addFile(

View File

@ -161,8 +161,6 @@ class ConfigTest extends \Psalm\Tests\TestCase
if (is_array($last_error) && $no_symlinking_error === $last_error['message']) { if (is_array($last_error) && $no_symlinking_error === $last_error['message']) {
$this->markTestSkipped($no_symlinking_error); $this->markTestSkipped($no_symlinking_error);
return;
} }
} }

View File

@ -11,8 +11,6 @@ class DestructiveAutoloaderTest extends TestCase
{ {
if (\version_compare(\PHP_VERSION, '7.2.0', '<')) { if (\version_compare(\PHP_VERSION, '7.2.0', '<')) {
$this->markTestSkipped('Test case requires PHP 7.2.'); $this->markTestSkipped('Test case requires PHP 7.2.');
return;
} }
$this->runPsalm(['--no-cache'], __DIR__ . '/' . '../fixtures/DestructiveAutoloader/', true); $this->runPsalm(['--no-cache'], __DIR__ . '/' . '../fixtures/DestructiveAutoloader/', true);

View File

@ -11,8 +11,6 @@ class SuicidalAutoloaderTest extends TestCase
{ {
if (\version_compare(\PHP_VERSION, '7.2.0', '<')) { if (\version_compare(\PHP_VERSION, '7.2.0', '<')) {
$this->markTestSkipped('Test case requires PHP 7.2.'); $this->markTestSkipped('Test case requires PHP 7.2.');
return;
} }
$this->runPsalm(['--no-cache'], __DIR__ . '/' . '../fixtures/SuicidalAutoloader/'); $this->runPsalm(['--no-cache'], __DIR__ . '/' . '../fixtures/SuicidalAutoloader/');

View File

@ -17,8 +17,6 @@ class MethodCallTest extends TestCase
{ {
if (class_exists('SoapClient') === false) { if (class_exists('SoapClient') === false) {
$this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!');
return;
} }
$this->addFile( $this->addFile(

View File

@ -19,8 +19,6 @@ class MethodSignatureTest extends TestCase
{ {
if (class_exists('SoapClient') === false) { if (class_exists('SoapClient') === false) {
$this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!');
return;
} }
$this->addFile( $this->addFile(
@ -58,8 +56,6 @@ class MethodSignatureTest extends TestCase
{ {
if (class_exists('SoapClient') === false) { if (class_exists('SoapClient') === false) {
$this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!');
return;
} }
$this->addFile( $this->addFile(
@ -89,8 +85,6 @@ class MethodSignatureTest extends TestCase
{ {
if (class_exists('SoapClient') === false) { if (class_exists('SoapClient') === false) {
$this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!');
return;
} }
$this->addFile( $this->addFile(
@ -265,8 +259,6 @@ class MethodSignatureTest extends TestCase
$this->expectException(\Psalm\Exception\CodeException::class); $this->expectException(\Psalm\Exception\CodeException::class);
if (class_exists('SoapClient') === false) { if (class_exists('SoapClient') === false) {
$this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!');
return;
} }
$this->addFile( $this->addFile(
@ -304,8 +296,6 @@ class MethodSignatureTest extends TestCase
if (class_exists('SoapClient') === false) { if (class_exists('SoapClient') === false) {
$this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!'); $this->markTestSkipped('Cannot run test, base class "SoapClient" does not exist!');
return;
} }
$this->addFile( $this->addFile(

View File

@ -40,14 +40,10 @@ trait InvalidCodeAnalysisTestTrait
if (strpos($test_name, 'PHP71-') !== false) { if (strpos($test_name, 'PHP71-') !== false) {
if (version_compare(PHP_VERSION, '7.1.0', '<')) { if (version_compare(PHP_VERSION, '7.1.0', '<')) {
$this->markTestSkipped('Test case requires PHP 7.1.'); $this->markTestSkipped('Test case requires PHP 7.1.');
return;
} }
} elseif (strpos($test_name, 'PHP80-') !== false) { } elseif (strpos($test_name, 'PHP80-') !== false) {
if (version_compare(PHP_VERSION, '8.0.0', '<')) { if (version_compare(PHP_VERSION, '8.0.0', '<')) {
$this->markTestSkipped('Test case requires PHP 8.0.'); $this->markTestSkipped('Test case requires PHP 8.0.');
return;
} }
} elseif (strpos($test_name, 'SKIPPED-') !== false) { } elseif (strpos($test_name, 'SKIPPED-') !== false) {
$this->markTestSkipped('Skipped due to a bug.'); $this->markTestSkipped('Skipped due to a bug.');

View File

@ -40,20 +40,14 @@ trait ValidCodeAnalysisTestTrait
if (strpos($test_name, 'PHP73-') !== false) { if (strpos($test_name, 'PHP73-') !== false) {
if (version_compare(PHP_VERSION, '7.3.0', '<')) { if (version_compare(PHP_VERSION, '7.3.0', '<')) {
$this->markTestSkipped('Test case requires PHP 7.3.'); $this->markTestSkipped('Test case requires PHP 7.3.');
return;
} }
} elseif (strpos($test_name, 'PHP71-') !== false) { } elseif (strpos($test_name, 'PHP71-') !== false) {
if (version_compare(PHP_VERSION, '7.1.0', '<')) { if (version_compare(PHP_VERSION, '7.1.0', '<')) {
$this->markTestSkipped('Test case requires PHP 7.1.'); $this->markTestSkipped('Test case requires PHP 7.1.');
return;
} }
} elseif (strpos($test_name, 'PHP80-') !== false) { } elseif (strpos($test_name, 'PHP80-') !== false) {
if (version_compare(PHP_VERSION, '8.0.0', '<')) { if (version_compare(PHP_VERSION, '8.0.0', '<')) {
$this->markTestSkipped('Test case requires PHP 8.0.'); $this->markTestSkipped('Test case requires PHP 8.0.');
return;
} }
} elseif (strpos($test_name, 'SKIPPED-') !== false) { } elseif (strpos($test_name, 'SKIPPED-') !== false) {
$this->markTestSkipped('Skipped due to a bug.'); $this->markTestSkipped('Skipped due to a bug.');

View File

@ -1491,6 +1491,45 @@ class UnusedCodeTest extends TestCase
', ',
'error_message' => 'UnusedFunctionCall', 'error_message' => 'UnusedFunctionCall',
], ],
'functionNeverUnevaluatedCode' => [
'<?php
/** @return never */
function neverReturns() {
die();
}
function f(): void {
neverReturns();
echo "hello";
}
',
'error_message' => 'UnevaluatedCode',
],
'methodNeverUnevaluatedCode' => [
'<?php
class A{
/** @return never */
function neverReturns() {
die();
}
function f(): void {
$this->neverReturns();
echo "hello";
}
}
',
'error_message' => 'UnevaluatedCode',
],
'exitNeverUnevaluatedCode' => [
'<?php
function f(): void {
exit();
echo "hello";
}
',
'error_message' => 'UnevaluatedCode',
],
]; ];
} }
} }