mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Fix #4475 - verify that used attributes actual use the Attribute attribute
This commit is contained in:
parent
763eff2e8b
commit
14807326fe
@ -129,55 +129,69 @@ class AttributeAnalyzer
|
||||
|
||||
$attribute_class_storage = $codebase->classlike_storage_provider->get($attribute->fq_class_name);
|
||||
|
||||
if ($attribute_class_storage->attributes) {
|
||||
foreach ($attribute_class_storage->attributes as $attribute_attribute) {
|
||||
if ($attribute_attribute->fq_class_name === 'Attribute') {
|
||||
if (!$attribute_attribute->args) {
|
||||
return;
|
||||
}
|
||||
$has_attribute_attribute = $attribute->fq_class_name === 'Attribute';
|
||||
|
||||
$first_arg = reset($attribute_attribute->args);
|
||||
foreach ($attribute_class_storage->attributes as $attribute_attribute) {
|
||||
if ($attribute_attribute->fq_class_name === 'Attribute') {
|
||||
$has_attribute_attribute = true;
|
||||
|
||||
$first_arg_type = $first_arg->type;
|
||||
if (!$attribute_attribute->args) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($first_arg_type instanceof UnresolvedConstantComponent) {
|
||||
$first_arg_type = new Union([
|
||||
\Psalm\Internal\Codebase\ConstantTypeResolver::resolve(
|
||||
$codebase->classlikes,
|
||||
$first_arg_type,
|
||||
$source instanceof \Psalm\Internal\Analyzer\StatementsAnalyzer ? $source : null
|
||||
)
|
||||
]);
|
||||
}
|
||||
$first_arg = reset($attribute_attribute->args);
|
||||
|
||||
if (!$first_arg_type->isSingleIntLiteral()) {
|
||||
return;
|
||||
}
|
||||
$first_arg_type = $first_arg->type;
|
||||
|
||||
$acceptable_mask = $first_arg_type->getSingleIntLiteral()->value;
|
||||
if ($first_arg_type instanceof UnresolvedConstantComponent) {
|
||||
$first_arg_type = new Union([
|
||||
\Psalm\Internal\Codebase\ConstantTypeResolver::resolve(
|
||||
$codebase->classlikes,
|
||||
$first_arg_type,
|
||||
$source instanceof \Psalm\Internal\Analyzer\StatementsAnalyzer ? $source : null
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
if (($acceptable_mask & $target) !== $target) {
|
||||
$target_map = [
|
||||
1 => 'class',
|
||||
2 => 'function',
|
||||
4 => 'method',
|
||||
8 => 'property',
|
||||
16 => 'class constant',
|
||||
32 => 'function/method parameter'
|
||||
];
|
||||
if (!$first_arg_type->isSingleIntLiteral()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (\Psalm\IssueBuffer::accepts(
|
||||
new InvalidAttribute(
|
||||
'This attribute can not be used on a ' . $target_map[$target],
|
||||
$attribute->name_location
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
$acceptable_mask = $first_arg_type->getSingleIntLiteral()->value;
|
||||
|
||||
if (($acceptable_mask & $target) !== $target) {
|
||||
$target_map = [
|
||||
1 => 'class',
|
||||
2 => 'function',
|
||||
4 => 'method',
|
||||
8 => 'property',
|
||||
16 => 'class constant',
|
||||
32 => 'function/method parameter'
|
||||
];
|
||||
|
||||
if (\Psalm\IssueBuffer::accepts(
|
||||
new InvalidAttribute(
|
||||
'This attribute can not be used on a ' . $target_map[$target],
|
||||
$attribute->name_location
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$has_attribute_attribute) {
|
||||
if (\Psalm\IssueBuffer::accepts(
|
||||
new InvalidAttribute(
|
||||
'The class ' . $attribute->fq_class_name . ' doesn’t have the Attribute attribute',
|
||||
$attribute->name_location
|
||||
),
|
||||
$source->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ abstract class Atomic implements TypeNode
|
||||
/**
|
||||
* @param array{int,int}|null $php_version
|
||||
* @param array<string, array<string, array{Union}>> $template_type_map
|
||||
* @param array<string, TypeAlias\LinkableTypeAlias> $type_aliases
|
||||
* @param array<string, TypeAlias> $type_aliases
|
||||
*/
|
||||
public static function create(
|
||||
string $value,
|
||||
|
@ -111,6 +111,17 @@ class AttributeTest extends TestCase
|
||||
public function providerInvalidCodeParse(): iterable
|
||||
{
|
||||
return [
|
||||
'attributeClassHasNoAttributeAnnotation' => [
|
||||
'<?php
|
||||
class A {}
|
||||
|
||||
#[A]
|
||||
class B {}',
|
||||
'error_message' => 'InvalidAttribute',
|
||||
[],
|
||||
false,
|
||||
'8.0'
|
||||
],
|
||||
'missingAttributeOnClass' => [
|
||||
'<?php
|
||||
use Foo\Bar\Pure;
|
||||
|
Loading…
x
Reference in New Issue
Block a user