1
0
Fork 0
php-language-server/src/SignatureHelpProvider.php

178 lines
7.2 KiB
PHP
Raw Normal View History

2017-01-19 18:33:31 +00:00
<?php
declare(strict_types = 1);
namespace LanguageServer;
use PhpParser\Node;
use LanguageServer\Index\ReadableIndex;
use LanguageServer\Protocol\{
Position,
SignatureHelp,
SignatureInformation,
ParameterInformation
};
class SignatureHelpProvider
{
/**
* @var DefinitionResolver
*/
private $definitionResolver;
/**
* @var ReadableIndex
*/
private $index;
/**
* @param DefinitionResolver $definitionResolver
* @param ReadableIndex $index
*/
public function __construct(DefinitionResolver $definitionResolver, ReadableIndex $index)
{
$this->definitionResolver = $definitionResolver;
$this->index = $index;
}
/**
* Returns signature help for a specific cursor position in a document
*
* @param PhpDocument $doc The opened document
* @param Position $pos The cursor position
* @return SignatureHelp
*/
public function provideSignature(PhpDocument $doc, Position $pos): SignatureHelp
{
$help = new SignatureHelp;
$help->signatures = [];
2017-01-19 20:18:14 +00:00
$newPos = clone $pos;
$line = explode("\n", $doc->getContent())[$newPos->line];
do {
$newPos->character --;
} while ($newPos->character > 0 && $line[$newPos->character] !== "(");
if (!$newPos->character) {
return $help;
}
$line = substr($line, 0, $newPos->character);
$newPos->character --;
$node = $doc->getNodeAtPosition($newPos);
if ($node instanceof Node\Expr\Error) {
$node = $node->getAttribute('parentNode');
}
if ($node instanceof Node\Expr\Error) {
$node = $node->getAttribute('parentNode');
}
2017-01-19 18:33:31 +00:00
if ($node instanceof Node\Expr\FuncCall) {
if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node)) {
$signature = new SignatureInformation;
2017-01-19 21:54:05 +00:00
$signature->label = str_replace('()', '', $def->fqn) . '('.implode(', ', $def->parameters).')';
2017-01-19 18:33:31 +00:00
$signature->documentation = $def->documentation;
$signature->parameters = [];
foreach ($def->parameters as $param) {
$p = new ParameterInformation;
$p->label = $param;
$signature->parameters[] = $p;
}
$help->signatures[] = $signature;
}
2017-01-19 20:18:14 +00:00
} else if ($node instanceof Node\Name\FullyQualified || $node === null) {
if (preg_match('([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$)', $line, $method)) {
$fqn = $method[0] . '()';
if ($def = $this->index->getDefinition($fqn)) {
$signature = new SignatureInformation;
2017-01-19 21:54:05 +00:00
$signature->label = $method[0] . '('.implode(', ', $def->parameters).')';
2017-01-19 20:18:14 +00:00
$signature->documentation = $def->documentation;
$signature->parameters = [];
foreach ($def->parameters as $param) {
$p = new ParameterInformation;
$p->label = $param;
$signature->parameters[] = $p;
}
$help->signatures[] = $signature;
}
}
2017-01-19 18:33:31 +00:00
} else if ($node instanceof Node\Expr\MethodCall) {
if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node)) {
$signature = new SignatureInformation;
2017-01-19 21:54:05 +00:00
$signature->label = str_replace('()', '', explode('->', $def->fqn)[1]) . '('.implode(', ', $def->parameters).')';
2017-01-19 18:33:31 +00:00
$signature->documentation = $def->documentation;
$signature->parameters = [];
foreach ($def->parameters as $param) {
$p = new ParameterInformation;
$p->label = $param;
$signature->parameters[] = $p;
}
$help->signatures[] = $signature;
}
2017-01-19 20:18:14 +00:00
} else if ($node instanceof Node\Expr\PropertyFetch) {
if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node->var)) {
2017-01-19 21:54:05 +00:00
$fqn = $def->fqn;
if (!$fqn) {
$fqns = DefinitionResolver::getFqnsFromType(
$this->definitionResolver->resolveExpressionNodeToType($node->var)
);
if (count($fqns)) {
$fqn = $fqns[0];
}
}
2017-01-19 20:18:14 +00:00
$method = trim(substr($line, strrpos($line, ">") + 1));
2017-01-19 21:54:05 +00:00
if ($method && $fqn) {
$fqn = $fqn . '->' . $method . '()';
2017-01-19 20:18:14 +00:00
if ($def = $this->index->getDefinition($fqn)) {
$signature = new SignatureInformation;
2017-01-19 21:54:05 +00:00
$signature->label = str_replace('()', '', explode('->', $def->fqn)[1]) . '('.implode(', ', $def->parameters).')';
2017-01-19 20:18:14 +00:00
$signature->documentation = $def->documentation;
$signature->parameters = [];
foreach ($def->parameters as $param) {
$p = new ParameterInformation;
$p->label = $param;
$signature->parameters[] = $p;
}
$help->signatures[] = $signature;
}
}
}
2017-01-19 18:33:31 +00:00
} else if ($node instanceof Node\Expr\StaticCall) {
2017-01-19 20:18:14 +00:00
if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node)) {
$signature = new SignatureInformation;
2017-01-19 21:54:05 +00:00
$signature->label = str_replace('()', '', explode('::', $def->fqn)[1]) . '('.implode(', ', $def->parameters).')';
2017-01-19 20:18:14 +00:00
$signature->documentation = $def->documentation;
$signature->parameters = [];
foreach ($def->parameters as $param) {
$p = new ParameterInformation;
$p->label = $param;
$signature->parameters[] = $p;
}
$help->signatures[] = $signature;
}
} else if ($node instanceof Node\Expr\ClassConstFetch) {
if ($def = $this->definitionResolver->resolveReferenceNodeToDefinition($node->class)) {
$method = trim(substr($line, strrpos($line, ":") + 1));
if ($method) {
$fqn = $def->fqn . '::' . $method . '()';
if ($def = $this->index->getDefinition($fqn)) {
$signature = new SignatureInformation;
2017-01-19 21:54:05 +00:00
$signature->label = str_replace('()', '', explode('::', $def->fqn)[1]) . '('.implode(', ', $def->parameters).')';
2017-01-19 20:18:14 +00:00
$signature->documentation = $def->documentation;
$signature->parameters = [];
foreach ($def->parameters as $param) {
$p = new ParameterInformation;
$p->label = $param;
$signature->parameters[] = $p;
}
$help->signatures[] = $signature;
}
}
2017-01-19 18:33:31 +00:00
}
}
return $help;
}
}