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

#1097 incoming call hierarchy #1164

Merged
merged 13 commits into from
Oct 10, 2023

Conversation

TheAngryByrd
Copy link
Member

@TheAngryByrd TheAngryByrd commented Sep 14, 2023

Definitely need a parsing/typed expert here.

  • Outgoing calls
    • I was able to use references and top level navigation items, but that comes with missing fidelity into nested expressions.
  • Incoming calls
    • Ranges aren't right but I wanted to get something up
    • Needed the type tree here to get function/method calls but that causes keepAssemblyContents to need to be set to true in the FSharpChecker (losing enablePartialTypeChecking in the process since they're mutually exclusive).

WHAT

🤖 Generated by Copilot at c68553f

This pull request enhances the F# language server by adding the call hierarchy feature and by refactoring the file management logic. It modifies the AdaptiveFSharpLspServer type to keep track of both open and closed files and to use this information for various language features. It also updates the Common.fs file to enable the CallHierarchyProvider capability.

🤖 Generated by Copilot at c68553f

CallHierarchyProvider
Enhances language server
Autumn of refactor

📞♻️🔎

WHY

HOW

🤖 Generated by Copilot at c68553f

  • Refactor the AdaptiveFSharpLspServer type to store and update information about both open and closed F# files in the workspace, and to simplify the logic of getting the project options, parsed results, and declarations for any file path. (link, link, link, link, link, link, link)
  • Implement the CallHierarchyIncomingCalls and TextDocumentPrepareCallHierarchy methods in the AdaptiveFSharpLspServer type to provide the functionality of finding the callers and callees of a given symbol in the workspace, using the existing parsing, type checking, and symbol use logic. (link)
  • Modify the workspaceSymbol function in the AdaptiveFSharpLspServer type to use the new function getAllDeclarations instead of the old function getAllOpenDeclarations, to improve the accuracy of the workspace symbol search feature. (link)
  • Add the CallHierarchyProvider capability to the Helpers module in the Common.fs file, to enable the language server to advertise its support for the call hierarchy feature to the LSP client. (link)
  • Remove an empty line from the code in the AdaptiveFSharpLspServer type, likely as a formatting or style adjustment. (link)

@TheAngryByrd TheAngryByrd changed the title 1097 call hierarchy 1 #1097 call hierarchy Sep 14, 2023
Copy link
Contributor

@baronfel baronfel left a comment

Choose a reason for hiding this comment

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

I played around with this and it already feels really great to use, but I confess that I have a hard time reasoning about the 'directions' (incoming/outgoing) and matching them to the FCS calls going on here. I'm also having a hard time seeing where the limitations/incorrect ranges are.

The feature itself is very exciting - a was using it in my 'normal' dev workflow for about an hour, so I can see it quickly becoming a go-to to help investigate deep chains.

|| x.IsPropertyGetterMethod
|| x.IsPropertySetterMethod
// TODO get bodyRange and check if it is in the range
range.Start.Line >= pos.Line && lookingFor
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you trying to emulate visibility here? So checking for other items in this file that are after the trigger position that are one of these types? I'm having a hard time wrapping my head around the 'direction' of the incoming/outgoing part so I'm very slow here :)

As it is, it kinda feels like this filter could be pushed down into the traversal function you have, so that we don't create/allocate so much.

Copy link
Member Author

Choose a reason for hiding this comment

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

Anything in the Outgoing implementation was some fever dream coding at like 11pm so I don’t know.

@TheAngryByrd
Copy link
Member Author

I confess that I have a hard time reasoning about the 'directions' (incoming/outgoing) and matching them to the FCS calls going on here.

Incoming is like walking the call tree back to its roots. (So a recursive fine all references essentially).

Outgoing is like walking the call tree to its leaves. (So a recursive find all functions called).

I might actually punt on the Outgoing for the moment because it isn’t really possible without the typed tree (as far as I can tell), As that disables partial type checking.

