Resolve Go To Definition targets through the workspace's current solution - #20462
xperiandri wants to merge 13 commits into
Conversation
✅ Release notes checked
|
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
a0e2ac3 to
e2cab44
Compare
This comment has been minimized.
This comment has been minimized.
|
🔍 Tooling Safety Check — Affects-Design-Time
|
T-Gro
left a comment
There was a problem hiding this comment.
🤖🕵️ If this fixes an issue or implements an RFC/suggestion, link it (Fixes #... when applicable). Otherwise, give a short management-level summary in simplified technical English: what user scenario improves and what this achieves.
Please apply this PR-description guidance. Remove the implementation inventory already visible in Files, but keep necessary scope, compatibility, and dependency caveats.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
e2cab44 to
ef4fe97
Compare
Head branch was pushed to by a user without write access
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ef4fe97 to
a82e2ec
Compare
|
@T-Gro I rebased and solved conflicts |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7db3dd1 to
6ce4cef
Compare
…r tests Test helpers so far put every synthetic file into one Roslyn project. CreateMultiProjectSolution creates one project per synthetic project with project references, the way VS wires project-to-project references; CreateMultiTargetSolution creates one project per target instance sharing the project path and the document paths, the way VS loads a multi-targeted project. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The document Roslyn hands to Go To Definition can come from a snapshot taken before every project of the solution finished loading. Deciding that a symbol is external because that snapshot has no document for its file sent F# to F# navigation into a generated signature, and the same lookup silently narrowed the scope of Find All References and Rename. Look the target up in the document's own solution first and in Workspace.CurrentSolution when it is missing, normalising the path and preferring the target-framework instance the origin project depends on. The branch of Go To Definition that already sits on the declaration moves into its own member. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…arget document Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
List.map followed by List.distinctBy allocates the mapped list and then the distinct one; a Seq pipeline materializes once, at Seq.toList. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… tuple CreateMultiProjectSolution and CreateMultiTargetSolution now both return a struct tuple, so callers destructure with the struct pattern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6ce4cef to
0c7c5c2
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved multi-target document selection and stale-solution rename/navigation issues remain.
Review effort: Lite
Findings: 1
What changed in this PR
Updates F# navigation and symbol resolution to use the workspace’s current solution when snapshots are stale.
Changes:
- Adds workspace-aware document and project resolution.
- Updates navigation, Find Usages, Rename, and symbol scoping.
- Adds multi-project regression tests and release notes.
| File | Summary |
|---|---|
vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs |
Adds multi-project and multi-target test helpers. |
vsintegration/tests/FSharp.Editor.Tests/GoToDefinitionServiceTests.fs |
Tests stale-snapshot navigation and symbol scope. |
vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs |
Resolves navigation targets through current solutions. |
vsintegration/src/FSharp.Editor/Navigation/FindUsagesService.fs |
Resolves declaration spans across solution documents. |
vsintegration/src/FSharp.Editor/LanguageService/Symbols.fs |
Uses workspace-aware documents for symbol scope. |
vsintegration/src/FSharp.Editor/LanguageService/SymbolHelpers.fs |
Resolves signature and implementation counterparts. |
vsintegration/src/FSharp.Editor/Common/CodeAnalysisExtensions.fs |
Adds document lookup and solution fallback helpers. |
docs/release-notes/.VisualStudio/18.vNext.md |
Documents the navigation fix. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| member document.TryGetSolutionDocumentFromPath(filePath: string) = | ||
| document.GetSolutionDocumentsWithFilePath filePath |> Seq.tryHeadV |
There was a problem hiding this comment.
Fixed in 98a1a20be3, by the route you suggest: TryGetSolutionDocumentFromPath now builds a range over the path and goes through TryGetSolutionDocumentFromFSharpRange, so one rule decides both — the origin's own project first, then a project that depends on the candidate's, then whatever is left.
It matters for exactly the three callers it has, and all three ask for the sibling of the document they start from: the .fs of a signature and the .fsi of an implementation in FindDefinitionAtPosition, and the counterpart file in SymbolHelpers. Each instance of a multi-targeted project holds that sibling and reads it under its own defines, so the answer has to come from the instance the origin belongs to.
Thirteen tests across GoToDefinitionServiceTests, FindReferences and the multi-target classes pass.
A sibling file looked up by path took whichever document came first, while the same lookup by range prefers the origin's project or one it depends on. The instances of a multi-targeted project hold the same file and read it under their own defines, so the path lookup now goes through that rule too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Go To Definition on a symbol in another F# project of the same solution opened a generated signature ("F# Metadata") instead of the source, and Go To Implementation reported nothing, while a large solution was still loading. Reproduced with the in-box tools on Visual Studio 18 Insiders on a solution with 135 project instances.
The navigation service decides a symbol is external by looking up its file in the
Solutionsnapshot it was handed, which can be one taken before every project finished loading. The same stale lookup narrowed Find All References and Rename to the wrong scope, and could miss declaration spans. The lookup now checks the document's own solution first — which keeps unsaved buffer text intact — and falls back to the workspace's current solution, normalising the path and preferring the target-framework instance the origin project depends on.🤖 Generated with Claude Code