Repository: phpactor/phpactor (php)

Issue:
Errors during renaming
Hey,
since a few days i get a lot of errors while renaming some classes. I am on the latest version from git (HEAD) and i am using VS Code as an editor.

```
[Error - 15:14:00] Request textDocument/codeAction failed.
  Message: Exception [Phpactor\LanguageServer\Core\Workspace\Exception\UnknownDocument] Unknown text document "file:///home/leo/code/website-laravel/app/Models/User.php" at /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Workspace/Workspace.php#45
  Code: -32603
```

Here is the full stacktrace. I also tried deleting everything in `~/.cache/phpactor` and reindexing the project, still the same error.
Greetings
Leo

```
[Error - 15:14:00] Request textDocument/codeAction failed.
  Message: Exception [Phpactor\LanguageServer\Core\Workspace\Exception\UnknownDocument] Unknown text document "file:///home/leo/code/website-laravel/app/Models/User.php" at /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Workspace/Workspace.php#45
  Code: -32603 
#0 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Handler/TextDocument/CodeActionHandler.php(54): Phpactor\LanguageServer\Core\Workspace\Workspace->get()
#1 [internal function]: Phpactor\LanguageServer\Handler\TextDocument\CodeActionHandler->Phpactor\LanguageServer\Handler\TextDocument\{closure}()
#2 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
#3 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Internal/Placeholder.php(149): Amp\Coroutine->Amp\{closure}()
#4 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Coroutine.php(123): Amp\Coroutine->resolve()
#5 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Internal/Placeholder.php(149): Amp\Coroutine->Amp\{closure}()
#6 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Deferred.php(53): Amp\Promise@anonymous->resolve()
#7 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Server/ResponseWatcher/DeferredResponseWatcher.php(21): Amp\Deferred->resolve()
#8 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/ResponseHandlingMiddleware.php(31): Phpactor\LanguageServer\Core\Server\ResponseWatcher\DeferredResponseWatcher->handle()
#9 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Middleware/RequestHandler.php(37): Phpactor\LanguageServer\Middleware\ResponseHandlingMiddleware->process()
#10 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/MethodAliasMiddleware.php(30): Phpactor\LanguageServer\Core\Middleware\RequestHandler->handle()
#11 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Middleware/RequestHandler.php(37): Phpactor\LanguageServer\Middleware\MethodAliasMiddleware->process()
#12 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/CancellationMiddleware.php(49): Phpactor\LanguageServer\Core\Middleware\RequestHandler->handle()
#13 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Middleware/RequestHandler.php(37): Phpactor\LanguageServer\Middleware\CancellationMiddleware->process()
#14 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/ShutdownMiddleware.php(68): Phpactor\LanguageServer\Core\Middleware\RequestHandler->handle()
#15 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Middleware/RequestHandler.php(37): Phpactor\LanguageServer\Middleware\ShutdownMiddleware->process()
#16 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/InitializeMiddleware.php(52): Phpactor\LanguageServer\Core\Middleware\RequestHandler->handle()
#17 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Middleware/RequestHandler.php(37): Phpactor\LanguageServer\Middleware\InitializeMiddleware->process()
#18 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/ErrorHandlingMiddleware.php(34): Phpactor\LanguageServer\Core\Middleware\RequestHandler->handle()
#19 [internal function]: Phpactor\LanguageServer\Middleware\ErrorHandlingMiddleware->Phpactor\LanguageServer\Middleware\{closure}()
#20 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#21 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#22 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Middleware/ErrorHandlingMiddleware.php(32): Amp\call()
#23 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Middleware/RequestHandler.php(37): Phpactor\LanguageServer\Middleware\ErrorHandlingMiddleware->process()
#24 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Dispatcher/Dispatcher/MiddlewareDispatcher.php(29): Phpactor\LanguageServer\Core\Middleware\RequestHandler->handle()
#25 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Server/LanguageServer.php(223): Phpactor\LanguageServer\Core\Dispatcher\Dispatcher\MiddlewareDispatcher->dispatch()
#26 [internal function]: Phpactor\LanguageServer\Core\Server\LanguageServer->Phpactor\LanguageServer\Core\Server\{closure}()
#27 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Coroutine.php(67): Generator->current()
#28 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/functions.php(96): Amp\Coroutine->__construct()
#29 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/functions.php(121): Amp\call()
#30 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Server/LanguageServer.php(221): Amp\asyncCall()
#31 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Server/LanguageServer.php(214): Phpactor\LanguageServer\Core\Server\LanguageServer->dispatchRequest()
#32 [internal function]: Phpactor\LanguageServer\Core\Server\LanguageServer->Phpactor\LanguageServer\Core\Server\{closure}()
#33 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Coroutine.php(118): Generator->send()
#34 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Internal/Placeholder.php(149): Amp\Coroutine->Amp\{closure}()
#35 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Coroutine.php(123): Amp\Coroutine->resolve()
#36 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Internal/Placeholder.php(149): Amp\Coroutine->Amp\{closure}()
#37 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Deferred.php(53): Amp\Promise@anonymous->resolve()
#38 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/byte-stream/lib/ResourceInputStream.php(109): Amp\Deferred->resolve()
#39 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Loop/Driver.php(119): Amp\ByteStream\ResourceInputStream::Amp\ByteStream\{closure}()
#40 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Loop/Driver.php(72): Amp\Loop\Driver->tick()
#41 /home/leo/code/github.com/phpactor/phpactor/vendor/amphp/amp/lib/Loop.php(95): Amp\Loop\Driver->run()
#42 /home/leo/code/github.com/phpactor/phpactor/vendor/phpactor/language-server/lib/Core/Server/LanguageServer.php(111): Amp\Loop::run()
#43 /home/leo/code/github.com/phpactor/phpactor/lib/Extension/LanguageServer/Command/StartCommand.php(50): Phpactor\LanguageServer\Core\Server\LanguageServer->run()
#44 /home/leo/code/github.com/phpactor/phpactor/vendor/symfony/console/Command/Command.php(298): Phpactor\Extension\LanguageServer\Command\StartCommand->execute()
#45 /home/leo/code/github.com/phpactor/phpactor/vendor/symfony/console/Application.php(1040): Symfony\Component\Console\Command\Command->run()
#46 /home/leo/code/github.com/phpactor/phpactor/vendor/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand()
#47 /home/leo/code/github.com/phpactor/phpactor/lib/Application.php(48): Symfony\Component\Console\Application->doRun()
#48 /home/leo/code/github.com/phpactor/phpactor/vendor/symfony/console/Application.php(171): Phpactor\Application->doRun()
#49 /home/leo/code/github.com/phpactor/phpactor/bin/phpactor(46): Symfony\Component\Console\Application->run()
#50 {main}
```

