-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathunseen.lean
More file actions
106 lines (92 loc) · 4.17 KB
/
unseen.lean
File metadata and controls
106 lines (92 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import Lean
import FltRegular
open Lean
def nameCode (n : Name) : String :=
if n = .anonymous then
"anonymous"
else
n.toString.replace "." "_"
def nameDisplay (n : Name) : String :=
n.components.getLast!.toString
def printDeps₁ (k : Name) (_v : Array Name) (print : String → IO Unit) : IO Unit := do
let n := k.componentsRev[1]!
print (nameCode k ++ " [label=\"" ++ nameDisplay k ++ "\"" ++
" group=\"" ++ n.toString ++ "\"]" ++ ";\n")
def printDeps₂ (k : Name) (v : Array Name) (print : String → IO Unit) : IO Unit := do
for val in v do
if (`FltRegular).isPrefixOf val then
print (nameCode val ++ " -> " ++ nameCode k ++ ";\n")
def group (name : Name) : Name :=
(name.eraseSuffix? name.componentsRev.head!).get!
def groups (imports : NameMap (Array Name)) : NameMap Unit :=
imports.foldl (fun xs k _ =>
if (`FltRegular).isPrefixOf k then xs.insert (group k) () else xs) ∅
/-- `#deptree` outputs a graphviz dependency graph to `depgraph.dot`. Build it with
`dot -Tpdf -Gnewrank=true -Goverlaps=false -Gsplines=ortho depgraph.dot > depgraph.pdf`. -/
elab "#deptree " : command => do
let env ← getEnv
let imports := env.importGraph
IO.FS.withFile "docs/depgraph.dot" IO.FS.Mode.write fun h => do
h.write "digraph {\n".toUTF8
h.write "compound=true;\n".toUTF8
for (gp, _) in groups imports do
h.write ("subgraph cluster_" ++ nameCode gp ++ " {\n").toUTF8
for (k, v) in imports do
if (`FltRegular).isPrefixOf k && group k = gp then do
printDeps₁ k v (fun s => h.write s.toUTF8)
h.write ("label = \"" ++ gp.toString ++ "\";\n").toUTF8
h.write ("margin = 32;\n").toUTF8
h.write ("pad = 32;\n").toUTF8
h.write ("penwidth = 5;\n").toUTF8
h.write ("color = cyan4;\n").toUTF8
h.write "}\n".toUTF8
for (k, v) in imports do
if (`FltRegular).isPrefixOf k then do
printDeps₂ k v (fun s => h.write s.toUTF8)
h.write "}\n".toUTF8
partial def allDeclsIn (module : Name) : Elab.Command.CommandElabM (Array Name) := do
let mFile ← findOLean module
unless (← mFile.pathExists) do
logError m!"object file '{mFile}' of module {module} does not exist"
let (md, _) ← readModuleData mFile
let decls ← md.constNames.filterM fun d =>
return !(← d.isBlackListed) && !(`injEq).isSuffixOf d && !(`sizeOf_spec).isSuffixOf d
return decls
def allFiles (env : Environment) : List Name :=
(env.importGraph.foldl (fun xs k _ => if (`FltRegular).isPrefixOf k then
k :: xs else xs) []).mergeSort
(toString · < toString ·)
def allDecls (env : Environment) : Elab.Command.CommandElabM NameSet :=
(fun l => NameSet.ofList (l.map (fun a => a.toList)).flatten) <$>
(List.mapM allDeclsIn (allFiles env))
/-- `#index` computes an index of the declations in the project and saves it to `index.csv`. -/
elab "#index " : command => do
let env ← getEnv
let allDecls ← allDecls env
let result ← List.mapM (fun decl => do
let ranges ← findDeclarationRanges? decl
let mod ← findModuleOf? decl
match (ranges, mod) with
| (some ranges, some mod) => pure (some (decl, ranges, mod))
| _ => pure none)
(allDecls.toList.mergeSort (toString · < toString ·))
let result' := result.filterMap id
IO.FS.withFile "docs/index.csv" IO.FS.Mode.write (fun h => do
for (decl, ranges, mod) in result' do
h.write (decl.toString ++ ", " ++ mod.toString ++ ", " ++
ranges.range.pos.line.repr ++ ", " ++ ranges.range.pos.column.repr ++ "\n").toUTF8)
/-- `#unseen` computes a list of the declarations in the project that are
defined but not used. The list is stored in `unseen_defs.txt`. -/
elab "#unseen " : command => do
let env ← getEnv
let allDecls ← allDecls env
let timeStart ← IO.monoMsNow
let unseen := env.constants.fold (init := allDecls) fun unseen name info =>
info.getUsedConstantsAsSet.foldl (init := unseen) fun unseen x =>
if x = name then unseen else unseen.erase x
IO.FS.withFile "docs/unseen_defs.txt" IO.FS.Mode.write (fun h => do
for v in unseen.toList.mergeSort (toString · < toString ·) do
h.write (v.toString ++ "\n").toUTF8)
let timeEnd ← IO.monoMsNow
logInfo m!"operation took {(timeEnd - timeStart) / 1000}s"
#unseen