aboutsummaryrefslogtreecommitdiff
path: root/module/scripts/module-imports.scm
diff options
context:
space:
mode:
Diffstat (limited to 'module/scripts/module-imports.scm')
-rw-r--r--module/scripts/module-imports.scm80
1 files changed, 80 insertions, 0 deletions
diff --git a/module/scripts/module-imports.scm b/module/scripts/module-imports.scm
new file mode 100644
index 00000000..8f9ab1b8
--- /dev/null
+++ b/module/scripts/module-imports.scm
@@ -0,0 +1,80 @@
+;;; 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.
+;;;
+;;; 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))
+ :use-module ((hnh module-introspection static-util) :select (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))