(dir-locals-collect-variables): Don't autoload if not needed (bug#74349)
authorStefan Monnier <monnier@iro.umontreal.ca>
Sun, 24 Nov 2024 03:05:33 +0000 (22:05 -0500)
committerEshel Yaron <me@eshelyaron.com>
Wed, 27 Nov 2024 19:54:00 +0000 (20:54 +0100)
While dir-local settings for `c-mode` may require (auto)loading `cc-mode.el`
to get all the `safe-local-variable` properties, they may not.  So before
(auto)loading that file, make sure we don't already have all the
`safe-local-variable` properties we need.

* lisp/files.el (dir-locals--load-mode-if-needed): New function.
(hack-one-local-variable): Don't inf-loop if `eval` calls a major mode.
(dir-locals-collect-variables): Use `dir-locals--load-mode-if-needed`.

(cherry picked from commit f713258416f224b93e4f25b2db24d5e8797bcbff)

lisp/files.el

index 2274ff54287348508e9adc55c4f0bba94676ffd9..bdcf0f4c00d72debe0b9262c00847483973a41a2 100644 (file)
@@ -4486,7 +4486,8 @@ already the major mode."
     ('eval
      (pcase val
        (`(add-hook ',hook . ,_) (hack-one-local-variable--obsolete hook)))
-     (save-excursion (eval val t)))
+     (let ((enable-local-variables nil)) ;FIXME: Should be buffer-local!
+       (save-excursion (eval val t))))
     (_
      (hack-one-local-variable--obsolete var)
      ;; Make sure the string has no text properties.
@@ -4532,6 +4533,21 @@ Returns the new list."
        ;; Need a new cons in case we setcdr later.
        (push (cons variable value) variables)))))
 
+(defun dir-locals--load-mode-if-needed (key alist)
+  ;; If KEY is an extra parent it may remain not loaded
+  ;; (hence with some of its mode-specific vars missing their
+  ;; `safe-local-variable' property), leading to spurious
+  ;; prompts about unsafe vars (bug#68246).
+  (when (and (symbolp key) (autoloadp (indirect-function key)))
+    (let ((unsafe nil))
+      (pcase-dolist (`(,var . ,_val) alist)
+        (unless (or (memq var '(mode eval))
+                    (get var 'safe-local-variable))
+          (setq unsafe t)))
+      (when unsafe
+        (ignore-errors
+          (autoload-do-load (indirect-function key)))))))
+
 (defun dir-locals-collect-variables (class-variables root variables
                                                      &optional predicate)
   "Collect entries from CLASS-VARIABLES into VARIABLES.
@@ -4562,15 +4578,9 @@ to see whether it should be considered."
                   (funcall predicate key)
                 (or (not key)
                     (derived-mode-p key)))
-              ;; If KEY is an extra parent it may remain not loaded
-              ;; (hence with some of its mode-specific vars missing their
-              ;; `safe-local-variable' property), leading to spurious
-              ;; prompts about unsafe vars (bug#68246).
-              (if (and (symbolp key) (autoloadp (indirect-function key)))
-                  (ignore-errors (autoload-do-load (indirect-function key))))
               (let* ((alist (cdr entry))
                      (subdirs (assq 'subdirs alist)))
-                (if (or (not subdirs)
+                (when (or (not subdirs)
                         (progn
                           (setq alist (remq subdirs alist))
                           (cdr-safe subdirs))
@@ -4579,6 +4589,7 @@ to see whether it should be considered."
                         ;; variables apply to this directory and N levels
                         ;; below it (0 == nil).
                         (equal root (expand-file-name default-directory)))
+                  (dir-locals--load-mode-if-needed key alist)
                     (setq variables (dir-locals-collect-mode-variables
                                      alist variables))))))))
       (error