44
55use Attribute ;
66use PhpParser \Node ;
7+ use PhpParser \Node \Stmt \Class_ ;
78use PHPStan \Analyser \MutatingScope ;
89use PHPStan \Analyser \Scope ;
910use PHPStan \Reflection \ReflectionProvider ;
1920final class TraitAttributesRule implements Rule
2021{
2122
23+ private int $ classId = 1 ;
24+
2225 public function __construct (
2326 private AttributesCheck $ attributesCheck ,
2427 private ReflectionProvider $ reflectionProvider ,
@@ -41,12 +44,18 @@ public function processNode(Node $node, Scope $scope): array
4144 if (!$ this ->reflectionProvider ->hasClass ($ traitName ->toString ())) {
4245 return [];
4346 }
44- $ classReflection = $ this ->reflectionProvider ->getClass ($ traitName ->toString ());
47+ $ traitClassReflection = $ this ->reflectionProvider ->getClass ($ traitName ->toString ());
4548
4649 if (!$ scope instanceof MutatingScope) {
4750 throw new ShouldNotHappenException ();
4851 }
49- $ scope = $ scope ->enterTrait ($ classReflection );
52+
53+ $ fakeClass = new Class_ (null , ['stmts ' => [new Node \Stmt \TraitUse ([$ traitName ])]], ['startLine ' => $ this ->classId , 'endLine ' => $ this ->classId ]);
54+ $ this ->classId ++;
55+
56+ $ fakeClassReflection = $ this ->reflectionProvider ->getAnonymousClassReflection ($ fakeClass , $ scope );
57+ $ scope = $ scope ->enterClass ($ fakeClassReflection );
58+ $ scope = $ scope ->enterTrait ($ traitClassReflection );
5059
5160 $ errors = $ this ->attributesCheck ->check (
5261 $ scope ,
@@ -55,7 +64,7 @@ public function processNode(Node $node, Scope $scope): array
5564 'class ' ,
5665 );
5766
58- if (count ($ classReflection ->getNativeReflection ()->getAttributes ('AllowDynamicProperties ' )) > 0 ) {
67+ if (count ($ traitClassReflection ->getNativeReflection ()->getAttributes ('AllowDynamicProperties ' )) > 0 ) {
5968 $ errors [] = RuleErrorBuilder::message ('Attribute class AllowDynamicProperties cannot be used with trait. ' )
6069 ->identifier ('trait.allowDynamicProperties ' )
6170 ->nonIgnorable ()
0 commit comments