mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Merge pull request #10176 from weirdan/flag-invalid-declares
This commit is contained in:
commit
d7ba2cc5ee
98
src/Psalm/Internal/Analyzer/Statements/DeclareAnalyzer.php
Normal file
98
src/Psalm/Internal/Analyzer/Statements/DeclareAnalyzer.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Internal\Analyzer\Statements;
|
||||
|
||||
use PhpParser;
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\Context;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Issue\UnrecognizedStatement;
|
||||
use Psalm\IssueBuffer;
|
||||
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class DeclareAnalyzer
|
||||
{
|
||||
public static function analyze(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
PhpParser\Node\Stmt\Declare_ $stmt,
|
||||
Context $context
|
||||
): void {
|
||||
foreach ($stmt->declares as $declaration) {
|
||||
$declaration_key = (string) $declaration->key;
|
||||
|
||||
if ($declaration_key === 'strict_types') {
|
||||
self::analyzeStrictTypesDeclaration($statements_analyzer, $declaration, $context);
|
||||
} elseif ($declaration_key === 'ticks') {
|
||||
self::analyzeTicksDeclaration($statements_analyzer, $declaration);
|
||||
} elseif ($declaration_key === 'encoding') {
|
||||
self::analyzeEncodingDeclaration($statements_analyzer, $declaration);
|
||||
} else {
|
||||
IssueBuffer::maybeAdd(
|
||||
new UnrecognizedStatement(
|
||||
'Psalm does not understand the declare statement ' . $declaration->key,
|
||||
new CodeLocation($statements_analyzer, $declaration),
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function analyzeStrictTypesDeclaration(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
PhpParser\Node\Stmt\DeclareDeclare $declaration,
|
||||
Context $context
|
||||
): void {
|
||||
if (!$declaration->value instanceof PhpParser\Node\Scalar\LNumber
|
||||
|| !in_array($declaration->value->value, [0, 1], true)
|
||||
) {
|
||||
IssueBuffer::maybeAdd(
|
||||
new UnrecognizedStatement(
|
||||
'strict_types declaration can only have 1 or 0 as a value',
|
||||
new CodeLocation($statements_analyzer, $declaration),
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues(),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($declaration->value->value === 1) {
|
||||
$context->strict_types = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static function analyzeTicksDeclaration(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
PhpParser\Node\Stmt\DeclareDeclare $declaration
|
||||
): void {
|
||||
if (!$declaration->value instanceof PhpParser\Node\Scalar\LNumber) {
|
||||
IssueBuffer::maybeAdd(
|
||||
new UnrecognizedStatement(
|
||||
'ticks declaration should have integer as a value',
|
||||
new CodeLocation($statements_analyzer, $declaration),
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static function analyzeEncodingDeclaration(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
PhpParser\Node\Stmt\DeclareDeclare $declaration
|
||||
): void {
|
||||
if (!$declaration->value instanceof PhpParser\Node\Scalar\String_) {
|
||||
IssueBuffer::maybeAdd(
|
||||
new UnrecognizedStatement(
|
||||
'encoding declaration should have string as a value',
|
||||
new CodeLocation($statements_analyzer, $declaration),
|
||||
),
|
||||
$statements_analyzer->getSuppressedIssues(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ use Psalm\Internal\Analyzer\Statements\Block\TryAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Block\WhileAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\BreakAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\ContinueAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\DeclareAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\EchoAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\Assignment\InstancePropertyAssignmentAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\AssignmentAnalyzer;
|
||||
@ -597,14 +598,7 @@ class StatementsAnalyzer extends SourceAnalyzer
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Label) {
|
||||
// do nothing
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Declare_) {
|
||||
foreach ($stmt->declares as $declaration) {
|
||||
if ((string) $declaration->key === 'strict_types'
|
||||
&& $declaration->value instanceof PhpParser\Node\Scalar\LNumber
|
||||
&& $declaration->value->value === 1
|
||||
) {
|
||||
$context->strict_types = true;
|
||||
}
|
||||
}
|
||||
DeclareAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\HaltCompiler) {
|
||||
$context->has_returned = true;
|
||||
} else {
|
||||
|
73
tests/Internal/Analyzer/DeclareAnalyzerTest.php
Normal file
73
tests/Internal/Analyzer/DeclareAnalyzerTest.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psalm\Tests\Internal\Analyzer;
|
||||
|
||||
use Psalm\Tests\TestCase;
|
||||
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
|
||||
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
|
||||
|
||||
final class DeclareAnalyzerTest extends TestCase
|
||||
{
|
||||
use ValidCodeAnalysisTestTrait;
|
||||
use InvalidCodeAnalysisTestTrait;
|
||||
|
||||
public function providerValidCodeParse(): iterable
|
||||
{
|
||||
yield 'declareStrictTypes1' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(strict_types=1);
|
||||
PHP,
|
||||
];
|
||||
|
||||
yield 'declareStrictTypes0' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(strict_types=0);
|
||||
PHP,
|
||||
];
|
||||
|
||||
yield 'declareTicks' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(ticks=5);
|
||||
PHP,
|
||||
];
|
||||
|
||||
yield 'declareEncoding' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(encoding='ISO-8859-1');
|
||||
PHP,
|
||||
];
|
||||
}
|
||||
|
||||
public function providerInvalidCodeParse(): iterable
|
||||
{
|
||||
yield 'declareUnknownDirective' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(whatever=123);
|
||||
PHP,
|
||||
'error_message' => 'UnrecognizedStatement',
|
||||
];
|
||||
|
||||
yield 'declareUnknownValueForStrictTypes' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(strict_types='forty-two');
|
||||
PHP,
|
||||
'error_message' => 'UnrecognizedStatement',
|
||||
];
|
||||
|
||||
yield 'declareInvalidValueForTicks' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(ticks='often');
|
||||
PHP,
|
||||
'error_message' => 'UnrecognizedStatement',
|
||||
];
|
||||
|
||||
yield 'declareInvalidValueForEncoding' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php declare(encoding=88591);
|
||||
PHP,
|
||||
'error_message' => 'UnrecognizedStatement',
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user