diff --git a/CHANGELOG.md b/CHANGELOG.md index e0369380f..e616e77ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,11 @@ Improvements: - Fix contextual completion in constructor agrument position #2504 - Basic support for `array_reduce` stub #2576 + - Support variadics in contextual completion #2603 Bug fixes: + - Only filter new object expression names in contextual completion #2603 - Fixing include and exclude patterns #2593 @mamazu ## 2024-03-09 diff --git a/lib/Completion/Bridge/WorseReflection/Completor/ContextSensitiveCompletor.php b/lib/Completion/Bridge/WorseReflection/Completor/ContextSensitiveCompletor.php index f4f5e08f8..81c6a5695 100644 --- a/lib/Completion/Bridge/WorseReflection/Completor/ContextSensitiveCompletor.php +++ b/lib/Completion/Bridge/WorseReflection/Completor/ContextSensitiveCompletor.php @@ -35,6 +35,13 @@ public function __construct(private TolerantCompletor $inner, private Reflector public function complete(Node $node, TextDocument $source, ByteOffset $offset): Generator { $generator = $this->inner->complete($node, $source, $offset); + if ( + !$node instanceof CallExpression && + ($node instanceof QualifiedName && !$node->parent instanceof ObjectCreationExpression) + ) { + yield from $generator; + return $generator->getReturn(); + } $type = $this->resolveFilterableType($node, $source, $offset); if (null === $type) { @@ -77,6 +84,7 @@ private function resolveFilterableType(Node $node, TextDocument $source, ByteOff { $argumentNb = 0; $memberAccessOrObjectCreation = $node; + $node = NodeUtil::firstDescendantNodeBeforeOffset($node, $offset->toInt()); if ($node instanceof QualifiedName) { $memberAccessOrObjectCreation = null; $argumentExpression = $node->getFirstAncestor(ArgumentExpression::class); @@ -89,9 +97,10 @@ private function resolveFilterableType(Node $node, TextDocument $source, ByteOff $memberAccessOrObjectCreation = $list->parent; } } - if ($node instanceof ArgumentExpressionList) { - $argumentNb = count(iterator_to_array($node->getValues())); - $memberAccessOrObjectCreation = $node->parent; + $argumentList = $node->getFirstAncestor(ArgumentExpressionList::class); + if ($argumentList instanceof ArgumentExpressionList) { + $argumentNb = max(0, count(iterator_to_array($argumentList->getValues())) - 1); + $memberAccessOrObjectCreation = $argumentList->parent; } if (!$memberAccessOrObjectCreation instanceof CallExpression && !$memberAccessOrObjectCreation instanceof ObjectCreationExpression) { @@ -103,7 +112,6 @@ private function resolveFilterableType(Node $node, TextDocument $source, ByteOff return null; } try { - ; $memberAccessOrObjectCreation = $this->reflector->reflectOffset($source, $offset)->nodeContext(); } catch (NotFound $e) { return null; @@ -155,7 +163,14 @@ private function typeFromParameters(ReflectionParameterCollection $parameters, i { $parameter = $parameters->at($argumentNb); if (null === $parameter) { - return null; + $lastParameter = $parameters->lastOrNull(); + if (null === $lastParameter) { + return null; + } + if (!$lastParameter->isVariadic()) { + return null; + } + $parameter = $lastParameter; } $type = $parameter->type(); diff --git a/lib/Completion/Tests/Unit/Bridge/WorseReflection/Completor/ContextSensitiveCompletorTest.php b/lib/Completion/Tests/Unit/Bridge/WorseReflection/Completor/ContextSensitiveCompletorTest.php index 4fac27174..42ad6b4bf 100644 --- a/lib/Completion/Tests/Unit/Bridge/WorseReflection/Completor/ContextSensitiveCompletorTest.php +++ b/lib/Completion/Tests/Unit/Bridge/WorseReflection/Completor/ContextSensitiveCompletorTest.php @@ -60,13 +60,13 @@ class Obj {} class Foo { public function bar(Obj $obj){}} $f = new Foo(); - $f->bar(<>) + $f->bar(new <>) EOT, [ 'Bar\Obj', ], ]; - yield 'namespaced open method call' => [ + yield 'static call returns all' => [ [ 'Bar\Foo', 'Bar\Obj', @@ -78,7 +78,26 @@ class Obj {} class Foo { public function bar(Obj $obj){}} $f = new Foo(); - $f->bar(<> + $f->bar(F<>) + EOT, + [ + 'Bar\Foo', + 'Bar\Obj', + ], + ]; + yield 'namespaced method call' => [ + [ + 'Bar\Foo', + 'Bar\Obj', + ], + <<<'EOT' + bar(new <>) EOT, [ 'Bar\Obj', @@ -95,7 +114,7 @@ class Obj {} class Foo { public function bar(Obj $obj){}} $f = new Foo(); - $f->bar(<> + $f->bar(new <>) EOT, [ 'Obj', @@ -112,7 +131,7 @@ class Obj {} class Foo { public function bar(Obj $obj){}} $f = new Foo(); - $f->bar(O<> + $f->bar(new O<> EOT, [ 'Obj', @@ -129,7 +148,7 @@ class Obj {} class Foo { public function bar($obj){}} $f = new Foo(); - $f->bar(O<> + $f->bar(new O<> EOT, [ 'Foo', @@ -148,12 +167,13 @@ class Baz {} class Foo { public function bar(Obj $obj, Baz $baz){}} $f = new Foo(); - $f->bar(Obj::new(),<> + $f->bar(Obj::new(), new <>) EOT, [ 'Baz', ], ]; + yield '2nd arg partial' => [ [ 'Obj', @@ -166,7 +186,7 @@ class Baz {} class Foo { public function bar(Obj $obj, Baz $baz){}} $f = new Foo(); - $f->bar(Obj::new(),B<> + $f->bar(Obj::new(),new B<> EOT, [ 'Baz', @@ -184,20 +204,20 @@ class Baz {} class Foo { public function bar(Obj $obj, Baz ...$baz){}} $f = new Foo(); - $f->bar(Obj::new(),B<> + $f->bar(Obj::new(),new B<> EOT, [ 'Baz', ], ]; - yield 'new' => [ + yield 'enum' => [ [ 'Obj', 'Baz', ], <<<'EOT' [ + yield 'on static call' => [ [ 'Obj', 'Baz', @@ -217,16 +237,15 @@ class Foo { public function bar(Obj $obj, Baz ...$baz){}} bar(new O<> + Foo::bar(new O<> EOT, [ 'Obj', ], ]; - yield 'static' => [ + yield 'on variadic' => [ [ 'Obj', 'Baz', @@ -235,9 +254,9 @@ class Foo { public function bar(Obj $obj, Baz ...$baz){}} + Foo::bar(new Obj(), new Obj(), new O<>) EOT, [ 'Obj', diff --git a/lib/Indexer/Model/IndexJob.php b/lib/Indexer/Model/IndexJob.php index 35838985d..d714a2948 100644 --- a/lib/Indexer/Model/IndexJob.php +++ b/lib/Indexer/Model/IndexJob.php @@ -3,12 +3,8 @@ namespace Phpactor\Indexer\Model; use Generator; -use Phar; -use PharFileInfo; use Phpactor\TextDocument\TextDocumentBuilder; -use RecursiveIteratorIterator; use SplFileInfo; -use UnexpectedValueException; class IndexJob { diff --git a/lib/WorseReflection/Core/Reflection/Collection/AbstractReflectionCollection.php b/lib/WorseReflection/Core/Reflection/Collection/AbstractReflectionCollection.php index a93a4f2e1..62159992c 100644 --- a/lib/WorseReflection/Core/Reflection/Collection/AbstractReflectionCollection.php +++ b/lib/WorseReflection/Core/Reflection/Collection/AbstractReflectionCollection.php @@ -116,6 +116,18 @@ public function last() return end($this->items); } + /** + * @return T|null + */ + public function lastOrNull() + { + if (empty($this->items)) { + return null; + } + + return end($this->items); + } + public function has(string $name): bool { return isset($this->items[$name]);