1
0
Fork 0

Remove obsolete NodeVisitors

pull/357/head
roblou 2017-05-19 14:17:21 -07:00
parent cf9590b9b7
commit 71d71a896c
9 changed files with 12 additions and 445 deletions

View File

@ -1,41 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use PhpParser\{NodeVisitorAbstract, Node};
class ColumnCalculator extends NodeVisitorAbstract
{
private $code;
private $codeLength;
public function __construct($code)
{
$this->code = $code;
$this->codeLength = strlen($code);
}
public function enterNode(Node $node)
{
$startFilePos = $node->getAttribute('startFilePos');
$endFilePos = $node->getAttribute('endFilePos');
if ($startFilePos > $this->codeLength || $endFilePos > $this->codeLength) {
throw new \RuntimeException('Invalid position information');
}
$startLinePos = strrpos($this->code, "\n", $startFilePos - $this->codeLength);
if ($startLinePos === false) {
$startLinePos = -1;
}
$endLinePos = strrpos($this->code, "\n", $endFilePos - $this->codeLength);
if ($endLinePos === false) {
$endLinePos = -1;
}
$node->setAttribute('startColumn', $startFilePos - $startLinePos);
$node->setAttribute('endColumn', $endFilePos - $endLinePos);
}
}

View File

@ -1,48 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use PhpParser\{NodeVisitorAbstract, Node};
use LanguageServer\{
Definition, FqnUtilities, DefinitionResolver
};
/**
* Collects definitions of classes, interfaces, traits, methods, properties and constants
* Depends on ReferencesAdder and NameResolver
*/
class DefinitionCollector extends NodeVisitorAbstract
{
/**
* Map from fully qualified name (FQN) to Definition
*
* @var Definition[]
*/
public $definitions = [];
/**
* Map from fully qualified name (FQN) to Node
*
* @var Node[]
*/
public $nodes = [];
private $definitionResolver;
public function __construct(DefinitionResolver $definitionResolver)
{
$this->definitionResolver = $definitionResolver;
}
public function enterNode(Node $node)
{
$fqn = FqnUtilities::getDefinedFqn($node);
// Only index definitions with an FQN (no variables)
if ($fqn === null) {
return;
}
$this->nodes[$fqn] = $node;
$this->definitions[$fqn] = $this->definitionResolver->createDefinitionFromNode($node, $fqn);
}
}

View File

@ -1,96 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use PhpParser;
use PhpParser\{NodeVisitorAbstract, Node, Comment};
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\Types\Context;
use Exception;
/**
* Decorates all nodes with a docBlock attribute that is an instance of phpDocumentor\Reflection\DocBlock
*/
class DocBlockParser extends NodeVisitorAbstract
{
/**
* @var DocBlockFactory
*/
private $docBlockFactory;
/**
* The current namespace context
*
* @var string
*/
private $namespace;
/**
* Prefix from a parent group use declaration
*
* @var string
*/
private $prefix;
/**
* Namespace aliases in the current context
*
* @var string[]
*/
private $aliases;
/**
* @var PhpParser\Error[]
*/
public $errors = [];
public function __construct(DocBlockFactory $docBlockFactory)
{
$this->docBlockFactory = $docBlockFactory;
}
public function beforeTraverse(array $nodes)
{
$this->namespace = '';
$this->prefix = '';
$this->aliases = [];
}
public function enterNode(Node $node)
{
if ($node instanceof Node\Stmt\Namespace_) {
$this->namespace = (string)$node->name;
} else if ($node instanceof Node\Stmt\GroupUse) {
$this->prefix = (string)$node->prefix . '\\';
} else if ($node instanceof Node\Stmt\UseUse) {
$this->aliases[$node->alias] = $this->prefix . (string)$node->name;
}
$docComment = $node->getDocComment();
if ($docComment === null) {
return;
}
$context = new Context($this->namespace, $this->aliases);
try {
$docBlock = $this->docBlockFactory->create($docComment->getText(), $context);
$node->setAttribute('docBlock', $docBlock);
} catch (Exception $e) {
$this->errors[] = new PhpParser\Error($e->getMessage(), [
'startFilePos' => $docComment->getFilePos(),
'endFilePos' => $docComment->getFilePos() + strlen($docComment->getText()),
'startLine' => $docComment->getLine(),
'endLine' => $docComment->getLine() + preg_match_all('/[\\n\\r]/', $docComment->getText()) + 1
]);
}
}
public function leaveNode(Node $node)
{
if ($node instanceof Node\Stmt\Namespace_) {
$this->namespace = '';
$this->aliases = [];
} else if ($node instanceof Node\Stmt\GroupUse) {
$this->prefix = '';
}
}
}

View File

