Skip to content

Commit 32ab9b0

Browse files
committed
Improve type resolver docs
1 parent a2c2ae3 commit 32ab9b0

23 files changed

Lines changed: 1593 additions & 416 deletions

src/TypeResolver.php

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace TypeLang\Parser;
66

77
use TypeLang\Parser\Traverser\TypeMapVisitor;
8+
use TypeLang\Parser\TypeResolver\PhpUseStatementsReader;
89
use TypeLang\Parser\TypeResolver\PhpUseStatementsTransformer;
910
use TypeLang\Type\TypeNode;
1011

@@ -41,7 +42,6 @@ public function __construct(
4142
* echo $ast->name->toString();
4243
* ```
4344
*
44-
* @api
4545
* @param non-empty-string $name
4646
*/
4747
public function withTypeImport(string $name): self
@@ -73,7 +73,6 @@ public function withTypeImport(string $name): self
7373
* echo $ast->name->toString();
7474
* ```
7575
*
76-
* @api
7776
* @param non-empty-string $name
7877
* @param non-empty-string $alias
7978
*/
@@ -82,6 +81,93 @@ public function withTypeImportAs(string $name, string $alias): self
8281
return new self([...$this->imports, $alias => $name]);
8382
}
8483

84+
/**
85+
* Registers every `use` import declared in the source file of the given
86+
* class, so that type names are resolved exactly as they would be inside
87+
* that class.
88+
*
89+
* For a class whose file declares:
90+
* ```
91+
* namespace App;
92+
*
93+
* use TypeLang\Parser\Node;
94+
* use TypeLang\Parser\Exception as Error;
95+
*
96+
* final class Example {}
97+
* ```
98+
*
99+
* You can reuse its imports like this:
100+
* ```
101+
* $ast = new TypeParser()
102+
* ->parse(<<<'PHP'
103+
* Error\SemanticException
104+
* PHP);
105+
*
106+
* $ast = new TypeResolver()
107+
* ->withTypeImportsOf(new \ReflectionClass(App\Example::class))
108+
* ->resolve($ast);
109+
*
110+
* // Expected Output:
111+
* // > TypeLang\Parser\Exception\SemanticException
112+
* echo $ast->name->toString();
113+
* ```
114+
*
115+
* @param \ReflectionClass<object> $class
116+
*/
117+
public function withTypeImportsFromClass(\ReflectionClass $class): self
118+
{
119+
$statements = new PhpUseStatementsReader()
120+
->getClassUseStatements($class);
121+
122+
return new self([...$this->imports, ...$statements]);
123+
}
124+
125+
/**
126+
* Registers every `use` import available in the source file of the given
127+
* function or method, so that type names are resolved exactly as they
128+
* would be inside that function's body.
129+
*
130+
* For a function whose file declares:
131+
* ```
132+
* namespace App;
133+
*
134+
* use TypeLang\Parser\Node;
135+
* use TypeLang\Parser\Exception as Error;
136+
*
137+
* function example(): void {}
138+
* ```
139+
*
140+
* You can reuse its imports like this:
141+
* ```
142+
* $ast = new TypeParser()
143+
* ->parse(<<<'PHP'
144+
* Error\SemanticException
145+
* PHP);
146+
*
147+
* $ast = new TypeResolver()
148+
* ->withTypeImportsFromFunction(new \ReflectionFunction('App\example'))
149+
* ->resolve($ast);
150+
*
151+
* // Expected Output:
152+
* // > TypeLang\Parser\Exception\SemanticException
153+
* echo $ast->name->toString();
154+
* ```
155+
*/
156+
public function withTypeImportsFromFunction(\ReflectionFunctionAbstract $function): self
157+
{
158+
if ($function instanceof \ReflectionMethod) {
159+
// For methods, we find the class and search by it. This will
160+
// allow us to traverse fewer PHP tokens (optimize), since the
161+
// class declaration is "higher".
162+
return $this->withTypeImportsFromClass($function->getDeclaringClass());
163+
}
164+
165+
$statements = new PhpUseStatementsReader()
166+
->getFunctionUseStatements($function);
167+
168+
return new self([...$this->imports, ...$statements]);
169+
}
170+
85171
private function createTraverser(): TraverserInterface
86172
{
87173
$transformer = new PhpUseStatementsTransformer($this->imports);
@@ -112,8 +198,6 @@ private function createTraverser(): TraverserInterface
112198
* // > TypeLang\Parser\Exception\SemanticException
113199
* // > }
114200
* ```
115-
*
116-
* @api
117201
*/
118202
public function resolve(TypeNode $type): TypeNode
119203
{

0 commit comments

Comments
 (0)