blob: 39dc78da88b61186c9d4f1227b66d225023d8d7a (
plain)
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
|
;;; Commentary:
;;;
;;; Scripts which finds unused imports in each file.
;;; Uses Guile's module system reflection to find what is imported,
;;; but simple looks at all unique symbols in the source file for what
;;; is used, which might lead to some discrepancies.
;;;
;;; TODO An explicit #:select list in an import leads this module
;;; to assume that all those symbols are in use
;;;
;;; Code:
(define-module (scripts module-imports)
:use-module ((srfi srfi-1) :select (lset-difference))
:use-module ((rnrs lists) :select (remp filter partition))
:use-module ((hnh module-introspection)
:select (module-declaration?
unique-symbols
get-forms))
:use-module ((hnh module-introspection module-uses) :select (module-uses*))
:export (main)
)
(define %summary "List imports, and how many are used.")
(define %synopsis "module-imports filename")
;;; Module use high scores
;;; $ grep -Ho '#\?:use-module' -R module | uniq -c | sort -n
(define (main . args)
(define filename (car args))
;; TODO Module declaration can reside inside a cond-expand block
(define-values (module-declaration-list forms)
(partition module-declaration?
(reverse (call-with-input-file filename get-forms))))
;; All symbols in source file, which are not in module declaration.
;; Otherwise all explicitly imported symbols would be marked as
;; used.
(define symbs (unique-symbols forms))
;; (format #t "~y" (find-module-declaration forms))
;; (format #t "~a~%" symbs)
;; TODO parameterize this to a command line argument
(define skip-list '((guile)
(guile-user)
(srfi srfi-1)
))
(define modules
;; If we didn't find the module declaration
(if (null? module-declaration-list)
;; Find symbols by best effort
(begin
(format #t "Using our make-shift module introspection~%")
(map (lambda (mod) (apply resolve-interface mod))
(remp (lambda (mod) (member (car mod) skip-list))
(module-uses* forms))))
;; If we did find the declaration, use the actual symbol in
(begin
(format #t "Using guile's true module introspection~%")
(remp (lambda (mod) (member (module-name mod) skip-list))
(module-uses (resolve-module
(cadr (car module-declaration-list))))))))
(format #t "=== ~a ===~%" filename)
(for-each (lambda (mod)
;; all symbols imported from module
(define all-symbols (module-map (lambda (key value) key) mod))
;; Thes subset of all imported symbols from module which are used
(define used-symbols
(filter (lambda (symb) (memv symb symbs))
all-symbols))
(define used-count (length used-symbols))
(define total-count (length (module-map list mod)))
(format #t "~a/~a ~a~% used ~s~% unused ~s~%"
used-count total-count (module-name mod)
used-symbols
(lset-difference eq? all-symbols used-symbols)))
modules)
(newline))
|