Skip to content

Add method GetDeclarationSymbols method to CheckFileResults/TypeCheckInfo #182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 2, 2014
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
12 changes: 12 additions & 0 deletions src/fsharp/vs/Symbols.fs
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,18 @@ and FSharpMemberFunctionOrValue(g:TcGlobals, thisCcu, tcImports, d:FSharpMemberO
| Some v -> Some v.Range
| None -> base.DeclarationLocation

member x.Overloads =
checkIsResolved()
match d with
| M m ->
match item with
| Item.MethodGroup (name, methodInfos) ->
methodInfos
|> List.filter (fun methodInfo -> not (methodInfo.NumArgs = m.NumArgs) )
|> List.map (fun mi -> FSharpMemberFunctionOrValue(g, thisCcu, tcImports, M mi, item))
|> Some
| _ -> None
| _ -> None

member x.DeclarationLocation =
checkIsResolved()
Expand Down
69 changes: 69 additions & 0 deletions src/fsharp/vs/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,71 @@ type TypeCheckInfo
let items = if isInterfaceFile then items |> List.filter IsValidSignatureFileItem else items
DeclarationSet.Create(infoReader,m,denv,items,reactorOps,checkAlive))
(fun msg -> DeclarationSet.Error msg)

member x.GetDeclarationSymbols (parseResultsOpt:ParseFileResults option, line, lineStr, colAtEndOfNamesAndResidue, qualifyingNames, partialName, hasTextChangedSinceLastTypecheck) =
let isInterfaceFile = SourceFileImpl.IsInterfaceFile mainInputFileName
ErrorScope.Protect
Range.range0
(fun () ->
match GetDeclItemsForNamesAtPosition(parseResultsOpt, Some qualifyingNames, Some partialName, line, lineStr, colAtEndOfNamesAndResidue, ResolveTypeNamesToCtors, ResolveOverloads.Yes, hasTextChangedSinceLastTypecheck) with
| None -> List.Empty
| Some(items,denv,m) ->
let items = items |> filterIntellisenseCompletionsBasedOnParseContext (parseResultsOpt |> Option.bind (fun x -> x.ParseTree)) (mkPos line colAtEndOfNamesAndResidue)
let items = if isInterfaceFile then items |> List.filter IsValidSignatureFileItem else items

//do filtering like Declarationset
let items = items |> RemoveExplicitlySuppressed g

// Sort by name. For things with the same name,
// - show types with fewer generic parameters first
// - show types before over other related items - they usually have very useful XmlDocs
let items =
items |> List.sortBy (fun d ->
let n =
match d with
| Item.Types (_,(TType_app(tcref,_) :: _)) -> 1 + tcref.TyparsNoRange.Length
// Put delegate ctors after types, sorted by #typars. RemoveDuplicateItems will remove FakeInterfaceCtor and DelegateCtor if an earlier type is also reported with this name
| Item.FakeInterfaceCtor (TType_app(tcref,_))
| Item.DelegateCtor (TType_app(tcref,_)) -> 1000 + tcref.TyparsNoRange.Length
// Put type ctors after types, sorted by #typars. RemoveDuplicateItems will remove DefaultStructCtors if a type is also reported with this name
| Item.CtorGroup (_, (cinfo :: _)) -> 1000 + 10 * (tcrefOfAppTy g cinfo.EnclosingType).TyparsNoRange.Length
| _ -> 0
(d.DisplayName,n))

// Remove all duplicates. We've put the types first, so this removes the DelegateCtor and DefaultStructCtor's.
let items = items |> RemoveDuplicateItems g

if verbose then dprintf "service.ml: mkDecls: %d found groups after filtering\n" (List.length items);

// Group by display name
let items = items |> List.groupBy (fun d -> d.DisplayName)

// Filter out operators (and list)
let items =
// Check whether this item looks like an operator.
let isOpItem(nm,item) =
match item with
| [Item.Value _]
| [Item.MethodGroup(_,[_])] ->
(IsOpName nm) && nm.[0]='(' && nm.[nm.Length-1]=')'
| [Item.UnionCase _] -> IsOpName nm
| _ -> false

let isFSharpList nm = (nm = "[]") // list shows up as a Type and a UnionCase, only such entity with a symbolic name, but want to filter out of intellisense

items |> List.filter (fun (nm,items) -> not (isOpItem(nm,items)) && not(isFSharpList nm))


let items =
// Filter out duplicate names
items |> List.map (fun (nm,itemsWithSameName) ->
match itemsWithSameName with
| [] -> failwith "Unexpected empty bag"
| items -> items |> List.map (fun item -> FSharpSymbol.Create(g, thisCcu, tcImports, item)))

//end filtering
items)
(fun msg -> List.empty)

