Skip to content
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

[#1094] Add support for Call Hierarchy #1096

Merged
merged 1 commit into from
Sep 29, 2021

Conversation

robertoaloi
Copy link
Member

@robertoaloi robertoaloi commented Sep 29, 2021

Description

This PR introduces support for Call Hierarchy.

Screenshot 2021-09-29 at 17 38 32

For a nicer overview of what the Call Hierarchy feature provides please watch this video.

There are still a couple of improvements possible (for example when it comes to recursive functions), which will be addressed as follow-ups.

The feature steps up the game when it comes to finding references (aka who calls this function). Erlang LS is already able to quickly identify callers, but that approach forces the developer to keep in mind the tree of already explored paths. Now that mental tree is available in the UI.

Emacs Support

To use it In Emacs you will require the lsp-treemacs package.

To see the incoming calls hierarchy:

M-x lsp-treemacs-call-hierarchy

To see the outgoing calls hierarchy:

C-u M-x lsp-treemacs-call-hierarchy

VS Code Support

Before this is available in VS Code we need to bump the languageclient package to 7.0.0, which is a breaking change.

Fixes #1094.

@robertoaloi robertoaloi merged commit 3902e3e into main Sep 29, 2021
@robertoaloi robertoaloi deleted the 1094-add-support-for-call-hierarchy branch September 29, 2021 17:24
{atom(), non_neg_integer()}) ->
binary().
function_signature({M, F, A}) ->
els_utils:to_binary(io_lib:format("~p:~ts/~p", [M, F, A]));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
els_utils:to_binary(io_lib:format("~p:~ts/~p", [M, F, A]));
els_utils:to_binary(io_lib:format("~p:~ts/~b", [M, F, A]));

#{ <<"item">> := Item } = Params,
#{ <<"uri">> := Uri } = Item,
POI = els_call_hierarchy_item:poi(Item),
Applications = applications_in_function_range(Uri, POI),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this took me a while to understand, applications are function applications, but in Erlang applications usually mean Erlang Applications.

Also I understand applications more as applications of the marked function. Maybe rename to calls_in_function_range or outgoing_calls

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it can be confusing. This refers to application in erl_syntax terms. We should probably bring clarity around this, either by renaming or via a comment.


-spec wrapping_functions(item(), non_neg_integer(), non_neg_integer()) ->
[poi()].
wrapping_functions(Document, Line, Column) ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this expected to return more than one function?

How is the behavior with funs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye :)
It will be always be a [] or a list with exactly one element. Returning a list allows to avoid caseing around in the calling code (if the list is empty, [] will be sent back to the client).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not taking funs into account at this stage.

reference_to_item(Reference) ->
#{uri := RefUri, range := RefRange} = Reference,
{ok, RefDoc} = els_utils:lookup_document(RefUri),
[WrappingPOI] = els_dt_document:wrapping_functions(RefDoc, RefRange),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this return more than one POI?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this case, this should always be one (see my comment above about why returning a list).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In your referenced comment you state zero or one. When zero, we get a crash.

@robertoaloi
Copy link
Member Author

I saw your comments only after the merge @TheGeorge , sorry about that 🙏
We can address a couple of them as follow ups.

alanz added a commit that referenced this pull request Jul 26, 2022
els_dt_document:wrapping_functions/2 can return zero or one items in a list.
Explicitly deal with both options.

See #1096 (comment)
alanz added a commit that referenced this pull request Jul 26, 2022
els_dt_document:wrapping_functions/2 can return zero or one items in a list.
Explicitly deal with both options.

See #1096 (comment)
alanz added a commit that referenced this pull request Jul 26, 2022
els_dt_document:wrapping_functions/2 can return zero or one items in a list.
Explicitly deal with both options.

See #1096 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Introduce support for Call Hierarchy
3 participants