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
39 changes: 39 additions & 0 deletions src/fsharp/vs/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,39 @@ type TypeCheckInfo
(fun msg ->
FSharpMethodGroup(msg,[| |]))

member scope.GetMethodsAsSymbols (line, lineStr, colAtEndOfNames, names) =
match GetDeclItemsForNamesAtPosition (None,Some(names), None, line, lineStr, colAtEndOfNames, ResolveTypeNamesToCtors, ResolveOverloads.No, fun _ -> false) with
| None | Some ([], _, _) -> None
| Some (items, denv, m) ->
let allItems =
items
|> List.collect (fun item ->
match item with
| Item.MethodGroup(nm,minfos) -> minfos |> List.map (fun minfo -> Item.MethodGroup(nm,[minfo]))
| Item.CtorGroup(nm,cinfos) -> cinfos |> List.map (fun minfo -> Item.CtorGroup(nm,[minfo]))
| Item.FakeInterfaceCtor _
| Item.DelegateCtor _ -> [item]
| Item.NewDef _
| Item.ILField _ -> []
| Item.Event _ -> []
| Item.RecdField(rfinfo) -> if isFunction g rfinfo.FieldType then [item] else []
| Item.Value v -> if isFunction g v.Type then [item] else []
| Item.UnionCase(ucr) -> if not ucr.UnionCase.IsNullary then [item] else []
| Item.ExnCase(ecr) -> if recdFieldsOfExnDefRef ecr |> nonNil then [item] else []
| Item.Property(_,pinfos) ->
let pinfo = List.head pinfos
if pinfo.IsIndexer then [item] else []
#if EXTENSIONTYPING
| Params.ItemIsTypeWithStaticArguments g _ -> [item] // we pretend that provided-types-with-static-args are method-like in order to get ParamInfo for them
#endif
| Item.CustomOperation(_name, _helpText, _minfo) -> [item]
| Item.TypeVar _ -> []
| Item.CustomBuilder _ -> []
| _ -> [] )

let symbols = allItems |> List.map (fun item -> FSharpSymbol.Create(g, thisCcu, tcImports, item))
Some (symbols, denv, m)

member scope.GetDeclarationLocation (line, lineStr, colAtEndOfNames, names, preferFlag) =
match GetDeclItemsForNamesAtPosition (None,Some(names), None, line, lineStr, colAtEndOfNames, ResolveTypeNamesToCtors,ResolveOverloads.Yes, fun _ -> false) with
| None
Expand Down Expand Up @@ -1789,6 +1822,12 @@ type FSharpCheckFileResults(errors: FSharpErrorInfo[], scopeOptX: TypeCheckInfo
scope.GetSymbolUseAtLocation (line, lineStr, colAtEndOfNames, names)
|> Option.map (fun (sym,denv,m) -> FSharpSymbolUse(scope.TcGlobals,denv,sym,ItemOccurence.Use,m)))

member info.GetMethodsAsSymbols (line, colAtEndOfNames, lineStr, names) =
reactorOp None (fun scope ->
scope.GetMethodsAsSymbols (line, lineStr, colAtEndOfNames, names)
|> Option.map (fun (symbols,denv,m) ->
symbols |> List.map (fun sym -> FSharpSymbolUse(scope.TcGlobals,denv,sym,ItemOccurence.Use,m))))

member info.GetSymbolAtLocationAlternate (line, colAtEndOfNames, lineStr, names) =
reactorOp None (fun scope ->
scope.GetSymbolUseAtLocation (line, lineStr, colAtEndOfNames, names)
Expand Down
7 changes: 7 additions & 0 deletions src/fsharp/vs/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ type FSharpCheckFileResults =
/// <param name="names">The identifiers at the location where the information is being requested.</param>
member GetMethodsAlternate : line:int * colAtEndOfNames:int * lineText:string * names:string list option -> Async<FSharpMethodGroup>

/// <summary>Compute a set of method overloads to show in a dialog relevant to the given code location. The resulting method overloads are returned as symbols.</summary>
/// <param name="line">The line number where the information is being requested.</param>
/// <param name="colAtEndOfNames">The column number at the end of the identifiers where the information is being requested.</param>
/// <param name="lineText">The text of the line where the information is being requested.</param>
/// <param name="names">The identifiers at the location where the information is being requested.</param>
member GetMethodsAsSymbols : line:int * colAtEndOfNames:int * lineText:string * names:string list -> Async<FSharpSymbolUse list option>

/// <summary>Resolve the names at the given location to the declaration location of the corresponding construct.</summary>
///
/// <param name="line">The line number where the information is being requested.</param>
Expand Down
34 changes: 34 additions & 0 deletions tests/service/EditorTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,40 @@ let ``Intro test`` () =
("Concat", ["arg0: obj"; "arg1: obj"; "arg2: obj"; "arg3: obj"]);
("Concat", ["str0: string"; "str1: string"; "str2: string"; "str3: string"])]

[<Test>]
let ``GetMethodsAsSymbols should return all overloads of a method as FSharpSymbolUse`` () =

let extractCurriedParams (symbol:FSharpSymbolUse) =
match symbol.Symbol with
| :? FSharpMemberOrFunctionOrValue as mvf ->
[for pg in mvf.CurriedParameterGroups do
for (p:FSharpParameter) in pg do
yield p.DisplayName, p.Type.Format (symbol.DisplayContext)]
| _ -> []

// Split the input & define file name
let inputLines = input.Split('\n')
let file = "/home/user/Test.fsx"
let untyped, typeCheckResults = parseAndTypeCheckFileInProject(file, input)
let methodsSymbols = typeCheckResults.GetMethodsAsSymbols(5, 27, inputLines.[4], ["String"; "Concat"]) |> Async.RunSynchronously
match methodsSymbols with
| Some methods ->
[ for ms in methods do
yield ms.Symbol.DisplayName, extractCurriedParams ms ]
|> List.sortBy (fun (_name, parameters) -> parameters.Length, (parameters |> List.map snd ))
|> shouldEqual
[("Concat", [("values", "Collections.Generic.IEnumerable<'T>")]);
("Concat", [("values", "Collections.Generic.IEnumerable<string>")]);
("Concat", [("arg0", "obj")]);
("Concat", [("args", "obj []")]);
("Concat", [("values", "string []")]);
("Concat", [("arg0", "obj"); ("arg1", "obj")]);
("Concat", [("str0", "string"); ("str1", "string")]);
("Concat", [("arg0", "obj"); ("arg1", "obj"); ("arg2", "obj")]);
("Concat", [("str0", "string"); ("str1", "string"); ("str2", "string")]);
("Concat", [("arg0", "obj"); ("arg1", "obj"); ("arg2", "obj"); ("arg3", "obj")]);
("Concat", [("str0", "string"); ("str1", "string"); ("str2", "string"); ("str3", "string")])]
| None -> failwith "No symbols returned"


let input2 =
Expand Down