Repository: phpactor/phpactor (php)

Issue:
Variable on right hand side of replacement assignment takes value of replaced var
`$types` is already resolved to "unknown" via. the assignment 
![image](https://user-images.githubusercontent.com/530801/172311347-cc30d36f-5b24-437d-9153-981ba2520fcf.png)


Pull request:
Gh 1705: Fix evaluation of replacement assignments
Fixes #1705 

(much of this code is so very wrong)

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2511de32..5f39886e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ Bug fixes:
   - Also highlight use statements when hovering on class #2039 @mamazu
   - Fix priotity of "internal" stub locator - facilitating enum completion #2040
   - Require posix extension #2042 @dacianb
+  - Fix evaluation of replacement assignments #1705
 
 Features:
 
diff --git a/doc/reference/configuration.rst b/doc/reference/configuration.rst
index d54f9e59..63c16fa0 100644
--- a/doc/reference/configuration.rst
+++ b/doc/reference/configuration.rst
@@ -1084,26 +1084,6 @@ Whether to decorate messages (null for auto-guessing)
 **Allowed values**: true, false, null
 
 
-.. _WorseReferenceFinderExtension:
-
-
-WorseReferenceFinderExtension
------------------------------
-
-
-.. _param_worse_reference_finder.plain_text_break_chars:
-
-
-``worse_reference_finder.plain_text_break_chars``
-"""""""""""""""""""""""""""""""""""""""""""""""""
-
-
-Type: array
-
-
-**Default**: ``[" ","\"","'","|","%","(",")","[","]",":","\r\n","\n","\r"]``
-
-
 .. _PhpExtension:
 
 
@@ -1674,6 +1654,19 @@ Path to pslam if different from vendor/bin/psalm
 **Default**: ``"%project_root%\/vendor\/bin\/psalm"``
 
 
+.. _param_language_server_psalm.show_info:
+
+
+``language_server_psalm.show_info``
+"""""""""""""""""""""""""""""""""""
+
+
+If infos from psalm should be displayed
+
+
+**Default**: ``true``
+
+
 .. _LanguageServerBlackfireExtension:
 
 
diff --git a/lib/WorseReflection/Core/Inference/Assignments.php b/lib/WorseReflection/Core/Inference/Assignments.php
index 683e0782..753dabe4 100644
--- a/lib/WorseReflection/Core/Inference/Assignments.php
+++ b/lib/WorseReflection/Core/Inference/Assignments.php
@@ -180,6 +180,13 @@ abstract class Assignments implements Countable, IteratorAggregate
         }));
     }
 
+    public function not(int $offset): Assignments
+    {
+        return new static(array_filter($this->variables, function (Variable $v) use ($offset) {
+            return $v->offset() !== $offset;
+        }));
+    }
+
     public function assignmentsOnly(): Assignments
     {
         return new static(array_filter($this->variables, function (Variable $v) {
diff --git a/lib/WorseReflection/Core/Inference/Resolver/VariableResolver.php b/lib/WorseReflection/Core/Inference/Resolver/VariableResolver.php
index 77dba832..23de41ed 100644
--- a/lib/WorseReflection/Core/Inference/Resolver/VariableResolver.php
+++ b/lib/WorseReflection/Core/Inference/Resolver/VariableResolver.php
@@ -3,6 +3,7 @@
 namespace Phpactor\WorseReflection\Core\Inference\Resolver;
 
 use Microsoft\PhpParser\Node;
+use Microsoft\PhpParser\Node\Expression\AssignmentExpression;
 use Microsoft\PhpParser\Node\Expression\BracedExpression;
 use Microsoft\PhpParser\Node\Expression\ScopedPropertyAccessExpression;
 use Microsoft\PhpParser\Node\Expression\Variable;
@@ -52,13 +53,26 @@ class VariableResolver implements Resolver
         }
 
         $variableName = $node->getText();
-        $frameVariable = $frame->locals()->byName($variableName)->lessThanOrEqualTo($node->getStartPosition())->lastOrNull();
+        $variables = $frame->locals()->byName($variableName);
+
+        // special handling for assignments
+        if ($assignment = $node->getFirstAncestor(AssignmentExpression::class)) {
+            assert($assignment instanceof AssignmentExpression);
+            // if we are dealintg with the right hand side of the assignement
+            if ($assignment->leftOperand !== $node) {
+                // do not consider the variable being assigned to
+                $variables = $variables->not($assignment->getStartPosition());
+            }
+        }
+
+        $frameVariable = $variables->lessThanOrEqualTo($node->getStartPosition())->lastOrNull();
 
         $type = new MissingType();
         if ($frameVariable) {
             $type = $frameVariable->type();
         }
 
+
         $context = NodeContextFactory::forVariableAt(
             $frame,
             $node->getStartPosition(),


Test patch:
diff --git a/lib/WorseReflection/Tests/Inference/assignment/replacement.test b/lib/WorseReflection/Tests/Inference/assignment/replacement.test
index 26706a3e..aa7b67dd 100644
--- a/lib/WorseReflection/Tests/Inference/assignment/replacement.test
+++ b/lib/WorseReflection/Tests/Inference/assignment/replacement.test
@@ -16,3 +16,5 @@ $foo = new Foo();
 $foo = $foo->withFoo($bar);
 
 wrAssertType('Test\Bar', $foo);
+wrAssertOffset('Test\Foo', 153);
+wrAssertOffset('Test\Bar', 145);