Skip to content

Commit

Permalink
Merge pull request #10828 from jack-worman/MissingClassConstType
Browse files Browse the repository at this point in the history
  • Loading branch information
weirdan authored Mar 20, 2024
2 parents 2c1ac98 + c7fc76e commit 3a1b10f
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 14 deletions.
1 change: 1 addition & 0 deletions config.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@
<xs:element name="MismatchingDocblockParamType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MismatchingDocblockPropertyType" 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="MissingClosureReturnType" type="IssueHandlerType" minOccurs="0" />
<xs:element name="MissingConstructor" type="IssueHandlerType" minOccurs="0" />
Expand Down
1 change: 1 addition & 0 deletions docs/running_psalm/error_levels.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ Level 5 and above allows a more non-verifiable code, and higher levels are even
- [InvalidDocblockParamName](issues/InvalidDocblockParamName.md)
- [InvalidFalsableReturnType](issues/InvalidFalsableReturnType.md)
- [InvalidStringClass](issues/InvalidStringClass.md)
- [MissingClassConstType](issues/MissingClassConstType.md)
- [MissingClosureParamType](issues/MissingClosureParamType.md)
- [MissingClosureReturnType](issues/MissingClosureReturnType.md)
- [MissingConstructor](issues/MissingConstructor.md)
Expand Down
1 change: 1 addition & 0 deletions docs/running_psalm/issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
- [MismatchingDocblockParamType](issues/MismatchingDocblockParamType.md)
- [MismatchingDocblockPropertyType](issues/MismatchingDocblockPropertyType.md)
- [MismatchingDocblockReturnType](issues/MismatchingDocblockReturnType.md)
- [MissingClassConstType](issues/MissingClassConstType.md)
- [MissingClosureParamType](issues/MissingClosureParamType.md)
- [MissingClosureReturnType](issues/MissingClosureReturnType.md)
- [MissingConstructor](issues/MissingConstructor.md)
Expand Down
21 changes: 21 additions & 0 deletions docs/running_psalm/issues/MissingClassConstType.md
Original file line number Diff line number Diff line change
@@ -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;
}
```
19 changes: 19 additions & 0 deletions src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
use Psalm\Issue\InvalidEnumBackingType;
use Psalm\Issue\InvalidEnumCaseValue;
use Psalm\Issue\InvalidTypeImport;
use Psalm\Issue\MissingClassConstType;
use Psalm\Issue\MissingDocblockType;
use Psalm\Issue\MissingPropertyType;
use Psalm\Issue\ParseError;
Expand Down Expand Up @@ -82,6 +83,7 @@
use function preg_match;
use function preg_replace;
use function preg_split;
use function sprintf;
use function strtolower;
use function trim;
use function usort;
Expand Down Expand Up @@ -1418,6 +1420,23 @@ private function visitClassConstDeclaration(
$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) {
$existing_constants[$const->name->name] = $constant_storage;
}
Expand Down
11 changes: 11 additions & 0 deletions src/Psalm/Issue/MissingClassConstType.php
Original file line number Diff line number Diff line change
@@ -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;
}
38 changes: 24 additions & 14 deletions tests/Config/PluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,20 @@ public function testStringAnalyzerPluginWithClassConstant(): void

$file_path = getcwd() . '/src/somefile.php';


$this->addFile(
$file_path,
'<?php
class A {
const C = [
"foo" => "Psalm\Internal\Analyzer\ProjectAnalyzer",
];
}',
sprintf(
<<<'PHP'
<?php
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());
Expand Down Expand Up @@ -173,14 +179,18 @@ public function testStringAnalyzerPluginWithClassConstantConcat(): void

$this->addFile(
$file_path,
'<?php
namespace Psalm;
class A {
const C = [
"foo" => \Psalm\Internal\Analyzer\ProjectAnalyzer::class . "::foo",
];
}',
sprintf(
<<<'PHP'
<?php
namespace Psalm;
class A {
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());
Expand Down
1 change: 1 addition & 0 deletions tests/DocumentationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ public function providerInvalidCodeParse(): array

case 'InvalidOverride':
case 'MissingOverrideAttribute':
case 'MissingClassConstType':
$php_version = '8.3';
break;
}
Expand Down
60 changes: 60 additions & 0 deletions tests/MissingClassConstTypeTest.php
Original file line number Diff line number Diff line change
@@ -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',
],
];
}
}

0 comments on commit 3a1b10f

Please sign in to comment.