@@ -48,9 +48,6 @@ public function enterNode(Node $node): void
4848 // handles trait definition like trait MyTrait {}
4949 $ this ->handleTraitNode ($ node );
5050
51- // handles trait usage like use MyTrait;
52- $ this ->handleTraitUseNode ($ node );
53-
5451 // handles code like $constantValue = StaticClass::constant;
5552 $ this ->handleStaticClassConstantNode ($ node );
5653
@@ -143,17 +140,7 @@ private function handleClassNode(Node $node): void
143140 $ this ->classDescriptionBuilder ->setClassName ($ node ->namespacedName ->toCodeString ());
144141 }
145142
146- foreach ($ node ->implements as $ interface ) {
147- $ this ->classDescriptionBuilder
148- ->addInterface ($ interface ->toString (), $ interface ->getLine ());
149- }
150-
151- if (null !== $ node ->extends ) {
152- $ this ->classDescriptionBuilder
153- ->addExtends ($ node ->extends ->toString (), $ node ->getLine ());
154- }
155-
156- $ this ->resolveInheritedInterfacesAndExtends ($ node );
143+ $ this ->resolveClassViaReflection ($ node );
157144
158145 $ this ->classDescriptionBuilder ->setFinal ($ node ->isFinal ());
159146
@@ -196,15 +183,7 @@ private function handleEnumNode(Node $node): void
196183 $ this ->classDescriptionBuilder ->setClassName ($ node ->namespacedName ->toCodeString ());
197184 $ this ->classDescriptionBuilder ->setEnum (true );
198185
199- foreach ($ node ->implements as $ interface ) {
200- $ this ->classDescriptionBuilder
201- ->addInterface ($ interface ->toString (), $ interface ->getLine ());
202- }
203-
204- // Resolve inherited interfaces from directly implemented interfaces
205- foreach ($ node ->implements as $ interface ) {
206- $ this ->addReflectedInterfaceParents ($ interface ->toString (), $ interface ->getLine ());
207- }
186+ $ this ->resolveEnumViaReflection ($ node );
208187 }
209188
210189 private function handleStaticClassConstantNode (Node $ node ): void
@@ -314,15 +293,7 @@ private function handleInterfaceNode(Node $node): void
314293 $ this ->classDescriptionBuilder ->setClassName ($ node ->namespacedName ->toCodeString ());
315294 $ this ->classDescriptionBuilder ->setInterface (true );
316295
317- foreach ($ node ->extends as $ interface ) {
318- $ this ->classDescriptionBuilder
319- ->addExtends ($ interface ->toString (), $ interface ->getLine ());
320- }
321-
322- // Resolve ancestor interfaces from directly extended interfaces
323- foreach ($ node ->extends as $ interface ) {
324- $ this ->addReflectedExtendedInterfaceParents ($ interface ->toString (), $ interface ->getLine ());
325- }
296+ $ this ->resolveInterfaceViaReflection ($ node );
326297 }
327298
328299 private function handleTraitNode (Node $ node ): void
@@ -339,18 +310,6 @@ private function handleTraitNode(Node $node): void
339310 $ this ->classDescriptionBuilder ->setTrait (true );
340311 }
341312
342- private function handleTraitUseNode (Node $ node ): void
343- {
344- if (!$ node instanceof Node \Stmt \TraitUse) {
345- return ;
346- }
347-
348- foreach ($ node ->traits as $ trait ) {
349- $ this ->classDescriptionBuilder
350- ->addTrait ($ trait ->toString (), $ trait ->getLine ());
351- }
352- }
353-
354313 private function handleReturnTypeDependency (Node $ node ): void
355314 {
356315 if (!$ node instanceof Node \Stmt \ClassMethod) {
@@ -425,38 +384,33 @@ private function handlePropertyHookNode(Node $node): void
425384 }
426385
427386 /**
428- * Use reflection to resolve interfaces and parent classes from the full inheritance chain.
429- * This enriches the ClassDescription with interfaces inherited from parent classes
430- * and parent interfaces, so that rules like Implement and Extend work across
431- * the entire hierarchy.
387+ * Use reflection to resolve all interfaces, parent classes and traits for a class.
432388 */
433- private function resolveInheritedInterfacesAndExtends (Node \Stmt \Class_ $ node ): void
389+ private function resolveClassViaReflection (Node \Stmt \Class_ $ node ): void
434390 {
435- // Resolve inherited interfaces from directly implemented interfaces
436- foreach ($ node ->implements as $ interface ) {
437- $ this ->addReflectedInterfaceParents ($ interface ->toString (), $ interface ->getLine ());
438- }
439-
440- // Resolve inherited interfaces and ancestor classes from parent class
441- if (null === $ node ->extends ) {
391+ if (null === $ node ->namespacedName ) {
442392 return ;
443393 }
444394
445- $ parentClassName = $ node ->extends -> toString ();
446- $ line = $ node ->extends -> getLine ();
395+ $ className = $ node ->namespacedName -> toCodeString ();
396+ $ line = $ node ->getLine ();
447397
448398 try {
449- /** @var class-string $parentClassName */
450- $ reflection = new \ReflectionClass ($ parentClassName );
399+ /** @var class-string $className */
400+ $ reflection = new \ReflectionClass ($ className );
451401
452402 foreach ($ reflection ->getInterfaceNames () as $ interfaceName ) {
453- $ this ->classDescriptionBuilder ->addReflectedInterface ($ interfaceName , $ line );
403+ $ this ->classDescriptionBuilder ->addInterface ($ interfaceName , $ line );
404+ }
405+
406+ $ parent = $ reflection ->getParentClass ();
407+ while (false !== $ parent ) {
408+ $ this ->classDescriptionBuilder ->addExtends ($ parent ->getName (), $ line );
409+ $ parent = $ parent ->getParentClass ();
454410 }
455411
456- $ ancestor = $ reflection ->getParentClass ();
457- while (false !== $ ancestor ) {
458- $ this ->classDescriptionBuilder ->addReflectedExtends ($ ancestor ->getName (), $ line );
459- $ ancestor = $ ancestor ->getParentClass ();
412+ foreach ($ reflection ->getTraitNames () as $ traitName ) {
413+ $ this ->classDescriptionBuilder ->addTrait ($ traitName , $ line );
460414 }
461415 } catch (\ReflectionException $ e ) {
462416 $ this ->parsingErrors [] = ParsingError::create (
@@ -467,17 +421,27 @@ private function resolveInheritedInterfacesAndExtends(Node\Stmt\Class_ $node): v
467421 }
468422
469423 /**
470- * Use reflection to discover parent interfaces of a given interface,
471- * adding them to the interfaces list (for classes and enums).
424+ * Use reflection to resolve all interfaces and traits for an enum.
472425 */
473- private function addReflectedInterfaceParents ( string $ interfaceName , int $ line ): void
426+ private function resolveEnumViaReflection ( Node \ Stmt \ Enum_ $ node ): void
474427 {
428+ if (null === $ node ->namespacedName ) {
429+ return ;
430+ }
431+
432+ $ className = $ node ->namespacedName ->toCodeString ();
433+ $ line = $ node ->getLine ();
434+
475435 try {
476- /** @var class-string $interfaceName */
477- $ reflection = new \ReflectionClass ($ interfaceName );
436+ /** @var class-string $className */
437+ $ reflection = new \ReflectionClass ($ className );
438+
439+ foreach ($ reflection ->getInterfaceNames () as $ interfaceName ) {
440+ $ this ->classDescriptionBuilder ->addInterface ($ interfaceName , $ line );
441+ }
478442
479- foreach ($ reflection ->getInterfaceNames () as $ parentInterfaceName ) {
480- $ this ->classDescriptionBuilder ->addReflectedInterface ( $ parentInterfaceName , $ line );
443+ foreach ($ reflection ->getTraitNames () as $ traitName ) {
444+ $ this ->classDescriptionBuilder ->addTrait ( $ traitName , $ line );
481445 }
482446 } catch (\ReflectionException $ e ) {
483447 $ this ->parsingErrors [] = ParsingError::create (
@@ -488,17 +452,23 @@ private function addReflectedInterfaceParents(string $interfaceName, int $line):
488452 }
489453
490454 /**
491- * Use reflection to discover parent interfaces of a given interface,
492- * adding them to the extends list (for interface definitions).
455+ * Use reflection to resolve all parent interfaces for an interface definition.
493456 */
494- private function addReflectedExtendedInterfaceParents ( string $ interfaceName , int $ line ): void
457+ private function resolveInterfaceViaReflection ( Node \ Stmt \ Interface_ $ node ): void
495458 {
459+ if (null === $ node ->namespacedName ) {
460+ return ;
461+ }
462+
463+ $ className = $ node ->namespacedName ->toCodeString ();
464+ $ line = $ node ->getLine ();
465+
496466 try {
497- /** @var class-string $interfaceName */
498- $ reflection = new \ReflectionClass ($ interfaceName );
467+ /** @var class-string $className */
468+ $ reflection = new \ReflectionClass ($ className );
499469
500- foreach ($ reflection ->getInterfaceNames () as $ parentInterfaceName ) {
501- $ this ->classDescriptionBuilder ->addReflectedExtends ( $ parentInterfaceName , $ line );
470+ foreach ($ reflection ->getInterfaceNames () as $ interfaceName ) {
471+ $ this ->classDescriptionBuilder ->addExtends ( $ interfaceName , $ line );
502472 }
503473 } catch (\ReflectionException $ e ) {
504474 $ this ->parsingErrors [] = ParsingError::create (
0 commit comments