-
Notifications
You must be signed in to change notification settings - Fork 154
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
Add CallNode field to NodeContext #2115
Conversation
68a19f7
to
464a482
Compare
60f5ed8
to
b3ad3c3
Compare
lib/ruby_lsp/document.rb
Outdated
@@ -159,6 +160,10 @@ def locate(node, char_position, node_types: []) | |||
nesting << candidate | |||
end | |||
|
|||
if candidate.is_a?(Prism::CallNode) | |||
call_node = candidate |
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 feel there may be situations that aren't properly handled with this approach, but haven't found a concrete one yet. 🤔
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 if the target itself is a call node? Does it find the right surrounding one?
For example:
call1(call2)
# ^ this should be the surrounding
# ^ this should be the target
Let's add a test for this case.
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.
Added a test and fixed the behaviour.
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.
The implementation looks good to me. Let's just test that possible corner case
lib/ruby_lsp/document.rb
Outdated
@@ -159,6 +160,10 @@ def locate(node, char_position, node_types: []) | |||
nesting << candidate | |||
end | |||
|
|||
if candidate.is_a?(Prism::CallNode) | |||
call_node = candidate |
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 if the target itself is a call node? Does it find the right surrounding one?
For example:
call1(call2)
# ^ this should be the surrounding
# ^ this should be the target
Let's add a test for this case.
@andyw8 could you add some description in the PR(s)? Neither PR describes what feature/problem we're trying to solve and it's not easy to review with this little information 🙂 |
I've expanded the PR description. |
(looking into the two failures, will set to draft) |
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 do we expect in these cases:
foo do
123 # this is the target
end
foo(
if bar
123 # this is the target
end
end
Are we expecting foo
being the call node in both cases?
@st0012 good question. This doesn't handle integers, but if we imagine those are symbols or string instead, then I'd say |
(the first case could be debatable... |
2fd6c34
to
ed93c79
Compare
@st0012 after pairing with @vinistock, we've changed the approach so that we do match non-immediate parents. It doesn't add much too much complexity, and allows us to have more flexibilities for future use cases. |
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.
Nice
elsif target.is_a?(Prism::SymbolNode) && parent.is_a?(Prism::BlockArgumentNode) | ||
target = parent |
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.
Let's add a comment so that we remember why this adjustment is necessary.
ed93c79
to
840277f
Compare
(merged on the command line since the labels check seemed to be stuck) |
Not a blocker, but what are the criteria for the types of node to have this field?
In that case, I think it should be named |
It's hard to say since we can't anticipate all the possible things an addon author might want to build. Currently I just have the Rails DSLs in mind. We can consider others case-by-case.
I'm open to changing it to that. @vinistock ? |
When we listen for node events, there are some situations where we are interested in not just the node, but the surrounding context. For cases such as a DSL call
has_many :users
, we make a definition request for the:users
symbol, but we also want to know the surrounding method (has_many
in this case). This will allow features such as Shopify/ruby-lsp-rails#397The implementation is fairly simple: While iterating over the queue, if the
parent
is aCallNode
, then we keep track of that. So at the end of the iteration, we have the innermostCallNode
, which we can then pass toNodeContext.new
.