Repository: qossmic/deptrac (php)

Issue:
Template parameters inside functions/methods
While deptrac now nicely recognizes template parameters of class/method/function signatures, it does not do so when the templated variable is used inside said function/method via `@var` annotation

Pull request:
Resolution of template vars defined at function-like level
Fixes #667 

Patch:
diff --git a/src/Ast/AstMap/ReferenceBuilder.php b/src/Ast/AstMap/ReferenceBuilder.php
index bacd3123..914585e9 100644
--- a/src/Ast/AstMap/ReferenceBuilder.php
+++ b/src/Ast/AstMap/ReferenceBuilder.php
@@ -188,4 +188,18 @@ abstract class ReferenceBuilder
 
         return $this;
     }
+
+    public function addTokenTemplate(string $tokenTemplate): void
+    {
+        $this->tokenTemplates[] = $tokenTemplate;
+    }
+
+    public function removeTokenTemplate(string $tokenTemplate): void
+    {
+        $key = array_search($tokenTemplate, $this->tokenTemplates, true);
+        if (false === $key) {
+            return;
+        }
+        unset($this->tokenTemplates[$key]);
+    }
 }
diff --git a/src/Ast/Parser/NikicPhpParser/FileReferenceVisitor.php b/src/Ast/Parser/NikicPhpParser/FileReferenceVisitor.php
index 04d357c4..648b3ca3 100644
--- a/src/Ast/Parser/NikicPhpParser/FileReferenceVisitor.php
+++ b/src/Ast/Parser/NikicPhpParser/FileReferenceVisitor.php
@@ -120,11 +120,23 @@ class FileReferenceVisitor extends NodeVisitorAbstract
             return null;
         }
 
+        if ($node instanceof Node\FunctionLike) {
+            foreach ($this->templatesFromDocs($node) as $template) {
+                $this->currentReference->addTokenTemplate($template);
+            }
+        }
+
         return null;
     }
 
     public function leaveNode(Node $node)
     {
+        if ($node instanceof Node\FunctionLike) {
+            foreach ($this->templatesFromDocs($node) as $template) {
+                $this->currentReference->removeTokenTemplate($template);
+            }
+        }
+
         // Resolve current reference scope
         if ($node instanceof Node\Stmt\Function_) {
             $this->currentReference = $this->fileReferenceBuilder;


Test patch:
diff --git a/tests/Ast/Parser/NikicPhpParser/Fixtures/TemplateTypes.php b/tests/Ast/Parser/NikicPhpParser/Fixtures/TemplateTypes.php
new file mode 100644
index 00000000..0f4a1f89
--- /dev/null
+++ b/tests/Ast/Parser/NikicPhpParser/Fixtures/TemplateTypes.php
@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Tests\Qossmic\Deptrac\AstRunner\AstParser\NikicPhpParser\Fixtures;
+
+/**
+ * @template Ta of AnotherThing
+ */
+class Thing
+{
+    /**
+     * @template Tb of string
+     */
+    public function method(): void
+    {
+        /**
+         * @var Tb $var
+         */
+        $var = '';
+    }
+}
+
+class AnotherThing
+{
+}
diff --git a/tests/Ast/Parser/NikicPhpParser/NikicPhpParserTest.php b/tests/Ast/Parser/NikicPhpParser/NikicPhpParserTest.php
index 0789e0d2..eb6b1a0d 100644
--- a/tests/Ast/Parser/NikicPhpParser/NikicPhpParserTest.php
+++ b/tests/Ast/Parser/NikicPhpParser/NikicPhpParserTest.php
@@ -8,6 +8,7 @@ use PhpParser\Lexer;
 use PhpParser\Parser;
 use PhpParser\ParserFactory;
 use PHPUnit\Framework\TestCase;
+use Qossmic\Deptrac\Ast\Parser\AnnotationReferenceExtractor;
 use Qossmic\Deptrac\Ast\Parser\Cache\AstFileReferenceInMemoryCache;
 use Qossmic\Deptrac\Ast\Parser\NikicPhpParser\NikicPhpParser;
 use Qossmic\Deptrac\Ast\Parser\TypeResolver;
@@ -68,4 +69,20 @@ final class NikicPhpParserTest extends TestCase
         self::assertCount(2, $astClassReferences[1]->getDependencies());
         self::assertCount(1, $astClassReferences[2]->getDependencies());
     }
+
+    public function testParseTemplateTypes(): void
+    {
+        $typeResolver = new TypeResolver();
+        $parser = new NikicPhpParser(
+            (new ParserFactory())->create(ParserFactory::ONLY_PHP7, new Lexer()),
+            new AstFileReferenceInMemoryCache(),
+            $typeResolver,
+            [new AnnotationReferenceExtractor($typeResolver)]
+        );
+
+        $filePath = __DIR__.'/Fixtures/TemplateTypes.php';
+        $astFileReference = $parser->parseFile($filePath);
+        $astClassReferences = $astFileReference->getClassLikeReferences();
+        self::assertCount(0, $astClassReferences[0]->getDependencies());
+    }
 }