Symbol support for Microsoft/tolerant-php-parser
parent
722898f74d
commit
15eed55158
|
@ -6,7 +6,7 @@ use Microsoft\PhpParser as Tolerant;
|
|||
use LanguageServer\Index\ReadableIndex;
|
||||
|
||||
class ParserResourceFactory {
|
||||
const PARSER_KIND = ParserKind::PHP_PARSER;
|
||||
const PARSER_KIND = ParserKind::TOLERANT_PHP_PARSER;
|
||||
|
||||
public function getParser() {
|
||||
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace LanguageServer\Protocol;
|
||||
|
||||
use PhpParser\Node;
|
||||
use Microsoft\PhpParser as Tolerant;
|
||||
|
||||
/**
|
||||
* Represents a location inside a resource, such as a line inside a text file.
|
||||
|
@ -22,12 +23,20 @@ class Location
|
|||
/**
|
||||
* Returns the location of the node
|
||||
*
|
||||
* @param Node $node
|
||||
* @param Node | Tolerant\Node $node
|
||||
* @return self
|
||||
*/
|
||||
public static function fromNode(Node $node)
|
||||
public static function fromNode($node)
|
||||
{
|
||||
if ($node instanceof Node) {
|
||||
return new self($node->getAttribute('ownerDocument')->getUri(), Range::fromNode($node));
|
||||
} else {
|
||||
$range = Tolerant\PositionUtilities::getRangeFromPosition($node->getStart(), $node->getWidth(), $node->getFileContents());
|
||||
return new self($node->getUri(), new Range(
|
||||
new Position($range->start->line, $range->start->character),
|
||||
new Position($range->end->line, $range->end->character)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(string $uri = null, Range $range = null)
|
||||
|
|
|
@ -10,58 +10,66 @@ use Exception;
|
|||
* Represents information about programming constructs like variables, classes,
|
||||
* interfaces etc.
|
||||
*/
|
||||
class TolerantSymbolInformation extends SymbolInformation
|
||||
class TolerantSymbolInformation
|
||||
{
|
||||
/**
|
||||
* Converts a Node to a SymbolInformation
|
||||
*
|
||||
* @param Tolerant\Node $node
|
||||
* @param string $fqn If given, $containerName will be extracted from it
|
||||
* @return self|null
|
||||
* @return SymbolInformation|null
|
||||
*/
|
||||
public static function fromNode($node, string $fqn = null)
|
||||
{
|
||||
$parent = $node->getAttribute('parentNode');
|
||||
$symbol = new self;
|
||||
if ($node instanceof Node\Stmt\Class_) {
|
||||
$symbol = new SymbolInformation();
|
||||
if ($node instanceof Tolerant\Node\Statement\ClassDeclaration) {
|
||||
$symbol->kind = SymbolKind::CLASS_;
|
||||
} else if ($node instanceof Node\Stmt\Trait_) {
|
||||
} else if ($node instanceof Tolerant\Node\Statement\TraitDeclaration) {
|
||||
$symbol->kind = SymbolKind::CLASS_;
|
||||
} else if ($node instanceof Node\Stmt\Interface_) {
|
||||
} else if ($node instanceof Tolerant\Node\Statement\InterfaceDeclaration) {
|
||||
$symbol->kind = SymbolKind::INTERFACE;
|
||||
} else if ($node instanceof Node\Name && $parent instanceof Node\Stmt\Namespace_) {
|
||||
} else if ($node instanceof Tolerant\Node\Statement\NamespaceDefinition) {
|
||||
$symbol->kind = SymbolKind::NAMESPACE;
|
||||
} else if ($node instanceof Node\Stmt\Function_) {
|
||||
} else if ($node instanceof Tolerant\Node\Statement\FunctionDeclaration) {
|
||||
$symbol->kind = SymbolKind::FUNCTION;
|
||||
} else if ($node instanceof Node\Stmt\ClassMethod) {
|
||||
} else if ($node instanceof Tolerant\Node\MethodDeclaration) {
|
||||
$symbol->kind = SymbolKind::METHOD;
|
||||
} else if ($node instanceof Node\Stmt\PropertyProperty) {
|
||||
} else if ($node instanceof Tolerant\Node\Expression\Variable && $node->getFirstAncestor(Tolerant\Node\PropertyDeclaration::class) !== null) {
|
||||
$symbol->kind = SymbolKind::PROPERTY;
|
||||
} else if ($node instanceof Node\Const_) {
|
||||
} else if ($node instanceof Tolerant\Node\ConstElement) {
|
||||
$symbol->kind = SymbolKind::CONSTANT;
|
||||
} else if (
|
||||
}
|
||||
|
||||
else if (
|
||||
(
|
||||
($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp)
|
||||
&& $node->var instanceof Node\Expr\Variable
|
||||
($node instanceof Tolerant\Node\Expression\AssignmentExpression)
|
||||
&& $node->leftOperand instanceof Tolerant\Node\Expression\Variable
|
||||
)
|
||||
|| $node instanceof Node\Expr\ClosureUse
|
||||
|| $node instanceof Node\Param
|
||||
|| $node instanceof Tolerant\Node\UseVariableName
|
||||
|| $node instanceof Tolerant\Node\Parameter
|
||||
) {
|
||||
$symbol->kind = SymbolKind::VARIABLE;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Name) {
|
||||
$symbol->name = (string)$node;
|
||||
} else if ($node instanceof Node\Expr\Assign || $node instanceof Node\Expr\AssignOp) {
|
||||
$symbol->name = $node->var->name;
|
||||
} else if ($node instanceof Node\Expr\ClosureUse) {
|
||||
$symbol->name = $node->var;
|
||||
} else if ($node instanceof Tolerant\Node\Expression\AssignmentExpression) {
|
||||
if ($node->leftOperand instanceof Tolerant\Node\Expression\Variable) {
|
||||
$symbol->name = $node->leftOperand->getName();
|
||||
} elseif ($node->leftOperand instanceof Tolerant\Token) {
|
||||
$symbol->name = trim($node->leftOperand->getText($node->getFileContents()), "$");
|
||||
}
|
||||
|
||||
} else if ($node instanceof Tolerant\Node\UseVariableName) {
|
||||
$symbol->name = $node->getName();
|
||||
} else if (isset($node->name)) {
|
||||
$symbol->name = (string)$node->name;
|
||||
$symbol->name = trim((string)$node->name->getText($node->getFileContents()), "$");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$symbol->location = Location::fromNode($node);
|
||||
if ($fqn !== null) {
|
||||
$parts = preg_split('/(::|->|\\\\)/', $fqn);
|
||||
|
|
|
@ -6,9 +6,12 @@ namespace LanguageServer;
|
|||
use LanguageServer\Protocol\TolerantSymbolInformation;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
|
||||
use phpDocumentor\Reflection\{Types, Type, Fqsen, TypeResolver};
|
||||
use phpDocumentor\Reflection\{
|
||||
DocBlockFactory, Types, Type, Fqsen, TypeResolver
|
||||
};
|
||||
use LanguageServer\Protocol\SymbolInformation;
|
||||
use LanguageServer\Index\ReadableIndex;
|
||||
use Microsoft\PhpParser as Tolerant;
|
||||
|
||||
class TolerantDefinitionResolver implements DefinitionResolverInterface
|
||||
{
|
||||
|
@ -38,99 +41,157 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Builds the declaration line for a given node
|
||||
* Builds the declaration line for a given node.
|
||||
*
|
||||
* @param Node $node
|
||||
*
|
||||
* @param Tolerant\Node $node
|
||||
* @return string
|
||||
*/
|
||||
public function getDeclarationLineFromNode($node): string
|
||||
{
|
||||
if ($node instanceof Node\Stmt\PropertyProperty || $node instanceof Node\Const_) {
|
||||
// Properties and constants can have multiple declarations
|
||||
// Use the parent node (that includes the modifiers), but only render the requested declaration
|
||||
$child = $node;
|
||||
/** @var Node */
|
||||
$node = $node->getAttribute('parentNode');
|
||||
$defLine = clone $node;
|
||||
$defLine->props = [$child];
|
||||
} else {
|
||||
$defLine = clone $node;
|
||||
// TODO Tolerant\Node\Statement\FunctionStaticDeclaration::class
|
||||
|
||||
// we should have a better way of determining whether something is a property or constant
|
||||
// If part of a declaration list -> get the parent declaration
|
||||
if (
|
||||
// PropertyDeclaration // public $a, $b, $c;
|
||||
$node instanceof Tolerant\Node\Expression\Variable &&
|
||||
($propertyDeclaration = $node->getFirstAncestor(Tolerant\Node\PropertyDeclaration::class)) !== null
|
||||
) {
|
||||
$defLine = $propertyDeclaration->getText();
|
||||
$defLineStart = $propertyDeclaration->getStart();
|
||||
|
||||
$defLine = \substr_replace(
|
||||
$defLine,
|
||||
$node->getFullText(),
|
||||
$propertyDeclaration->propertyElements->getFullStart() - $defLineStart,
|
||||
$propertyDeclaration->propertyElements->getWidth()
|
||||
);
|
||||
} elseif (
|
||||
// ClassConstDeclaration or ConstDeclaration // const A = 1, B = 2;
|
||||
$node instanceof Tolerant\Node\ConstElement &&
|
||||
($constDeclaration = $node->getFirstAncestor(Tolerant\Node\Statement\ConstDeclaration::class, Tolerant\Node\ClassConstDeclaration::class))
|
||||
) {
|
||||
$defLine = $constDeclaration->getText();
|
||||
$defLineStart = $constDeclaration->getStart();
|
||||
|
||||
$defLine = \substr_replace(
|
||||
$defLine,
|
||||
$node->getFullText(),
|
||||
$constDeclaration->constElements->getFullStart() - $defLineStart,
|
||||
$constDeclaration->constElements->getWidth()
|
||||
);
|
||||
}
|
||||
// Don't include the docblock in the declaration string
|
||||
$defLine->setAttribute('comments', []);
|
||||
if (isset($defLine->stmts)) {
|
||||
$defLine->stmts = [];
|
||||
|
||||
// Get the current node
|
||||
else {
|
||||
$defLine = $node->getText();
|
||||
}
|
||||
$defText = $this->prettyPrinter->prettyPrint([$defLine]);
|
||||
return strstr($defText, "\n", true) ?: $defText;
|
||||
|
||||
$defLine = \strtok($defLine, "\n");
|
||||
|
||||
return $defLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the documentation string for a node, if it has one
|
||||
*
|
||||
* @param Node $node
|
||||
* @param Tolerant\Node $node
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDocumentationFromNode($node)
|
||||
{
|
||||
if ($node instanceof Node\Stmt\PropertyProperty || $node instanceof Node\Const_) {
|
||||
$node = $node->getAttribute('parentNode');
|
||||
// For properties and constants, set the node to the declaration node, rather than the individual property.
|
||||
// This is because they get defined as part of a list.
|
||||
$constOrPropertyDeclaration = $node->getFirstAncestor(
|
||||
Tolerant\Node\PropertyDeclaration::class,
|
||||
Tolerant\Node\Statement\ConstDeclaration::class,
|
||||
Tolerant\Node\ClassConstDeclaration::class
|
||||
);
|
||||
if ($constOrPropertyDeclaration !== null) {
|
||||
$node = $constOrPropertyDeclaration;
|
||||
}
|
||||
if ($node instanceof Node\Param) {
|
||||
$fn = $node->getAttribute('parentNode');
|
||||
$docBlock = $fn->getAttribute('docBlock');
|
||||
|
||||
// For parameters, parse the documentation to get the parameter tag.
|
||||
if ($node instanceof Tolerant\Node\Parameter) {
|
||||
$functionLikeDeclaration = $this->getFunctionLikeDeclarationFromParameter($node);
|
||||
$variableName = $node->variableName->getText($node->getFileContents());
|
||||
$docBlock = $this->getDocBlock($functionLikeDeclaration);
|
||||
|
||||
if ($docBlock !== null) {
|
||||
$tags = $docBlock->getTagsByName('param');
|
||||
foreach ($tags as $tag) {
|
||||
if ($tag->getVariableName() === $node->name) {
|
||||
return $tag->getDescription()->render();
|
||||
$parameterDocBlockTag = $this->getDocBlockTagForParameter($docBlock, $variableName);
|
||||
return $parameterDocBlockTag !== null ? $parameterDocBlockTag->getDescription()->render() : null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$docBlock = $node->getAttribute('docBlock');
|
||||
// for everything else, get the doc block summary corresponding to the current node.
|
||||
else {
|
||||
$docBlock = $this->getDocBlock($node);
|
||||
if ($docBlock !== null) {
|
||||
return $docBlock->getSummary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDocBlock(Tolerant\Node $node) {
|
||||
// TODO context information
|
||||
static $docBlockFactory;
|
||||
$docBlockFactory = $docBlockFactory ?? DocBlockFactory::createInstance();
|
||||
$docCommentText = $node->getDocCommentText();
|
||||
return $docCommentText !== null ? $docBlockFactory->create($docCommentText) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Definition for a definition node
|
||||
*
|
||||
* @param Node $node
|
||||
* @param Tolerant\Node $node
|
||||
* @param string $fqn
|
||||
* @return Definition
|
||||
*/
|
||||
public function createDefinitionFromNode($node, string $fqn = null): Definition
|
||||
{
|
||||
$parent = $node->getAttribute('parentNode');
|
||||
$def = new Definition;
|
||||
$def->canBeInstantiated = $node instanceof Node\Stmt\Class_;
|
||||
|
||||
// this determines whether the suggestion will show after "new"
|
||||
$def->isClass = $node instanceof Tolerant\Node\Statement\ClassDeclaration;
|
||||
|
||||
$def->isGlobal = (
|
||||
$node instanceof Node\Stmt\ClassLike
|
||||
|| ($node instanceof Node\Name && $parent instanceof Node\Stmt\Namespace_)
|
||||
|| $node instanceof Node\Stmt\Function_
|
||||
|| $parent instanceof Node\Stmt\Const_
|
||||
$node instanceof Tolerant\Node\Statement\InterfaceDeclaration
|
||||
|| $node instanceof Tolerant\Node\Statement\ClassDeclaration
|
||||
|| $node instanceof Tolerant\Node\Statement\TraitDeclaration
|
||||
|
||||
|| $node instanceof Tolerant\Node\Statement\NamespaceDefinition && $node->name !== null
|
||||
|
||||
|| $node instanceof Tolerant\Node\Statement\FunctionDeclaration
|
||||
|
||||
|| $node instanceof Tolerant\Node\Statement\ConstDeclaration
|
||||
|| $node instanceof Tolerant\Node\ClassConstDeclaration
|
||||
);
|
||||
|
||||
$def->isStatic = (
|
||||
($node instanceof Node\Stmt\ClassMethod && $node->isStatic())
|
||||
|| ($node instanceof Node\Stmt\PropertyProperty && $parent->isStatic())
|
||||
($node instanceof Tolerant\Node\MethodDeclaration && $node->isStatic())
|
||||
|| ($node instanceof Tolerant\Node\Expression\Variable &&
|
||||
($propertyDeclaration = $node->getFirstAncestor(Tolerant\Node\PropertyDeclaration::class)) !== null &&
|
||||
$propertyDeclaration->isStatic())
|
||||
);
|
||||
$def->fqn = $fqn;
|
||||
if ($node instanceof Node\Stmt\Class_) {
|
||||
if ($node instanceof Tolerant\Node\Statement\ClassDeclaration) {
|
||||
$def->extends = [];
|
||||
if ($node->extends) {
|
||||
$def->extends[] = (string)$node->extends;
|
||||
if ($node->classBaseClause !== null && $node->classBaseClause->baseClass !== null) {
|
||||
$def->extends[] = (string)$node->classBaseClause->baseClass;
|
||||
}
|
||||
} else if ($node instanceof Node\Stmt\Interface_) {
|
||||
// TODO what about class interfaces
|
||||
} else if ($node instanceof Tolerant\Node\Statement\InterfaceDeclaration) {
|
||||
$def->extends = [];
|
||||
foreach ($node->extends as $n) {
|
||||
if ($node->interfaceBaseClause !== null && $node->interfaceBaseClause->interfaceNameList !== null) {
|
||||
foreach ($node->interfaceBaseClause->interfaceNameList->getChildNodes() as $n) {
|
||||
$def->extends[] = (string)$n;
|
||||
}
|
||||
}
|
||||
}
|
||||
$def->symbolInformation = TolerantSymbolInformation::fromNode($node, $fqn);
|
||||
$def->type = $this->getTypeFromNode($node);
|
||||
// $def->type = $this->getTypeFromNode($node); //TODO
|
||||
$def->type = new Types\Mixed;
|
||||
$def->declarationLine = $this->getDeclarationLineFromNode($node);
|
||||
$def->documentation = $this->getDocumentationFromNode($node);
|
||||
return $def;
|
||||
|
@ -796,60 +857,97 @@ class TolerantDefinitionResolver implements DefinitionResolverInterface
|
|||
* Returns the fully qualified name (FQN) that is defined by a node
|
||||
* Returns null if the node does not declare any symbol that can be referenced by an FQN
|
||||
*
|
||||
* @param Node $node
|
||||
* @param Tolerant\Node $node
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getDefinedFqn($node)
|
||||
{
|
||||
$parent = $node->getAttribute('parentNode');
|
||||
$parent = $node->getParent();
|
||||
// Anonymous classes don't count as a definition
|
||||
if ($node instanceof Node\Stmt\ClassLike && isset($node->name)) {
|
||||
// Class, interface or trait declaration
|
||||
return (string)$node->namespacedName;
|
||||
} else if ($node instanceof Node\Name && $parent instanceof Node\Stmt\Namespace_) {
|
||||
return (string)$node;
|
||||
} else if ($node instanceof Node\Stmt\Function_) {
|
||||
// INPUT OUTPUT:
|
||||
// namespace A\B;
|
||||
// class C { } A\B\C
|
||||
// interface C { } A\B\C
|
||||
// trait C { } A\B\C
|
||||
if (
|
||||
$node instanceof Tolerant\Node\Statement\ClassDeclaration ||
|
||||
$node instanceof Tolerant\Node\Statement\InterfaceDeclaration ||
|
||||
$node instanceof Tolerant\Node\Statement\TraitDeclaration
|
||||
) {
|
||||
return (string) $node->getNamespacedName();
|
||||
}
|
||||
|
||||
// INPUT OUTPUT:
|
||||
// namespace A\B; A\B
|
||||
else if ($node instanceof Tolerant\Node\Statement\NamespaceDefinition && $node->name instanceof Tolerant\Node\QualifiedName) {
|
||||
return (string) $node->name;
|
||||
}
|
||||
// INPUT OUTPUT:
|
||||
// namespace A\B;
|
||||
// function a(); A\B\a();
|
||||
else if ($node instanceof Tolerant\Node\Statement\FunctionDeclaration) {
|
||||
// Function: use functionName() as the name
|
||||
return (string)$node->namespacedName . '()';
|
||||
} else if ($node instanceof Node\Stmt\ClassMethod) {
|
||||
return (string)$node->getNamespacedName() . '()';
|
||||
}
|
||||
// INPUT OUTPUT
|
||||
// namespace A\B;
|
||||
// class C {
|
||||
// function a () {} A\B\C::a()
|
||||
// static function b() {} A\B\C->b()
|
||||
// }
|
||||
else if ($node instanceof Tolerant\Node\MethodDeclaration) {
|
||||
// Class method: use ClassName->methodName() as name
|
||||
$class = $node->getAttribute('parentNode');
|
||||
$class = $node->getFirstAncestor(Tolerant\Node\Statement\ClassDeclaration::class);
|
||||
if (!isset($class->name)) {
|
||||
// Ignore anonymous classes
|
||||
return null;
|
||||
}
|
||||
if ($node->isStatic()) {
|
||||
return (string)$class->namespacedName . '::' . (string)$node->name . '()';
|
||||
return (string)$class->getNamespacedName() . '::' . $node->getName() . '()';
|
||||
} else {
|
||||
return (string)$class->namespacedName . '->' . (string)$node->name . '()';
|
||||
return (string)$class->getNamespacedName() . '->' . $node->getName() . '()';
|
||||
}
|
||||
} else if ($node instanceof Node\Stmt\PropertyProperty) {
|
||||
$property = $node->getAttribute('parentNode');
|
||||
$class = $property->getAttribute('parentNode');
|
||||
if (!isset($class->name)) {
|
||||
// Ignore anonymous classes
|
||||
return null;
|
||||
}
|
||||
if ($property->isStatic()) {
|
||||
|
||||
// INPUT OUTPUT
|
||||
// namespace A\B;
|
||||
// class C {
|
||||
// static $a = 4, $b = 4 A\B\C::$a, A\B\C::$b
|
||||
// $a = 4, $b = 4 A\B\C->$a, A\B\C->$b
|
||||
// }
|
||||
else if (
|
||||
$node instanceof Tolerant\Node\Expression\Variable &&
|
||||
($propertyDeclaration = $node->getFirstAncestor(Tolerant\Node\PropertyDeclaration::class)) !== null &&
|
||||
($classDeclaration = $node->getFirstAncestor(Tolerant\Node\Statement\ClassDeclaration::class)) !== null)
|
||||
{
|
||||
if ($propertyDeclaration->isStatic()) {
|
||||
// Static Property: use ClassName::$propertyName as name
|
||||
return (string)$class->namespacedName . '::$' . (string)$node->name;
|
||||
} else {
|
||||
return (string)$classDeclaration->getNamespacedName() . '::$' . (string)$node->getName();
|
||||
} elseif (($name = $node->getName()) !== null) {
|
||||
// Instance Property: use ClassName->propertyName as name
|
||||
return (string)$class->namespacedName . '->' . (string)$node->name;
|
||||
return (string)$classDeclaration->getNamespacedName() . '->' . $name;
|
||||
}
|
||||
} else if ($node instanceof Node\Const_) {
|
||||
$parent = $node->getAttribute('parentNode');
|
||||
if ($parent instanceof Node\Stmt\Const_) {
|
||||
}
|
||||
|
||||
// INPUT OUTPUT
|
||||
// namespace A\B;
|
||||
// const FOO = 5; A\B\FOO
|
||||
// class C {
|
||||
// const $a, $b = 4 A\B\C::$a(), A\B\C::$b
|
||||
// }
|
||||
else if ($node instanceof Tolerant\Node\ConstElement) {
|
||||
$constDeclaration = $node->getFirstAncestor(Tolerant\Node\Statement\ConstDeclaration::class, Tolerant\Node\ClassConstDeclaration::class);
|
||||
if ($constDeclaration instanceof Tolerant\Node\Statement\ConstDeclaration) {
|
||||
// Basic constant: use CONSTANT_NAME as name
|
||||
return (string)$node->namespacedName;
|
||||
return (string)$node->getNamespacedName();
|
||||
}
|
||||
if ($parent instanceof Node\Stmt\ClassConst) {
|
||||
if ($constDeclaration instanceof Tolerant\Node\ClassConstDeclaration) {
|
||||
// Class constant: use ClassName::CONSTANT_NAME as name
|
||||
$class = $parent->getAttribute('parentNode');
|
||||
if (!isset($class->name) || $class->name instanceof Node\Expr) {
|
||||
$classDeclaration = $constDeclaration->getFirstAncestor(Tolerant\Node\Statement\ClassDeclaration::class);
|
||||
if (!isset($classDeclaration->name)) {
|
||||
return null;
|
||||
}
|
||||
return (string)$class->namespacedName . '::' . $node->name;
|
||||
return (string)$classDeclaration->getNamespacedName() . '::' . $node->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,20 +22,29 @@ use Microsoft\PhpParser as Tolerant;
|
|||
class TolerantTreeAnalyzer implements TreeAnalyzerInterface {
|
||||
private $parser;
|
||||
|
||||
/** @var Tolerant\Node */
|
||||
private $stmts;
|
||||
|
||||
public function __construct(Parser $parser, $content, $docBlockFactory, $definitionResolver, $uri) {
|
||||
/**
|
||||
* TolerantTreeAnalyzer constructor.
|
||||
* @param Tolerant\Parser $parser
|
||||
* @param $content
|
||||
* @param $docBlockFactory
|
||||
* @param TolerantDefinitionResolver $definitionResolver
|
||||
* @param $uri
|
||||
*/
|
||||
public function __construct($parser, $content, $docBlockFactory, $definitionResolver, $uri) {
|
||||
$this->uri = $uri;
|
||||
$this->parser = $parser;
|
||||
$this->docBlockFactory = $docBlockFactory;
|
||||
$this->definitionResolver = $definitionResolver;
|
||||
$this->content = $content;
|
||||
$this->$stmts = $this->parser->parse($content);
|
||||
$this->stmts = $this->parser->parseSourceFile($content, $uri);
|
||||
|
||||
// TODO - docblock errors
|
||||
|
||||
foreach ($this->stmts->getDescendantNodes() as $node) {
|
||||
$fqn = DefinitionResolver::getDefinedFqn($node);
|
||||
$fqn = $definitionResolver::getDefinedFqn($node);
|
||||
// Only index definitions with an FQN (no variables)
|
||||
if ($fqn === null) {
|
||||
continue;
|
||||
|
@ -47,7 +56,8 @@ class TolerantTreeAnalyzer implements TreeAnalyzerInterface {
|
|||
|
||||
public function getDiagnostics() {
|
||||
$diagnostics = [];
|
||||
foreach (Tolerant\DiagnosticsProvider::getDiagnostics($tolerantStmts) as $_error) {
|
||||
$content = $this->stmts->getFileContents();
|
||||
foreach (Tolerant\DiagnosticsProvider::getDiagnostics($this->stmts) as $_error) {
|
||||
$range = Tolerant\PositionUtilities::getRangeFromPosition($_error->start, $_error->length, $content);
|
||||
|
||||
$diagnostics[] = new Diagnostic(
|
||||
|
|
|
@ -28,7 +28,7 @@ class TreeAnalyzer implements TreeAnalyzerInterface {
|
|||
|
||||
private $diagnostics;
|
||||
|
||||
public function __construct(Parser $parser, $content, $docBlockFactory, $definitionResolver, $uri) {
|
||||
public function __construct($parser, $content, $docBlockFactory, $definitionResolver, $uri) {
|
||||
$this->uri = $uri;
|
||||
$this->parser = $parser;
|
||||
$this->docBlockFactory = $docBlockFactory;
|
||||
|
|
|
@ -20,7 +20,7 @@ use Sabre\Uri;
|
|||
use Microsoft\PhpParser as Tolerant;
|
||||
|
||||
interface TreeAnalyzerInterface {
|
||||
public function __construct(Parser $parser, $content, $docBlockFactory, $definitionResolver, $uri);
|
||||
public function __construct($parser, $content, $docBlockFactory, $definitionResolver, $uri);
|
||||
|
||||
public function getDiagnostics();
|
||||
|
||||
|
|
|
@ -88,8 +88,8 @@ abstract class ServerTestCase extends TestCase
|
|||
'whatever()' => new Location($globalReferencesUri, new Range(new Position(21, 0), new Position(23, 1))),
|
||||
|
||||
// Namespaced
|
||||
'TestNamespace' => new Location($symbolsUri, new Range(new Position( 2, 10), new Position( 2, 23))),
|
||||
'SecondTestNamespace' => new Location($useUri, new Range(new Position( 2, 10), new Position( 2, 29))),
|
||||
'TestNamespace' => new Location($symbolsUri, new Range(new Position( 2, 0), new Position( 2, 24))),
|
||||
'SecondTestNamespace' => new Location($useUri, new Range(new Position( 2, 0), new Position( 2, 30))),
|
||||
'TestNamespace\\TEST_CONST' => new Location($symbolsUri, new Range(new Position( 9, 6), new Position( 9, 22))),
|
||||
'TestNamespace\\TestClass' => new Location($symbolsUri, new Range(new Position(20, 0), new Position(61, 1))),
|
||||
'TestNamespace\\ChildClass' => new Location($symbolsUri, new Range(new Position(99, 0), new Position(99, 37))),
|
||||
|
|
|
@ -29,7 +29,7 @@ class SymbolTest extends ServerTestCase
|
|||
$referencesUri = pathToUri(realpath(__DIR__ . '/../../../fixtures/references.php'));
|
||||
// @codingStandardsIgnoreStart
|
||||
$this->assertEquals([
|
||||
new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 10), new Position(2, 23))), ''),
|
||||
new SymbolInformation('TestNamespace', SymbolKind::NAMESPACE, new Location($referencesUri, new Range(new Position(2, 0), new Position(2, 24))), ''),
|
||||
// Namespaced
|
||||
new SymbolInformation('TEST_CONST', SymbolKind::CONSTANT, $this->getDefinitionLocation('TestNamespace\\TEST_CONST'), 'TestNamespace'),
|
||||
new SymbolInformation('TestClass', SymbolKind::CLASS_, $this->getDefinitionLocation('TestNamespace\\TestClass'), 'TestNamespace'),
|
||||
|
|
Loading…
Reference in New Issue