2020use PHPStan \Reflection \ReflectionProvider \ReflectionProviderProvider ;
2121use PHPStan \ShouldNotHappenException ;
2222use PHPStan \Type \Generic \GenericObjectType ;
23- use PHPStan \Type \Generic \TemplateType ;
2423use PHPStan \Type \Generic \TemplateTypeFactory ;
2524use PHPStan \Type \Generic \TemplateTypeHelper ;
2625use PHPStan \Type \Generic \TemplateTypeMap ;
@@ -134,29 +133,6 @@ public function getResolvedPhpDoc(
134133 private function createResolvedPhpDocBlock (string $ phpDocKey , NameScope $ nameScope , string $ phpDocString , string $ fileName ): ResolvedPhpDocBlock
135134 {
136135 $ phpDocNode = $ this ->resolvePhpDocStringToDocNode ($ phpDocString );
137- $ templateTags = $ this ->phpDocNodeResolver ->resolveTemplateTags ($ phpDocNode , $ nameScope );
138- $ templateTypeScope = $ nameScope ->getTemplateTypeScope ();
139-
140- if ($ templateTypeScope !== null ) {
141- $ templateTypeMap = new TemplateTypeMap (array_map (static fn (TemplateTag $ tag ): Type => TemplateTypeFactory::fromTemplateTag ($ templateTypeScope , $ tag ), $ templateTags ));
142- $ nameScope = $ nameScope ->withTemplateTypeMap (
143- new TemplateTypeMap (array_merge (
144- $ nameScope ->getTemplateTypeMap ()->getTypes (),
145- $ templateTypeMap ->getTypes (),
146- )),
147- );
148- $ templateTags = $ this ->phpDocNodeResolver ->resolveTemplateTags ($ phpDocNode , $ nameScope );
149- $ templateTypeMap = new TemplateTypeMap (array_map (static fn (TemplateTag $ tag ): Type => TemplateTypeFactory::fromTemplateTag ($ templateTypeScope , $ tag ), $ templateTags ));
150- $ nameScope = $ nameScope ->withTemplateTypeMap (
151- new TemplateTypeMap (array_merge (
152- $ nameScope ->getTemplateTypeMap ()->getTypes (),
153- $ templateTypeMap ->getTypes (),
154- )),
155- );
156- } else {
157- $ templateTypeMap = TemplateTypeMap::createEmpty ();
158- }
159-
160136 if ($ this ->resolvedPhpDocBlockCacheCount >= 512 ) {
161137 $ this ->resolvedPhpDocBlockCache = array_slice (
162138 $ this ->resolvedPhpDocBlockCache ,
@@ -168,12 +144,23 @@ private function createResolvedPhpDocBlock(string $phpDocKey, NameScope $nameSco
168144 $ this ->resolvedPhpDocBlockCacheCount --;
169145 }
170146
147+ $ templateTypeMap = $ nameScope ->getTemplateTypeMap ();
148+ $ phpDocTemplateTypes = [];
149+ $ templateTags = $ this ->phpDocNodeResolver ->resolveTemplateTags ($ phpDocNode , $ nameScope );
150+ foreach (array_keys ($ templateTags ) as $ name ) {
151+ $ templateType = $ templateTypeMap ->getType ($ name );
152+ if ($ templateType === null ) {
153+ continue ;
154+ }
155+ $ phpDocTemplateTypes [$ name ] = $ templateType ;
156+ }
157+
171158 $ this ->resolvedPhpDocBlockCache [$ phpDocKey ] = ResolvedPhpDocBlock::create (
172159 $ phpDocNode ,
173160 $ phpDocString ,
174161 $ fileName ,
175162 $ nameScope ,
176- $ templateTypeMap ,
163+ new TemplateTypeMap ( $ phpDocTemplateTypes ) ,
177164 $ templateTags ,
178165 $ this ->phpDocNodeResolver ,
179166 );
@@ -193,7 +180,7 @@ private function resolvePhpDocStringToDocNode(string $phpDocString): PhpDocNode
193180 private function getNameScopeMap (string $ fileName ): array
194181 {
195182 if (!isset ($ this ->memoryCache [$ fileName ])) {
196- $ cacheKey = sprintf ('%s-phpdocstring-v19-trait-detection-recursion ' , $ fileName );
183+ $ cacheKey = sprintf ('%s-phpdocstring-v20-template-tags ' , $ fileName );
197184 $ variableCacheKey = sprintf ('%s-%s ' , implode (', ' , array_map (static fn (array $ file ): string => sprintf ('%s-%d ' , $ file ['filename ' ], $ file ['modifiedTime ' ]), $ this ->getCachedDependentFilesWithTimestamps ($ fileName ))), $ this ->phpVersion ->getVersionString ());
198185 $ map = $ this ->cache ->load ($ cacheKey , $ variableCacheKey );
199186
@@ -322,14 +309,15 @@ function (Node $node) use ($fileName, $lookForTrait, &$traitFound, $traitMethodA
322309
323310 $ className = $ classStack [count ($ classStack ) - 1 ] ?? null ;
324311 $ functionName = $ functionStack [count ($ functionStack ) - 1 ] ?? null ;
325- $ resolvableTemplateTypes = ($ className !== null && $ lookForTrait === null ) || $ functionName !== null ;
326312
327313 if ($ node instanceof Node \Stmt \ClassLike || $ node instanceof Node \Stmt \ClassMethod || $ node instanceof Node \Stmt \Function_) {
328314 $ phpDocString = GetLastDocComment::forNode ($ node );
329315 if ($ phpDocString !== '' ) {
330- $ typeMapStack [] = function () use ($ namespace , $ uses , $ className , $ functionName , $ phpDocString , $ typeMapStack, $ resolvableTemplateTypes ): TemplateTypeMap {
316+ $ typeMapStack [] = function () use ($ namespace , $ uses , $ className , $ functionName , $ phpDocString , $ typeMapStack ): TemplateTypeMap {
331317 $ phpDocNode = $ this ->resolvePhpDocStringToDocNode ($ phpDocString );
332- $ nameScope = new NameScope ($ namespace , $ uses , $ className , $ functionName );
318+ $ typeMapCb = $ typeMapStack [count ($ typeMapStack ) - 1 ] ?? null ;
319+ $ currentTypeMap = $ typeMapCb !== null ? $ typeMapCb () : null ;
320+ $ nameScope = new NameScope ($ namespace , $ uses , $ className , $ functionName , $ currentTypeMap );
333321 $ templateTags = $ this ->phpDocNodeResolver ->resolveTemplateTags ($ phpDocNode , $ nameScope );
334322 $ templateTypeScope = $ nameScope ->getTemplateTypeScope ();
335323 if ($ templateTypeScope === null ) {
@@ -339,28 +327,11 @@ function (Node $node) use ($fileName, $lookForTrait, &$traitFound, $traitMethodA
339327 $ nameScope = $ nameScope ->withTemplateTypeMap ($ templateTypeMap );
340328 $ templateTags = $ this ->phpDocNodeResolver ->resolveTemplateTags ($ phpDocNode , $ nameScope );
341329 $ templateTypeMap = new TemplateTypeMap (array_map (static fn (TemplateTag $ tag ): Type => TemplateTypeFactory::fromTemplateTag ($ templateTypeScope , $ tag ), $ templateTags ));
342- $ typeMapCb = $ typeMapStack [count ($ typeMapStack ) - 1 ] ?? null ;
343330
344- return ( new TemplateTypeMap (array_merge (
345- $ typeMapCb !== null ? $ typeMapCb () ->getTypes () : [],
331+ return new TemplateTypeMap (array_merge (
332+ $ currentTypeMap !== null ? $ currentTypeMap ->getTypes () : [],
346333 $ templateTypeMap ->getTypes (),
347- )))->map (static fn (string $ name , Type $ type ): Type => TypeTraverser::map ($ type , static function (Type $ type , callable $ traverse ) use ($ className , $ resolvableTemplateTypes ): Type {
348- if (!$ type instanceof TemplateType) {
349- return $ traverse ($ type );
350- }
351-
352- if (!$ resolvableTemplateTypes ) {
353- return $ traverse ($ type ->toArgument ());
354- }
355-
356- $ scope = $ type ->getScope ();
357-
358- if ($ scope ->getClassName () === null || $ scope ->getFunctionName () !== null || $ scope ->getClassName () !== $ className ) {
359- return $ traverse ($ type ->toArgument ());
360- }
361-
362- return $ traverse ($ type );
363- }));
334+ ));
364335 };
365336 }
366337 }
0 commit comments