1
0
Fork 0

add getNodeAtPosition, fix definition collector tests

pull/357/head
Sara Itani 2017-03-05 16:34:01 -08:00
parent 15eed55158
commit cdf8fc36e1
4 changed files with 67 additions and 65 deletions

View File

@ -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);
}
}
}

View File

@ -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;
}
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);
}
}
/**

View File

@ -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();
}
}

View File

@ -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;");