* add identifier analysis script

* add identifier analysis script
This commit is contained in:
Don Syme 2022-07-11 16:44:32 +01:00 коммит произвёл GitHub
Родитель 5055281af2
Коммит de49e2f14f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 152 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,152 @@
// Print some stats about identifiers grouped by type
//
#r "nuget: Ionide.ProjInfo"
#I @"..\..\artifacts\bin\fsc\Debug\net6.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)
|> 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.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.ToString())
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
*)