Subject: bug#61266: closed (Re: bug#61266: [PATCH 1/1] lint: Add unused-modules linter.)

From: [email-masked] (GNU bug Tracking System)
Date: Mon, 20 Feb 2023 10:54:02 +0000

Your bug report

#61266: [PATCH 1/1] lint: Add unused-modules linter.

which was filed against the guix-patches package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
61266: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=61266
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#61266: [PATCH 1/1] lint: Add unused-modules linter.
From: Ludovic Courtès <[email-masked]>
To: Reily Siegel <[email-masked]>
Cc: [email-masked]
Date: Mon, 20 Feb 2023 11:53:45 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

Hi Reily,

Reily Siegel <[email-masked]> skribis:

> Ludovic Courtès <[email-masked]> writes:
>
>> I have just submitted a patch adding a ‘-Wunused-module’ warning to
>> Guile’s compiler, which avoids these issues:
>>
>>   https://lists.gnu.org/archive/html/guile-devel/2023-02/msg00026.html
>>
>> I wonder if we should stick to that and avoid having a lint warning
>> altogether.  WDYT?
>
> This is probably a much more workable approach. Another problem with
> lint checkers that I forgot to mention in my initial patch is that they
> are really designed to work on packages, not files.

Alright, I’m closing this issue but let’s reopen it if we eventually
change our mind.

Thanks for looking into this!

Ludo’.

Subject: [PATCH 1/1] lint: Add unused-modules linter.
From: Reily Siegel <[email-masked]>
To: [email-masked]
Date: Sat, 4 Feb 2023 00:59:42 -0500
List-Id: <debbugs-submit.debbugs.gnu.org>

* guix/lint.scm (file-module): New function.
(module-dependencies): New function.
(sexp-symbols): New function.
(file-symbols): New function.
(report-unused-module): New function.
(check-unused-modules): New function.
(%local-checkers): Add check-unused-modules.
---
 guix/lint.scm | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/guix/lint.scm b/guix/lint.scm
index 8e3976171f..38c8595bd6 100644
--- a/guix/lint.scm
+++ b/guix/lint.scm
@@ -14,6 +14,7 @@
 ;;; Copyright © 2021 Xinglu Chen <[email-masked]>
 ;;; Copyright © 2021, 2022 Maxime Devos <[email-masked]>
 ;;; Copyright © 2021 Brice Waegeneire <[email-masked]>
+;;; Copyright © 2023 Reily Siegel <[email-masked]>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -37,6 +38,7 @@ (define-module (guix lint)
   #:autoload   (guix base64) (base64-encode)
   #:use-module (guix build-system)
   #:use-module (guix diagnostics)
+  #:use-module (guix discovery)
   #:use-module (guix download)
   #:use-module (guix ftp-client)
   #:use-module (guix http-client)
@@ -1843,6 +1845,62 @@ (define (check-formatting package)
                                        (G_ "source file not found"))))))))
         '())))
 
+(define (file-module file)
+  "Return the resolved module defined in FILE."
+  (call-with-input-file file
+    (lambda (port)
+      (let loop ()
+        (match (read port)
+          (('define-module module . _) (resolve-module module))
+          ((? eof-object?) #f)
+          (_ (loop)))))))
+
+(define (module-dependencies module)
+  "Return an alist of (module . public-exports) for each of MODULE's imports."
+  (fold-module-public-variables*
+   (lambda (module sym _ alist)
+     (assoc-set! alist module (cons sym (or (assoc-ref alist module) '()))))
+   '()
+   (module-uses module)))
+
+(define (sexp-symbols sexp)
+  "Return all symols in SEXP."
+  (match sexp
+    ((? symbol?) (list sexp))
+    ((? list?) (apply append (map sexp-symbols sexp)))
+    (_ '())))
+
+(define (file-symbols file)
+  "Return all symbols in FILE."
+  (call-with-input-file file
+    (lambda (port)
+      (let loop ((res '()))
+        (let ((sexp (read port)))
+          (if (eof-object? sexp)
+              res
+              (loop (append res (sexp-symbols sexp)))))))))
+
+(define (report-unused-module package module)
+  "Report a warning that MODULE is not used in the file where PACKAGE is defined."
+  (make-warning package
+                (G_ "Imported module ~a is not used.")
+                (list (module-name module))))
+
+(define (check-unused-modules package)
+  "Check if the file in which PACKAGE is defined contains unused module imports."
+  (let* ((file (package-file package))
+         (symbols (file-symbols file))
+         (dependencies (module-dependencies (file-module file))))
+    (fold
+     (match-lambda*
+       (((module . publics) res)
+        (if (null? (lset-intersection eq? publics symbols))
+            (cons (report-unused-module package module)
+                  res)
+            res)))
+     '()
+     dependencies)))
+
 
 ;;;
 ;;; List of checkers.
@@ -1922,7 +1980,11 @@ (define %local-checkers
    (lint-checker
      (name        'formatting)
      (description "Look for formatting issues in the source")
-     (check       check-formatting))))
+     (check       check-formatting))
+   (lint-checker
+     (name        'unused-modules)
+     (description "Look for unused modules in the package file")
+     (check       check-unused-modules))))
 
 (define %network-dependent-checkers
   (list