From f79b95d35d71c14f876a9a657bc111dc60537a31 Mon Sep 17 00:00:00 2001 From: serefarikan Date: Sun, 21 Dec 2025 17:26:44 +0000 Subject: [PATCH] Fix SourceLink go-to-definition failure on .NET 10 When FSharp.Core is built on Linux (as in .NET 10), the PDB contains Linux-style paths. FSAC's getFileName was calling Path.GetFileName on non-Windows, which stripped the directory portion, causing the PDB document lookup to fail. Fix: - getFileName: Keep full FCS path, just normalize backslashes - compareRepoPath: Use suffix matching to handle workspace prefixes --- .../ParseAndCheckResults.fs | 9 ++-- src/FsAutoComplete.Core/Sourcelink.fs | 46 +++++++++++++++---- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/FsAutoComplete.Core/ParseAndCheckResults.fs b/src/FsAutoComplete.Core/ParseAndCheckResults.fs index cfbf57f54..72cdcb023 100644 --- a/src/FsAutoComplete.Core/ParseAndCheckResults.fs +++ b/src/FsAutoComplete.Core/ParseAndCheckResults.fs @@ -43,10 +43,11 @@ type ParseAndCheckResults let logger = LogProvider.getLoggerByName "ParseAndCheckResults" let getFileName (loc: range) = - if Ionide.ProjInfo.ProjectSystem.Environment.isWindows then - UMX.tag loc.FileName - else - UMX.tag (Path.GetFileName loc.FileName) + // Keep the full FCS path, just normalize backslashes to forward slashes. + // FCS may prepend a workspace prefix if the PDB path isn't absolute on this platform. + // The comparison in Sourcelink.compareRepoPath will handle the prefix via suffix matching. + let normalized = loc.FileName.Replace('\\', '/') + UMX.tag normalized member __.TryFindDeclaration (pos: Position) (lineStr: LineStr) = async { diff --git a/src/FsAutoComplete.Core/Sourcelink.fs b/src/FsAutoComplete.Core/Sourcelink.fs index 6a427da56..11989b41a 100644 --- a/src/FsAutoComplete.Core/Sourcelink.fs +++ b/src/FsAutoComplete.Core/Sourcelink.fs @@ -46,16 +46,42 @@ type private Document = Language: System.Guid IsEmbedded: bool } -let private compareRepoPath (d: Document) targetFile = - if Environment.isWindows then - let s = UMX.untag d.Name - let s' = normalizePath s |> UMX.untag - let s' = UMX.tag s' - s' = targetFile - else - let t = UMX.untag targetFile |> UMX.tag - let t' = normalizeRepoPath t - normalizeRepoPath d.Name = t' +let private compareRepoPath (d: Document) fcsPath = + // The fcsPath is the full path from FCS (normalized, backslashes converted to forward slashes). + // FCS may prepend a workspace prefix if the PDB path wasn't absolute on this platform. + // The d.Name is a PDB document entry (the original path from when the DLL was compiled). + // + // The PDB document should be a SUFFIX of (or equal to) the FCS path: + // - FCS path: /workspaces/project/D:/a/_work/1/s/src/FSharp.Core/list.fs + // - PDB doc: D:/a/_work/1/s/src/FSharp.Core/list.fs + // → fcsPath.EndsWith("/" + pdbDoc) = true + // + // - FCS path: /__w/1/s/src/fsharp/src/FSharp.Core/list.fs + // - PDB doc: /__w/1/s/src/fsharp/src/FSharp.Core/list.fs + // → fcsPath == pdbDoc = true + + let docNormalized: string = + if Environment.isWindows then + let s = UMX.untag d.Name + let normalized = normalizePath s |> UMX.untag + UMX.tag normalized + else + normalizeRepoPath d.Name + + let fcsNormalized: string = + if Environment.isWindows then + fcsPath + else + let t: string = UMX.untag fcsPath + let tagged: string = UMX.tag t + normalizeRepoPath tagged + + let docStr = UMX.untag docNormalized + let fcsStr = UMX.untag fcsNormalized + + // PDB doc should be suffix of (or equal to) FCS path + fcsStr = docStr + || fcsStr.EndsWith("/" + docStr, System.StringComparison.Ordinal) let private pdbForDll (dllPath: string) = UMX.tag (Path.ChangeExtension(UMX.untag dllPath, ".pdb"))