F# 编译器服务:获取范围内可见的名称列表

F# Compiler Service: get a list of names visible in the scope

如何获得在 FSC 范围内可见的名称列表? 我试过这个:

#r "../../packages/FSharp.Compiler.Service.16.0.2/lib/net45/FSharp.Compiler.Service.dll"
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.SourceCodeServices

do 
    let file = "TestFileName.fsx"
    let checker = SourceCodeServices.FSharpChecker.Create()

    let code = 
        """
let testStr = "x"
t
"""
    async{  
        let! options, _ = checker.GetProjectOptionsFromScript(file,code)
        let! parseRes,checkAnser = checker.ParseAndCheckFileInProject(file, 0, code, options)                               
        match checkAnser with
        | FSharpCheckFileAnswer.Succeeded checkRes ->
            let! decls =
                checkRes.GetDeclarationListInfo(
                    Some parseRes,  //ParsedFileResultsOpt
                    3 ,              //line
                    1 ,              //colAtEndOfPartialName
                    "t" ,            //lineText
                    [ "t" ] ,        //qualifyingNames
                    "" ,             //partialName
                    ( fun _ -> [] )  //getAllSymbols: (unit -> AssemblySymbol list) 
                    )

            if Seq.isEmpty decls.Items then 
                printfn "*no declarations found*" 
            else
                decls.Items 
                |> Seq.sortBy (fun d -> d.Name) 
                |> Seq.truncate 10 
                |> Seq.iter (fun d -> printfn "decl: %s" d.Name)

        | _ -> failwithf "*Parsing did not finish... "        
        } |> Async.RunSynchronously

但它只打印 "no declarations found"。我不仅希望 testStr,而且希望所有其他默认可用的名称。 我没有在 documentation.

中找到示例

qualifyingNames 应该是一个空列表,它是用点分隔的 prefix,不包括最后一个(可能是部分的)ident。但是,FCS 中没有一种方法可以 returns 未过滤的范围名称列表,但添加一个非常容易。

根据 vasily-kirichenko 的回答并使用当前的 FCS 17.0.1 我想出了这个解决方案:

#r "../../packages/FSharp.Compiler.Service.17.0.1/lib/net45/FSharp.Compiler.Service.dll"
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.SourceCodeServices

do 
    let file = "TestFileName.fsx"
    let checker = SourceCodeServices.FSharpChecker.Create()

    let code = 
        """
let testStr = "x"
testStr.
"""
    async{  
        let! options, _ = checker.GetProjectOptionsFromScript(file,code)
        let! parseRes,checkAnser = checker.ParseAndCheckFileInProject(file, 0, code, options)                               
        match checkAnser with
        | FSharpCheckFileAnswer.Succeeded checkRes ->
            let! decls =
                let partialName = PartialLongName.Empty 6 //use any location before before the dot to get all declarations in scope
                //let partialName = PartialLongName.Empty 7 //use the loacation of the dot (7) to get memebers of string
                checkRes.GetDeclarationListInfo(
                    Some parseRes,  // ParsedFileResultsOpt
                    3 ,             // line                   
                    "testStr." ,    // lineText
                    partialName,    // PartialLongName
                    ( fun _ -> [] ) // getAllSymbols: (unit -> AssemblySymbol list) 
                    )

            if Seq.isEmpty decls.Items then 
                printfn "*no declarations found*" 
            else
                decls.Items 
                |> Seq.sortBy (fun d -> d.Name) 
                |> Seq.truncate 10 
                |> Seq.iter (fun d -> printfn "decl: %s" d.Name)


        | _ -> failwithf "*Parsing did not finish... "        
        } |> Async.RunSynchronously