Skip to content

Commit

Permalink
more refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
smoench committed Feb 9, 2020
1 parent 3e2b334 commit 4579815
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,37 @@
use SensioLabs\Deptrac\AstRunner\AstMap\ClassReferenceBuilder;
use SensioLabs\Deptrac\AstRunner\AstMap\FileOccurrence;
use SensioLabs\Deptrac\AstRunner\Resolver\ClassDependencyResolver;
use SensioLabs\Deptrac\AstRunner\Resolver\NameScope;
use SensioLabs\Deptrac\AstRunner\Resolver\TypeResolver;
use SensioLabs\Deptrac\AstRunner\Resolver\TypeScope;

class AstClassReferenceResolver extends NodeVisitorAbstract
class ClassReferenceVisitor extends NodeVisitorAbstract
{
private $fileReference;

/** @var ClassDependencyResolver[] */
private $classDependencyResolvers;

/** @var NameScope */
private $currentTypeContext;
/** @var TypeScope */
private $currentTypeScope;

/** @var ClassReferenceBuilder */
private $currentClassReferenceBuilder;

/** @var TypeResolver */
private $typeResolver;

public function __construct(AstFileReference $fileReference, ClassDependencyResolver ...$classDependencyResolvers)
{
$this->currentTypeContext = new NameScope('global');
$this->currentTypeScope = new TypeScope('');
$this->fileReference = $fileReference;
$this->classDependencyResolvers = $classDependencyResolvers;
$this->typeResolver = new TypeResolver();
}

public function enterNode(Node $node)
{
if ($node instanceof Node\Stmt\Namespace_) {
$this->currentTypeContext = new NameScope($node->name ? $node->name->toCodeString() : 'global');
$this->currentTypeScope = new TypeScope($node->name ? $node->name->toCodeString() : '');
}

if (!$node instanceof Node\Stmt\ClassLike) {
Expand Down Expand Up @@ -79,7 +84,7 @@ public function enterNode(Node $node)
public function leaveNode(Node $node)
{
if ($node instanceof Node\Stmt\UseUse) {
$this->currentTypeContext->addUse($node->name->toCodeString(), $node->getAlias()->toString());
$this->currentTypeScope->addUse($node->name->toCodeString(), $node->getAlias()->toString());
$this->fileReference->addDependency(
AstDependency::useStmt(
ClassLikeName::fromFQCN($node->name->toCodeString()),
Expand All @@ -93,47 +98,55 @@ public function leaveNode(Node $node)
}

if ($node instanceof Node\Stmt\TraitUse) {
foreach ($node->traits as $trait) {
$this->currentClassReferenceBuilder->trait($trait->toCodeString(), $trait->getLine());
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, ...$node->traits) as $classLikeName) {
$this->currentClassReferenceBuilder->trait($classLikeName, $node->getLine());
}
}

if ($node instanceof Node\Expr\Instanceof_ && $this->isQualifiedType($node->class)) {
$this->currentClassReferenceBuilder->instanceof($node->class->toCodeString(), $node->class->getLine());
if ($node instanceof Node\Expr\Instanceof_ && $node->class instanceof Node\Name) {
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, $node->class) as $classLikeName) {
$this->currentClassReferenceBuilder->instanceof($classLikeName, $node->class->getLine());
}
}

if ($node instanceof Node\Param && $this->isQualifiedType($node->type)) {
$this->currentClassReferenceBuilder->parameter($node->type->toCodeString(), $node->type->getLine());
if ($node instanceof Node\Param && null !== $node->type) {
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, $node->type) as $classLikeName) {
$this->currentClassReferenceBuilder->parameter($classLikeName, $node->type->getLine());
}
}

if ($node instanceof Node\Expr\New_ && $this->isQualifiedType($node->class)) {
$this->currentClassReferenceBuilder->newStatement($node->class->toCodeString(), $node->class->getLine());
if ($node instanceof Node\Expr\New_ && $node->class instanceof Node\Name) {
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, $node->class) as $classLikeName) {
$this->currentClassReferenceBuilder->newStatement($classLikeName, $node->class->getLine());
}
}

if ($node instanceof Node\Expr\StaticPropertyFetch && $this->isQualifiedType($node->class)) {
$this->currentClassReferenceBuilder->staticProperty($node->class->toCodeString(), $node->class->getLine());
if ($node instanceof Node\Expr\StaticPropertyFetch && $node->class instanceof Node\Name) {
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, $node->class) as $classLikeName) {
$this->currentClassReferenceBuilder->staticProperty($classLikeName, $node->class->getLine());
}
}

if ($node instanceof Node\Expr\StaticCall && $this->isQualifiedType($node->class)) {
$this->currentClassReferenceBuilder->staticMethod($node->class->toCodeString(), $node->class->getLine());
if ($node instanceof Node\Expr\StaticCall && $node->class instanceof Node\Name) {
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, $node->class) as $classLikeName) {
$this->currentClassReferenceBuilder->staticMethod($classLikeName, $node->class->getLine());
}
}