@TheAngryByrd TheAngryByrd force-pushed the 1097-call-hierarchy-1 branch 2 times, most recently from 1ea071b to 5c3953e Compare October 9, 2023 02:19
@TheAngryByrd
Copy link
Member Author

  • IncomingCalls is pretty much completed. I could add more tests here.
  • I removed OutgoingCalls because of what I outlined previously. Unless there's something I've missed, I don't think it's an easy fix.
  • I was bad and did some extra work here (can move to own branch if necessary)
    • I cleaned up AdaptiveExtensions a bit
    • I added a Version to DiagnosticCollection. We occasionally get TextSync issues, while I think there's something else going on, I think stopping it at the DiagnosticCollection will stop it from being a problem.

@TheAngryByrd TheAngryByrd marked this pull request as ready for review October 9, 2023 02:41
@baronfel baronfel changed the title #1097 call hierarchy #1097 incoming call hierarchy Oct 9, 2023
Comment on lines +607 to +610
if ct.IsCancellationRequested then
Task.FromCanceled<_>(ct)
else
Task.FromResult(mapping a ct))
Copy link
Contributor

Choose a reason for hiding this comment

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

oooohhhh, this is subtle. good spot.

Comment on lines 21 to 31
// type LspPos = Ionide.LanguageServerProtocol.Types.Position
// type LspRange = Ionide.LanguageServerProtocol.Types.Range

module Lsp = Ionide.LanguageServerProtocol.Types

module LspRange =
// static member Create (start: LspPos) (end_: LspPos) : LspRange =
// { Start = start; End = end_ }
let Zero: Lsp.Range =
{ Start = { Line = 0; Character = 0 }
End = { Line = 0; Character = 0 } }
Copy link
Member Author

Choose a reason for hiding this comment

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

I think this should be removed. I was trying to figure out which things were 0 and 1 based.

| FSharpImplementationFileDeclaration.InitAction(e) -> visitExpr f e


fileDecls |> Seq.iter (visitDeclaration memberCallHandler)
Copy link
Member Author

Choose a reason for hiding this comment

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

Could delete this also since I punted on Outgoing for now.


[<RequireQualifiedAccess>]
type NotificationEvent =
| ParseError of errors: FSharpDiagnostic[] * file: string<LocalPath>
| ParseError of errors: FSharpDiagnostic[] * file: string<LocalPath> * version: int
Copy link
Contributor

Choose a reason for hiding this comment

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

I really wonder if we need some kind of 'file@version' abstraction here. Not now, but just immediately comes to mind.

@@ -6,7 +6,7 @@ Expecto
Expecto.Diff
Microsoft.NET.Test.Sdk
YoloDev.Expecto.TestSdk
AltCover
# AltCover
Copy link
Member Author

Choose a reason for hiding this comment

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

Was getting annoyed at test times taking a long time due to this coverage hooking. Need to revert.

Comment on lines +81 to +87
| Add(source, version, diags) ->
match Map.tryFind source state with
| Some(oldVersion, _) when oldVersion > version -> return! loop state
| _ ->
let newState = state |> Map.add source (version, diags)
do! send uri newState
return! loop newState
Copy link
Member Author

Choose a reason for hiding this comment

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

Added to prevent out of date diagnostics possibly updating a file.

@TheAngryByrd TheAngryByrd merged commit f328907 into ionide:main Oct 10, 2023
9 checks passed
nojaf pushed a commit to nojaf/FsAutoComplete that referenced this pull request Nov 3, 2023
* WIP Incoming Hierarchy

* Call Hierarchy Incoming calls

* outgoing call poc

* Using TryRangeOfNameOfNearestOuterBindingContainingPos for CallHierarchyIncomingCalls

* Fixing incoming call hierarchy plus tests

* Fixing incoming call typechecks

* formatting

* Fixing up Adaptive Cancellation

* Adding Versioning to DiagnosticCollection

* Fixing tests

* cleanup

* cleanup

* revert removing altcover

---------

Co-authored-by: Chet Husk <[email protected]>
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.

2 participants