member scope.GetReferenceResolutionToolTipText(line,col) : ToolTipText =
let pos = mkPos line col
Expand Down Expand Up @@ -1673,6 +1738,10 @@ type CheckFileResults(errors: ErrorInfo[], scopeOptX: TypeCheckInfo option, buil
let hasTextChangedSinceLastTypecheck = defaultArg hasTextChangedSinceLastTypecheck (fun _ -> false)
reactorOp DeclarationSet.Empty (fun scope -> scope.GetDeclarations(parseResultsOpt, line, lineStr, colAtEndOfNamesAndResidue, qualifyingNames, partialName, hasTextChangedSinceLastTypecheck))

member info.GetDeclarationSymbols(parseResultsOpt, line, colAtEndOfNamesAndResidue, lineStr, qualifyingNames, partialName, ?hasTextChangedSinceLastTypecheck) =
let hasTextChangedSinceLastTypecheck = defaultArg hasTextChangedSinceLastTypecheck (fun _ -> false)
reactorOp List.empty (fun scope -> scope.GetDeclarationSymbols(parseResultsOpt, line, lineStr, colAtEndOfNamesAndResidue, qualifyingNames, partialName, hasTextChangedSinceLastTypecheck))

/// Resolve the names at the given location to give a data tip
member info.GetToolTipTextAlternate(line, colAtEndOfNames, lineStr, names, tokenTag) =
let dflt = ToolTipText []
Expand Down
24 changes: 24 additions & 0 deletions src/fsharp/vs/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,30 @@ type CheckFileResults =

member GetDeclarationsAlternate : ParsedFileResultsOpt:ParseFileResults option * line: int * colAtEndOfPartialName: int * lineText:string * qualifyingNames: string list * partialName: string * ?hasTextChangedSinceLastTypecheck: (obj * range -> bool) -> Async<DeclarationSet>

/// <summary>Get the items for a declaration list in FSharpSymbol format</summary>
///
/// <param name="ParsedFileResultsOpt">
/// If this is present, it is used to filter declarations based on location in the
/// parse tree, specifically at 'open' declarations, 'inherit' of class or interface
/// 'record field' locations and r.h.s. of 'range' operator a..b
/// </param>
/// <param name="line">The line number where the completion is happening</param>
/// <param name="colAtEndOfNamesAndResidue">The column number (1-based) at the end of the 'names' text </param>
/// <param name="qualifyingNames">The long identifier to the left of the '.'</param>
/// <param name="partialName">The residue of a partial long identifier to the right of the '.'</param>
/// <param name="lineStr">The residue of a partial long identifier to the right of the '.'</param>
/// <param name="lineText">
/// The text of the line where the completion is happening. This is only used to make a couple
/// of adhoc corrections to completion accuracy (e.g. checking for "..")
/// </param>
/// <param name="hasTextChangedSinceLastTypecheck">
/// If text has been used from a captured name resolution from the typecheck, then
/// callback to the client to check if the text has changed. If it has, then give up
/// and assume that we're going to repeat the operation later on.
/// </param>
member GetDeclarationSymbols : ParsedFileResultsOpt:ParseFileResults option * line: int * colAtEndOfPartialName: int * lineText:string * qualifyingNames: string list * partialName: string * ?hasTextChangedSinceLastTypecheck: (obj * range -> bool) -> Async<FSharpSymbol list list>


/// <summary>Compute a formatted tooltip for the given location</summary>
///
/// <param name="line">The line number where the information is being requested.</param>
Expand Down
61 changes: 61 additions & 0 deletions tests/service/EditorTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,65 @@ type Test() =

let decls = typeCheckResults.GetDeclarationsAlternate(Some untyped, 4, 15, inputLines.[3], [], "", fun _ -> false)|> Async.RunSynchronously
decls.Items |> Seq.exists (fun d -> d.Name = "abc") |> shouldEqual true

[<Test; Ignore("Currently failing, see #139")>]
let ``Symbol based find function from member 1`` () =
let input =
"""
type Test() =
let abc a b c = a + b + c
member x.Test = """

// Split the input & define file name
let inputLines = input.Split('\n')
let file = "/home/user/Test.fsx"
let untyped, typeCheckResults = parseAndTypeCheckFileInProject(file, input)

let decls = typeCheckResults.GetDeclarationSymbols(Some untyped, 4, 21, inputLines.[3], [], "", fun _ -> false)|> Async.RunSynchronously
let item = decls |> List.tryFind (fun d -> d.Head.DisplayName = "abc")
match item with
| Some items ->
for symbol in items do
printf "%s" symbol.DisplayName
| _ -> ()
decls |> Seq.exists (fun d -> d.Head.DisplayName = "abc") |> shouldEqual true

[<Test>]
let ``Symbol based find function from member 2`` () =
let input =
"""
type Test() =
let abc a b c = a + b + c
member x.Test = a"""

// Split the input & define file name
let inputLines = input.Split('\n')
let file = "/home/user/Test.fsx"
let untyped, typeCheckResults = parseAndTypeCheckFileInProject(file, input)

let decls = typeCheckResults.GetDeclarationSymbols(Some untyped, 4, 22, inputLines.[3], [], "", fun _ -> false)|> Async.RunSynchronously
let item = decls |> List.tryFind (fun d -> d.Head.DisplayName = "abc")
match item with
| Some items ->
for symbol in items do
printf "%s" symbol.DisplayName
| _ -> ()
decls |> Seq.exists (fun d -> d.Head.DisplayName = "abc") |> shouldEqual true
true |> should equal true

[<Test>]
let ``Symbol based find function from var`` () =
let input =
"""
type Test() =
let abc a b c = a + b + c
let test = """

// Split the input & define file name
let inputLines = input.Split('\n')
let file = "/home/user/Test.fsx"
let untyped, typeCheckResults = parseAndTypeCheckFileInProject(file, input)

let decls = typeCheckResults.GetDeclarationSymbols(Some untyped, 4, 15, inputLines.[3], [], "", fun _ -> false)|> Async.RunSynchronously
decls|> Seq .exists (fun d -> d.Head.DisplayName = "abc") |> shouldEqual true