if ($node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\Closure) {
if ($this->isQualifiedType($node->returnType)) {
$this->currentClassReferenceBuilder->returnType($node->returnType->toCodeString(), $node->returnType->getLine());
} elseif ($node->returnType instanceof Node\NullableType && $this->isQualifiedType($node->returnType->type)) {
$this->currentClassReferenceBuilder->returnType($node->returnType->type->toCodeString(), $node->returnType->getLine());
if (($node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\Closure) && null !== $node->returnType) {
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, $node->returnType) as $classLikeName) {
$this->currentClassReferenceBuilder->returnType($classLikeName, $node->returnType->getLine());
}
}

if ($node instanceof Node\Stmt\Catch_) {
foreach ($node->types as $type) {
$this->currentClassReferenceBuilder->catchStmt($type->toCodeString(), $type->getLine());
foreach ($this->typeResolver->resolvePHPParserTypes($this->currentTypeScope, ...$node->types) as $classLikeName) {
$this->currentClassReferenceBuilder->catchStmt($classLikeName, $node->getLine());
}
}

foreach ($this->classDependencyResolvers as $resolver) {
$resolver->processNode($node, $this->currentClassReferenceBuilder, $this->currentTypeContext);
$resolver->processNode($node, $this->currentClassReferenceBuilder, $this->currentTypeScope);
}

return null;
Expand All @@ -147,17 +160,4 @@ public function afterTraverse(array $nodes)

return null;
}

private function isQualifiedType($type): bool
{
if (null === $type) {
return false;
}

if ($type instanceof Node\Name) {
return !$type->isSpecialClassName();
}

return false;
}
}
28 changes: 17 additions & 11 deletions src/AstRunner/AstParser/NikicPhpParser/NikicPhpParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class NikicPhpParser implements AstParser
*/
private $classDependencyResolvers;

/**
* @var NodeTraverser
*/
private $traverser;

public function __construct(
FileParser $fileParser,
AstFileReferenceCache $cache,
Expand All @@ -44,6 +49,9 @@ public function __construct(
$this->fileParser = $fileParser;
$this->cache = $cache;
$this->classDependencyResolvers = $classDependencyResolvers;

$this->traverser = new NodeTraverser();
$this->traverser->addVisitor(new NameResolver());
}

public function supports($data): bool
Expand All @@ -67,12 +75,11 @@ public function parse($data): AstFileReference
}

$fileReference = new AstFileReference($data->getRealPath());
$visitor = new ClassReferenceVisitor($fileReference, ...$this->classDependencyResolvers);

$traverser = new NodeTraverser();
$traverser->addVisitor(new NameResolver());
$traverser->addVisitor(new AstClassReferenceResolver($fileReference, ...$this->classDependencyResolvers));

$traverser->traverse($this->fileParser->parse($data));
$this->traverser->addVisitor($visitor);
$this->traverser->traverse($this->fileParser->parse($data));
$this->traverser->removeVisitor($visitor);

$this->cache->set($fileReference);

Expand All @@ -91,21 +98,20 @@ public function getAstForClassReference(AstClassReference $classReference): ?Nod
return null;
}

