66use PhpParser \NodeTraverser ;
77use PhpParser \NodeVisitorAbstract ;
88use PHPStan \Analyser \NameScope ;
9+ use PHPStan \Analyser \Scope ;
910use PHPStan \Parser \Parser ;
1011use PHPStan \PhpDocParser \Lexer \Lexer ;
1112use PHPStan \PhpDocParser \Parser \PhpDocParser ;
1213use PHPStan \PhpDocParser \Parser \TokenIterator ;
13- use ReflectionFunctionAbstract ;
14- use ReflectionMethod ;
14+ use PHPStan \Reflection \MethodReflection ;
15+ use ReflectionException ;
16+ use ReflectionFunction ;
1517use function sprintf ;
1618use function strtolower ;
1719
@@ -46,31 +48,54 @@ public function __construct(Parser $phpParser, Lexer $phpDocLexer, PhpDocParser
4648 /**
4749 * @return string[][]
4850 */
49- public function read (ReflectionFunctionAbstract $ reflection ): array
51+ public function read (Scope $ scope ): array
5052 {
51- $ functionName = $ reflection -> getName ();
53+ $ reflection = $ scope -> getFunction ();
5254
53- if (!isset ($ this ->annotations [$ functionName ])) {
54- $ this ->annotations [$ functionName ] = $ this ->parse ($ reflection );
55+ if ($ reflection === null ) {
56+ return [];
57+ }
58+
59+ $ namespace = $ scope ->getNamespace ();
60+ $ sourceFile = $ scope ->getFile ();
61+
62+ $ key = $ namespace . ':: ' . $ sourceFile . ':: ' ;
63+
64+ $ classReflection = $ scope ->getClassReflection ();
65+
66+ if ($ classReflection !== null ) {
67+ $ key .= $ classReflection ->getName ();
68+ }
69+
70+ $ key .= $ reflection ->getName ();
71+
72+ if (!isset ($ this ->annotations [$ key ])) {
73+ $ this ->annotations [$ key ] = $ this ->parse ($ reflection , $ sourceFile , $ namespace );
5574 }
5675
57- return $ this ->annotations [$ functionName ];
76+ return $ this ->annotations [$ key ];
5877 }
5978
6079 /**
80+ * @param \PHPStan\Reflection\FunctionReflection|\PHPStan\Reflection\MethodReflection $reflection
81+ *
6182 * @return string[][]
6283 */
63- private function parse (ReflectionFunctionAbstract $ reflection ): array
84+ private function parse ($ reflection, string $ sourceFile , ? string $ namespace = null ): array
6485 {
65- $ docComment = $ reflection ->getDocComment ();
86+ try {
87+ $ docBlock = $ this ->getDocblock ($ reflection );
88+ } catch (ReflectionException $ exception ) {
89+ return [];
90+ }
6691
67- if ($ docComment === false ) {
92+ if ($ docBlock === null ) {
6893 return [];
6994 }
7095
71- $ tokens = new TokenIterator ($ this ->phpDocLexer ->tokenize ($ docComment ));
96+ $ tokens = new TokenIterator ($ this ->phpDocLexer ->tokenize ($ docBlock ));
7297 $ phpDocNode = $ this ->phpDocParser ->parse ($ tokens );
73- $ nameScope = $ this ->createNameScope ($ reflection );
98+ $ nameScope = $ this ->createNameScope ($ sourceFile , $ namespace );
7499
75100 $ annotations = [];
76101 foreach ($ phpDocNode ->getThrowsTagValues () as $ tagValue ) {
@@ -86,17 +111,31 @@ private function parse(ReflectionFunctionAbstract $reflection): array
86111 return $ annotations ;
87112 }
88113
89- private function createNameScope (ReflectionFunctionAbstract $ reflection ): NameScope
114+ /**
115+ * @param \PHPStan\Reflection\FunctionReflection|\PHPStan\Reflection\MethodReflection $reflection
116+ *
117+ * @throws ReflectionException
118+ */
119+ private function getDocblock ($ reflection ): ?string
90120 {
91- $ namespace = $ reflection instanceof ReflectionMethod ?
92- $ reflection ->getDeclaringClass ()->getNamespaceName () :
93- $ reflection ->getNamespaceName ();
121+ if ($ reflection instanceof MethodReflection) {
122+ $ declaringClass = $ reflection ->getDeclaringClass ();
123+ $ nativeClassReflection = $ declaringClass ->getNativeReflection ();
124+ $ nativeMethodReflection = $ nativeClassReflection ->getMethod ($ reflection ->getName ());
125+ $ docBlock = $ nativeMethodReflection ->getDocComment ();
94126
95- /** @var string $fileName */
96- $ fileName = $ reflection ->getFileName ();
97- $ usesMap = $ this ->getUsesMap ($ fileName , $ namespace );
127+ return $ docBlock !== false ? $ docBlock : null ;
128+ }
98129
99- return new NameScope ($ namespace , $ usesMap );
130+ $ functionReflection = new ReflectionFunction ($ reflection ->getName ());
131+ $ docBlock = $ functionReflection ->getDocComment ();
132+
133+ return $ docBlock !== false ? $ docBlock : null ;
134+ }
135+
136+ private function createNameScope (string $ sourceFile , ?string $ namespace = null ): NameScope
137+ {
138+ return new NameScope ($ namespace , $ this ->getUsesMap ($ sourceFile , (string ) $ namespace ));
100139 }
101140
102141 /**
@@ -114,7 +153,7 @@ private function getUsesMap(string $fileName, string $namespace): array
114153 /**
115154 * @return string[][]
116155 */
117- private function createUsesMap (string $ fileName ): array
156+ private function createUsesMap (string $ sourceFile ): array
118157 {
119158 $ visitor = new class extends NodeVisitorAbstract {
120159
@@ -170,7 +209,7 @@ private function addUse(string $alias, string $className): void
170209
171210 $ traverser = new NodeTraverser ();
172211 $ traverser ->addVisitor ($ visitor );
173- $ traverser ->traverse ($ this ->phpParser ->parseFile ($ fileName ));
212+ $ traverser ->traverse ($ this ->phpParser ->parseFile ($ sourceFile ));
174213
175214 return $ visitor ->uses ;
176215 }
0 commit comments