Skip to content
Merged
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
8 changes: 7 additions & 1 deletion src/Compiler/Checking/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2078,7 +2078,13 @@ type TcResultsSinkImpl(tcGlobals, ?sourceText: ISourceText) =

let keyOpt =
match item with
| Item.Value vref -> Some (endPos, vref.DisplayName)
| Item.Value vref ->
if (vref.IsPropertyGetterMethod || vref.IsPropertySetterMethod)
&& not (System.String.IsNullOrWhiteSpace vref.Id.idText) then
// We don't want to skip a symbol if both getter and setter are present.
Some (endPos, vref.Id.idText)
else
Some (endPos, vref.DisplayName)
| Item.OtherName (ident = Some id) -> Some (endPos, id.idText)
| _ -> None

Expand Down
1 change: 1 addition & 0 deletions src/Compiler/Service/FSharpCheckerResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ type internal TypeCheckInfo
||
#endif
nameMatchesResidue tcref.DisplayName)
| Item.Value v when (v.IsPropertyGetterMethod || v.IsPropertySetterMethod) -> residue = v.Id.idText || residue = n1
| _ -> residue = n1)

/// Post-filter items to make sure they have precisely the right name
Expand Down
32 changes: 22 additions & 10 deletions tests/service/ProjectAnalysisTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3443,27 +3443,33 @@ let ``Test Project24 all symbols`` () =
("``.ctor``", "file1", ((4, 5), (4, 23)), ["defn"], ["member"; "ctor"]);
("NameGetSet", "file1", ((5, 13), (5, 23)), ["defn"], ["member"; "getter"]);
("int", "file1", ((7, 20), (7, 23)), ["type"], ["abbrev"]);
("NameGetSet", "file1", ((5, 13), (5, 23)), ["defn"], ["member"; "setter"]);
("NameGet", "file1", ((9, 13), (9, 20)), ["defn"], ["member"; "getter"]);
("int", "file1", ((11, 20), (11, 23)), ["type"], ["abbrev"]);
("NameGet", "file1", ((9, 13), (9, 20)), ["defn"], ["member"; "setter"]);
("int", "file1", ((14, 21), (14, 24)), ["type"], ["abbrev"]);
("NameSet", "file1", ((13, 13), (13, 20)), ["defn"], ["member"; "setter"]);
("StaticNameGetSet", "file1", ((16, 18), (16, 34)), ["defn"],
["member"; "getter"]);
("int", "file1", ((18, 20), (18, 23)), ["type"], ["abbrev"]);
("int", "file1", ((18, 20), (18, 23)), ["type"], ["abbrev"])
("StaticNameGetSet", "file1", ((16, 18), (16, 34)), ["defn"], ["member"; "setter"]);
("StaticNameGet", "file1", ((20, 18), (20, 31)), ["defn"],
["member"; "getter"]);
("int", "file1", ((22, 20), (22, 23)), ["type"], ["abbrev"]);
("int", "file1", ((22, 20), (22, 23)), ["type"], ["abbrev"])
("StaticNameGet", "file1", ((20, 18), (20, 31)), ["defn"], ["member"; "setter"]);
("int", "file1", ((25, 21), (25, 24)), ["type"], ["abbrev"]);
("StaticNameSet", "file1", ((24, 18), (24, 31)), ["defn"],
["member"; "setter"]);
("AutoPropGet", "file1", ((27, 15), (27, 26)), ["defn"],
["member"; "getter"]);
("AutoPropGetSet", "file1", ((28, 15), (28, 29)), ["defn"],
["member"; "getter"]);
("AutoPropGetSet", "file1", ((28, 15), (28, 29)), ["defn"], ["member"; "setter"])
("StaticAutoPropGet", "file1", ((30, 22), (30, 39)), ["defn"],
["member"; "getter"]);
("StaticAutoPropGetSet", "file1", ((31, 22), (31, 42)), ["defn"],
["member"; "getter"]);
["member"; "getter"])
("StaticAutoPropGetSet", "file1", ((31, 22), (31, 42)), ["defn"], ["member"; "setter"]);
("x", "file1", ((5, 11), (5, 12)), ["defn"], []);
("int", "file1", ((7, 20), (7, 23)), ["type"], ["abbrev"]);
("v", "file1", ((7, 17), (7, 18)), ["defn"], []);
Expand Down Expand Up @@ -3549,22 +3555,28 @@ let ``Test symbol uses of properties with both getters and setters`` () =
[|("TypeWithProperties", "file1", ((4, 5), (4, 23)), ["class"]);
("``.ctor``", "file1", ((4, 5), (4, 23)), ["member"; "ctor"]);
("NameGetSet", "file1", ((5, 13), (5, 23)), ["member"; "getter"]);
("int", "file1", ((7, 20), (7, 23)), ["abbrev"]);
("int", "file1", ((7, 20), (7, 23)), ["abbrev"])
("NameGetSet", "file1", ((5, 13), (5, 23)), ["member"; "setter"]);
("NameGet", "file1", ((9, 13), (9, 20)), ["member"; "getter"]);
("int", "file1", ((11, 20), (11, 23)), ["abbrev"]);
("int", "file1", ((11, 20), (11, 23)), ["abbrev"])
("NameGet", "file1", ((9, 13), (9, 20)), ["member"; "setter"]);
("int", "file1", ((14, 21), (14, 24)), ["abbrev"]);
("NameSet", "file1", ((13, 13), (13, 20)), ["member"; "setter"]);
("StaticNameGetSet", "file1", ((16, 18), (16, 34)), ["member"; "getter"]);
("int", "file1", ((18, 20), (18, 23)), ["abbrev"]);
("int", "file1", ((18, 20), (18, 23)), ["abbrev"])
("StaticNameGetSet", "file1", ((16, 18), (16, 34)), ["member"; "setter"]);
("StaticNameGet", "file1", ((20, 18), (20, 31)), ["member"; "getter"]);
("int", "file1", ((22, 20), (22, 23)), ["abbrev"]);
("int", "file1", ((22, 20), (22, 23)), ["abbrev"])
("StaticNameGet", "file1", ((20, 18), (20, 31)), ["member"; "setter"]);
("int", "file1", ((25, 21), (25, 24)), ["abbrev"]);
("StaticNameSet", "file1", ((24, 18), (24, 31)), ["member"; "setter"]);
("AutoPropGet", "file1", ((27, 15), (27, 26)), ["member"; "getter"]);
("AutoPropGetSet", "file1", ((28, 15), (28, 29)), ["member"; "getter"]);
("AutoPropGetSet", "file1", ((28, 15), (28, 29)), ["member"; "getter"])
("AutoPropGetSet", "file1", ((28, 15), (28, 29)), ["member"; "setter"]);
("StaticAutoPropGet", "file1", ((30, 22), (30, 39)), ["member"; "getter"]);
("StaticAutoPropGetSet", "file1", ((31, 22), (31, 42)),
["member"; "getter"]);
["member"; "getter"])
("StaticAutoPropGetSet", "file1", ((31, 22), (31, 42)), ["member"; "setter"])
("x", "file1", ((5, 11), (5, 12)), []);
("int", "file1", ((7, 20), (7, 23)), ["abbrev"]);
("v", "file1", ((7, 17), (7, 18)), []);
Expand Down Expand Up @@ -3626,7 +3638,7 @@ let ``Test symbol uses of properties with both getters and setters`` () =
("PropertyTest", "file1", ((2, 7), (2, 19)), ["module"])|]