$finding = new FindingVisitor(
$findingVisitor = new FindingVisitor(
static function (Node $node): bool {
return $node instanceof Node\Stmt\ClassLike;
}
);

$traverser = new NodeTraverser();
$traverser->addVisitor(new NameResolver());
$traverser->addVisitor($finding);
$traverser->traverse(
$this->traverser->addVisitor($findingVisitor);
$this->traverser->traverse(
$this->fileParser->parse(new \SplFileInfo($classReference->getFileReference()->getFilepath()))
);
$this->traverser->removeVisitor($findingVisitor);

/** @var Node\Stmt\ClassLike[] $classLikeNodes */
$classLikeNodes = $finding->getFoundNodes();
$classLikeNodes = $findingVisitor->getFoundNodes();

foreach ($classLikeNodes as $classLikeNode) {
if (isset($classLikeNode->namespacedName) && $classLikeNode->namespacedName instanceof Node\Name) {
Expand Down
10 changes: 5 additions & 5 deletions src/AstRunner/Resolver/AnnotationDependencyResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function __construct(TypeResolver $typeResolver)
$this->typeResolver = $typeResolver;
}

public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, NameScope $nameScope): void
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, TypeScope $typeScope): void
{
if (!$node instanceof Node\Stmt\Property
&& !$node instanceof Node\Expr\Variable
Expand All @@ -48,31 +48,31 @@ public function processNode(Node $node, ClassReferenceBuilder $classReferenceBui
$docNode = $this->docParser->parse($tokens);

foreach ($docNode->getParamTagValues() as $tag) {
$types = $this->typeResolver->resolveType($tag->type, $nameScope);
$types = $this->typeResolver->resolvePHPStanDocParserType($tag->type, $typeScope);

foreach ($types as $type) {
$classReferenceBuilder->parameter($type, $docComment->getLine());
}
}

foreach ($docNode->getVarTagValues() as $tag) {
$types = $this->typeResolver->resolveType($tag->type, $nameScope);
$types = $this->typeResolver->resolvePHPStanDocParserType($tag->type, $typeScope);

foreach ($types as $type) {
$classReferenceBuilder->variable($type, $docComment->getLine());
}
}

foreach ($docNode->getReturnTagValues() as $tag) {
$types = $this->typeResolver->resolveType($tag->type, $nameScope);
$types = $this->typeResolver->resolvePHPStanDocParserType($tag->type, $typeScope);

foreach ($types as $type) {
$classReferenceBuilder->returnType($type, $docComment->getLine());
}
}

foreach ($docNode->getThrowsTagValues() as $tag) {
$types = $this->typeResolver->resolveType($tag->type, $nameScope);
$types = $this->typeResolver->resolvePHPStanDocParserType($tag->type, $typeScope);

foreach ($types as $type) {
$classReferenceBuilder->throwStatement($type, $docComment->getLine());
Expand Down
2 changes: 1 addition & 1 deletion src/AstRunner/Resolver/AnonymousClassResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class AnonymousClassResolver implements ClassDependencyResolver
{
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, NameScope $nameScope): void
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, TypeScope $typeScope): void
{
if (!$node instanceof Node\Stmt\Class_ || null !== $node->name) {
return;
Expand Down
2 changes: 1 addition & 1 deletion src/AstRunner/Resolver/ClassConstantResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class ClassConstantResolver implements ClassDependencyResolver
{
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, NameScope $nameScope): void
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, TypeScope $typeScope): void
{
if (!$node instanceof ClassConstFetch || !$node->class instanceof Node\Name || $node->class->isSpecialClassName()) {
return;
Expand Down
2 changes: 1 addition & 1 deletion src/AstRunner/Resolver/ClassDependencyResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

interface ClassDependencyResolver
{
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, NameScope $nameScope): void;
public function processNode(Node $node, ClassReferenceBuilder $classReferenceBuilder, TypeScope $typeScope): void;
}
50 changes: 45 additions & 5 deletions src/AstRunner/Resolver/TypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Context;
use phpDocumentor\Reflection\Types\Object_;
use PhpParser\Node;
use PhpParser\NodeAbstract;
use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\IntersectionTypeNode;
Expand All @@ -31,27 +33,65 @@ public function __construct()
/**
* @return string[]
*/
public function resolveType(TypeNode $type, NameScope $nameScope): array
public function resolvePHPParserTypes(TypeScope $typeScope, NodeAbstract ...$nodes): array
{
if (null === $nodes || [] === $nodes) {
return [];
}

$types = [];
foreach ($nodes as $node) {
$types[] = $this->resolvePHPParserType($typeScope, $node);
}

return array_merge([], ...$types);
}

private function resolvePHPParserType(TypeScope $typeScope, NodeAbstract $node): array
{
if ($node instanceof Node\Name && $node->isSpecialClassName()) {
return [];
}

if ($node instanceof Node\Name) {
return $this->resolveString($node->toCodeString(), $typeScope);
}

if ($node instanceof Node\NullableType) {
return $this->resolvePHPParserType($typeScope, $node->type);
}

if ($node instanceof Node\UnionType) {
return $this->resolvePHPParserTypes($typeScope, ...$node->types);
}

return [];
}

/**
* @return string[]
*/
public function resolvePHPStanDocParserType(TypeNode $type, TypeScope $nameScope): array
{
if ($type instanceof IdentifierTypeNode) {
return $this->resolveString($type->name, $nameScope);
}
if ($type instanceof NullableTypeNode) {
return $this->resolveType($type->type, $nameScope);
return $this->resolvePHPStanDocParserType($type->type, $nameScope);
}
if ($type instanceof ArrayTypeNode) {
return $this->resolveType($type->type, $nameScope);
return $this->resolvePHPStanDocParserType($type->type, $nameScope);
}
if ($type instanceof UnionTypeNode || $type instanceof IntersectionTypeNode) {
return array_merge([], ...array_map(function (TypeNode $typeNode) use ($nameScope) {
return $this->resolveType($typeNode, $nameScope);
return $this->resolvePHPStanDocParserType($typeNode, $nameScope);
}, $type->types));
}

return $this->resolveString((string) $type, $nameScope);
}

public function resolveString(string $type, NameScope $nameScope): array
public function resolveString(string $type, TypeScope $nameScope): array
{
$context = new Context($nameScope->getNamespace(), $nameScope->getUses());
$resolvedType = $this->typeResolver->resolve($type, $context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

namespace SensioLabs\Deptrac\AstRunner\Resolver;

class NameScope
class TypeScope
{
/**
* @var string|null
* @var string
*/
private $namespace;

Expand Down

0 comments on commit 4579815

Please sign in to comment.