1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

MissingClassConstType

This commit is contained in:
Jack Worman 2024-03-14 13:12:01 -04:00
parent 4ea41cb69a
commit c7fc76ec57
No known key found for this signature in database
9 changed files with 139 additions and 14 deletions

View File

@ -313,6 +313,7 @@
<xs:element name="MismatchingDocblockParamType" type="IssueHandlerType" minOccurs="0" /> <xs:element name="MismatchingDocblockParamType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MismatchingDocblockPropertyType" type="IssueHandlerType" minOccurs="0" /> <xs:element name="MismatchingDocblockPropertyType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MismatchingDocblockReturnType" type="IssueHandlerType" minOccurs="0" /> <xs:element name="MismatchingDocblockReturnType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingClassConstType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingClosureParamType" type="IssueHandlerType" minOccurs="0" /> <xs:element name="MissingClosureParamType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingClosureReturnType" type="IssueHandlerType" minOccurs="0" /> <xs:element name="MissingClosureReturnType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingConstructor" type="IssueHandlerType" minOccurs="0" /> <xs:element name="MissingConstructor" type="IssueHandlerType" minOccurs="0" />

View File

@ -232,6 +232,7 @@ Level 5 and above allows a more non-verifiable code, and higher levels are even
- [InvalidDocblockParamName](issues/InvalidDocblockParamName.md) - [InvalidDocblockParamName](issues/InvalidDocblockParamName.md)
- [InvalidFalsableReturnType](issues/InvalidFalsableReturnType.md) - [InvalidFalsableReturnType](issues/InvalidFalsableReturnType.md)
- [InvalidStringClass](issues/InvalidStringClass.md) - [InvalidStringClass](issues/InvalidStringClass.md)
- [MissingClassConstType](issues/MissingClassConstType.md)
- [MissingClosureParamType](issues/MissingClosureParamType.md) - [MissingClosureParamType](issues/MissingClosureParamType.md)
- [MissingClosureReturnType](issues/MissingClosureReturnType.md) - [MissingClosureReturnType](issues/MissingClosureReturnType.md)
- [MissingConstructor](issues/MissingConstructor.md) - [MissingConstructor](issues/MissingConstructor.md)

View File

@ -113,6 +113,7 @@
- [MismatchingDocblockParamType](issues/MismatchingDocblockParamType.md) - [MismatchingDocblockParamType](issues/MismatchingDocblockParamType.md)
- [MismatchingDocblockPropertyType](issues/MismatchingDocblockPropertyType.md) - [MismatchingDocblockPropertyType](issues/MismatchingDocblockPropertyType.md)
- [MismatchingDocblockReturnType](issues/MismatchingDocblockReturnType.md) - [MismatchingDocblockReturnType](issues/MismatchingDocblockReturnType.md)
- [MissingClassConstType](issues/MissingClassConstType.md)
- [MissingClosureParamType](issues/MissingClosureParamType.md) - [MissingClosureParamType](issues/MissingClosureParamType.md)
- [MissingClosureReturnType](issues/MissingClosureReturnType.md) - [MissingClosureReturnType](issues/MissingClosureReturnType.md)
- [MissingConstructor](issues/MissingConstructor.md) - [MissingConstructor](issues/MissingConstructor.md)

View File

@ -0,0 +1,21 @@
# MissingClassConstType
Emitted when a class constant doesn't have a declared type.
```php
<?php
class A {
public const B = 0;
}
```
Correct with:
```php
<?php
class A {
public const int B = 0;
}
```

View File

