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
VS Go to definition from C# to F# #14377
VS Go to definition from C# to F# #14377
Conversation
This is ready for the first iteration, please see comments in the OP, regarding tests and what's supported. |
let mutable locations = Seq.empty | ||
|
||
for project in projects do |
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.
We could probably do this in parallel.
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 is just a fool-proof, we expect it always be only a single project, parallel then will give you a bunch of overhead
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.
Right, didn't notice where it's coming from. Is it even theoretically possible there will be multiple projects with the same assembly name? Because maybe you could replace filter
with tryFind
and it would be a bit simpler.
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.
Is it even theoretically possible there will be multiple projects with the same assembly name?
Very unlikely, I have never seen it before.
Because maybe you could replace
filter
withtryFind
and it would be a bit simpler.
I'll see how it looks with option
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.
With option it could look something like this (After also adding DocCommentId.EntityPath
):
let project = workspace.CurrentSolution.Projects |> Seq.tryFind (fun p -> p.IsFSharp && p.AssemblyName = assemblyName)
let locations =
project
|> Option.map (fun project ->
let! checker, _, _, options = project.GetFSharpCompilationOptionsAsync(cancellationToken)
let! result = checker.ParseAndCheckProject(options)
let entity = path.EntityPath |> result.AssemblySignature.FindEntityByPath
match path with
| DocCommentId.Member ({ MemberOrValName = memberOrVal; GenericParameters = genericParametersCount }, memberType) ->
entity |> tryFindVal memberOrVal documentationCommentId memberType genericParametersCount
| DocCommentId.Field { MemberOrValName = memberOrVal } ->
entity |> tryFindFieldByName memberOrVal
| DocCommentId.Type _ ->
Seq.singleton entity.DeclarationLocation
| DocCommentId.None ->
Seq.empty
|> Seq.map (fun m -> (m, project)))
|> Option.defaultValue Seq.empty
A bit easier to see what's going on with arrows only going in one direction :)
let entity = result.AssemblySignature.FindEntityByPath (entityPath) | ||
match entity with | ||
| Some e -> |
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.
probably should replace with Option.map/iter or something
Annoying question - any idea/chance to test this? |
No, I've asked the same question in the first paragraph |
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.
Looks pretty good, no tests yet though. (That's rich coming from me :-))
Yeah, that's the question - I'm not yet entirely sure how to do that. |
…ytovskii/fsharp into vs-external-goto-definition
Ok, this is ready, I failed (gave up really) to add proper tests in headless VS, but added to the important part - parser for doccomment id. |
WIP
VS Go to definition from C# to F#let mutable locations = Seq.empty | ||
|
||
for project in projects do |
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.
With option it could look something like this (After also adding DocCommentId.EntityPath
):
let project = workspace.CurrentSolution.Projects |> Seq.tryFind (fun p -> p.IsFSharp && p.AssemblyName = assemblyName)
let locations =
project
|> Option.map (fun project ->
let! checker, _, _, options = project.GetFSharpCompilationOptionsAsync(cancellationToken)
let! result = checker.ParseAndCheckProject(options)
let entity = path.EntityPath |> result.AssemblySignature.FindEntityByPath
match path with
| DocCommentId.Member ({ MemberOrValName = memberOrVal; GenericParameters = genericParametersCount }, memberType) ->
entity |> tryFindVal memberOrVal documentationCommentId memberType genericParametersCount
| DocCommentId.Field { MemberOrValName = memberOrVal } ->
entity |> tryFindFieldByName memberOrVal
| DocCommentId.Type _ ->
Seq.singleton entity.DeclarationLocation
| DocCommentId.None ->
Seq.empty
|> Seq.map (fun m -> (m, project)))
|> Option.defaultValue Seq.empty
A bit easier to see what's going on with arrows only going in one direction :)
T:
prefix for typesT:N.X.Nested
- typeT:N.X.D
- delegateM:
prefix is for methodsM:N.X.#ctor
- constructorM:N.X.#ctor(System.Int32)
- constructor with one parameterM:N.X.f
- method with unit parameterM:N.X.bb(System.String,System.Int32@)
- method with two parametersM:N.X.gg(System.Int16[],System.Int32[0:,0:])
- method with two parameters, 1d and 2d arrayM:N.X.op_Addition(N.X,N.X)
- operatorM:N.X.op_Explicit(N.X)~System.Int32
- operator with return typeM:N.GenericMethod.WithNestedType``1(N.GenericType{``0}.NestedType)
- generic type with one parameterM:N.GenericMethod.WithIntOfNestedType``1(N.GenericType{System.Int32}.NestedType)
- generic type with one parameterM:N.X.N#IX{N#KVP{System#String,System#Int32}}#IXA(N.KVP{System.String,System.Int32})
- explicit interface implementationE:
prefix for eventsE:N.X.d
.F:
prefix for fieldsF:N.X.q
- fieldP:
prefix for propertiesP:N.X.prop
- property with getter and setterSupported scenarios:
The following are out of scope for this 1st implementation:
Next steps:
IStreamingFindUsagesPresenter
when we can't distinguish which exact method/function to go to.