@@ -41,10 +41,10 @@ final class Php8SignatureMapProvider implements SignatureMapProvider
4141
4242 private const DIRECTORY = __DIR__ . '/../../../vendor/phpstan/php-8-stubs ' ;
4343
44- /** @var array<string, array<string, array{ClassMethod, string}>> */
44+ /** @var array<lowercase- string, array<lowercase- string, array{ClassMethod, string}>> */
4545 private array $ methodNodes = [];
4646
47- /** @var array<string, array<string, Type|null>> */
47+ /** @var array<lowercase- string, array<lowercase- string, Type|null>> */
4848 private array $ constantTypes = [];
4949
5050 private Php8StubsMap $ map ;
@@ -82,10 +82,26 @@ private function findMethodNode(string $className, string $methodName): ?array
8282 {
8383 $ lowerClassName = strtolower ($ className );
8484 $ lowerMethodName = strtolower ($ methodName );
85+
86+ $ this ->findClassStubs ($ className );
8587 if (isset ($ this ->methodNodes [$ lowerClassName ][$ lowerMethodName ])) {
8688 return $ this ->methodNodes [$ lowerClassName ][$ lowerMethodName ];
8789 }
8890
91+ return null ;
92+ }
93+
94+ private function findClassStubs (string $ className ): void
95+ {
96+ $ lowerClassName = strtolower ($ className );
97+
98+ if (
99+ isset ($ this ->methodNodes [$ lowerClassName ])
100+ || isset ($ this ->constantTypes [$ lowerClassName ])
101+ ) {
102+ return ;
103+ }
104+
89105 $ stubFile = self ::DIRECTORY . '/ ' . $ this ->map ->classes [$ lowerClassName ];
90106 $ nodes = $ this ->fileNodesFetcher ->fetchNodes ($ stubFile );
91107 $ classes = $ nodes ->getClassNodes ();
@@ -98,20 +114,37 @@ private function findMethodNode(string $className, string $methodName): ?array
98114 throw new ShouldNotHappenException (sprintf ('Class %s stub not found in %s. ' , $ className , $ stubFile ));
99115 }
100116
117+ $ this ->methodNodes [$ lowerClassName ] = [];
118+ $ this ->constantTypes [$ lowerClassName ] = [];
119+
120+ // find and remember all methods/constants within the stubFile
101121 foreach ($ class [0 ]->getNode ()->stmts as $ stmt ) {
102- if (!$ stmt instanceof ClassMethod) {
122+ if ($ stmt instanceof ClassMethod) {
123+ if (!$ this ->isForCurrentVersion ($ stmt ->attrGroups )) {
124+ continue ;
125+ }
126+
127+ $ this ->methodNodes [$ lowerClassName ][$ stmt ->name ->toLowerString ()] = [$ stmt , $ stubFile ];
128+
103129 continue ;
104130 }
105131
106- if ($ stmt ->name ->toLowerString () === $ lowerMethodName ) {
132+ if (!$ stmt instanceof ClassConst) {
133+ continue ;
134+ }
135+
136+ foreach ($ stmt ->consts as $ const ) {
137+ if ($ stmt ->type === null ) {
138+ continue ;
139+ }
140+
107141 if (!$ this ->isForCurrentVersion ($ stmt ->attrGroups )) {
108142 continue ;
109143 }
110- return $ this ->methodNodes [$ lowerClassName ][$ lowerMethodName ] = [$ stmt , $ stubFile ];
144+
145+ $ this ->constantTypes [$ lowerClassName ][$ const ->name ->toLowerString ()] = ParserNodeTypeToPHPStanType::resolve ($ stmt ->type , null );
111146 }
112147 }
113-
114- return null ;
115148 }
116149
117150 /**
@@ -481,44 +514,12 @@ private function findConstantType(string $className, string $constantName): ?Typ
481514 {
482515 $ lowerClassName = strtolower ($ className );
483516 $ lowerConstantName = strtolower ($ constantName );
517+
518+ $ this ->findClassStubs ($ className );
484519 if (isset ($ this ->constantTypes [$ lowerClassName ][$ lowerConstantName ])) {
485520 return $ this ->constantTypes [$ lowerClassName ][$ lowerConstantName ];
486521 }
487522
488- $ stubFile = self ::DIRECTORY . '/ ' . $ this ->map ->classes [$ lowerClassName ];
489- $ nodes = $ this ->fileNodesFetcher ->fetchNodes ($ stubFile );
490- $ classes = $ nodes ->getClassNodes ();
491- if (count ($ classes ) !== 1 ) {
492- throw new ShouldNotHappenException (sprintf ('Class %s stub not found in %s. ' , $ className , $ stubFile ));
493- }
494-
495- $ class = $ classes [$ lowerClassName ];
496- if (count ($ class ) !== 1 ) {
497- throw new ShouldNotHappenException (sprintf ('Class %s stub not found in %s. ' , $ className , $ stubFile ));
498- }
499-
500- foreach ($ class [0 ]->getNode ()->stmts as $ stmt ) {
501- if (!$ stmt instanceof ClassConst) {
502- continue ;
503- }
504-
505- foreach ($ stmt ->consts as $ const ) {
506- if ($ const ->name ->toString () !== $ constantName ) {
507- continue ;
508- }
509-
510- if (!$ this ->isForCurrentVersion ($ stmt ->attrGroups )) {
511- continue ;
512- }
513-
514- if ($ stmt ->type === null ) {
515- return null ;
516- }
517-
518- return $ this ->constantTypes [$ lowerClassName ][$ lowerConstantName ] = ParserNodeTypeToPHPStanType::resolve ($ stmt ->type , null );
519- }
520- }
521-
522523 return null ;
523524 }
524525
0 commit comments