(or emacs irrelevant)

Elisp linting options

I discovered today that I was using declare-function in a wrong way. So I'll share how to use it properly.

declare-function

I was just using it to shut up the byte compiler's "not known to be defined" warning. Turns out that it can also be used to check if the functions actually exist in the file to which they point to. You can use check-declare-file to check one file, or check-declare-directory to recursively check the whole directory.

Here's an example output:

Warning (check-declare): helm-info.el said `Info-goto-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-info.el said `Info-find-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-plugin.el said `Info-goto-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-plugin.el said `Info-find-node' was defined in info.el.gz: arglist mismatch
Warning (check-declare): helm-emms.el said `with-current-emms-playlist' was defined in emms.el: function not found
Warning (check-declare): projectile.el said `ggtags-ensure-project' was defined in ggtags.el: file not found
Warning (check-declare): projectile.el said `ggtags-update-tags' was defined in ggtags.el: file not found
Warning (check-declare): async-bytecomp.el said `package-desc-reqs' was defined in package.el.gz: function not found

My mistake was assuming that the FILE argument of declare-function was somehow related to require. But of course it had to be simply the name of the file that contains the said function. If the referenced file is in an external package, e.g. (declare-function cider-repl-return "ext:cider-repl") can be used.

checkdoc

This one is actually very useful once you embrace it. It will tsk-tsk you until all your functions are documented. And since you're already writing a docstring, might as well make it good. Sometimes this leads me to removing a function that's called only once, just so that I don't have to document it.

byte-compile-file

Leaving the obvious for last. This will speed up the code in addition to checking for errors. In dired you can use:

  • several m (dired-mark) followed by B (dired-do-byte-compile).
  • a single *% (dired-mark-files-regexp) el$ followed by B.

I even have a compile target in lispy's Makefile:

compile:
    $(CASK) exec $(EMACS) -batch $(LOAD) -l lispy-test.el -l compile.elt

Here are the contents of compile.elt:

(require 'check-declare)
(setq check-declare-ext-errors t)
(setq files '("lispy.el"
              "lispy-inline.el"
              "le-clojure.el"
              "le-scheme.el"
              "le-lisp.el"))
(mapc #'byte-compile-file files)
(ert t)
(apply #'check-declare-files files)