1
0
Fork 0

Merge branch 'master' into jens1o-foreach-variables

pull/529/head
Felix Becker 2017-11-18 17:00:34 -08:00 committed by GitHub
commit 56e2006e30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 172 additions and 108 deletions

View File

@ -23,7 +23,7 @@ install:
- composer install --prefer-dist --no-interaction - composer install --prefer-dist --no-interaction
script: script:
- vendor/bin/phpcs -n - vendor/bin/phpcs -n
- vendor/bin/phpunit --coverage-clover=coverage.xml - vendor/bin/phpunit --coverage-clover=coverage.xml --colors=always
- bash <(curl -s https://codecov.io/bash) - bash <(curl -s https://codecov.io/bash)
jobs: jobs:

18
.vscode/launch.json vendored
View File

@ -1,6 +1,14 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"name": "PHPUnit",
"type": "php",
"request": "launch",
"program": "${workspaceRoot}/vendor/phpunit/phpunit/phpunit",
// "args": ["--filter", "testDefinitionForSelfKeyword"],
"cwd": "${workspaceRoot}"
},
{ {
"name": "Listen for XDebug", "name": "Listen for XDebug",
"type": "php", "type": "php",
@ -14,16 +22,6 @@
"program": "${file}", "program": "${file}",
"cwd": "${fileDirname}", "cwd": "${fileDirname}",
"port": 9000 "port": 9000
},
{
"name": "PHPUnit",
"type": "php",
"request": "launch",
"program": "${workspaceRoot}/vendor/phpunit/phpunit/phpunit",
"cwd": "${workspaceRoot}",
"args": [
// "--filter", "CompletionTest"
]
} }
] ]
} }

View File

