mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Fix #1654 - understand templated completions
This commit is contained in:
parent
92ef851b9c
commit
a1c9ad501b
@ -1118,6 +1118,87 @@ class Codebase
|
||||
return [$recent_type, $gap];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, \LanguageServerProtocol\CompletionItem>
|
||||
*/
|
||||
public function getCompletionItemsForClassishThing(string $type_string, string $gap) : array
|
||||
{
|
||||
$instance_completion_items = [];
|
||||
$static_completion_items = [];
|
||||
|
||||
$type = Type::parseString($type_string);
|
||||
|
||||
$completion_items = [];
|
||||
|
||||
foreach ($type->getTypes() as $atomic_type) {
|
||||
if ($atomic_type instanceof Type\Atomic\TNamedObject) {
|
||||
try {
|
||||
$class_storage = $this->classlike_storage_provider->get($atomic_type->value);
|
||||
|
||||
foreach ($class_storage->appearing_method_ids as $declaring_method_id) {
|
||||
$method_storage = $this->methods->getStorage($declaring_method_id);
|
||||
|
||||
$instance_completion_items[] = new \LanguageServerProtocol\CompletionItem(
|
||||
(string)$method_storage,
|
||||
\LanguageServerProtocol\CompletionItemKind::METHOD,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$method_storage->cased_name . '()'
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class_storage->declaring_property_ids as $property_name => $declaring_class) {
|
||||
$property_storage = $this->properties->getStorage(
|
||||
$declaring_class . '::$' . $property_name
|
||||
);
|
||||
|
||||
$instance_completion_items[] = new \LanguageServerProtocol\CompletionItem(
|
||||
$property_storage->getInfo() . ' $' . $property_name,
|
||||
\LanguageServerProtocol\CompletionItemKind::PROPERTY,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
($gap === '::' ? '$' : '') . $property_name
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class_storage->class_constant_locations as $const_name => $_) {
|
||||
$static_completion_items[] = new \LanguageServerProtocol\CompletionItem(
|
||||
'const ' . $const_name,
|
||||
\LanguageServerProtocol\CompletionItemKind::VARIABLE,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$const_name
|
||||
);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($gap === '->') {
|
||||
$completion_items = array_merge(
|
||||
$completion_items,
|
||||
$instance_completion_items
|
||||
);
|
||||
} else {
|
||||
$completion_items = array_merge(
|
||||
$completion_items,
|
||||
$instance_completion_items,
|
||||
$static_completion_items
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $completion_items;
|
||||
}
|
||||
|
||||
private static function getPositionFromOffset(int $offset, string $file_contents) : Position
|
||||
{
|
||||
$file_contents = substr($file_contents, 0, $offset);
|
||||
|
@ -264,61 +264,7 @@ class TextDocument
|
||||
$completion_items = [];
|
||||
|
||||
if ($gap === '->' || $gap === '::') {
|
||||
$instance_completion_items = [];
|
||||
$static_completion_items = [];
|
||||
|
||||
try {
|
||||
$class_storage = $this->codebase->classlike_storage_provider->get($recent_type);
|
||||
|
||||
foreach ($class_storage->appearing_method_ids as $declaring_method_id) {
|
||||
$method_storage = $this->codebase->methods->getStorage($declaring_method_id);
|
||||
|
||||
$instance_completion_items[] = new CompletionItem(
|
||||
(string)$method_storage,
|
||||
CompletionItemKind::METHOD,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$method_storage->cased_name . '()'
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class_storage->declaring_property_ids as $property_name => $declaring_class) {
|
||||
$property_storage = $this->codebase->properties->getStorage(
|
||||
$declaring_class . '::$' . $property_name
|
||||
);
|
||||
|
||||
$instance_completion_items[] = new CompletionItem(
|
||||
$property_storage->getInfo() . ' $' . $property_name,
|
||||
CompletionItemKind::PROPERTY,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
($gap === '::' ? '$' : '') . $property_name
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($class_storage->class_constant_locations as $const_name => $_) {
|
||||
$static_completion_items[] = new CompletionItem(
|
||||
'const ' . $const_name,
|
||||
CompletionItemKind::VARIABLE,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$const_name
|
||||
);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
error_log($e->getMessage());
|
||||
return new Success([]);
|
||||
}
|
||||
|
||||
$completion_items = $gap === '->'
|
||||
? $instance_completion_items
|
||||
: array_merge($instance_completion_items, $static_completion_items);
|
||||
$completion_items = $this->codebase->getCompletionItemsForClassishThing($recent_type, $gap);
|
||||
|
||||
error_log('Found ' . count($completion_items) . ' items');
|
||||
}
|
||||
|
@ -201,4 +201,60 @@ class CompletionTest extends \Psalm\Tests\TestCase
|
||||
|
||||
$this->assertSame(['B\C', '->'], $codebase->getCompletionDataAtPosition('somefile.php', new Position(16, 39)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testCompletionOnTemplatedThisProperty()
|
||||
{
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
$config = $codebase->config;
|
||||
$config->throw_exception = false;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
namespace B;
|
||||
|
||||
/** @template T */
|
||||
class C {
|
||||
/** @var T */
|
||||
private $t;
|
||||
|
||||
/** @param T $t */
|
||||
public function __construct($t) {
|
||||
$this->t = $t;
|
||||
}
|
||||
|
||||
public function otherFunction() : void
|
||||
}
|
||||
|
||||
class A {
|
||||
/** @var C<string> */
|
||||
protected $cee_me;
|
||||
|
||||
public function __construct() {
|
||||
$this->cee_me = new C("hello");
|
||||
}
|
||||
|
||||
public function foo() : void {
|
||||
$this->cee_me->
|
||||
}
|
||||
}'
|
||||
);
|
||||
|
||||
$codebase = $this->project_analyzer->getCodebase();
|
||||
|
||||
$codebase->file_provider->openFile('somefile.php');
|
||||
$codebase->scanFiles();
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
|
||||
$completion_data = $codebase->getCompletionDataAtPosition('somefile.php', new Position(25, 39));
|
||||
|
||||
$this->assertSame(['B\C<string>', '->'], $completion_data);
|
||||
|
||||
$completion_items = $codebase->getCompletionItemsForClassishThing($completion_data[0], $completion_data[1]);
|
||||
|
||||
$this->assertCount(3, $completion_items);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user