Skip to content

Resolve Go To Definition targets through the workspace's current solution - #20462

Open
xperiandri wants to merge 4 commits into
dotnet:mainfrom
xperiandri:fix/gtd-stale-solution
Open

Resolve Go To Definition targets through the workspace's current solution#20462
xperiandri wants to merge 4 commits into
dotnet:mainfrom
xperiandri:fix/gtd-stale-solution

Conversation

@xperiandri

Copy link
Copy Markdown
Contributor

Description

Go To Definition in an F# file, on a symbol declared in another F# project of the same solution, opened a generated signature (the "F# Metadata" document) instead of the source, and Go To Implementation reported nothing. Reproduced with the in-box tools on Visual Studio 18 Insiders while a large solution (135 project instances) was still loading.

Root cause, measured in the debugger: GoToDefinition.FindDefinitionAtPosition decides that a symbol is external when originDocument.Project.Solution has no document for the file FCS reports. The Document Roslyn hands to the navigation service can come from a snapshot taken before every project finished loading: for the same path, originDocument.Project.Solution.GetDocumentIdsWithFilePath returned 0 documents while Workspace.CurrentSolution.GetDocumentIdsWithFilePath returned 2. Every later lookup in that method (TryGetDocumentFromPath for the signature/implementation counterparts) used the same snapshot, so even a symbol that passed the first check could end in a silent no-op. The same lookup in GetSymbolScope narrowed the scope of Find All References and Rename, and rangeToDocumentSpans could miss declaration spans.

Fix: Document gains TryFindInSolutions, GetSolutionDocumentsWithFilePath, TryGetSolutionDocumentFromPath and TryGetSolutionDocumentFromFSharpRange (CodeAnalysisExtensions.fs). They look in the document's own solution first, which keeps forks carrying unsaved buffer text intact, and in Workspace.CurrentSolution when that has nothing; they normalise the path (the old ContainsDocumentWithFilePath check did not) and prefer the target-framework instance the origin project depends on. All lookups in GoToDefinition.fs, the scope computation in Symbols.fs, the signature/implementation counterpart lookup in SymbolHelpers.fs and rangeToDocumentSpans in FindUsagesService.fs use them. The "caret is already on the declaration" branch of FindDefinitionAtPosition moves into FindCounterpartOfDeclarationAtCaret, and the repeated "declaration in this implementation document → navigable item" sequence into FindNavigableDeclarationIn.

Tests: RoslynTestHelpers can now build a Roslyn solution with several F# projects wired by project references (CreateMultiProjectSolution) and one with several target-framework instances of a single project (CreateMultiTargetSolution); the F# options come from the same SyntheticProject, so FCS gets in-memory project references the way it does in VS. GoToDefinitionServiceTests reproduces the measured condition — the origin document taken from a solution fork that lacks the library document while the workspace has it — and checks that the lookup, FindDefinitionAtPosition and GetSymbolScope all resolve the library, plus a control that a symbol whose file is in no solution is still reported as external.

Checklist

  • Test cases added

  • Performance benchmarks added in case of performance changes

  • Release notes entry updated:

    Please make sure to add an entry with short succinct description of the change as well as link to this pull request to the respective release notes file, if applicable.

    Release notes files:

    • If anything under src/Compiler has been changed, please make sure to make an entry in docs/release-notes/.FSharp.Compiler.Service/<version>.md, where <version> is usually "highest" one, e.g. 42.8.200
    • If language feature was added (i.e. LanguageFeatures.fsi was changed), please add it to docs/release-notes/.Language/preview.md
    • If a change to FSharp.Core was made, please make sure to edit docs/release-notes/.FSharp.Core/<version>.md where version is "highest" one, e.g. 8.0.200.

    Information about the release notes entries format can be found in the documentation.
    Example:

    If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.

🤖 Generated with Claude Code

xperiandri and others added 3 commits September 6, 2026 09:43
…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>
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

❗ Release notes required

You can open this PR in browser to add release notes: open in github.dev


✅ Found changes and release notes in following paths:

Change path Release notes path Description
`vsintegration/src` docs/release-notes/.VisualStudio/18.vNext.md

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

1 participant