add getNodeAtPosition, fix definition collector tests
parent
15eed55158
commit
cdf8fc36e1
|
@ -8,7 +8,7 @@ use LanguageServer\Index\ReadableIndex;
|
|||
class ParserResourceFactory {
|
||||
const PARSER_KIND = ParserKind::TOLERANT_PHP_PARSER;
|
||||
|
||||
public function getParser() {
|
||||
public static function getParser() {
|
||||
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
||||
return new Parser;
|
||||
} else {
|
||||
|
@ -16,11 +16,20 @@ class ParserResourceFactory {
|
|||
}
|
||||
}
|
||||
|
||||
public function getDefinitionResolver(ReadableIndex $index) {
|
||||
public static function getDefinitionResolver(ReadableIndex $index) {
|
||||
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
||||
return new DefinitionResolver($index);
|
||||
} else {
|
||||
return new TolerantDefinitionResolver($index);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getTreeAnalyzer($parser, $content, $docBlockFactory, $definitionResolver, $uri)
|
||||
{
|
||||
if (self::PARSER_KIND === ParserKind::PHP_PARSER) {
|
||||
return new TreeAnalyzer($parser, $content, $docBlockFactory, $definitionResolver, $uri);
|
||||
} else {
|
||||
return new TolerantTreeAnalyzer($parser, $content, $docBlockFactory, $definitionResolver, $uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class PhpDocument
|
|||
/**
|
||||
* The AST of the document
|
||||
*
|
||||
* @var Node[]
|
||||
* @var Node[] | Tolerant\Node
|
||||
*/
|
||||
private $stmts;
|
||||
|
||||
|
@ -161,11 +161,7 @@ class PhpDocument
|
|||
$this->definitions = null;
|
||||
$this->definitionNodes = null;
|
||||
|
||||
$treeAnalyzerClass = $this->parser instanceof Parser
|
||||
? TreeAnalyzer::class
|
||||
: TolerantTreeAnalyzer::class;
|
||||
|
||||
$treeAnalyzer = new $treeAnalyzerClass($this->parser, $content, $this->docBlockFactory, $this->definitionResolver, $this->uri);
|
||||
$treeAnalyzer = ParserResourceFactory::getTreeAnalyzer($this->parser, $content, $this->docBlockFactory, $this->definitionResolver, $this->uri);
|
||||
|
||||
$this->diagnostics = $treeAnalyzer->getDiagnostics();
|
||||
|
||||
|
@ -251,11 +247,17 @@ class PhpDocument
|
|||
if ($this->stmts === null) {
|
||||
return null;
|
||||
}
|
||||
$traverser = new NodeTraverser;
|
||||
$finder = new NodeAtPositionFinder($position);
|
||||
$traverser->addVisitor($finder);
|
||||
$traverser->traverse($this->stmts);
|
||||
return $finder->node;
|
||||
|
||||
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());
|
||||
return $this->stmts->getDescendantNodeAtPosition($offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,17 +4,12 @@ declare(strict_types = 1);
|
|||
namespace LanguageServer\Tests\Server\TextDocument;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PhpParser\{NodeTraverser, Node};
|
||||
use PhpParser\NodeVisitor\NameResolver;
|
||||
use PhpParser\{Node};
|
||||
use phpDocumentor\Reflection\DocBlockFactory;
|
||||
use LanguageServer\{
|
||||
ParserResourceFactory, LanguageClient, PhpDocument, PhpDocumentLoader, Parser, DefinitionResolver
|
||||
ParserResourceFactory
|
||||
};
|
||||
use LanguageServer\ContentRetriever\FileSystemContentRetriever;
|
||||
use LanguageServer\Protocol\ClientCapabilities;
|
||||
use LanguageServer\Index\{ProjectIndex, Index, DependenciesIndex};
|
||||
use LanguageServer\Tests\MockProtocolStream;
|
||||
use LanguageServer\NodeVisitor\{ReferencesAdder, DefinitionCollector};
|
||||
use LanguageServer\Index\{Index};
|
||||
use function LanguageServer\pathToUri;
|
||||
use Microsoft\PhpParser as Tolerant;
|
||||
|
||||
|
@ -23,23 +18,7 @@ class DefinitionCollectorTest extends TestCase
|
|||
public function testCollectsSymbols()
|
||||
{
|
||||
$path = realpath(__DIR__ . '/../../fixtures/symbols.php');
|
||||
$uri = pathToUri($path);
|
||||
$parser = ParserResourceFactory::getParser();
|
||||
$docBlockFactory = DocBlockFactory::createInstance();
|
||||
$index = new Index;
|
||||
$definitionResolver = ParserResourceFactory::getDefinitionResolver($index);
|
||||
$content = file_get_contents($path);
|
||||
$document = new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
|
||||
$stmts = $parser->parse($content);
|
||||
|
||||
$traverser = new NodeTraverser;
|
||||
$traverser->addVisitor(new NameResolver);
|
||||
$traverser->addVisitor(new ReferencesAdder($document));
|
||||
$definitionCollector = new DefinitionCollector($definitionResolver);
|
||||
$traverser->addVisitor($definitionCollector);
|
||||
$traverser->traverse($stmts);
|
||||
|
||||
$defNodes = $definitionCollector->nodes;
|
||||
$defNodes = $this->collectDefinitions($path);
|
||||
|
||||
$this->assertEquals([
|
||||
'TestNamespace',
|
||||
|
@ -55,43 +34,47 @@ class DefinitionCollectorTest extends TestCase
|
|||
'TestNamespace\\test_function()',
|
||||
'TestNamespace\\ChildClass'
|
||||
], array_keys($defNodes));
|
||||
$this->assertInstanceOf(Node\Const_::class, $defNodes['TestNamespace\\TEST_CONST']);
|
||||
$this->assertInstanceOf(Node\Stmt\Class_::class, $defNodes['TestNamespace\\TestClass']);
|
||||
$this->assertInstanceOf(Node\Const_::class, $defNodes['TestNamespace\\TestClass::TEST_CLASS_CONST']);
|
||||
$this->assertInstanceOf(Node\Stmt\PropertyProperty::class, $defNodes['TestNamespace\\TestClass::$staticTestProperty']);
|
||||
$this->assertInstanceOf(Node\Stmt\PropertyProperty::class, $defNodes['TestNamespace\\TestClass->testProperty']);
|
||||
$this->assertInstanceOf(Node\Stmt\ClassMethod::class, $defNodes['TestNamespace\\TestClass::staticTestMethod()']);
|
||||
$this->assertInstanceOf(Node\Stmt\ClassMethod::class, $defNodes['TestNamespace\\TestClass->testMethod()']);
|
||||
$this->assertInstanceOf(Node\Stmt\Trait_::class, $defNodes['TestNamespace\\TestTrait']);
|
||||
$this->assertInstanceOf(Node\Stmt\Interface_::class, $defNodes['TestNamespace\\TestInterface']);
|
||||
$this->assertInstanceOf(Node\Stmt\Function_::class, $defNodes['TestNamespace\\test_function()']);
|
||||
$this->assertInstanceOf(Node\Stmt\Class_::class, $defNodes['TestNamespace\\ChildClass']);
|
||||
|
||||
|
||||
$this->assertInstanceOf(Tolerant\Node\ConstElement::class, $defNodes['TestNamespace\\TEST_CONST']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\TestClass']);
|
||||
$this->assertInstanceOf(Tolerant\Node\ConstElement::class, $defNodes['TestNamespace\\TestClass::TEST_CLASS_CONST']);
|
||||
// TODO - should we parse properties more strictly?
|
||||
$this->assertInstanceOf(Tolerant\Node\Expression\Variable::class, $defNodes['TestNamespace\\TestClass::$staticTestProperty']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Expression\Variable::class, $defNodes['TestNamespace\\TestClass->testProperty']);
|
||||
$this->assertInstanceOf(Tolerant\Node\MethodDeclaration::class, $defNodes['TestNamespace\\TestClass::staticTestMethod()']);
|
||||
$this->assertInstanceOf(Tolerant\Node\MethodDeclaration::class, $defNodes['TestNamespace\\TestClass->testMethod()']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\TraitDeclaration::class, $defNodes['TestNamespace\\TestTrait']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\InterfaceDeclaration::class, $defNodes['TestNamespace\\TestInterface']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\FunctionDeclaration::class, $defNodes['TestNamespace\\test_function()']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\ClassDeclaration::class, $defNodes['TestNamespace\\ChildClass']);
|
||||
}
|
||||
|
||||
public function testDoesNotCollectReferences()
|
||||
{
|
||||
$path = realpath(__DIR__ . '/../../fixtures/references.php');
|
||||
$defNodes = $this->collectDefinitions($path);
|
||||
|
||||
$this->assertEquals(['TestNamespace', 'TestNamespace\\whatever()'], array_keys($defNodes));
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\NamespaceDefinition::class, $defNodes['TestNamespace']);
|
||||
$this->assertInstanceOf(Tolerant\Node\Statement\FunctionDeclaration::class, $defNodes['TestNamespace\\whatever()']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return Node
|
||||
*/
|
||||
private function collectDefinitions($path):array
|
||||
{
|
||||
$uri = pathToUri($path);
|
||||
$parser = ParserResourceFactory::getParser();
|
||||
|
||||
$docBlockFactory = DocBlockFactory::createInstance();
|
||||
$index = new Index;
|
||||
$definitionResolver = ParserResourceFactory::getDefinitionResolver($index);
|
||||
$content = file_get_contents($path);
|
||||
$document = new PhpDocument($uri, $content, $index, $parser, $docBlockFactory, $definitionResolver);
|
||||
$stmts = $parser->parse($content);
|
||||
|
||||
$traverser = new NodeTraverser;
|
||||
$traverser->addVisitor(new NameResolver);
|
||||
$traverser->addVisitor(new ReferencesAdder($document));
|
||||
$definitionCollector = new DefinitionCollector($definitionResolver);
|
||||
$traverser->addVisitor($definitionCollector);
|
||||
$traverser->traverse($stmts);
|
||||
|
||||
$defNodes = $definitionCollector->nodes;
|
||||
|
||||
$this->assertEquals(['TestNamespace', 'TestNamespace\\whatever()'], array_keys($defNodes));
|
||||
$this->assertInstanceOf(Node\Name::class, $defNodes['TestNamespace']);
|
||||
$this->assertInstanceOf(Node\Stmt\Namespace_::class, $defNodes['TestNamespace']->getAttribute('parentNode'));
|
||||
$this->assertInstanceOf(Node\Stmt\Function_::class, $defNodes['TestNamespace\\whatever()']);
|
||||
$treeAnalyzer = ParserResourceFactory::getTreeAnalyzer($parser, $content, $docBlockFactory, $definitionResolver, $uri);
|
||||
return $treeAnalyzer->getDefinitionNodes();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,18 @@ class PhpDocumentTest extends TestCase
|
|||
{
|
||||
$document = $this->createDocument('whatever', "<?php\n$\$a = new SomeClass;");
|
||||
$node = $document->getNodeAtPosition(new Position(1, 13));
|
||||
$this->assertInstanceOf(Node\Name\FullyQualified::class, $node);
|
||||
$this->assertQualifiedName($node);
|
||||
$this->assertEquals('SomeClass', (string)$node);
|
||||
}
|
||||
|
||||
private function assertQualifiedName($node) {
|
||||
if ($node instanceof Node) {
|
||||
$this->assertInstanceOf(Node\Name\FullyQualified::class, $node);
|
||||
} else {
|
||||
$this->assertInstanceOf(Tolerant\Node\QualifiedName::class, $node);
|
||||
}
|
||||
}
|
||||
|
||||
public function testIsVendored()
|
||||
{
|
||||
$document = $this->createDocument('file:///dir/vendor/x.php', "<?php\n$\$a = new SomeClass;");
|
||||
|
|
Loading…
Reference in New Issue