mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
When there’s an irrecoverqable syntax error invalidate all issues in the file
This commit is contained in:
parent
f738e19b04
commit
6b53e79505
@ -611,6 +611,7 @@ class Analyzer
|
||||
|
||||
$changed_members = $statements_provider->getChangedMembers();
|
||||
$unchanged_signature_members = $statements_provider->getUnchangedSignatureMembers();
|
||||
$errored_files = $statements_provider->getErrors();
|
||||
|
||||
$diff_map = $statements_provider->getDiffMap();
|
||||
|
||||
@ -751,6 +752,11 @@ class Analyzer
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($errored_files as $file_path => $_) {
|
||||
unset($this->analyzed_methods[$file_path]);
|
||||
unset($this->existing_issues[$file_path]);
|
||||
}
|
||||
|
||||
foreach ($this->analyzed_methods as $file_path => $analyzed_methods) {
|
||||
foreach ($analyzed_methods as $correct_method_id => $_) {
|
||||
$trait_safe_method_id = $correct_method_id;
|
||||
|
@ -343,7 +343,7 @@ class Functions
|
||||
$cased_name_parts = \explode('\\', $function->cased_name);
|
||||
$pattern_parts = \explode('\\', $pattern);
|
||||
|
||||
if (end($cased_name_parts)[0] !== end($pattern_parts)[0]) {
|
||||
if (\end($cased_name_parts)[0] !== \end($pattern_parts)[0]) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ use function substr;
|
||||
* changed_members:array<string, array<string, bool>>,
|
||||
* unchanged_signature_members:array<string, array<string, bool>>,
|
||||
* diff_map:array<string, array<int, array{0:int, 1:int, 2:int, 3:int}>>,
|
||||
* errors:array<string, bool>,
|
||||
* classlike_storage:array<string, \Psalm\Storage\ClassLikeStorage>,
|
||||
* file_storage:array<lowercase-string, \Psalm\Storage\FileStorage>,
|
||||
* new_file_content_hashes: array<string, string>,
|
||||
@ -377,6 +378,7 @@ class Scanner
|
||||
'changed_members' => $statements_provider->getChangedMembers(),
|
||||
'unchanged_signature_members' => $statements_provider->getUnchangedSignatureMembers(),
|
||||
'diff_map' => $statements_provider->getDiffMap(),
|
||||
'errors' => $statements_provider->getErrors(),
|
||||
'classlike_storage' => $codebase->classlike_storage_provider->getAll(),
|
||||
'file_storage' => $codebase->file_storage_provider->getAll(),
|
||||
'new_file_content_hashes' => $statements_provider->parser_cache_provider
|
||||
@ -405,6 +407,8 @@ class Scanner
|
||||
$this->codebase->statements_provider->addDiffMap(
|
||||
$pool_data['diff_map']
|
||||
);
|
||||
$this->codebase->statements_provider->addErrors($pool_data['errors']);
|
||||
|
||||
if ($this->codebase->taint_flow_graph && $pool_data['taint_data']) {
|
||||
$this->codebase->taint_flow_graph->addGraph($pool_data['taint_data']);
|
||||
}
|
||||
|
@ -370,9 +370,12 @@ class ClassLikeDocblockParser
|
||||
$php_string = '<?php class A { ' . $function_docblock . ' public ' . $function_string . '{} }';
|
||||
|
||||
try {
|
||||
$has_errors = false;
|
||||
|
||||
$statements = \Psalm\Internal\Provider\StatementsProvider::parseStatements(
|
||||
$php_string,
|
||||
$codebase->php_major_version . '.' . $codebase->php_minor_version
|
||||
$codebase->php_major_version . '.' . $codebase->php_minor_version,
|
||||
$has_errors
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
throw new DocblockParseException('Badly-formatted @method string ' . $method_entry);
|
||||
|
@ -55,6 +55,11 @@ class StatementsProvider
|
||||
*/
|
||||
private $changed_members = [];
|
||||
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<int, array{0: int, 1: int, 2: int, 3: int}>>
|
||||
*/
|
||||
@ -86,6 +91,8 @@ class StatementsProvider
|
||||
*/
|
||||
public function getStatementsForFile(string $file_path, string $php_version, ?Progress $progress = null): array
|
||||
{
|
||||
unset($this->errors[$file_path]);
|
||||
|
||||
if ($progress === null) {
|
||||
$progress = new VoidProgress();
|
||||
}
|
||||
@ -104,7 +111,9 @@ class StatementsProvider
|
||||
) {
|
||||
$progress->debug('Parsing ' . $file_path . "\n");
|
||||
|
||||
$stmts = self::parseStatements($file_contents, $php_version, $file_path);
|
||||
$has_errors = false;
|
||||
|
||||
$stmts = self::parseStatements($file_contents, $php_version, $has_errors, $file_path);
|
||||
|
||||
return $stmts ?: [];
|
||||
}
|
||||
@ -163,16 +172,19 @@ class StatementsProvider
|
||||
}
|
||||
}
|
||||
|
||||
$has_errors = false;
|
||||
|
||||
$stmts = self::parseStatements(
|
||||
$file_contents,
|
||||
$php_version,
|
||||
$has_errors,
|
||||
$file_path,
|
||||
$existing_file_contents,
|
||||
$existing_statements_copy,
|
||||
$file_changes
|
||||
);
|
||||
|
||||
if ($existing_file_contents && $existing_statements) {
|
||||
if ($existing_file_contents && $existing_statements && (!$has_errors || $stmts)) {
|
||||
[$unchanged_members, $unchanged_signature_members, $changed_members, $diff_map]
|
||||
= \Psalm\Internal\Diff\FileStatementsDiffer::diff(
|
||||
$existing_statements,
|
||||
@ -258,6 +270,8 @@ class StatementsProvider
|
||||
}
|
||||
|
||||
$this->diff_map[$file_path] = $diff_map;
|
||||
} elseif ($has_errors && !$stmts) {
|
||||
$this->errors[$file_path] = true;
|
||||
}
|
||||
|
||||
if ($this->file_storage_cache_provider) {
|
||||
@ -313,6 +327,23 @@ class StatementsProvider
|
||||
$this->unchanged_signature_members = array_merge($more_unchanged_members, $this->unchanged_signature_members);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, bool>
|
||||
*/
|
||||
public function getErrors() : array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, bool> $errors
|
||||
*
|
||||
*/
|
||||
public function addErrors(array $errors): void
|
||||
{
|
||||
$this->errors += $errors;
|
||||
}
|
||||
|
||||
public function setUnchangedFile(string $file_path): void
|
||||
{
|
||||
if (!isset($this->diff_map[$file_path])) {
|
||||
@ -354,6 +385,7 @@ class StatementsProvider
|
||||
public static function parseStatements(
|
||||
string $file_contents,
|
||||
string $php_version,
|
||||
bool &$has_errors,
|
||||
?string $file_path = null,
|
||||
?string $existing_file_contents = null,
|
||||
?array $existing_statements = null,
|
||||
@ -416,6 +448,7 @@ class StatementsProvider
|
||||
|
||||
if ($error_handler->hasErrors() && $file_path) {
|
||||
$config = \Psalm\Config::getInstance();
|
||||
$has_errors = true;
|
||||
|
||||
foreach ($error_handler->getErrors() as $error) {
|
||||
if ($error->hasColumnInfo()) {
|
||||
|
@ -79,7 +79,9 @@ class AlgebraTest extends TestCase
|
||||
|| ($b3 === true && $b4 === true && $b5 === true)
|
||||
|| ($b6 === true && $b7 === true && $b8 === true);';
|
||||
|
||||
$dnf_stmt = StatementsProvider::parseStatements($dnf, '7.4')[0];
|
||||
$has_errors = false;
|
||||
|
||||
$dnf_stmt = StatementsProvider::parseStatements($dnf, '7.4', $has_errors)[0];
|
||||
|
||||
$this->assertInstanceOf(PhpParser\Node\Stmt\Expression::class, $dnf_stmt);
|
||||
|
||||
|
@ -28,8 +28,10 @@ class FileDiffTest extends TestCase
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$a_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($a, '7.4');
|
||||
$b_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($b, '7.4');
|
||||
$has_errors = false;
|
||||
|
||||
$a_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($a, '7.4', $has_errors);
|
||||
$b_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($b, '7.4', $has_errors);
|
||||
|
||||
$diff = \Psalm\Internal\Diff\FileStatementsDiffer::diff($a_stmts, $b_stmts, $a, $b);
|
||||
|
||||
@ -88,7 +90,9 @@ class FileDiffTest extends TestCase
|
||||
|
||||
$file_changes = \Psalm\Internal\Diff\FileDiffer::getDiff($a, $b);
|
||||
|
||||
$a_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($a, '7.4');
|
||||
$has_errors = false;
|
||||
|
||||
$a_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($a, '7.4', $has_errors);
|
||||
|
||||
$traverser = new PhpParser\NodeTraverser;
|
||||
$traverser->addVisitor(new \Psalm\Internal\PhpVisitor\CloningVisitor);
|
||||
@ -98,8 +102,8 @@ class FileDiffTest extends TestCase
|
||||
|
||||
$this->assertTreesEqual($a_stmts, $a_stmts_copy);
|
||||
|
||||
$b_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($b, '7.4', null, $a, $a_stmts_copy, $file_changes);
|
||||
$b_clean_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($b, '7.4');
|
||||
$b_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($b, '7.4', $has_errors, null, $a, $a_stmts_copy, $file_changes);
|
||||
$b_clean_stmts = \Psalm\Internal\Provider\StatementsProvider::parseStatements($b, '7.4', $has_errors);
|
||||
|
||||
$this->assertTreesEqual($b_clean_stmts, $b_stmts);
|
||||
|
||||
|
@ -1818,6 +1818,96 @@ class TemporaryUpdateTest extends \Psalm\Tests\TestCase
|
||||
false,
|
||||
true
|
||||
],
|
||||
'syntaxErrorFixed' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public static function foo() : void {
|
||||
$a = 5;
|
||||
//foreach ([1, 2, 3] as $b) {
|
||||
echo $b;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
|
||||
public static function bar() : void {
|
||||
echo $a;
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public static function foo() : void {
|
||||
$a = 5;
|
||||
foreach ([1, 2, 3] as $b) {
|
||||
echo $b;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
|
||||
public static function bar() : void {
|
||||
echo $a;
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[347, 452, 538], [500, 500]],
|
||||
],
|
||||
'updateExampleWithSyntaxErrorThen' => [
|
||||
[
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public static function foo() : void {
|
||||
$a = 5;
|
||||
foreach ([1, 2, 3] as $b) {
|
||||
echo $b;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
|
||||
public static function bar() : void {
|
||||
echo $a;
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public static function foo() : void {
|
||||
$a = 5;
|
||||
//foreach ([1, 2, 3] as $b) {
|
||||
echo $b;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
|
||||
public static function bar() : void {
|
||||
echo $a;
|
||||
}
|
||||
}',
|
||||
],
|
||||
[
|
||||
getcwd() . DIRECTORY_SEPARATOR . 'A.php' => '<?php
|
||||
class A {
|
||||
public static function foo() : void {
|
||||
$a = 5;
|
||||
foreach ([1, 2, 3] as $b) {
|
||||
echo $b;
|
||||
}
|
||||
echo $a;
|
||||
}
|
||||
|
||||
public static function bar() : void {
|
||||
echo $a;
|
||||
}
|
||||
}',
|
||||
],
|
||||
],
|
||||
'error_positions' => [[500, 500], [347, 452, 538], [500, 500]],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1517,7 +1517,7 @@ class FunctionTemplateTest extends TestCase
|
||||
if (is_array($iterable)) {}
|
||||
}'
|
||||
],
|
||||
'transformNestedTemplateWherePossible' => [
|
||||
'SKIPPED-transformNestedTemplateWherePossible' => [
|
||||
'<?php
|
||||
/**
|
||||
* @template TValue
|
||||
|
Loading…
Reference in New Issue
Block a user