@ -1,45 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use PhpParser\{NodeVisitorAbstract, Node, NodeTraverser};
use LanguageServer\Protocol\{Position, Range};
/**
* Finds the Node at a specified position
* Depends on ColumnCalculator
*/
class NodeAtPositionFinder extends NodeVisitorAbstract
{
/**
* The node at the position, if found
*
* @var Node|null
*/
public $node;
/**
* @var Position
*/
private $position;
/**
* @param Position $position The position where the node is located
*/
public function __construct(Position $position)
{
$this->position = $position;
}
public function leaveNode(Node $node)
{
if ($this->node === null) {
$range = Range::fromNode($node);
if ($range->includes($this->position)) {
$this->node = $node;
return NodeTraverser::STOP_TRAVERSAL;
}
}
}
}

View File

@ -1,54 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use PhpParser\{NodeVisitorAbstract, Node};
/**
* Decorates all nodes with parent and sibling references (similar to DOM nodes)
*/
class ReferencesAdder extends NodeVisitorAbstract
{
/**
* @var Node[]
*/
private $stack = [];
/**
* @var Node
*/
private $previous;
/**
* @var mixed
*/
private $document;
/**
* @param mixed $document The value for the ownerDocument attribute
*/
public function __construct($document = null)
{
$this->document = $document;
}
public function enterNode(Node $node)
{
$node->setAttribute('ownerDocument', $this->document);
if (!empty($this->stack)) {
$node->setAttribute('parentNode', end($this->stack));
}
if (isset($this->previous) && $this->previous->getAttribute('parentNode') === $node->getAttribute('parentNode')) {
$node->setAttribute('previousSibling', $this->previous);
$this->previous->setAttribute('nextSibling', $node);
}
$this->stack[] = $node;
}
public function leaveNode(Node $node)
{
$this->previous = $node;
array_pop($this->stack);
}
}

View File

@ -1,77 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use LanguageServer\DefinitionResolverInterface;
use PhpParser\{
Node, NodeVisitorAbstract
};
/**
* Collects references to classes, interfaces, traits, methods, properties and constants
* Depends on ReferencesAdder and NameResolver
*/
class ReferencesCollector extends NodeVisitorAbstract
{
/**
* Map from fully qualified name (FQN) to array of nodes that reference the symbol
*
* @var Node[][]
*/
public $nodes = [];
/**
* @var DefinitionResolver
*/
private $definitionResolver;
/**
* @param DefinitionResolver $definitionResolver The definition resolver to resolve reference nodes to definitions
*/
public function __construct(DefinitionResolver $definitionResolver)
{
$this->definitionResolver = $definitionResolver;
}
public function enterNode(Node $node)
{
// Check if the node references any global symbol
$fqn = $this->definitionResolver->resolveReferenceNodeToFqn($node);
if ($fqn) {
$parent = $node->getAttribute('parentNode');
$grandParent = $parent ? $parent->getAttribute('parentNode') : null;
$this->addReference($fqn, $node);
if (
$node instanceof Node\Name
&& $node->isQualified()
&& !($parent instanceof Node\Stmt\Namespace_ && $parent->name === $node)
) {
// Add references for each referenced namespace
$ns = $fqn;
while (($pos = strrpos($ns, '\\')) !== false) {
$ns = substr($ns, 0, $pos);
$this->addReference($ns, $node);
}
}
// Namespaced constant access and function calls also need to register a reference
// to the global version because PHP falls back to global at runtime
// http://php.net/manual/en/language.namespaces.fallback.php
if ($parent instanceof Node\Expr\ConstFetch || $parent instanceof Node\Expr\FuncCall) {
$parts = explode('\\', $fqn);
if (count($parts) > 1) {
$globalFqn = end($parts);
$this->addReference($globalFqn, $node);
}
}
}
}
private function addReference(string $fqn, Node $node)
{
if (!isset($this->nodes[$fqn])) {
$this->nodes[$fqn] = [];
}
$this->nodes[$fqn][] = $node;
}
}

View File