let getSampleSymbolUseOpt =
backgroundTypedParse1.GetSymbolUseAtLocation(9,20,"",["NameGet"])
backgroundTypedParse1.GetSymbolUseAtLocation(9,20,"",["get_NameGet"])


let getSampleSymbol = getSampleSymbolUseOpt.Value.Symbol
Expand Down
47 changes: 47 additions & 0 deletions tests/service/Symbols.fs
Original file line number Diff line number Diff line change
Expand Up @@ -427,3 +427,50 @@ let f2 b1 b2 b3 b4 b5 =
mfv.FullType.AllInterfaces.Count |> should equal 0
| _ -> ()
| _ -> ()

module FSharpMemberOrFunctionOrValue =
[<Test>]
let ``Both Set and Get symbols are present`` () =
let _, checkResults = getParseAndCheckResults """
namespace Foo

type Foo =
member _.X
with get (y: int) : string = ""
and set (a: int) (b: float) = ()
"""

// "X" resolves a symbol but it will either be the get or set symbol.
// Use get_ or set_ to differentiate.
let xSymbol = checkResults.GetSymbolUseAtLocation(5, 14, " member _.X", [ "X" ])
Assert.True xSymbol.IsSome

let getSymbol = findSymbolUseByName "get_X" checkResults
match getSymbol.Symbol with
| :? FSharpMemberOrFunctionOrValue as mfv ->
Assert.AreEqual(1, mfv.CurriedParameterGroups.[0].Count)
| symbol -> Assert.Fail $"Expected {symbol} to be FSharpMemberOrFunctionOrValue"

let setSymbol = findSymbolUseByName "set_X" checkResults
match setSymbol.Symbol with
| :? FSharpMemberOrFunctionOrValue as mfv ->
Assert.AreEqual(2, mfv.CurriedParameterGroups.[0].Count)
| symbol -> Assert.Fail $"Expected {symbol} to be FSharpMemberOrFunctionOrValue"

[<Test>]
let ``AutoProperty with get,set has two symbols`` () =
let _, checkResults = getParseAndCheckResults """
namespace Foo

type Foo =
member val AutoPropGetSet = 0 with get, set
"""

let getSymbol = findSymbolUseByName "get_AutoPropGetSet" checkResults
let setSymbol = findSymbolUseByName "set_AutoPropGetSet" checkResults

match getSymbol.Symbol, setSymbol.Symbol with
| :? FSharpMemberOrFunctionOrValue as getMfv,
(:? FSharpMemberOrFunctionOrValue as setMfv) ->
Assert.AreNotEqual(getMfv.CurriedParameterGroups, setMfv.CurriedParameterGroups)
| _ -> Assert.Fail "Expected symbols to be FSharpMemberOrFunctionOrValue"