Repository: phpactor/phpactor (php)

Issue:
Possible bug with same name properties / methods
Given the following code:
```php
<?php

class test {
    public string $foo;

    public function foo(): string {
        return $this->foo;
    }
}

$b = new test();

$b->|CURSOR|
```

When at cursor it only provides the method foo as autocomplete option.

I found this because I have virtual methods that are the same as methods yet have a different return type.

<img width="266" alt="Screenshot 2023-04-17 at 13 33 07" src="https://user-images.githubusercontent.com/866743/232472343-5c379cb5-8bd5-4ce7-9c54-5aed611e592e.png">

Pull request description:
Gh 2214
Fixes #2214 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9251d01c..e7beb918 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@ Features:
 
 Bug fixes:
 
+  - Do not deduplicate suggestions of different types (e.g. prop/method with same name) #2214
   - Support parsing interface clause on enums #2220
   - Do not make fully qualified name usage relative in class-mover #2208 @mamazu
   - Fix resolution of `self` type (esp. in relation to traits) #2116
diff --git a/lib/Completion/Core/Completor/DedupeCompletor.php b/lib/Completion/Core/Completor/DedupeCompletor.php
index f9355ca4..d8eee499 100644
--- a/lib/Completion/Core/Completor/DedupeCompletor.php
+++ b/lib/Completion/Core/Completor/DedupeCompletor.php
@@ -19,7 +19,7 @@ class DedupeCompletor implements Completor
         $seen = [];
         $suggestions = $this->innerCompletor->complete($source, $byteOffset);
         foreach ($suggestions as $suggestion) {
-            $key = $suggestion->name();
+            $key = $suggestion->name().$suggestion->type();
 
             if ($this->matchNameImport) {
                 $key .= $suggestion->nameImport();
diff --git a/lib/WorseReflection/Bridge/TolerantParser/Reflection/ReflectionProperty.php b/lib/WorseReflection/Bridge/TolerantParser/Reflection/ReflectionProperty.php
index f42b5a20..96fbbf13 100644
--- a/lib/WorseReflection/Bridge/TolerantParser/Reflection/ReflectionProperty.php
+++ b/lib/WorseReflection/Bridge/TolerantParser/Reflection/ReflectionProperty.php
@@ -39,9 +39,9 @@ class ReflectionProperty extends AbstractReflectionClassMember implements CoreRe
 
     public function declaringClass(): ReflectionClassLike
     {
-        /** @var NamespacedNameInterface $classDeclaration */
+        /** @var NamespacedNameInterface|null $classDeclaration */
         $classDeclaration = $this->propertyDeclaration->getFirstAncestor(ClassDeclaration::class, TraitDeclaration::class);
-        $class = $classDeclaration->getNamespacedName();
+        $class = $classDeclaration?->getNamespacedName();
 
         if (null === $class) {
             throw new InvalidArgumentException(sprintf(


Test patch:
diff --git a/lib/Completion/Tests/Unit/Core/Completor/DedupeCompletorTest.php b/lib/Completion/Tests/Unit/Core/Completor/DedupeCompletorTest.php
index f9b34a62..f0c7f904 100644
--- a/lib/Completion/Tests/Unit/Core/Completor/DedupeCompletorTest.php
+++ b/lib/Completion/Tests/Unit/Core/Completor/DedupeCompletorTest.php
@@ -30,6 +30,26 @@ class DedupeCompletorTest extends TestCase
         $this->assertTrue($suggestions->getReturn());
     }
 
+    public function testDedupeWithSuggestionsOfDifferentTypes(): void
+    {
+        $source = TextDocumentBuilder::create('foobar')->build();
+        $offset = ByteOffset::fromInt(10);
+
+        $inner = new ArrayCompletor([
+            Suggestion::createWithOptions('foobar', ['type' => Suggestion::TYPE_ENUM]),
+            Suggestion::create('barfoo'),
+            Suggestion::create('foobar'),
+        ]);
+        $dedupe = new DedupeCompletor($inner);
+        $suggestions = $dedupe->complete($source, $offset);
+        self::assertEquals([
+            Suggestion::createWithOptions('foobar', ['type' => Suggestion::TYPE_ENUM]),
+            Suggestion::create('barfoo'),
+            Suggestion::create('foobar'),
+        ], iterator_to_array($suggestions));
+        $this->assertTrue($suggestions->getReturn());
+    }
+
     public function testDeduplicatesWithFqn(): void
     {
         $source = TextDocumentBuilder::create('foobar')->build();