@ -48,6 +48,7 @@ use Psalm\Issue\InvalidDocblock;
use Psalm\Issue\InvalidEnumBackingType; use Psalm\Issue\InvalidEnumBackingType;
use Psalm\Issue\InvalidEnumCaseValue; use Psalm\Issue\InvalidEnumCaseValue;
use Psalm\Issue\InvalidTypeImport; use Psalm\Issue\InvalidTypeImport;
use Psalm\Issue\MissingClassConstType;
use Psalm\Issue\MissingDocblockType; use Psalm\Issue\MissingDocblockType;
use Psalm\Issue\MissingPropertyType; use Psalm\Issue\MissingPropertyType;
use Psalm\Issue\ParseError; use Psalm\Issue\ParseError;
@ -82,6 +83,7 @@ use function ltrim;
use function preg_match; use function preg_match;
use function preg_replace; use function preg_replace;
use function preg_split; use function preg_split;
use function sprintf;
use function strtolower; use function strtolower;
use function trim; use function trim;
use function usort; use function usort;
@ -1418,6 +1420,23 @@ final class ClassLikeNodeScanner
$description, $description,
); );
if ($this->codebase->analysis_php_version_id >= 8_03_00
&& $stmt->type === null
) {
IssueBuffer::maybeAdd(
new MissingClassConstType(
sprintf(
'Class constant "%s::%s" should have a declared type.',
$storage->name,
$const->name->name,
),
new CodeLocation($this->file_scanner, $const),
),
$suppressed_issues,
);
}
if ($exists) { if ($exists) {
$existing_constants[$const->name->name] = $constant_storage; $existing_constants[$const->name->name] = $constant_storage;
} }

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Psalm\Issue;
final class MissingClassConstType extends CodeIssue
{
public const ERROR_LEVEL = 2;
public const SHORTCODE = 359;
}

View File

@ -133,14 +133,20 @@ class PluginTest extends TestCase
$file_path = getcwd() . '/src/somefile.php'; $file_path = getcwd() . '/src/somefile.php';
$this->addFile( $this->addFile(
$file_path, $file_path,
'<?php sprintf(
class A { <<<'PHP'
const C = [ <?php
"foo" => "Psalm\Internal\Analyzer\ProjectAnalyzer", class A {
]; const %s C = [
}', "foo" => "Psalm\Internal\Analyzer\ProjectAnalyzer",
];
}
PHP,
$this->project_analyzer->getCodebase()->analysis_php_version_id >= 8_03_00 ? 'array' : '',
),
); );
$this->analyzeFile($file_path, new Context()); $this->analyzeFile($file_path, new Context());
@ -173,14 +179,18 @@ class PluginTest extends TestCase
$this->addFile( $this->addFile(
$file_path, $file_path,
'<?php sprintf(
namespace Psalm; <<<'PHP'
<?php
class A { namespace Psalm;
const C = [ class A {
"foo" => \Psalm\Internal\Analyzer\ProjectAnalyzer::class . "::foo", const %s C = [
]; "foo" => \Psalm\Internal\Analyzer\ProjectAnalyzer::class . "::foo",
}', ];
}
PHP,
$this->project_analyzer->getCodebase()->analysis_php_version_id >= 8_03_00 ? 'array' : '',
),
); );
$this->analyzeFile($file_path, new Context()); $this->analyzeFile($file_path, new Context());

View File

@ -316,6 +316,7 @@ class DocumentationTest extends TestCase
case 'InvalidOverride': case 'InvalidOverride':
case 'MissingOverrideAttribute': case 'MissingOverrideAttribute':
case 'MissingClassConstType':
$php_version = '8.3'; $php_version = '8.3';
break; break;
} }

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Psalm\Tests;
use Psalm\Issue\MissingClassConstType;
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;
class MissingClassConstTypeTest extends TestCase
{
use ValidCodeAnalysisTestTrait;
use InvalidCodeAnalysisTestTrait;
public function providerValidCodeParse(): iterable
{
return [
'has type; >= PHP 8.3' => [
'code' => <<<'PHP'
<?php
class A {
public const int B = 0;
}
PHP,
'assertions' => [],
'ignored_issues' => [],
'php_version' => '8.3',
],
'no type; < PHP 8.3' => [
'code' => <<<'PHP'
<?php
class A {
public const B = 0;
}
PHP,
'assertions' => [],
'ignored_issues' => [],
'php_version' => '8.2',
],
];
}
public function providerInvalidCodeParse(): iterable
{
return [
'no type; >= PHP 8.3' => [
'code' => <<<'PHP'
<?php
class A {
public const B = 0;
}
PHP,
'error_message' => MissingClassConstType::getIssueType(),
'error_levels' => [],
'php_version' => '8.3',
],
];
}
}