]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix bug#76305
authorEshel Yaron <me@eshelyaron.com>
Sat, 15 Feb 2025 16:37:42 +0000 (17:37 +0100)
committerEshel Yaron <me@eshelyaron.com>
Sat, 15 Feb 2025 16:37:42 +0000 (17:37 +0100)
lisp/emacs-lisp/scope.el
lisp/progmodes/elisp-mode.el
lisp/use-package/use-package-core.el

index 687a2163433340040ab6e3b42bc0ccb92ef63ddc..eb00cd1785951a8742d50051172c32311c83542d 100644 (file)
@@ -30,6 +30,8 @@
 
 (defvar scope-counter nil)
 
+(defvar scope--local nil)
+
 (defvar scope-callback #'ignore)
 
 (defvar scope-current-let-alist-form nil)
@@ -57,7 +59,8 @@ Optional argument LOCAL is a local context to extend."
   (let* ((beg (scope-sym-pos sym))
          (bare (bare-symbol sym))
          (name (symbol-name bare))
-         (len (length name)))
+         (len (length name))
+         (scope--local local))
     (when (and beg (not (booleanp bare)))
       (cond
        ((keywordp bare) (scope-report 'constant beg len))
index 56002e475effbbd780f4c35abe7f01a7a45637f3..6c9c0f829ecc5a95008b9b6a27dfab03743d20cd 100644 (file)
@@ -673,154 +673,20 @@ be used instead.
 
 ;;; Completion at point for Elisp
 
-(defun elisp--local-variables-1 (vars sexp)
-  "Return VARS locally bound around the witness, or nil if not found."
-  (let (res)
-    (while
-        (unless
-            (setq res
-                  (pcase sexp
-                    (`(,(or 'let 'let*) ,bindings)
-                     (let ((vars vars))
-                       (when (eq 'let* (car sexp))
-                         (dolist (binding (cdr (reverse bindings)))
-                           (push (or (car-safe binding) binding) vars)))
-                       (elisp--local-variables-1
-                        vars (car (cdr-safe (car (last bindings)))))))
-                    (`(,(or 'let 'let*) ,bindings . ,body)
-                     (let ((vars vars))
-                       (dolist (binding bindings)
-                         (push (or (car-safe binding) binding) vars))
-                       (elisp--local-variables-1 vars (car (last body)))))
-                    (`(lambda ,_args)
-                     ;; FIXME: Look for the witness inside `args'.
-                     (setq sexp nil))
-                    (`(lambda ,args . ,body)
-                     (elisp--local-variables-1
-                      (let ((args (if (listp args) args)))
-                        ;; FIXME: Exit the loop if witness is in args.
-                        (append (remq '&optional (remq '&rest args)) vars))
-                      (car (last body))))
-                    (`(condition-case ,_ ,e) (elisp--local-variables-1 vars e))
-                    (`(condition-case ,v ,_ . ,catches)
-                     (elisp--local-variables-1
-                      (cons v vars) (cdr (car (last catches)))))
-                    (`(quote . ,_)
-                     ;; FIXME: Look for the witness inside sexp.
-                     (setq sexp nil))
-                    ;; FIXME: Handle `cond'.
-                    (`(,_ . ,_)
-                     (elisp--local-variables-1 vars (car (last sexp))))
-                    ('elisp--witness--lisp (or vars '(nil)))
-                    (_ nil)))
-          ;; We didn't find the witness in the last element so we try to
-          ;; backtrack to the last-but-one.
-          (setq sexp (ignore-errors (butlast sexp)))))
-    res))
-
-(defvar warning-minimum-log-level)
-
-(defvar elisp--local-macroenv
-  `((cl-eval-when . ,(lambda (&rest args) `(progn . ,(cdr args))))
-    (eval-when-compile . ,(lambda (&rest args) `(progn . ,args)))
-    (eval-and-compile . ,(lambda (&rest args) `(progn . ,args))))
-  "Environment to use while tentatively expanding macros.
-This is used to try and avoid the most egregious problems linked to the
-use of `macroexpand-all' as a way to find the \"underlying raw code\".")
+(defvar scope--local)
 
-(defvar elisp--macroexpand-untrusted-warning t)
-
-(defun elisp--safe-macroexpand-all (sexp)
-  (if (not (trusted-content-p))
-      ;; FIXME: We should try and do better here, either using a notion
-      ;; of "safe" macros, or with `bwrap', or ...
-      (progn
-        (when elisp--macroexpand-untrusted-warning
-          (setq-local elisp--macroexpand-untrusted-warning nil) ;Don't spam!
-          (let ((inhibit-message t))      ;Only log.
-            (message "Completion of local vars is disabled in %s (untrusted content)"
-                     (buffer-name))))
-        sexp)
-    (let ((macroexpand-advice
-           (lambda (expander form &rest args)
-             (condition-case err
-                 (apply expander form args)
-               (error
-                (message "Ignoring macroexpansion error: %S" err) form)))))
-      (unwind-protect
-          ;; Silence any macro expansion errors when
-          ;; attempting completion at point (bug#58148).
-          (let ((inhibit-message t)
-                (macroexp-inhibit-compiler-macros t)
-                (warning-minimum-log-level :emergency))
-            (advice-add 'macroexpand-1 :around macroexpand-advice)
-            (macroexpand-all sexp elisp--local-macroenv))
-        (advice-remove 'macroexpand-1 macroexpand-advice)))))
-
-(defun elisp--local-variables ()
-  "Return a list of locally let-bound variables at point."
-  (save-excursion
-    (skip-syntax-backward "w_")
-    (let* ((ppss (syntax-ppss))
-           (txt (buffer-substring-no-properties (or (car (nth 9 ppss)) (point))
-                                                (or (nth 8 ppss) (point))))
-           (closer ()))
-      (dolist (p (nth 9 ppss))
-        (push (cdr (syntax-after p)) closer))
-      (setq closer (apply #'string closer))
-      (let* ((sexp (condition-case nil
-                       (car (read-from-string
-                             (concat txt "elisp--witness--lisp" closer)))
-                     ((invalid-read-syntax end-of-file) nil)))
-             (vars (elisp--local-variables-1
-                    nil (elisp--safe-macroexpand-all sexp))))
-        (delq nil
-              (mapcar (lambda (var)
-                        (and (symbolp var)
-                             (not (string-match (symbol-name var) "\\`[&_]"))
-                             ;; Eliminate uninterned vars.
-                             (intern-soft var)
-                             var))
-                      vars))))))
-
-(defun elisp--expect-function-p (pos)
-  "Return non-nil if the symbol at position POS is expected to be a function."
-  (or
-   (and (eq (char-before pos) ?')
-        (eq (char-before (1- pos)) ?#))
-   (save-excursion
-     (let ((parent (nth 1 (syntax-ppss pos))))
-       (when parent
-         (goto-char parent)
-         (and
-          (looking-at (concat "(\\(cl-\\)?"
-                              (regexp-opt '("declare-function"
-                                            "function" "defadvice"
-                                            "callf" "callf2"
-                                            "defsetf"))
-                              "[ \t\r\n]+"))
-          (eq (match-end 0) pos)))))))
-
-(defun elisp--form-quoted-p (pos)
-  "Return non-nil if the form at POS is not evaluated.
-It can be quoted, or be inside a quoted form."
-  ;; FIXME: Do some macro expansion maybe.
-  (save-excursion
-    (let ((state (syntax-ppss pos)))
-      (or (nth 8 state)   ; Code inside strings usually isn't evaluated.
-          (let ((nesting (cons (point) (reverse (nth 9 state))))
-                res)
-            (while (and nesting (not res))
-              (goto-char (pop nesting))
-              (cond
-               ((or (eq (char-after) ?\[)
-                    (progn
-                      (skip-chars-backward " ")
-                      (memq (char-before) '(?' ?` ?‘))))
-                (setq res t))
-               ((eq (char-before) ?,)
-                (setq nesting nil))))
-            res)))))
+(defun elisp-local-variables (&optional pos)
+  "Return list of local variable names in scope at POS."
+  (let (all res)
+    (save-excursion
+      (if pos (goto-char pos) (setq pos (point)))
+      (beginning-of-defun)
+      (scope (lambda (_type beg len _id &optional _def)
+               (when (<= beg pos (+ beg len))
+                 (setq all (nconc (mapcar #'car scope--local) all))))))
+    (dolist (sym all)
+      (let* ((var sym)) (unless (memq var res) (setq res (cons var res)))))
+    res))
 
 ;; FIXME: Support for Company brings in features which straddle eldoc.
 ;; We should consolidate this, so that major modes can provide all that
@@ -845,7 +711,7 @@ It can be quoted, or be inside a quoted form."
           (cond
            ((fboundp symbol) (describe-function symbol))
            ((boundp symbol) (describe-variable symbol))
-           ((featurep symbol) (describe-package symbol))
+           ((featurep symbol) (describe-library symbol))
            ((facep symbol) (describe-face symbol))
            (t (signal 'user-error nil)))
           (help-buffer))))))
@@ -934,7 +800,7 @@ in `completion-at-point-functions' (which see)."
                                                 (when (<= beg pos (+ beg len))
                                                   (throw 'sym-type type))))
                                        nil))
-                            ((variable constant) (let ((local-vars (elisp--local-variables)))
+                            ((variable constant) (let ((local-vars (elisp-local-variables)))
                                                    (lambda (sym) (or (elisp--shorthand-aware-boundp sym)
                                                                      (memq sym local-vars)))))
                             ((function macro special-form top-level) #'elisp--shorthand-aware-fboundp)
@@ -1496,10 +1362,7 @@ confidence."
                 (substring file 3))
       file)))
 
-(defun elisp-load-path-roots ()
-  (if (boundp 'package-user-dir)
-      (cons package-user-dir load-path)
-    load-path))
+(defun elisp-load-path-roots () load-path)
 
 ;;; Elisp Interaction mode
 
index b601fbc37ada7ec0af7c87139df4721b9fa10e74..c457b5310525c1715eaa20c87b6cd975e9bb2eff 100644 (file)
@@ -673,15 +673,6 @@ extending any keys already present."
   (let* ((name-symbol (if (stringp name) (intern name) name))
          (name-string (symbol-name name-symbol)))
 
-    ;; The function `elisp--local-variables' inserts this unbound variable into
-    ;; macro forms to determine the locally bound variables for
-    ;; `elisp-completion-at-point'. It ends up throwing a lot of errors since it
-    ;; can occupy the position of a keyword (or look like a second argument to a
-    ;; keyword that takes one). Deleting it when it's at the top level should be
-    ;; harmless since there should be no locally bound variables to discover
-    ;; here anyway.
-    (setq args (delq 'elisp--witness--lisp args))
-
     ;; Reduce the set of keywords down to its most fundamental expression.
     (setq args (use-package-unalias-keywords name-symbol args))