From 36e2ea6881fc8d735963841c87ceed3eb2976548 Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Sun, 30 Jun 2019 11:12:50 -0400 Subject: [PATCH] Fix #1822 - update use statements with classes --- .../CodeLocation/DocblockTypeLocation.php | 6 -- src/Psalm/Codebase.php | 55 ++++++++++++++++--- .../Internal/Visitor/ReflectorVisitor.php | 4 +- tests/LanguageServer/CompletionTest.php | 20 ++++++- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/Psalm/CodeLocation/DocblockTypeLocation.php b/src/Psalm/CodeLocation/DocblockTypeLocation.php index 9cb2c480931..85812c55c81 100644 --- a/src/Psalm/CodeLocation/DocblockTypeLocation.php +++ b/src/Psalm/CodeLocation/DocblockTypeLocation.php @@ -5,12 +5,6 @@ class DocblockTypeLocation extends \Psalm\CodeLocation { - /** @var int */ - public $raw_file_start; - - /** @var int */ - public $raw_file_end; - /** @var int */ public $raw_line_number; diff --git a/src/Psalm/Codebase.php b/src/Psalm/Codebase.php index 9362a8b2c07..7b7d36dc8b0 100644 --- a/src/Psalm/Codebase.php +++ b/src/Psalm/Codebase.php @@ -1353,6 +1353,47 @@ public function getCompletionItemsForPartialSymbol( continue; } + $extra_edits = []; + + $insertion_text = Type::getStringFromFQCLN( + $storage->name, + $aliases && $aliases->namespace ? $aliases->namespace : null, + $aliases ? $aliases->uses_flipped : [], + null + ); + + if ($aliases + && $aliases->namespace + && $insertion_text === '\\' . $storage->name + && $aliases->namespace_first_stmt_start + ) { + $file_contents = $this->getFileContents($file_path); + + $class_name = \preg_replace('/^.*\\\/', '', $storage->name); + + if ($aliases->uses_end) { + $position = self::getPositionFromOffset($aliases->uses_end, $file_contents); + $extra_edits[] = new \LanguageServerProtocol\TextEdit( + new Range( + $position, + $position + ), + \PHP_EOL . 'use ' . $storage->name . ';' + ); + } else { + $position = self::getPositionFromOffset($aliases->namespace_first_stmt_start, $file_contents); + $extra_edits[] = new \LanguageServerProtocol\TextEdit( + new Range( + $position, + $position + ), + 'use ' . $storage->name . ';' . \PHP_EOL . \PHP_EOL + ); + } + + $insertion_text = $class_name; + } + $completion_items[] = new \LanguageServerProtocol\CompletionItem( $storage->name, \LanguageServerProtocol\CompletionItemKind::CLASS_, @@ -1360,12 +1401,9 @@ public function getCompletionItemsForPartialSymbol( null, null, $storage->name, - Type::getStringFromFQCLN( - $storage->name, - $aliases && $aliases->namespace ? $aliases->namespace : null, - $aliases ? $aliases->uses_flipped : [], - null - ) + $insertion_text, + null, + $extra_edits ); } @@ -1375,9 +1413,12 @@ public function getCompletionItemsForPartialSymbol( private static function getPositionFromOffset(int $offset, string $file_contents) : Position { $file_contents = substr($file_contents, 0, $offset); + + $before_newline_count = strrpos($file_contents, "\n", $offset - strlen($file_contents)); + return new Position( substr_count($file_contents, "\n"), - $offset - (int)strrpos($file_contents, "\n", strlen($file_contents)) + $offset - (int)$before_newline_count - 1 ); } diff --git a/src/Psalm/Internal/Visitor/ReflectorVisitor.php b/src/Psalm/Internal/Visitor/ReflectorVisitor.php index 0defe3db2fa..1a82e82a148 100644 --- a/src/Psalm/Internal/Visitor/ReflectorVisitor.php +++ b/src/Psalm/Internal/Visitor/ReflectorVisitor.php @@ -240,7 +240,7 @@ public function enterNode(PhpParser\Node $node) $this->aliases->uses_start = (int) $node->getAttribute('startFilePos'); } - $this->aliases->uses_end = (int) $node->getAttribute('endFilePos'); + $this->aliases->uses_end = (int) $node->getAttribute('endFilePos') + 1; } elseif ($node instanceof PhpParser\Node\Stmt\GroupUse) { $use_prefix = implode('\\', $node->prefix->parts); @@ -270,7 +270,7 @@ public function enterNode(PhpParser\Node $node) $this->aliases->uses_start = (int) $node->getAttribute('startFilePos'); } - $this->aliases->uses_end = (int) $node->getAttribute('endFilePos'); + $this->aliases->uses_end = (int) $node->getAttribute('endFilePos') + 1; } elseif ($node instanceof PhpParser\Node\Stmt\ClassLike) { if ($this->skip_if_descendants) { return; diff --git a/tests/LanguageServer/CompletionTest.php b/tests/LanguageServer/CompletionTest.php index 687faa0451e..e15fc484941 100644 --- a/tests/LanguageServer/CompletionTest.php +++ b/tests/LanguageServer/CompletionTest.php @@ -688,7 +688,7 @@ function foo() : void { /** * @return void */ - public function testCompletionOnNewExceptionWithNamespace() + public function testCompletionOnNewExceptionWithNamespaceNoUse() { $codebase = $this->project_analyzer->getCodebase(); $config = $codebase->config; @@ -724,7 +724,15 @@ function foo() : void { $this->assertCount(1, $completion_items); $this->assertSame('Exception', $completion_items[0]->label); - $this->assertSame('\Exception', $completion_items[0]->insertText); + $this->assertSame('Exception', $completion_items[0]->insertText); + + $this->assertNotNull($completion_items[0]->additionalTextEdits); + $this->assertCount(1, $completion_items[0]->additionalTextEdits); + $this->assertSame('use Exception;' . \PHP_EOL . \PHP_EOL, $completion_items[0]->additionalTextEdits[0]->newText); + $this->assertSame(3, $completion_items[0]->additionalTextEdits[0]->range->start->line); + $this->assertSame(16, $completion_items[0]->additionalTextEdits[0]->range->start->character); + $this->assertSame(3, $completion_items[0]->additionalTextEdits[0]->range->end->line); + $this->assertSame(16, $completion_items[0]->additionalTextEdits[0]->range->end->character); } /** @@ -769,6 +777,14 @@ function foo() : void { $completion_items = $codebase->getCompletionItemsForPartialSymbol($completion_data[0], $completion_data[2], 'somefile.php'); $this->assertCount(5, $completion_items); + + $this->assertNotNull($completion_items[0]->additionalTextEdits); + $this->assertCount(1, $completion_items[0]->additionalTextEdits); + $this->assertSame(\PHP_EOL . 'use ArrayObject;', $completion_items[0]->additionalTextEdits[0]->newText); + $this->assertSame(3, $completion_items[0]->additionalTextEdits[0]->range->start->line); + $this->assertSame(44, $completion_items[0]->additionalTextEdits[0]->range->start->character); + $this->assertSame(3, $completion_items[0]->additionalTextEdits[0]->range->end->line); + $this->assertSame(44, $completion_items[0]->additionalTextEdits[0]->range->end->character); } /**