Skip to content
Closed
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
9 changes: 5 additions & 4 deletions fcs/samples/EditorService/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ printfn "%A" tip
let partialName = GetPartialLongNameEx(inputLines.[4], 23)

// Get declarations (autocomplete) for a location
let decls =
parsed.GetDeclarationListInfo(Some untyped, 5, inputLines.[4], partialName, (fun () -> []))
let decls =
parsed.GetDeclarationListInfo(Some untyped, 5, inputLines.[4], partialName)
|> Async.RunSynchronously

for item in decls.Items do
printfn " - %s" item.Name
match decls with
| FSharpDeclarationListInfo.Info (items, _, _) -> items |> Array.iter (fun item -> printfn " - %s" item.Name)
| _ -> ()
32 changes: 12 additions & 20 deletions src/fsharp/vs/ServiceDeclarationLists.fs
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ module internal DescriptionListsImpl =

/// An intellisense declaration
[<Sealed>]
type FSharpDeclarationListItem(name: string, nameInCode: string, fullName: string, glyph: FSharpGlyph, info, accessibility: FSharpAccessibility option,
type FSharpDeclarationListItem(name: string, nameInCode: string, fullName: string, glyph: FSharpGlyph, info, symbol: FSharpSymbol,
kind: CompletionItemKind, isOwnMember: bool, priority: int, isResolved: bool, namespaceToOpen: string option) =

let mutable descriptionTextHolder: FSharpToolTipText<_> option = None
Expand Down Expand Up @@ -544,8 +544,8 @@ type FSharpDeclarationListItem(name: string, nameInCode: string, fullName: strin
)
(fun err -> FSharpToolTipText [FSharpStructuredToolTipElement.CompositionError err])
member decl.DescriptionText = decl.StructuredDescriptionText |> Tooltips.ToFSharpToolTipText
member __.Glyph = glyph
member __.Accessibility = accessibility
member __.Glyph = glyph
member __.Symbol = symbol
member __.Kind = kind
member __.IsOwnMember = isOwnMember
member __.MinorPriority = priority
Expand All @@ -554,18 +554,18 @@ type FSharpDeclarationListItem(name: string, nameInCode: string, fullName: strin
member __.NamespaceToOpen = namespaceToOpen

/// A table of declarations for Intellisense completion
[<Sealed>]
type FSharpDeclarationListInfo(declarations: FSharpDeclarationListItem[], isForType: bool, isError: bool) =
member __.Items = declarations
member __.IsForType = isForType
member __.IsError = isError
type FSharpDeclarationListInfo =
| Empty
| Info of Items: FSharpDeclarationListItem[] * IsForType: bool * DisplayContext: FSharpDisplayContext
| Error of FSharpToolTipText<Layout>

// Make a 'Declarations' object for a set of selected items
static member Create(infoReader:InfoReader, m, denv, getAccessibility, items: CompletionItem list, reactor, currentNamespaceOrModule: string[] option, isAttributeApplicationContext: bool, checkAlive) =
static member Create(infoReader:InfoReader, m, denv, createSymbol: (Item -> FSharpSymbol), items: CompletionItem list, reactor, currentNamespaceOrModule: string[] option, isAttributeApplicationContext: bool, checkAlive) =
let g = infoReader.g
let isForType = items |> List.exists (fun x -> x.Type.IsSome)
let items = items |> SymbolHelpers.RemoveExplicitlySuppressedCompletionItems g

let displayContext = FSharpDisplayContext(fun _ -> denv)

let tyconRefOptEq tref1 tref2 =
match tref1 with
| Some tref1 -> tyconRefEq g tref1 tref2
Expand Down Expand Up @@ -687,18 +687,10 @@ type FSharpDeclarationListInfo(declarations: FSharpDeclarationListItem[], isForT
| ns -> Some (ns |> String.concat "."))

FSharpDeclarationListItem(
name, nameInCode, fullName, glyph, Choice1Of2 (items, infoReader, m, denv, reactor, checkAlive), getAccessibility item.Item,
name, nameInCode, fullName, glyph, Choice1Of2 (items, infoReader, m, denv, reactor, checkAlive), createSymbol item.Item,
item.Kind, item.IsOwnMember, item.MinorPriority, item.Unresolved.IsNone, namespaceToOpen))

new FSharpDeclarationListInfo(Array.ofList decls, isForType, false)

static member Error msg =
new FSharpDeclarationListInfo(
[| FSharpDeclarationListItem("<Note>", "<Note>", "<Note>", FSharpGlyph.Error, Choice2Of2 (FSharpToolTipText [FSharpStructuredToolTipElement.CompositionError msg]),
None, CompletionItemKind.Other, false, 0, false, None) |], false, true)

static member Empty = FSharpDeclarationListInfo([| |], false, false)

FSharpDeclarationListInfo.Info(Array.ofList decls, isForType, displayContext)


/// Represents one method (or other item) in a method group. The item may represent either a method or
Expand Down
23 changes: 7 additions & 16 deletions src/fsharp/vs/ServiceDeclarationLists.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type internal FSharpDeclarationListItem =

member Glyph : FSharpGlyph

member Accessibility : FSharpAccessibility option
member Symbol : FSharpSymbol

member Kind : CompletionItemKind

Expand All @@ -60,8 +60,7 @@ type internal FSharpDeclarationListItem =

member NamespaceToOpen : string option


[<Sealed>]
[<RequireQualifiedAccess>]
/// Represents a set of declarations in F# source code, with information attached ready for display by an editor.
/// Returned by GetDeclarations.
//
Expand All @@ -71,19 +70,11 @@ type FSharpDeclarationListInfo =
#else
type internal FSharpDeclarationListInfo =
#endif

member Items : FSharpDeclarationListItem[]

member IsForType : bool

member IsError : bool

// Implementation details used by other code in the compiler
static member internal Create : infoReader:InfoReader * m:range * denv:DisplayEnv * getAccessibility:(Item -> FSharpAccessibility option) * items:CompletionItem list * reactor:IReactorOperations * currentNamespace:string[] option * isAttributeApplicationContex:bool * checkAlive:(unit -> bool) -> FSharpDeclarationListInfo

static member internal Error : message:string -> FSharpDeclarationListInfo

static member Empty : FSharpDeclarationListInfo
| Empty
| Info of Items: FSharpDeclarationListItem[] * IsForType: bool * DisplayContext: FSharpDisplayContext
| Error of FSharpToolTipText<Layout>
// Implementation details used by other code in the compiler
static member internal Create: infoReader:InfoReader * m:range * denv:DisplayEnv * createSymbol: (Item -> FSharpSymbol) * items:CompletionItem list * reactor:IReactorOperations * currentNamespace:string[] option * isAttributeApplicationContex:bool * checkAlive:(unit -> bool) -> FSharpDeclarationListInfo

/// Represents one parameter for one method (or other item) in a group.
[<Sealed>]
Expand Down
32 changes: 23 additions & 9 deletions src/fsharp/vs/service.fs
Original file line number Diff line number Diff line change
Expand Up @@ -904,24 +904,25 @@ type TypeCheckInfo
scope.IsRelativeNameResolvable(cursorPos, plid, symbol.Item)

/// Get the auto-complete items at a location
member __.GetDeclarations (ctok, parseResultsOpt, line, lineStr, partialName, getAllSymbols, hasTextChangedSinceLastTypecheck) =
member __.GetDeclarations (ctok, parseResultsOpt, line, lineStr, partialName, getAllSymbols, shortTypeNames, hasTextChangedSinceLastTypecheck) =
let isInterfaceFile = SourceFileImpl.IsInterfaceFile mainInputFileName
ErrorScope.Protect Range.range0
(fun () ->
match GetDeclItemsForNamesAtPosition(ctok, parseResultsOpt, Some partialName.QualifyingIdents, Some partialName.PartialIdent, partialName.LastDotPos, line, lineStr, partialName.EndColumn + 1, ResolveTypeNamesToCtors, ResolveOverloads.Yes, getAllSymbols, hasTextChangedSinceLastTypecheck) with
| None -> FSharpDeclarationListInfo.Empty
| Some (items, denv, ctx, m) ->
| Some (items, denv, ctx, m) ->
let denv = if shortTypeNames then { denv with shortTypeNames = true } else denv
let createSymbol item = FSharpSymbol.Create(g, thisCcu, tcImports, item)
let items = if isInterfaceFile then items |> List.filter (fun x -> IsValidSignatureFileItem x.Item) else items
let getAccessibility item = FSharpSymbol.GetAccessibility (FSharpSymbol.Create(g, thisCcu, tcImports, item))
let currentNamespaceOrModule =
parseResultsOpt
|> Option.bind (fun x -> x.ParseTree)
|> Option.map (fun parsedInput -> UntypedParseImpl.GetFullNameOfSmallestModuleOrNamespaceAtPoint(parsedInput, mkPos line 0))
let isAttributeApplication = ctx = Some CompletionContext.AttributeApplication
FSharpDeclarationListInfo.Create(infoReader,m,denv,getAccessibility,items,reactorOps,currentNamespaceOrModule,isAttributeApplication,checkAlive))
FSharpDeclarationListInfo.Create(infoReader,m,denv,createSymbol,items,reactorOps,currentNamespaceOrModule,isAttributeApplication,checkAlive))
(fun msg ->
Trace.TraceInformation(sprintf "FCS: recovering from error in GetDeclarations: '%s'" msg)
FSharpDeclarationListInfo.Error msg)
FSharpDeclarationListInfo.Error(FSharpToolTipText [FSharpStructuredToolTipElement.CompositionError msg]))

