2626use PhpParser \Node \InterpolatedStringPart ;
2727use PhpParser \Node \Name ;
2828use PhpParser \Node \Name \FullyQualified ;
29+ use PhpParser \Node \PropertyHook ;
2930use PhpParser \Node \Scalar \String_ ;
31+ use PhpParser \Node \Stmt \ClassMethod ;
32+ use PhpParser \Node \Stmt \Function_ ;
3033use PhpParser \NodeFinder ;
3134use PHPStan \Node \ExecutionEndNode ;
3235use PHPStan \Node \Expr \AlwaysRememberedExpr ;
5255use PHPStan \Php \PhpVersions ;
5356use PHPStan \PhpDoc \Tag \TemplateTag ;
5457use PHPStan \Reflection \Assertions ;
58+ use PHPStan \Reflection \AttributeReflection ;
59+ use PHPStan \Reflection \AttributeReflectionFactory ;
5560use PHPStan \Reflection \Callables \CallableParametersAcceptor ;
5661use PHPStan \Reflection \Callables \SimpleImpurePoint ;
5762use PHPStan \Reflection \Callables \SimpleThrowPoint ;
@@ -212,6 +217,7 @@ public function __construct(
212217 private ConstantResolver $ constantResolver ,
213218 private ScopeContext $ context ,
214219 private PhpVersion $ phpVersion ,
220+ private AttributeReflectionFactory $ attributeReflectionFactory ,
215221 private int |array |null $ configPhpVersion ,
216222 private bool $ declareStrictTypes = false ,
217223 private PhpFunctionFromParserNodeReflection |null $ function = null ,
@@ -2974,6 +2980,7 @@ public function enterClassMethod(
29742980 $ this ->getRealParameterTypes ($ classMethod ),
29752981 array_map (fn (Type $ type ): Type => $ this ->transformStaticType (TemplateTypeHelper::toArgument ($ type )), $ phpDocParameterTypes ),
29762982 $ this ->getRealParameterDefaultValues ($ classMethod ),
2983+ $ this ->getParameterAttributes ($ classMethod ),
29772984 $ this ->transformStaticType ($ this ->getFunctionType ($ classMethod ->returnType , false , false )),
29782985 $ phpDocReturnType !== null ? $ this ->transformStaticType (TemplateTypeHelper::toArgument ($ phpDocReturnType )) : null ,
29792986 $ throwType ,
@@ -2990,6 +2997,7 @@ public function enterClassMethod(
29902997 $ immediatelyInvokedCallableParameters ,
29912998 array_map (fn (Type $ type ): Type => $ this ->transformStaticType (TemplateTypeHelper::toArgument ($ type )), $ phpDocClosureThisTypeParameters ),
29922999 $ isConstructor ,
3000+ $ this ->attributeReflectionFactory ->fromAttrGroups ($ classMethod ->attrGroups , InitializerExprContext::fromStubParameter ($ this ->getClassReflection ()->getName (), $ this ->getFile (), $ classMethod )),
29933001 ),
29943002 !$ classMethod ->isStatic (),
29953003 );
@@ -3059,6 +3067,7 @@ public function enterPropertyHook(
30593067 $ realParameterTypes ,
30603068 $ phpDocParameterTypes ,
30613069 [],
3070+ $ this ->getParameterAttributes ($ hook ),
30623071 $ realReturnType ,
30633072 $ phpDocReturnType ,
30643073 $ throwType ,
@@ -3075,6 +3084,7 @@ public function enterPropertyHook(
30753084 [],
30763085 [],
30773086 false ,
3087+ $ this ->attributeReflectionFactory ->fromAttrGroups ($ hook ->attrGroups , InitializerExprContext::fromStubParameter ($ this ->getClassReflection ()->getName (), $ this ->getFile (), $ hook )),
30783088 ),
30793089 true ,
30803090 );
@@ -3138,6 +3148,27 @@ private function getRealParameterDefaultValues(Node\FunctionLike $functionLike):
31383148 return $ realParameterDefaultValues ;
31393149 }
31403150
3151+ /**
3152+ * @return array<string, list<AttributeReflection>>
3153+ */
3154+ private function getParameterAttributes (ClassMethod |Function_ |PropertyHook $ functionLike ): array
3155+ {
3156+ $ parameterAttributes = [];
3157+ $ className = null ;
3158+ if ($ this ->isInClass ()) {
3159+ $ className = $ this ->getClassReflection ()->getName ();
3160+ }
3161+ foreach ($ functionLike ->getParams () as $ parameter ) {
3162+ if (!$ parameter ->var instanceof Variable || !is_string ($ parameter ->var ->name )) {
3163+ throw new ShouldNotHappenException ();
3164+ }
3165+
3166+ $ parameterAttributes [$ parameter ->var ->name ] = $ this ->attributeReflectionFactory ->fromAttrGroups ($ parameter ->attrGroups , InitializerExprContext::fromStubParameter ($ className , $ this ->getFile (), $ functionLike ));
3167+ }
3168+
3169+ return $ parameterAttributes ;
3170+ }
3171+
31413172 /**
31423173 * @api
31433174 * @param Type[] $phpDocParameterTypes
@@ -3171,6 +3202,7 @@ public function enterFunction(
31713202 $ this ->getRealParameterTypes ($ function ),
31723203 array_map (static fn (Type $ type ): Type => TemplateTypeHelper::toArgument ($ type ), $ phpDocParameterTypes ),
31733204 $ this ->getRealParameterDefaultValues ($ function ),
3205+ $ this ->getParameterAttributes ($ function ),
31743206 $ this ->getFunctionType ($ function ->returnType , $ function ->returnType === null , false ),
31753207 $ phpDocReturnType !== null ? TemplateTypeHelper::toArgument ($ phpDocReturnType ) : null ,
31763208 $ throwType ,
@@ -3184,6 +3216,7 @@ public function enterFunction(
31843216 array_map (static fn (Type $ type ): Type => TemplateTypeHelper::toArgument ($ type ), $ parameterOutTypes ),
31853217 $ immediatelyInvokedCallableParameters ,
31863218 $ phpDocClosureThisTypeParameters ,
3219+ $ this ->attributeReflectionFactory ->fromAttrGroups ($ function ->attrGroups , InitializerExprContext::fromStubParameter (null , $ this ->getFile (), $ function )),
31873220 ),
31883221 false ,
31893222 );
0 commit comments