Remove obsolete NodeVisitors
parent
cf9590b9b7
commit
71d71a896c
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 = '';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,17 +4,11 @@ declare(strict_types = 1);
|
|||
namespace LanguageServer;
|
||||
|
||||
use LanguageServer\Index\Index;
|
||||
use LanguageServer\NodeVisitor\{
|
||||
NodeAtPositionFinder
|
||||
};
|
||||
use LanguageServer\Protocol\{
|
||||
Diagnostic, Position, Range
|
||||
};
|
||||
use Microsoft\PhpParser as Tolerant;
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use PhpParser\{
|
||||
Node, NodeTraverser
|
||||
};
|
||||
|
||||
class PhpDocument
|
||||
{
|
||||
|
@ -61,7 +55,7 @@ class PhpDocument
|
|||
/**
|
||||
* The AST of the document
|
||||
*
|
||||
* @var Node[] | Tolerant\Node
|
||||
* @var Tolerant\Node
|
||||
*/
|
||||
private $stmts;
|
||||
|
||||
|
@ -75,14 +69,14 @@ class PhpDocument
|
|||
/**
|
||||
* Map from fully qualified name (FQN) to Node
|
||||
*
|
||||
* @var Node[]
|
||||
* @var Tolerant\Node
|
||||
*/
|
||||
private $definitionNodes;
|
||||
|
||||
/**
|
||||
* Map from fully qualified name (FQN) to array of nodes that reference the symbol
|
||||
*
|
||||
* @var Node[][]
|
||||
* @var Tolerant\Node[][]
|
||||
*/
|
||||
private $referenceNodes;
|
||||
|
||||
|
@ -121,7 +115,7 @@ class PhpDocument
|
|||
* Get all references of a fully qualified name
|
||||
*
|
||||
* @param string $fqn The fully qualified name of the symbol
|
||||
* @return Node[]
|
||||
* @return Tolerant\Node[]
|
||||
*/
|
||||
public function getReferenceNodesByFqn(string $fqn)
|
||||
{
|
||||
|
@ -226,7 +220,7 @@ class PhpDocument
|
|||
/**
|
||||
* Returns the AST of the document
|
||||
*
|
||||
* @return Node[] | Tolerant\Node | null
|
||||
* @return Tolerant\Node | null
|
||||
*/
|
||||
public function getStmts()
|
||||
{
|
||||
|
@ -245,20 +239,12 @@ class PhpDocument
|
|||
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());
|
||||
$node = $this->stmts->getDescendantNodeAtPosition($offset);
|
||||
if ($node !== null && $node->getStart() > $offset) {
|
||||
return null;
|
||||
}
|
||||
return $node;
|
||||
$offset = $position->toOffset($this->stmts->getFileContents());
|
||||
$node = $this->stmts->getDescendantNodeAtPosition($offset);
|
||||
if ($node !== null && $node->getStart() > $offset) {
|
||||
return null;
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,7 +267,7 @@ class PhpDocument
|
|||
* Returns the definition node for a fully qualified name
|
||||
*
|
||||
* @param string $fqn
|
||||
* @return Node|null
|
||||
* @return Tolerant\Node|null
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @return Node[]
|
||||
* @return Tolerant\Node[]
|
||||
*/
|
||||
public function getDefinitionNodes()
|
||||
{
|
||||
|
|
|
@ -4,14 +4,6 @@ declare(strict_types = 1);
|
|||
namespace LanguageServer;
|
||||
|
||||
use LanguageServer\Protocol\{Diagnostic, DiagnosticSeverity, Range, Position, TextEdit};
|
||||
use LanguageServer\NodeVisitor\{
|
||||
NodeAtPositionFinder,
|
||||
ReferencesAdder,
|
||||
DocBlockParser,
|
||||
DefinitionCollector,
|
||||
ColumnCalculator,
|
||||
ReferencesCollector
|
||||
};
|
||||
use LanguageServer\Index\Index;
|
||||
use PhpParser\{Error, ErrorHandler, Node, NodeTraverser, Parser};
|
||||
use PhpParser\NodeVisitor\NameResolver;
|
||||
|
|
Loading…
Reference in New Issue