/// Get the symbols for auto-complete items at a location
member __.GetDeclarationListSymbols (ctok, parseResultsOpt, line, lineStr, partialName, hasTextChangedSinceLastTypecheck) =
Expand Down Expand Up @@ -1232,6 +1233,11 @@ type TypeCheckInfo
member __.GetFormatSpecifierLocationsAndArity() =
sSymbolUses.GetFormatSpecifierLocationsAndArity()

member __.GetAllResolvedSymbols() =
sResolutions.CapturedNameResolutions
|> Seq.map (fun (cnr: CapturedNameResolution) -> cnr.Range, FSharpSymbol.Create(g, thisCcu, tcImports, cnr.Item))
|> Array.ofSeq

member __.GetSemanticClassification(range: range option) : (range * SemanticClassificationType) [] =
ErrorScope.Protect Range.range0
(fun () ->
Expand Down Expand Up @@ -1891,13 +1897,15 @@ type FSharpCheckFileResults(filename: string, errors: FSharpErrorInfo[], scopeOp
member info.Errors = errors

member info.HasFullTypeCheckInfo = details.IsSome

/// Intellisense autocompletions
member info.GetDeclarationListInfo(parseResultsOpt, line, lineStr, partialName, getAllEntities, ?hasTextChangedSinceLastTypecheck, ?userOpName: string) =
member info.GetDeclarationListInfo(parseResultsOpt, line, lineStr, partialName, ?getAllEntities, ?shortTypeNames, ?hasTextChangedSinceLastTypecheck, ?userOpName: string) =
let userOpName = defaultArg userOpName "Unknown"
let getAllEntities = defaultArg getAllEntities (fun _ -> [])
let shortTypeNames = defaultArg shortTypeNames false
let hasTextChangedSinceLastTypecheck = defaultArg hasTextChangedSinceLastTypecheck (fun _ -> false)
reactorOp userOpName "GetDeclarations" FSharpDeclarationListInfo.Empty (fun ctok scope ->
scope.GetDeclarations(ctok, parseResultsOpt, line, lineStr, partialName, getAllEntities, hasTextChangedSinceLastTypecheck))
reactorOp userOpName "GetDeclarations" FSharpDeclarationListInfo.Empty (fun ctok scope ->
scope.GetDeclarations(ctok, parseResultsOpt, line, lineStr, partialName, getAllEntities, shortTypeNames, hasTextChangedSinceLastTypecheck))

member info.GetDeclarationListSymbols(parseResultsOpt, line, lineStr, partialName, ?hasTextChangedSinceLastTypecheck, ?userOpName: string) =
let userOpName = defaultArg userOpName "Unknown"
Expand Down Expand Up @@ -2000,6 +2008,12 @@ type FSharpCheckFileResults(filename: string, errors: FSharpErrorInfo[], scopeOp
yield FSharpSymbolUse(scope.TcGlobals, denv, symbol, itemOcc, m) |])
|> async.Return

member info.GetAllResolvedSymbols() =
threadSafeOp
(fun () -> [| |])
(fun scope -> scope.GetAllResolvedSymbols())
|> async.Return

member info.GetUsesOfSymbolInFile(symbol:FSharpSymbol) =
threadSafeOp
(fun () -> [| |])
Expand Down
12 changes: 11 additions & 1 deletion src/fsharp/vs/service.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,21 @@ type internal FSharpCheckFileResults =
/// <param name="getAllSymbols">
/// Function that returns all symbols from current and referenced assemblies.
/// </param>
/// </param>
/// <param name="getAdditionalInfo">
/// Function that returns additional info about a symbol in completion context.
/// </param>
/// </param>
/// <param name="shortTypeNames">
/// Hide non-opened namespaces in type names in item descriptions and additional info.
/// </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>
/// <param name="userOpName">An optional string used for tracing compiler operations associated with this request.</param>
member GetDeclarationListInfo : ParsedFileResultsOpt:FSharpParseFileResults option * line: int * lineText:string * partialName: PartialLongName * getAllSymbols: (unit -> AssemblySymbol list) * ?hasTextChangedSinceLastTypecheck: (obj * range -> bool) * ?userOpName: string -> Async<FSharpDeclarationListInfo>
member GetDeclarationListInfo : ParsedFileResultsOpt:FSharpParseFileResults option * line: int * lineText:string * partialName: PartialLongName * ?getAllSymbols: (unit -> AssemblySymbol list) * ?shortTypeNames: bool * ?hasTextChangedSinceLastTypecheck: (obj * range -> bool) * ?userOpName: string -> Async<FSharpDeclarationListInfo>

/// <summary>Get the items for a declaration list in FSharpSymbol format</summary>
///
Expand Down Expand Up @@ -257,6 +265,8 @@ type internal FSharpCheckFileResults =
/// Get all textual usages of all symbols throughout the file
member GetAllUsesOfAllSymbolsInFile : unit -> Async<FSharpSymbolUse[]>

member GetAllResolvedSymbols: unit -> Async<(range * FSharpSymbol)[]>

/// Get the textual usages that resolved to the given symbol throughout the file
member GetUsesOfSymbolInFile : symbol:FSharpSymbol -> Async<FSharpSymbolUse[]>

Expand Down
25 changes: 20 additions & 5 deletions tests/service/EditorTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ let ``Intro test`` () =
// (sprintf "%A" tip).Replace("\n","") |> shouldEqual """FSharpToolTipText [Single ("val foo : unit -> unitFull name: Test.foo",None)]"""
// Get declarations (autocomplete) for a location
let partialName = { QualifyingIdents = []; PartialIdent = "msg"; EndColumn = 22; LastDotPos = None }
let decls = typeCheckResults.GetDeclarationListInfo(Some parseResult, 7, inputLines.[6], partialName, (fun _ -> []), fun _ -> false)|> Async.RunSynchronously
let decls =
typeCheckResults.GetDeclarationListInfo(Some parseResult, 7, inputLines.[6], partialName,
hasTextChangedSinceLastTypecheck = (fun _ -> false))
|> Async.RunSynchronously
CollectionAssert.AreEquivalent(stringMethods,[ for item in decls.Items -> item.Name ])
// Get overloads of the String.Concat method
let methods = typeCheckResults.GetMethods(5, 27, inputLines.[4], Some ["String"; "Concat"]) |> Async.RunSynchronously
Expand Down Expand Up @@ -286,7 +289,10 @@ let ``Expression typing test`` () =
// gives the results for the string type.
//
for col in 42..43 do
let decls = typeCheckResults.GetDeclarationListInfo(Some parseResult, 2, inputLines.[1], PartialLongName.Empty(col), (fun _ -> []), fun _ -> false)|> Async.RunSynchronously
let decls =
typeCheckResults.GetDeclarationListInfo(Some parseResult, 2, inputLines.[1], PartialLongName.Empty(col),
hasTextChangedSinceLastTypecheck = (fun _ -> false))
|> Async.RunSynchronously
let autoCompleteSet = set [ for item in decls.Items -> item.Name ]
autoCompleteSet |> shouldEqual (set stringMethods)

Expand All @@ -307,7 +313,10 @@ type Test() =
let file = "/home/user/Test.fsx"
let parseResult, typeCheckResults = parseAndCheckScript(file, input)

let decls = typeCheckResults.GetDeclarationListInfo(Some parseResult, 4, inputLines.[3], PartialLongName.Empty(20), (fun _ -> []), fun _ -> false)|> Async.RunSynchronously
let decls =
typeCheckResults.GetDeclarationListInfo(Some parseResult, 4, inputLines.[3], PartialLongName.Empty(20),
hasTextChangedSinceLastTypecheck = (fun _ -> false))
|> Async.RunSynchronously
let item = decls.Items |> Array.tryFind (fun d -> d.Name = "abc")
decls.Items |> Seq.exists (fun d -> d.Name = "abc") |> shouldEqual true

Expand All @@ -324,7 +333,10 @@ type Test() =
let file = "/home/user/Test.fsx"
let parseResult, typeCheckResults = parseAndCheckScript(file, input)

let decls = typeCheckResults.GetDeclarationListInfo(Some parseResult, 4, inputLines.[3], PartialLongName.Empty(21), (fun _ -> []), fun _ -> false)|> Async.RunSynchronously
let decls =
typeCheckResults.GetDeclarationListInfo(Some parseResult, 4, inputLines.[3], PartialLongName.Empty(21),
hasTextChangedSinceLastTypecheck = (fun _ -> false))
|> Async.RunSynchronously
let item = decls.Items |> Array.tryFind (fun d -> d.Name = "abc")
decls.Items |> Seq.exists (fun d -> d.Name = "abc") |> shouldEqual true

Expand All @@ -341,7 +353,10 @@ type Test() =
let file = "/home/user/Test.fsx"
let parseResult, typeCheckResults = parseAndCheckScript(file, input)

let decls = typeCheckResults.GetDeclarationListInfo(Some parseResult, 4, inputLines.[3], PartialLongName.Empty(14), (fun _ -> []), fun _ -> false)|> Async.RunSynchronously
let decls =
typeCheckResults.GetDeclarationListInfo(Some parseResult, 4, inputLines.[3], PartialLongName.Empty(14),
hasTextChangedSinceLastTypecheck = (fun _ -> false))
|> Async.RunSynchronously
decls.Items |> Seq.exists (fun d -> d.Name = "abc") |> shouldEqual true

[<Test; Ignore("Currently failing, see #139")>]
Expand Down
Loading