@ -1,50 +0,0 @@
<?php
declare(strict_types = 1);
namespace LanguageServer\NodeVisitor;
use PhpParser\{NodeVisitorAbstract, Node, NodeTraverser};
/**
* Collects all references to a variable
*/
class VariableReferencesCollector extends NodeVisitorAbstract
{
/**
* Array of references to the variable
*
* @var Node\Expr\Variable[]
*/
public $nodes = [];
/**
* @var string
*/
private $name;
/**
* @param string $name The variable name
*/
public function __construct(string $name)
{
$this->name = $name;
}
public function enterNode(Node $node)
{
if ($node instanceof Node\Expr\Variable && $node->name === $this->name) {
$this->nodes[] = $node;
} else if ($node instanceof Node\FunctionLike) {
// If we meet a function node, dont traverse its statements, they are in another scope
// except it is a closure that has imported the variable through use
if ($node instanceof Node\Expr\Closure) {
foreach ($node->uses as $use) {
if ($use->var === $this->name) {
return;
}
}
}
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
}
}

View File

@ -4,17 +4,11 @@ declare(strict_types = 1);
namespace LanguageServer; namespace LanguageServer;
use LanguageServer\Index\Index; use LanguageServer\Index\Index;
use LanguageServer\NodeVisitor\{
NodeAtPositionFinder
};
use LanguageServer\Protocol\{ use LanguageServer\Protocol\{
Diagnostic, Position, Range Diagnostic, Position, Range
}; };
use Microsoft\PhpParser as Tolerant; use Microsoft\PhpParser as Tolerant;
use phpDocumentor\Reflection\DocBlockFactory; use phpDocumentor\Reflection\DocBlockFactory;
use PhpParser\{
Node, NodeTraverser
};
class PhpDocument class PhpDocument
{ {
@ -61,7 +55,7 @@ class PhpDocument
/** /**
* The AST of the document * The AST of the document
* *
* @var Node[] | Tolerant\Node * @var Tolerant\Node
*/ */
private $stmts; private $stmts;
@ -75,14 +69,14 @@ class PhpDocument
/** /**
* Map from fully qualified name (FQN) to Node * Map from fully qualified name (FQN) to Node
* *
* @var Node[] * @var Tolerant\Node
*/ */
private $definitionNodes; private $definitionNodes;
/** /**
* Map from fully qualified name (FQN) to array of nodes that reference the symbol * Map from fully qualified name (FQN) to array of nodes that reference the symbol
* *
* @var Node[][] * @var Tolerant\Node[][]
*/ */
private $referenceNodes; private $referenceNodes;
@ -121,7 +115,7 @@ class PhpDocument
* Get all references of a fully qualified name * Get all references of a fully qualified name
* *
* @param string $fqn The fully qualified name of the symbol * @param string $fqn The fully qualified name of the symbol
* @return Node[] * @return Tolerant\Node[]
*/ */
public function getReferenceNodesByFqn(string $fqn) public function getReferenceNodesByFqn(string $fqn)
{ {
@ -226,7 +220,7 @@ class PhpDocument
/** /**
* Returns the AST of the document * Returns the AST of the document
* *
* @return Node[] | Tolerant\Node | null * @return Tolerant\Node | null
*/ */
public function getStmts() public function getStmts()
{ {
@ -245,13 +239,6 @@ class PhpDocument
return null; return null;
} }
if (\is_array($this->stmts)) {
$traverser = new NodeTraverser;
$finder = new NodeAtPositionFinder($position);
$traverser->addVisitor($finder);
$traverser->traverse($this->stmts);
return $finder->node;
} else {
$offset = $position->toOffset($this->stmts->getFileContents()); $offset = $position->toOffset($this->stmts->getFileContents());
$node = $this->stmts->getDescendantNodeAtPosition($offset); $node = $this->stmts->getDescendantNodeAtPosition($offset);
if ($node !== null && $node->getStart() > $offset) { if ($node !== null && $node->getStart() > $offset) {
@ -259,7 +246,6 @@ class PhpDocument
} }
return $node; return $node;
} }
}
/** /**
* Returns a range of the content * Returns a range of the content
@ -281,7 +267,7 @@ class PhpDocument
* Returns the definition node for a fully qualified name * Returns the definition node for a fully qualified name
* *
* @param string $fqn * @param string $fqn
* @return Node|null * @return Tolerant\Node|null
*/ */
public function getDefinitionNodeByFqn(string $fqn) public function getDefinitionNodeByFqn(string $fqn)
{ {
@ -291,7 +277,7 @@ class PhpDocument
/** /**
* Returns a map from fully qualified name (FQN) to Nodes defined in this document * Returns a map from fully qualified name (FQN) to Nodes defined in this document
* *
* @return Node[] * @return Tolerant\Node[]
*/ */
public function getDefinitionNodes() public function getDefinitionNodes()
{ {

View File

@ -4,14 +4,6 @@ declare(strict_types = 1);
namespace LanguageServer; namespace LanguageServer;
use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, TextEdit}; use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, TextEdit};
use LanguageServer\NodeVisitor\{
NodeAtPositionFinder,
ReferencesAdder,
DocBlockParser,
DefinitionCollector,
ColumnCalculator,
ReferencesCollector
};
use LanguageServer\Index\Index; use LanguageServer\Index\Index;
use PhpParser\{Error, ErrorHandler, Node, NodeTraverser, Parser}; use PhpParser\{Error, ErrorHandler, Node, NodeTraverser, Parser};
use PhpParser\NodeVisitor\NameResolver; use PhpParser\NodeVisitor\NameResolver;