-
Notifications
You must be signed in to change notification settings - Fork 185
Signature help #438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Signature help #438
Conversation
Currently this PR is not ready for merging - I want to get some opinions on the approach and fix as necessary. There is one major problem I noticed so far - the currently active parameter is not properly determined (as soon as something is written it shifts one parameter to the right) - I would like some help with that if someone can spare the time and have a look, as I am not very familiar with tolerant parser's objects. One thing I definitely noticed - this implementation is way cleaner than the one with PhpParser. |
Codecov Report
@@ Coverage Diff @@
## master #438 +/- ##
============================================
+ Coverage 79.38% 79.96% +0.57%
- Complexity 837 867 +30
============================================
Files 56 60 +4
Lines 1979 2051 +72
============================================
+ Hits 1571 1640 +69
- Misses 408 411 +3
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very good and is what I had in mind for the implementation (no use of lexer/tokenizer).
src/DefinitionResolver.php
Outdated
@@ -234,6 +235,18 @@ public function createDefinitionFromNode(Node $node, string $fqn = null): Defini | |||
$def->documentation = $this->getDocumentationFromNode($node); | |||
} | |||
|
|||
$def->parameters = []; | |||
if (property_exists($node, 'parameters') && $node->parameters) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you do this without reflection? i.e. instanceof
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will need @roblourens help for this - I have no idea what to check for. From what I gather it is a trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roblourens could you add an interface for FunctionHeader
or callables so this can be checked for with instanceof
?
if (!($node instanceof ArgumentExpressionList) && | ||
!($node instanceof CallExpression) | ||
) { | ||
return new SignatureHelp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A signature without label
is not valid according to the docblock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no label
property in the SignatureHelp
object - maybe I am missin something - please explain? This is supposed to be an empty result (no nested SignatureHelpInformation
objects).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixfbecker please provide further information on how I can help improve this? I am still not sure what the issue is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I confused it with the SignatureInformation class
src/SignatureHelpProvider.php
Outdated
return new SignatureHelp( | ||
[ | ||
new SignatureInformation( | ||
trim(str_replace(['public', 'protected', 'private', 'function', 'static'], '', $def->declarationLine)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't like the string manipulation here, you could have a parameter $function
. I would rather extend Definition
with another property or method (if possible, without saving new duplicate data to save RAM)
src/Definition.php
Outdated
@@ -97,6 +98,12 @@ class Definition | |||
* @var string | |||
*/ | |||
public $documentation; | |||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add an empty line above this
src/DefinitionResolver.php
Outdated
//var_dump($param); die(); | ||
$def->parameters[] = new ParameterInformation( | ||
$this->getDeclarationLineFromNode($param), | ||
//$param->getName(), // TODO: rebuild this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does this mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was old code - I am cleaning it up.
src/Server/TextDocument.php
Outdated
@@ -411,4 +416,12 @@ public function xdefinition(TextDocumentIdentifier $textDocument, Position $posi | |||
return [new SymbolLocationInformation($descriptor, $def->symbolInformation->location)]; | |||
}); | |||
} | |||
|
|||
public function signatureHelp(TextDocumentIdentifier $textDocument, Position $position): Promise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a docblock for this method with the description from the protocol spec (makes it easier for newcomers to understand the purpose of the method)
Maybe @roblourens can help with the parser specifics, he knows more about it than me. Maybe the parameters array gets a |
The count should be OK now, but I will need @roblourens help with the |
I am afraid the failing build is not my fault - please advise on how to proceed?
I do not get this error locally. |
weird |
I'm not sure what you mean by "the property_exists issue". Your change from the last commit seems good to me - I think it's better to explicitly check the type with |
@roblourens it would be nice if checking for a callable, function-like node only required a single |
I've been using this branch for a few days now. Issues I've noticed so far:
I will look into the second issue - I will create a test and try to fix it. It would be great if someone else also tried this branch, just so that we can gather opinions (although subjective) about performance - I am using a Surface Pro 4 (i5, 8GB) and experience no issues, but it may be different for someone else. |
I do see some relevant helpers in |
I think an interface would be more useful for static analysis if we ever implement type narrowing through |
@vakata do you feel this is stable enough to release? |
{ | ||
$parts = explode('(', $declaration, 2); | ||
$name = array_reverse(explode(' ', trim($parts[0])))[0]; | ||
return $name . '(' . $parts[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method looks like it would ignore many edge cases, for example (
or spaces inside a default string value.
Why attempt to explode a declaration string when we have a parser available? I would add the wanted output to the Definition
class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am absolutely certain that this code does not ignore any edge cases - the first (
in a declaration is always after the function name. The function name is always the last token after all modifiers.
I am not sure how to change the current implementation in a robust way - all I need is to remove the modifiers and leave the function name, but keep all parameters (along with their type and default values). Doing this using the parser would require quite a huge block of code (from what I gather) especially since there is no way to pretty print the result.
Basically I would be reconstructing the already available declaration using string concatenation by inspecting the underlying AST just to remove the public / private / abstract / static / function keywords that precede the function name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, maybe I'm was just unable to follow this code.
- you split the declaration into two parts, the part before the
(
(function name and keywords) and the rest - you trim whitespace from the first part (function name and keywords)
- you split the first part by (function name and keywords) by spaces
- you reverse the whole array
- you take the first (initially last) element (function name)
- you concatenate the function name,
(
and the rest
I am pretty sure end()
is faster to get the last array element than reversing the whole array and taking the first element
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
end
requires a reference, which would mean creating a middle step and allocating a separate variable for the array. I am not very familiar with PHP internals, but I believe this means allocating storage in the heap, instead of the stack, so as far as optimization goes - I am not sure which will be faster and more memory efficient. Anyway - this really is a micro-optimization. I will create a few tests and change it if necessary.
EDIT: For what it is worth - I created a very crude test and at least for my configuration using a temporary array and end
is on average about 3% slower.
@felixfbecker as I mentioned in my previous comment:
|
I don't work on any PHP project currently so I can't do any real usage testing. I don't think a lot of people will try it out by cloning this branch, you could build a .vsix though. Otherwise I would just release it and let people try it out. |
If you feel the issue I described above is minor enough I am OK with publishing. I am not sure many people would download the .vsix anyway. If this PR is merged I will still try to fix the issue next week in a separate PR. |
well, if somebody builds me such a file or lets me know how I do that, I'm happy to test it. :) |
@vakata any update? |
@vakata are you still working on this? |
@felixfbecker no, I haven't had the time to do any further work. Actually the only thing that was left was the occasional slip up in position calculation, but I doubt I will have time any time soon to work on this. |
Could I do something to help you? @vakata |
@felixfbecker @jens1o sorry I was not around sooner. Currently the only issue I have with this PR is the occasional position miscalculation, but I doubt I will have time to work on it any time soon. I guess the most helpful thing would be for someone else beside me to test this change and share if all worked fine. |
Closing in favor of #547 |
Initial idea to start the discussion (still needs work)