Pull request description:
Gh 2518 errors renaming
Ignore "text document not found" errors for no-longer-existing references when renaming classes

Fixes #2518 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2317593..888e6ac8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,9 @@ Improvements:
 
 Bug fixes:
 
+  - Fix division by zero edge case
+  - Fix crash if referenced file no longer exists on class rename #2518
+  - Fix diagnostic process concurrency and do not lint outdated files #2538
   - Fix detection of import used relatively in an annotation #2539
   - Fix PHAR crashing issue on PHP8.3 #2533
   - Fix UTF-16 conversion for LSP #2530 #2557
diff --git a/lib/Rename/Adapter/ReferenceFinder/ClassMover/ClassRenamer.php b/lib/Rename/Adapter/ReferenceFinder/ClassMover/ClassRenamer.php
index cf89d418..a2a52ece 100644
--- a/lib/Rename/Adapter/ReferenceFinder/ClassMover/ClassRenamer.php
+++ b/lib/Rename/Adapter/ReferenceFinder/ClassMover/ClassRenamer.php
@@ -24,6 +24,7 @@ use Phpactor\Rename\Model\Renamer;
 use Phpactor\ReferenceFinder\ReferenceFinder;
 use Phpactor\TextDocument\ByteOffset;
 use Phpactor\TextDocument\ByteOffsetRange;
