зеркало из https://github.com/dotnet/fsharp.git
154 строки
5.4 KiB
Plaintext
154 строки
5.4 KiB
Plaintext
// Print some stats about identifiers grouped by type
|
|
//
|
|
|
|
#r "nuget: Ionide.ProjInfo"
|
|
#I @"..\..\artifacts\bin\fsc\Debug\net7.0\"
|
|
#r "FSharp.Compiler.Service.dll"
|
|
|
|
open System
|
|
open System.IO
|
|
open Ionide.ProjInfo
|
|
open FSharp.Compiler.CodeAnalysis
|
|
open FSharp.Compiler.Symbols
|
|
open Ionide.ProjInfo.Types
|
|
|
|
let argv = fsi.CommandLineArgs
|
|
|
|
if argv.Length = 1 then
|
|
eprintfn "usage:"
|
|
eprintfn " dotnet fsi tests/scripts/identifierAnalysisByType.fsx <project-file>"
|
|
eprintfn ""
|
|
eprintfn "examples:"
|
|
eprintfn " dotnet fsi tests/scripts/identifierAnalysisByType.fsx src/FSharp.Build/FSharp.Build.fsproj"
|
|
eprintfn " dotnet fsi tests/scripts/identifierAnalysisByType.fsx src/Compiler/FSharp.Compiler.Service.fsproj"
|
|
eprintfn ""
|
|
eprintfn "Sample output is at https://gist.github.com/dsyme/abfa11bebf0713251418906d55c08804"
|
|
|
|
//let projectFile = Path.Combine(__SOURCE_DIRECTORY__, @"..\..\src\Compiler\FSharp.Compiler.Service.fsproj")
|
|
//let projectFile = Path.Combine(__SOURCE_DIRECTORY__, @"..\..\src\FSharp.Build\FSharp.Build.fsproj")
|
|
let projectFile = Path.GetFullPath(argv[1])
|
|
|
|
let cwd = System.Environment.CurrentDirectory |> System.IO.DirectoryInfo
|
|
|
|
let _toolsPath = Init.init cwd None
|
|
|
|
printfn "Cracking project options...."
|
|
let opts =
|
|
match ProjectLoader.getProjectInfo projectFile [] BinaryLogGeneration.Off [] with
|
|
| Result.Ok res -> res
|
|
| Result.Error err -> failwithf "%s" err
|
|
|
|
let checker = FSharpChecker.Create()
|
|
|
|
let checkerOpts = checker.GetProjectOptionsFromCommandLineArgs(projectFile, [| yield! opts.SourceFiles; yield! opts.OtherOptions |] )
|
|
|
|
printfn "Checking project...."
|
|
let results = checker.ParseAndCheckProject(checkerOpts) |> Async.RunSynchronously
|
|
|
|
printfn "Grouping symbol uses...."
|
|
let symbols = results.GetAllUsesOfAllSymbols()
|
|
|
|
let rec stripTy (ty: FSharpType) =
|
|
if ty.IsAbbreviation then stripTy ty.AbbreviatedType else ty
|
|
|
|
let getTypeText (sym: FSharpMemberOrFunctionOrValue) =
|
|
let ty = stripTy sym.FullType
|
|
FSharpType.Prettify(ty).Format(FSharpDisplayContext.Empty)
|
|
|
|
symbols
|
|
|> Array.choose (fun vUse -> match vUse.Symbol with :? FSharpMemberOrFunctionOrValue as v -> Some (v, vUse.Range) | _ -> None)
|
|
|> Array.filter (fun (v, _) -> v.GenericParameters.Count = 0)
|
|
|> Array.filter (fun (v, _) -> v.CurriedParameterGroups.Count = 0)
|
|
|> Array.filter (fun (v, _) -> not v.FullType.IsGenericParameter)
|
|
|> Array.map (fun (v, vUse) -> getTypeText v, v, vUse.ToString())
|
|
|> Array.filter (fun (vTypeText, v, _) ->
|
|
match vTypeText with
|
|
| "System.String" -> false
|
|
| "System.Boolean" -> false
|
|
| "System.Int32" -> false
|
|
| "System.Int64" -> false
|
|
| "System.Object" -> false
|
|
| "Microsoft.FSharp.Collections.List<Microsoft.FSharp.Core.string>" -> false
|
|
| "Microsoft.FSharp.Core.Option<Microsoft.FSharp.Core.string>" -> false
|
|
| s when s.EndsWith(" Microsoft.FSharp.Core.[]") -> false // for now filter array types
|
|
| _ when v.DisplayName.StartsWith "_" -> false
|
|
| _ -> true)
|
|
|> Array.groupBy (fun (vTypeText, _, _) -> vTypeText)
|
|
|> Array.map (fun (key, g) ->
|
|
key,
|
|
(g
|
|
|> Array.distinctBy (fun (_, _, vUse) -> vUse)
|
|
|> Array.groupBy (fun (_, v, _) -> v.DisplayName)
|
|
|> Array.sortByDescending (snd >> Array.length)))
|
|
|> Array.filter (fun (_, g) -> g.Length > 1)
|
|
|> Array.sortByDescending (fun (key, g) -> Array.length g)
|
|
|> Array.iter (fun (key, g) ->
|
|
let key = key.Replace("Microsoft.FSharp", "FSharp").Replace("FSharp.Core.", "")
|
|
printfn "Type: %s" key
|
|
for (nm, entries) in g do
|
|
printfn " %s (%d times)" nm (Array.length entries)
|
|
for (_, _, vUse) in entries do
|
|
printfn " %s" vUse
|
|
printfn "")
|
|
|
|
(*
|
|
let isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
|
|
|
let dotnet =
|
|
if isWindows then
|
|
"dotnet.exe"
|
|
else
|
|
"dotnet"
|
|
let fileExists pathToFile =
|
|
try
|
|
File.Exists(pathToFile)
|
|
with _ ->
|
|
false
|
|
// Look for global install of dotnet sdk
|
|
let getDotnetGlobalHostPath () =
|
|
let pf = Environment.GetEnvironmentVariable("ProgramW6432")
|
|
|
|
let pf =
|
|
if String.IsNullOrEmpty(pf) then
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
|
|
else
|
|
pf
|
|
|
|
let candidate = Path.Combine(pf, "dotnet", dotnet)
|
|
|
|
if fileExists candidate then
|
|
Some candidate
|
|
else
|
|
// Can't find it --- give up
|
|
None
|
|
|
|
let getDotnetHostPath () =
|
|
let probePathForDotnetHost () =
|
|
let paths =
|
|
let p = Environment.GetEnvironmentVariable("PATH")
|
|
|
|
if not (isNull p) then
|
|
p.Split(Path.PathSeparator)
|
|
else
|
|
[||]
|
|
|
|
paths |> Array.tryFind (fun f -> fileExists (Path.Combine(f, dotnet)))
|
|
|
|
match (Environment.GetEnvironmentVariable("DOTNET_HOST_PATH")) with
|
|
// Value set externally
|
|
| value when not (String.IsNullOrEmpty(value)) && fileExists value -> Some value
|
|
| _ ->
|
|
// Probe for netsdk install, dotnet. and dotnet.exe is a constant offset from the location of System.Int32
|
|
let candidate =
|
|
let assemblyLocation = Path.GetDirectoryName(typeof<Int32>.Assembly.Location)
|
|
Path.GetFullPath(Path.Combine(assemblyLocation, "..", "..", "..", dotnet))
|
|
|
|
if fileExists candidate then
|
|
Some candidate
|
|
else
|
|
match probePathForDotnetHost () with
|
|
| Some f -> Some(Path.Combine(f, dotnet))
|
|
| None -> getDotnetGlobalHostPath ()
|
|
let dotnetExe = getDotnetHostPath () |> Option.map System.IO.FileInfo
|
|
*)
|