@ -264,13 +264,38 @@ class DefinitionResolver
// Other references are references to a global symbol that have an FQN // Other references are references to a global symbol that have an FQN
// Find out the FQN // Find out the FQN
$fqn = $this->resolveReferenceNodeToFqn($node); $fqn = $this->resolveReferenceNodeToFqn($node);
if ($fqn === null) { if (!$fqn) {
return null; return null;
} }
if ($fqn === 'self' || $fqn === 'static') {
// Resolve self and static keywords to the containing class
// (This is not 100% correct for static but better than nothing)
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode) {
return;
}
$fqn = (string)$classNode->getNamespacedName();
if (!$fqn) {
return;
}
} else if ($fqn === 'parent') {
// Resolve parent keyword to the base class FQN
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode || !$classNode->classBaseClause || !$classNode->classBaseClause->baseClass) {
return;
}
$fqn = (string)$classNode->classBaseClause->baseClass->getResolvedName();
if (!$fqn) {
return;
}
}
// If the node is a function or constant, it could be namespaced, but PHP falls back to global // If the node is a function or constant, it could be namespaced, but PHP falls back to global
// http://php.net/manual/en/language.namespaces.fallback.php // http://php.net/manual/en/language.namespaces.fallback.php
// TODO - verify that this is not a method // TODO - verify that this is not a method
$globalFallback = ParserHelpers\isConstantFetch($node) || $parent instanceof Node\Expression\CallExpression; $globalFallback = ParserHelpers\isConstantFetch($node) || $parent instanceof Node\Expression\CallExpression;
// Return the Definition object from the index index // Return the Definition object from the index index
return $this->index->getDefinition($fqn, $globalFallback); return $this->index->getDefinition($fqn, $globalFallback);
} }
@ -278,6 +303,7 @@ class DefinitionResolver
/** /**
* Given any node, returns the FQN of the symbol that is referenced * Given any node, returns the FQN of the symbol that is referenced
* Returns null if the FQN could not be resolved or the reference node references a variable * Returns null if the FQN could not be resolved or the reference node references a variable
* May also return "static", "self" or "parent"
* *
* @param Node $node * @param Node $node
* @return string|null * @return string|null

View File

@ -140,8 +140,9 @@ class TreeAnalyzer
$this->definitionNodes[$fqn] = $node; $this->definitionNodes[$fqn] = $node;
$this->definitions[$fqn] = $this->definitionResolver->createDefinitionFromNode($node, $fqn); $this->definitions[$fqn] = $this->definitionResolver->createDefinitionFromNode($node, $fqn);
} else { } else {
$parent = $node->parent; $parent = $node->parent;
if (!( if (
( (
// $node->parent instanceof Node\Expression\ScopedPropertyAccessExpression || // $node->parent instanceof Node\Expression\ScopedPropertyAccessExpression ||
($node instanceof Node\Expression\ScopedPropertyAccessExpression || ($node instanceof Node\Expression\ScopedPropertyAccessExpression ||
@ -150,10 +151,39 @@ class TreeAnalyzer
$node->parent instanceof Node\Expression\CallExpression || $node->parent instanceof Node\Expression\CallExpression ||
$node->memberName instanceof PhpParser\Token $node->memberName instanceof PhpParser\Token
)) ))
|| ($parent instanceof Node\Statement\NamespaceDefinition && $parent->name !== null && $parent->name->getStart() === $node->getStart())) || ($parent instanceof Node\Statement\NamespaceDefinition && $parent->name !== null && $parent->name->getStart() === $node->getStart())
) { ) {
return;
}
$fqn = $this->definitionResolver->resolveReferenceNodeToFqn($node); $fqn = $this->definitionResolver->resolveReferenceNodeToFqn($node);
if ($fqn !== null) { if (!$fqn) {
return;
}
if ($fqn === 'self' || $fqn === 'static') {
// Resolve self and static keywords to the containing class
// (This is not 100% correct for static but better than nothing)
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode) {
return;
}
$fqn = (string)$classNode->getNamespacedName();
if (!$fqn) {
return;
}
} else if ($fqn === 'parent') {
// Resolve parent keyword to the base class FQN
$classNode = $node->getFirstAncestor(Node\Statement\ClassDeclaration::class);
if (!$classNode || !$classNode->classBaseClause || !$classNode->classBaseClause->baseClass) {
return;
}
$fqn = (string)$classNode->classBaseClause->baseClass->getResolvedName();
if (!$fqn) {
return;
}
}
$this->addReference($fqn, $node); $this->addReference($fqn, $node);
if ( if (
@ -187,8 +217,6 @@ class TreeAnalyzer
} }
} }
} }
}
}
/** /**
* @return Diagnostic[] * @return Diagnostic[]

View File

@ -122,15 +122,16 @@ abstract class ServerTestCase extends TestCase
0 => new Location($referencesUri, new Range(new Position(29, 5), new Position(29, 15))) 0 => new Location($referencesUri, new Range(new Position(29, 5), new Position(29, 15)))
], ],
'TestNamespace\\TestClass' => [ 'TestNamespace\\TestClass' => [
0 => new Location($symbolsUri , new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {} 0 => new Location($symbolsUri, new Range(new Position(48, 13), new Position(48, 17))), // echo self::TEST_CLASS_CONST;
1 => new Location($referencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass(); 1 => new Location($symbolsUri , new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {}
2 => new Location($referencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod(); 2 => new Location($referencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass();
3 => new Location($referencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty; 3 => new Location($referencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod();
4 => new Location($referencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST; 4 => new Location($referencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty;
5 => new Location($referencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param) 5 => new Location($referencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST;
6 => new Location($referencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass 6 => new Location($referencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param)
7 => new Location($referencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty; 7 => new Location($referencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
8 => new Location($useUri, new Range(new Position( 4, 4), new Position( 4, 27))), // use TestNamespace\TestClass; 8 => new Location($referencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty;
9 => new Location($useUri, new Range(new Position( 4, 4), new Position( 4, 27))), // use TestNamespace\TestClass;
], ],
'TestNamespace\\TestChild' => [ 'TestNamespace\\TestChild' => [
0 => new Location($referencesUri, new Range(new Position(42, 5), new Position(42, 25))), // echo $child->testProperty; 0 => new Location($referencesUri, new Range(new Position(42, 5), new Position(42, 25))), // echo $child->testProperty;
@ -176,14 +177,15 @@ abstract class ServerTestCase extends TestCase
1 => new Location($globalReferencesUri, new Range(new Position(29, 5), new Position(29, 15))) 1 => new Location($globalReferencesUri, new Range(new Position(29, 5), new Position(29, 15)))
], ],
'TestClass' => [ 'TestClass' => [
0 => new Location($globalSymbolsUri, new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {} 0 => new Location($globalSymbolsUri, new Range(new Position(48, 13), new Position(48, 17))), // echo self::TEST_CLASS_CONST;
1 => new Location($globalReferencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass(); 1 => new Location($globalSymbolsUri, new Range(new Position(99, 25), new Position(99, 34))), // class ChildClass extends TestClass {}
2 => new Location($globalReferencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod(); 2 => new Location($globalReferencesUri, new Range(new Position( 4, 11), new Position( 4, 20))), // $obj = new TestClass();
3 => new Location($globalReferencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty; 3 => new Location($globalReferencesUri, new Range(new Position( 7, 0), new Position( 7, 9))), // TestClass::staticTestMethod();
4 => new Location($globalReferencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST; 4 => new Location($globalReferencesUri, new Range(new Position( 8, 5), new Position( 8, 14))), // echo TestClass::$staticTestProperty;
5 => new Location($globalReferencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param) 5 => new Location($globalReferencesUri, new Range(new Position( 9, 5), new Position( 9, 14))), // TestClass::TEST_CLASS_CONST;
6 => new Location($globalReferencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass 6 => new Location($globalReferencesUri, new Range(new Position(21, 18), new Position(21, 27))), // function whatever(TestClass $param)
7 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty; 7 => new Location($globalReferencesUri, new Range(new Position(21, 37), new Position(21, 46))), // function whatever(TestClass $param): TestClass
8 => new Location($globalReferencesUri, new Range(new Position(39, 0), new Position(39, 9))), // TestClass::$staticTestProperty[123]->testProperty;
], ],
'TestChild' => [ 'TestChild' => [
0 => new Location($globalReferencesUri, new Range(new Position(42, 5), new Position(42, 25))), // echo $child->testProperty; 0 => new Location($globalReferencesUri, new Range(new Position(42, 5), new Position(42, 25))), // echo $child->testProperty;

View File

@ -29,11 +29,23 @@ class GlobalTest extends ServerTestCase
$this->assertEquals([], $result); $this->assertEquals([], $result);
} }
public function testDefinitionForSelfKeyword()
{
// echo self::TEST_CLASS_CONST;
// Get definition for self
$reference = $this->getReferenceLocations('TestClass')[0];
$result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri),
$reference->range->start
)->wait();
$this->assertEquals($this->getDefinitionLocation('TestClass'), $result);
}
public function testDefinitionForClassLike() public function testDefinitionForClassLike()
{ {
// $obj = new TestClass(); // $obj = new TestClass();
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -45,7 +57,7 @@ class GlobalTest extends ServerTestCase
{ {
// TestClass::staticTestMethod(); // TestClass::staticTestMethod();
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[1]; $reference = $this->getReferenceLocations('TestClass')[2];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -57,7 +69,7 @@ class GlobalTest extends ServerTestCase
{ {
// echo TestClass::$staticTestProperty; // echo TestClass::$staticTestProperty;
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[2]; $reference = $this->getReferenceLocations('TestClass')[3];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -69,7 +81,7 @@ class GlobalTest extends ServerTestCase
{ {
// TestClass::TEST_CLASS_CONST; // TestClass::TEST_CLASS_CONST;
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[3]; $reference = $this->getReferenceLocations('TestClass')[4];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -213,7 +225,7 @@ class GlobalTest extends ServerTestCase
{ {
// function whatever(TestClass $param) { // function whatever(TestClass $param) {
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[4]; $reference = $this->getReferenceLocations('TestClass')[5];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -225,7 +237,7 @@ class GlobalTest extends ServerTestCase
{ {
// function whatever(TestClass $param): TestClass { // function whatever(TestClass $param): TestClass {
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[5]; $reference = $this->getReferenceLocations('TestClass')[6];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start

View File

@ -34,7 +34,7 @@ class NamespacedTest extends GlobalTest
{ {
// use TestNamespace\TestClass; // use TestNamespace\TestClass;
// Get definition for TestClass // Get definition for TestClass
$reference = $this->getReferenceLocations('TestClass')[6]; $reference = $this->getReferenceLocations('TestClass')[7];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start
@ -46,7 +46,7 @@ class NamespacedTest extends GlobalTest
{ {
// use TestNamespace\{TestTrait, TestInterface}; // use TestNamespace\{TestTrait, TestInterface};
// Get definition for TestInterface // Get definition for TestInterface
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->definition( $result = $this->textDocument->definition(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start

View File

@ -15,7 +15,7 @@ class HoverTest extends ServerTestCase
{ {
// $obj = new TestClass(); // $obj = new TestClass();
// Get hover for TestClass // Get hover for TestClass
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->hover( $result = $this->textDocument->hover(
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),
$reference->range->start $reference->range->start

View File

@ -151,7 +151,7 @@ class GlobalTest extends ServerTestCase
{ {
// $obj = new TestClass(); // $obj = new TestClass();
// Get references for TestClass // Get references for TestClass
$reference = $this->getReferenceLocations('TestClass')[0]; $reference = $this->getReferenceLocations('TestClass')[1];
$result = $this->textDocument->references( $result = $this->textDocument->references(
new ReferenceContext, new ReferenceContext,
new TextDocumentIdentifier($reference->uri), new TextDocumentIdentifier($reference->uri),

View File

@ -3,7 +3,7 @@
"Fixtures\\Prophecy\\EmptyClass": [ "Fixtures\\Prophecy\\EmptyClass": [
"./WithReturnTypehints.php" "./WithReturnTypehints.php"
], ],
"self": [ "Fixtures\\Prophecy\\WithReturnTypehints": [
"./WithReturnTypehints.php" "./WithReturnTypehints.php"
], ],
"Fixtures\\Prophecy\\__CLASS__": [ "Fixtures\\Prophecy\\__CLASS__": [
@ -11,9 +11,6 @@
], ],
"__CLASS__": [ "__CLASS__": [
"./WithReturnTypehints.php" "./WithReturnTypehints.php"
],
"parent": [
"./WithReturnTypehints.php"
] ]
}, },
"definitions": { "definitions": {

View File

@ -1,5 +1,9 @@
{ {
"references": [], "references": {
"A": [
"./nameToken.php"
]
},
"definitions": { "definitions": {
"A": { "A": {
"fqn": "A", "fqn": "A",

View File

@ -2,9 +2,6 @@
"references": { "references": {
"MyNamespace\\B": [ "MyNamespace\\B": [
"./parent1.php" "./parent1.php"
],
"parent": [
"./parent1.php"
] ]
}, },
"definitions": { "definitions": {

View File

@ -5,9 +5,6 @@
], ],
"MyNamespace\\B->b()": [ "MyNamespace\\B->b()": [
"./parent3.php" "./parent3.php"
],
"parent": [
"./parent3.php"
] ]
}, },
"definitions": { "definitions": {

View File

@ -6,7 +6,7 @@
"MyNamespace\\A::b()": [ "MyNamespace\\A::b()": [
"./self1.php" "./self1.php"
], ],
"self": [ "MyNamespace\\A": [
"./self1.php" "./self1.php"
] ]
}, },

View File

@ -6,7 +6,7 @@
"MyNamespace\\A::b()": [ "MyNamespace\\A::b()": [
"./self2.php" "./self2.php"
], ],
"self": [ "MyNamespace\\A": [
"./self2.php" "./self2.php"
] ]
}, },

View File

@ -6,7 +6,7 @@
"MyNamespace\\A->b()": [ "MyNamespace\\A->b()": [
"./self3.php" "./self3.php"
], ],
"self": [ "MyNamespace\\A": [
"./self3.php" "./self3.php"
] ]
}, },

View File

@ -1,6 +1,6 @@
{ {
"references": { "references": {
"self": [ "MyNamespace\\A": [
"./self4.php" "./self4.php"
], ],
"MyNamespace\\A->addTestFile()": [ "MyNamespace\\A->addTestFile()": [

View File

@ -6,7 +6,7 @@
"MyNamespace\\A::b()": [ "MyNamespace\\A::b()": [
"./static1.php" "./static1.php"
], ],
"static": [ "MyNamespace\\A": [
"./static1.php" "./static1.php"
] ]
}, },

View File

@ -6,7 +6,7 @@
"MyNamespace\\A::b()": [ "MyNamespace\\A::b()": [
"./static2.php" "./static2.php"
], ],
"static": [ "MyNamespace\\A": [
"./static2.php" "./static2.php"
] ]
}, },

View File

@ -3,10 +3,10 @@
"MyNamespace\\B": [ "MyNamespace\\B": [
"./static3.php" "./static3.php"
], ],
"MyNamespace\\b()": [ "static->b()": [
"./static3.php" "./static3.php"
], ],
"b()": [ "MyNamespace\\A": [
"./static3.php" "./static3.php"
] ]
}, },

View File

@ -2,6 +2,9 @@
"references": { "references": {
"MyNamespace\\B": [ "MyNamespace\\B": [
"./static4.php" "./static4.php"
],
"MyNamespace\\A": [
"./static4.php"
] ]
}, },
"definitions": { "definitions": {