1818use Roave \BetterReflection \SourceLocator \SourceStubber \Exception \CouldNotFindPhpStormStubs ;
1919use Roave \BetterReflection \Util \ConstantNodeChecker ;
2020use Traversable ;
21+ use function array_change_key_case ;
2122use function array_key_exists ;
2223use function assert ;
2324use function constant ;
2425use function count ;
2526use function defined ;
2627use function explode ;
2728use function file_get_contents ;
28- use function in_array ;
2929use function is_dir ;
3030use function is_string ;
3131use function sprintf ;
@@ -67,9 +67,22 @@ final class PhpStormStubsSourceStubber implements SourceStubber
6767 /** @var array<string, Node\Stmt\Function_> */
6868 private $ functionNodes = [];
6969
70- /** @var array<string, Node\Stmt\Const_|Node\Expr\FuncCall> */
70+ /**
71+ * `null` means "failed lookup" for constant that is not case insensitive
72+ *
73+ * @var array<string, Node\Stmt\Const_|Node\Expr\FuncCall|null>
74+ */
7175 private $ constantNodes = [];
7276
77+ /** @var array<lowercase-string, string> */
78+ private $ classMap ;
79+
80+ /** @var array<lowercase-string, string> */
81+ private $ functionMap ;
82+
83+ /** @var array<lowercase-string, string> */
84+ private $ constantMap ;
85+
7386 public function __construct (Parser $ phpParser )
7487 {
7588 $ this ->phpParser = $ phpParser ;
@@ -81,21 +94,27 @@ public function __construct(Parser $phpParser)
8194 $ this ->nodeTraverser = new NodeTraverser ();
8295 $ this ->nodeTraverser ->addVisitor (new NameResolver ());
8396 $ this ->nodeTraverser ->addVisitor ($ this ->cachingVisitor );
97+
98+ $ this ->classMap = array_change_key_case (PhpStormStubsMap::CLASSES );
99+ $ this ->functionMap = array_change_key_case (PhpStormStubsMap::FUNCTIONS );
100+ $ this ->constantMap = array_change_key_case (PhpStormStubsMap::CONSTANTS );
84101 }
85102
86103 public function generateClassStub (string $ className ) : ?StubData
87104 {
88- if (! array_key_exists ($ className , PhpStormStubsMap::CLASSES )) {
105+ $ lowercaseClassName = strtolower ($ className );
106+
107+ if (! array_key_exists ($ lowercaseClassName , $ this ->classMap )) {
89108 return null ;
90109 }
91110
92- $ filePath = PhpStormStubsMap:: CLASSES [ $ className ];
111+ $ filePath = $ this -> classMap [ $ lowercaseClassName ];
93112
94- if (! array_key_exists ($ className , $ this ->classNodes )) {
113+ if (! array_key_exists ($ lowercaseClassName , $ this ->classNodes )) {
95114 $ this ->parseFile ($ filePath );
96115 }
97116
98- $ stub = $ this ->createStub ($ this ->classNodes [$ className ]);
117+ $ stub = $ this ->createStub ($ this ->classNodes [$ lowercaseClassName ]);
99118
100119 if ($ className === Traversable::class) {
101120 // See https://github.com/JetBrains/phpstorm-stubs/commit/0778a26992c47d7dbee4d0b0bfb7fad4344371b1#diff-575bacb45377d474336c71cbf53c1729
@@ -107,37 +126,52 @@ public function generateClassStub(string $className) : ?StubData
107126
108127 public function generateFunctionStub (string $ functionName ) : ?StubData
109128 {
110- if (! array_key_exists ($ functionName , PhpStormStubsMap::FUNCTIONS )) {
129+ $ lowercaseFunctionName = strtolower ($ functionName );
130+
131+ if (! array_key_exists ($ lowercaseFunctionName , $ this ->functionMap )) {
111132 return null ;
112133 }
113134
114- $ filePath = PhpStormStubsMap:: FUNCTIONS [ $ functionName ];
135+ $ filePath = $ this -> functionMap [ $ lowercaseFunctionName ];
115136
116- if (! array_key_exists ($ functionName , $ this ->functionNodes )) {
137+ if (! array_key_exists ($ lowercaseFunctionName , $ this ->functionNodes )) {
117138 $ this ->parseFile ($ filePath );
118139 }
119140
120- return new StubData ($ this ->createStub ($ this ->functionNodes [$ functionName ]), $ this ->getExtensionFromFilePath ($ filePath ));
141+ return new StubData ($ this ->createStub ($ this ->functionNodes [$ lowercaseFunctionName ]), $ this ->getExtensionFromFilePath ($ filePath ));
121142 }
122143
123144 public function generateConstantStub (string $ constantName ) : ?StubData
124145 {
125- // https://github.com/JetBrains/phpstorm-stubs/pull/591
126- if (in_array ($ constantName , ['TRUE ' , 'FALSE ' , 'NULL ' ], true )) {
127- $ constantName = strtolower ($ constantName );
146+ $ lowercaseConstantName = strtolower ($ constantName );
147+
148+ if (! array_key_exists ($ lowercaseConstantName , $ this ->constantMap )) {
149+ return null ;
128150 }
129151
130- if (! array_key_exists ($ constantName , PhpStormStubsMap::CONSTANTS )) {
152+ if (array_key_exists ($ lowercaseConstantName , $ this ->constantNodes )
153+ && $ this ->constantNodes [$ lowercaseConstantName ] === null
154+ ) {
131155 return null ;
132156 }
133157
134- $ filePath = PhpStormStubsMap::CONSTANTS [$ constantName ];
158+ $ filePath = $ this ->constantMap [$ lowercaseConstantName ];
159+ $ constantNode = $ this ->constantNodes [$ constantName ] ?? $ this ->constantNodes [$ lowercaseConstantName ] ?? null ;
135160
136- if (! array_key_exists ( $ constantName , $ this -> constantNodes ) ) {
161+ if ($ constantNode === null ) {
137162 $ this ->parseFile ($ filePath );
163+
164+ $ constantNode = $ this ->constantNodes [$ constantName ] ?? $ this ->constantNodes [$ lowercaseConstantName ] ?? null ;
165+
166+ if ($ constantNode === null ) {
167+ // Still `null` - the constant is not case-insensitive. Save `null` so we don't parse the file again for the same $constantName
168+ $ this ->constantNodes [$ lowercaseConstantName ] = null ;
169+
170+ return null ;
171+ }
138172 }
139173
140- return new StubData ($ this ->createStub ($ this -> constantNodes [ $ constantName ] ), $ this ->getExtensionFromFilePath ($ filePath ));
174+ return new StubData ($ this ->createStub ($ constantNode ), $ this ->getExtensionFromFilePath ($ filePath ));
141175 }
142176
143177 private function parseFile (string $ filePath ) : void
@@ -158,7 +192,8 @@ private function parseFile(string $filePath) : void
158192 foreach ($ this ->cachingVisitor ->getClassNodes () as $ className => $ classNode ) {
159193 assert (is_string ($ className ));
160194 assert ($ classNode instanceof Node \Stmt \ClassLike);
161- $ this ->classNodes [$ className ] = $ classNode ;
195+
196+ $ this ->classNodes [strtolower ($ className )] = $ classNode ;
162197 }
163198
164199 /**
@@ -167,7 +202,8 @@ private function parseFile(string $filePath) : void
167202 foreach ($ this ->cachingVisitor ->getFunctionNodes () as $ functionName => $ functionNode ) {
168203 assert (is_string ($ functionName ));
169204 assert ($ functionNode instanceof Node \Stmt \Function_);
170- $ this ->functionNodes [$ functionName ] = $ functionNode ;
205+
206+ $ this ->functionNodes [strtolower ($ functionName )] = $ functionNode ;
171207 }
172208
173209 /**
0 commit comments