diff --git a/src/Compiler/Service/ItemKey.fs b/src/Compiler/Service/ItemKey.fs index 68977c68f1a..6c24777c00c 100644 --- a/src/Compiler/Service/ItemKey.fs +++ b/src/Compiler/Service/ItemKey.fs @@ -234,9 +234,9 @@ and [] ItemKeyStoreBuilder() = | TType_forall (_, ty) -> writeType false ty | TType_app (tcref, _, _) -> - match tcref.TypeAbbrev with - | Some ty -> writeType isStandalone ty - | None -> writeEntityRef tcref + match isStandalone, tcref.TypeAbbrev with + | false, Some ty -> writeType false ty + | _ -> writeEntityRef tcref | TType_tuple (_, tinst) -> writeString ItemKeyTags.typeTuple diff --git a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/FindReferences.fs b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/FindReferences.fs index 41709e2fe74..c4e53d014c6 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharpChecker/FindReferences.fs +++ b/tests/FSharp.Compiler.ComponentTests/FSharpChecker/FindReferences.fs @@ -3,6 +3,7 @@ open Xunit open FSharp.Compiler.CodeAnalysis open FSharp.Test.ProjectGeneration +open FSharp.Test.ProjectGeneration.Helpers type Occurence = Definition | InType | Use @@ -198,7 +199,7 @@ let foo x = 5""" }) } [] -let ``We find a type that has been aliased`` () = +let ``We find values of a type that has been aliased`` () = let project = SyntheticProject.Create("TypeAliasTest", { sourceFile "First" [] with @@ -218,3 +219,24 @@ let ``We find a type that has been aliased`` () = "FileSecond.fs", 6, 12, 29 ]) } + +[] +let ``We don't find type aliases for a type`` () = + + let source = """ +type MyType = + member _.foo = "boo" + member x.this : mytype = x +and mytype = MyType +""" + + let fileName, options, checker = singleFileChecker source + + let symbolUse = getSymbolUse fileName source "MyType" options checker |> Async.RunSynchronously + + checker.FindBackgroundReferencesInFile(fileName, options, symbolUse.Symbol, fastCheck = true) + |> Async.RunSynchronously + |> expectToFind [ + fileName, 2, 5, 11 + fileName, 5, 13, 19 + ] diff --git a/tests/FSharp.Test.Utilities/ProjectGeneration.fs b/tests/FSharp.Test.Utilities/ProjectGeneration.fs index c67a9e6c5b3..e029d382248 100644 --- a/tests/FSharp.Test.Utilities/ProjectGeneration.fs +++ b/tests/FSharp.Test.Utilities/ProjectGeneration.fs @@ -370,10 +370,10 @@ module ProjectOperations = let actual = foundRanges |> Seq.map (fun r -> Path.GetFileName(r.FileName), r.StartLine, r.StartColumn, r.EndColumn) - |> Seq.sortBy (fun (file, _, _, _) -> file) + |> Seq.sort |> Seq.toArray - Assert.Equal<(string * int * int * int)[]>(expected |> Seq.toArray, actual) + Assert.Equal<(string * int * int * int)[]>(expected |> Seq.sort |> Seq.toArray, actual) let rec saveProject (p: SyntheticProject) generateSignatureFiles checker = async { @@ -401,6 +401,65 @@ module ProjectOperations = } +module Helpers = + + let getSymbolUse fileName (source: string) (symbolName: string) options (checker: FSharpChecker) = + async { + let index = source.IndexOf symbolName + let line = source |> Seq.take index |> Seq.where ((=) '\n') |> Seq.length + let fullLine = source.Split '\n' |> Array.item line + let colAtEndOfNames = fullLine.IndexOf symbolName + symbolName.Length + + let! results = checker.ParseAndCheckFileInProject( + fileName, 0, SourceText.ofString source, options) + + let typeCheckResults = getTypeCheckResult results + + let symbolUse = + typeCheckResults.GetSymbolUseAtLocation(line + 1, colAtEndOfNames, fullLine, [symbolName]) + + return symbolUse |> Option.defaultWith (fun () -> + failwith $"No symbol found in {fileName} at {line}:{colAtEndOfNames}\nFile contents:\n\n{source}\n") + } + + let singleFileChecker source = + + let fileName = "test.fs" + + let getSource _ = source |> SourceText.ofString |> Some + + let checker = FSharpChecker.Create( + keepAllBackgroundSymbolUses = false, + enableBackgroundItemKeyStoreAndSemanticClassification = true, + enablePartialTypeChecking = true, + captureIdentifiersWhenParsing = true, + documentSource = DocumentSource.Custom getSource) + + let options = + let baseOptions, _ = + checker.GetProjectOptionsFromScript( + fileName, + SourceText.ofString "", + assumeDotNetFramework = false + ) + |> Async.RunSynchronously + + { baseOptions with + ProjectFileName = "project" + ProjectId = None + SourceFiles = [|fileName|] + IsIncompleteTypeCheckEnvironment = false + UseScriptResolutionRules = false + LoadTime = DateTime() + UnresolvedReferences = None + OriginalLoadReferences = [] + Stamp = None } + + fileName, options, checker + +open Helpers + + type WorkflowContext = { Project: SyntheticProject Signatures: Map @@ -601,26 +660,12 @@ type ProjectWorkflowBuilder member this.PlaceCursor(workflow: Async, fileId, symbolName: string) = async { let! ctx = workflow - - let source = renderSourceFile ctx.Project (ctx.Project.Find fileId) - let index = source.IndexOf symbolName - let line = source |> Seq.take index |> Seq.where ((=) '\n') |> Seq.length - let fullLine = source.Split '\n' |> Array.item line - let colAtEndOfNames = fullLine.IndexOf symbolName + symbolName.Length - - let! results = checkFile fileId ctx.Project checker - let typeCheckResults = getTypeCheckResult results - - let su = - typeCheckResults.GetSymbolUseAtLocation(line + 1, colAtEndOfNames, fullLine, [symbolName]) - - if su.IsNone then - let file = ctx.Project.Find fileId - - failwith - $"No symbol found in {file.FileName} at {line}:{colAtEndOfNames}\nFile contents:\n\n{source}\n" - - return { ctx with Cursor = su } + let file = ctx.Project.Find fileId + let fileName = ctx.Project.ProjectDir ++ file.FileName + let source = renderSourceFile ctx.Project file + let options= ctx.Project.GetProjectOptions checker + let! su = getSymbolUse fileName source symbolName options checker + return { ctx with Cursor = Some su } } /// Find all references within a single file, results are provided to the 'processResults' function