Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
([PR #19724](https://github.com/dotnet/fsharp/pull/19724))
* Emit debug points at a stack-empty position ([PR #19877](https://github.com/dotnet/fsharp/pull/19877))
* Fix spurious XmlDoc warnings (unknown parameter / no documentation for parameter) under `--warnon:3390` when a get/set property documents the full parameter set across both accessors. ([Issue #13684](https://github.com/dotnet/fsharp/issues/13684), [PR #19884](https://github.com/dotnet/fsharp/pull/19884))
* Fix Go-to-Definition for provided constructors that lack `TypeProviderDefinitionLocationAttribute`. Navigation now falls back to the declaring type instead of silently failing. ([Issue #5538](https://github.com/dotnet/fsharp/issues/5538), [PR #19917](https://github.com/dotnet/fsharp/pull/19917))

### Added

Expand Down
12 changes: 9 additions & 3 deletions src/Compiler/Symbols/SymbolHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,28 @@ module internal SymbolHelpers =
let rangeOfPropInfo preferFlag (pinfo: PropInfo) =
match pinfo with
#if !NO_TYPEPROVIDERS
| ProvidedProp(_, pi, _) -> Construct.ComputeDefinitionLocationOfProvidedItem pi
| ProvidedProp(_, pi, _) ->
Construct.ComputeDefinitionLocationOfProvidedItem pi
|> Option.orElseWith (fun () -> Some(rangeOfEntityRef preferFlag pinfo.DeclaringTyconRef))
#endif
| _ -> pinfo.ArbitraryValRef |> Option.map (rangeOfValRef preferFlag)

let rangeOfMethInfo (g: TcGlobals) preferFlag (minfo: MethInfo) =
match minfo with
#if !NO_TYPEPROVIDERS
| ProvidedMeth(_, mi, _, _) -> Construct.ComputeDefinitionLocationOfProvidedItem mi
| ProvidedMeth(_, mi, _, _) ->
Construct.ComputeDefinitionLocationOfProvidedItem mi
|> Option.orElseWith (fun () -> Some(rangeOfEntityRef preferFlag minfo.DeclaringTyconRef))
#endif
| DefaultStructCtor(_, AppTy g (tcref, _)) -> Some(rangeOfEntityRef preferFlag tcref)
| _ -> minfo.ArbitraryValRef |> Option.map (rangeOfValRef preferFlag)

let rangeOfEventInfo preferFlag (einfo: EventInfo) =
match einfo with
#if !NO_TYPEPROVIDERS
| ProvidedEvent (_, ei, _) -> Construct.ComputeDefinitionLocationOfProvidedItem ei
| ProvidedEvent(_, ei, _) ->
Construct.ComputeDefinitionLocationOfProvidedItem ei
|> Option.orElseWith (fun () -> Some(rangeOfEntityRef preferFlag einfo.DeclaringTyconRef))
#endif
| _ -> einfo.ArbitraryValRef |> Option.map (rangeOfValRef preferFlag)

Expand Down
78 changes: 78 additions & 0 deletions tests/FSharp.Compiler.Service.Tests/ProjectAnalysisTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3788,6 +3788,84 @@ let ``Test Project25 symbol uses of type-provided members`` () =
[| ("file1", ((5, 8), (5, 21))) // line 5: T().DoNothing
("file1", ((10, 8), (10, 26))) |] // line 10: MyType().DoNothing

[<Fact; RunTestCasesInSequence>]
let ``GetDeclarationLocation on a provided-ctor without DefinitionLocationAttribute returns DeclFound (regression #5538)`` () =
let wholeProjectResults =
Project25.checker.ParseAndCheckProject(Project25.options.Value)
|> Async.RunImmediate

wholeProjectResults.Diagnostics.Length |> shouldEqual 0

let parseResults, checkAnswer =
Project25.checker.ParseAndCheckFileInProject(
Project25.fileName1,
0,
SourceText.ofString (FileSystem.OpenFileForReadShim(Project25.fileName1).ReadAllText()),
Project25.options.Value)
|> Async.RunImmediate

let checkResults =
match checkAnswer with
| FSharpCheckFileAnswer.Succeeded r -> r
| _ -> failwith "type-check did not finish"

ignore parseResults

// line 5: `let _ = T().DoNothing()`
// col-index 8 is `T`, end of identifier is col 9.
// `T` at this position resolves to Item.CtorGroup(ProvidedMeth :: _),
// which is the broken case in issue #5538.
let declLocation =
checkResults.GetDeclarationLocation(
line = 5,
colAtEndOfNames = 9,
lineText = "let _ = T().DoNothing()",
names = [ "T" ])

match declLocation with
| FindDeclResult.DeclFound _ -> ()
| FindDeclResult.DeclNotFound reason ->
failwithf "expected DeclFound for provided-ctor `T()`, got DeclNotFound %A" reason
| FindDeclResult.ExternalDecl _ ->
failwith "expected DeclFound for provided-ctor `T()`, got ExternalDecl"

[<Fact; RunTestCasesInSequence>]
let ``GetDeclarationLocation on a provided-ctor invoked through the original provided name returns DeclFound (regression #5538)`` () =
let wholeProjectResults =
Project25.checker.ParseAndCheckProject(Project25.options.Value)
|> Async.RunImmediate

wholeProjectResults.Diagnostics.Length |> shouldEqual 0

let _, checkAnswer =
Project25.checker.ParseAndCheckFileInProject(
Project25.fileName1,
0,
SourceText.ofString (FileSystem.OpenFileForReadShim(Project25.fileName1).ReadAllText()),
Project25.options.Value)
|> Async.RunImmediate

let checkResults =
match checkAnswer with
| FSharpCheckFileAnswer.Succeeded r -> r
| _ -> failwith "type-check did not finish"

// line 10: `let _ = MyType().DoNothing()`
// col-index 8 is `M`, end of identifier `MyType` is col 14.
let declLocation =
checkResults.GetDeclarationLocation(
line = 10,
colAtEndOfNames = 14,
lineText = "let _ = MyType().DoNothing()",
names = [ "MyType" ])

match declLocation with
| FindDeclResult.DeclFound _ -> ()
| FindDeclResult.DeclNotFound reason ->
failwithf "expected DeclFound for provided-ctor `MyType()`, got DeclNotFound %A" reason
| FindDeclResult.ExternalDecl _ ->
failwith "expected DeclFound for provided-ctor `MyType()`, got ExternalDecl"

[<Fact; RunTestCasesInSequence>]
let ``Test Project25 symbol uses of type-provided types`` () =
let wholeProjectResults = Project25.checker.ParseAndCheckProject(Project25.options.Value) |> Async.RunImmediate
Expand Down
Loading