+use Phpactor\TextDocument\Exception\TextDocumentNotFound;
 use Phpactor\TextDocument\TextDocument;
 use Phpactor\TextDocument\TextDocumentLocator;
 use RuntimeException;
@@ -96,7 +97,11 @@ final class ClassRenamer implements Renamer
                 continue;
             }
 
-            $referenceDocument = $this->locator->get($reference->location()->uri());
+            try {
+                $referenceDocument = $this->locator->get($reference->location()->uri());
+            } catch (TextDocumentNotFound) {
+                continue;
+            }
 
             $edits = $this->classMover->replaceReferences(
                 $this->classMover->findReferences($referenceDocument->__toString(), $originalName->__toString()),
diff --git a/lib/Rename/Model/NameToUriConverter.php b/lib/Rename/Model/NameToUriConverter.php
index 62cea9f3..efb94677 100644
--- a/lib/Rename/Model/NameToUriConverter.php
+++ b/lib/Rename/Model/NameToUriConverter.php
@@ -10,5 +10,5 @@ interface NameToUriConverter
     /**
      * @throws CouldNotConvertUriToClass
      */
-    public function convert(string $uri): TextDocumentUri;
+    public function convert(string $className): TextDocumentUri;
 }
diff --git a/lib/WorseReflection/Core/Type/NumericType.php b/lib/WorseReflection/Core/Type/NumericType.php
index 8e43c52b..9a2edf22 100644
--- a/lib/WorseReflection/Core/Type/NumericType.php
+++ b/lib/WorseReflection/Core/Type/NumericType.php
@@ -33,7 +33,8 @@ abstract class NumericType extends ScalarType
     public function divide(NumericType $right): NumericType
     {
         if ($this instanceof Literal && $right instanceof Literal) {
-            if ($right->value() === 0) {
+            /** @phpstan-ignore-next-line it's a scalar */
+            if (intval($right->value()) === 0) {
                 return $this->withValue(0);
             }
 
diff --git a/lib/WorseReflection/TypeUtil.php b/lib/WorseReflection/TypeUtil.php
index 12991996..cd77ba98 100644
--- a/lib/WorseReflection/TypeUtil.php
+++ b/lib/WorseReflection/TypeUtil.php
@@ -63,6 +63,9 @@ class TypeUtil
 
     public static function toNumber(Type $type): NumericType
     {
+        if ($type instanceof NumericType) {
+            return $type;
+        }
         if ($type instanceof Literal && $type instanceof ScalarType) {
             $value = (string)$type->value();
             return TypeFactory::fromNumericString($value);


Test patch:
diff --git a/lib/Rename/Adapter/Test/TestNameToUriConverter.php b/lib/Rename/Adapter/Test/TestNameToUriConverter.php
new file mode 100644
index 00000000..34cf4bac
--- /dev/null
+++ b/lib/Rename/Adapter/Test/TestNameToUriConverter.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Phpactor\Rename\Adapter\Test;
+
+use Phpactor\Rename\Model\NameToUriConverter;
+use Phpactor\TextDocument\TextDocumentUri;
+use RuntimeException;
+
+final class TestNameToUriConverter implements NameToUriConverter
+{
+    /**
+     * @param array<string,TextDocumentUri> $map
+     */
+    public function __construct(private array $map)
+    {
+    }
+
+    public function convert(string $className): TextDocumentUri
+    {
+        if (!isset($this->map[$className])) {
+            throw new RuntimeException(sprintf(
+                'Test class name "%s" not mapped to file',
+                $className
+            ));
+        }
+
+        return $this->map[$className];
+    }
+
+}
diff --git a/lib/Rename/Tests/Adapter/ReferenceFinder/ClassMover/ClassRenamerTest.php b/lib/Rename/Tests/Adapter/ReferenceFinder/ClassMover/ClassRenamerTest.php
index 6ef9f8a7..7d5f3ff7 100644
--- a/lib/Rename/Tests/Adapter/ReferenceFinder/ClassMover/ClassRenamerTest.php
+++ b/lib/Rename/Tests/Adapter/ReferenceFinder/ClassMover/ClassRenamerTest.php
@@ -5,13 +5,18 @@ namespace Phpactor\Rename\Tests\Adapter\ReferenceFinder\ClassMover;
 use Generator;
 use Microsoft\PhpParser\Parser;
 use Phpactor\ClassMover\ClassMover;
+use Phpactor\ReferenceFinder\PotentialLocation;
 use Phpactor\Rename\Adapter\ReferenceFinder\ClassMover\ClassRenamer;
+use Phpactor\Rename\Adapter\Test\TestNameToUriConverter;
 use Phpactor\Rename\Model\LocatedTextEdits;
 use Phpactor\Rename\Model\LocatedTextEditsMap;
 use Phpactor\Rename\Model\NameToUriConverter;
+use Phpactor\Rename\Model\ReferenceFinder\PredefinedReferenceFinder;
 use Phpactor\Rename\Tests\Adapter\ReferenceFinder\ReferenceRenamerIntegrationTestCase;
 use Phpactor\Extension\LanguageServerRename\Tests\Util\OffsetExtractor;
 use Phpactor\TextDocument\ByteOffset;
+use Phpactor\TextDocument\ByteOffsetRange;
+use Phpactor\TextDocument\Location;
 use Phpactor\TextDocument\TextDocument;
 use Phpactor\TextDocument\TextDocumentBuilder;
 use Phpactor\TextDocument\TextDocumentLocator\InMemoryDocumentLocator;
@@ -19,6 +24,35 @@ use Phpactor\TextDocument\TextDocumentUri;
 
 class ClassRenamerTest extends ReferenceRenamerIntegrationTestCase
 {
+    public function testRenameWithReferenceToNonExistingFile(): void
+    {
+        $finder = new PredefinedReferenceFinder(
+            PotentialLocation::surely(
+                new Location(
+                    TextDocumentUri::fromString('file:///not-existing'),
+                    ByteOffsetRange::fromInts(1, 1)
+                )
+            )
+        );
+
+        $converter =  new TestNameToUriConverter([
+            'Foobar' => TextDocumentUri::fromString('file:///foobar'),
+            'FoobarBaz' => TextDocumentUri::fromString('file:///foobar-new'),
+        ]);
+        $renamer = new ClassRenamer(
+            $converter,
+            $converter,
+            $finder,
+            InMemoryDocumentLocator::fromTextDocuments([]),
+            new Parser(),
+            new ClassMover()
+        );
+
+        $textDocument = TextDocumentBuilder::fromPathAndString('/path', '<?php class Foobar{}');
+        iterator_to_array($renamer->rename($textDocument, ByteOffset::fromInt(12), 'FoobarBaz'), false);
+        $this->addToAssertionCount(1);
+    }
+
     /**
      * @dataProvider provideRename
      */
diff --git a/lib/WorseReflection/Tests/Inference/arithmetic/zero-division.test b/lib/WorseReflection/Tests/Inference/arithmetic/zero-division.test
new file mode 100644
index 00000000..9b43913e
--- /dev/null
+++ b/lib/WorseReflection/Tests/Inference/arithmetic/zero-division.test
@@ -0,0 +1,6 @@
+<?php
+
+wrAssertType('0', 0/0);
+wrAssertType('0', 0/0.0);
+wrAssertType('0', 0.0/0.0);
+wrAssertType('0', 1/0.0);