add lint that (let [] ...) should be (do ...)

This commit is contained in:
XeroOl 2025-06-19 12:56:29 -05:00
parent e355534d8d
commit 6f946c76ea
5 changed files with 60 additions and 23 deletions

View File

@ -35,7 +35,8 @@ There are no global settings. They're all stored in the `server` object.
:var-never-set (option true)
:op-with-no-arguments (option true)
:multival-in-middle-of-call (option true)
:no-decreasing-comparison (option false)}
:no-decreasing-comparison (option false)
:empty-let (option true)}
:libraries (option {})
:extra-globals (option "")})

View File

@ -242,6 +242,22 @@ the `file.diagnostics` field, filling it with diagnostics."
:severity message.severity.WARN
:code :inline-unpack}))
(λ empty-let [server file _ call]
(case call
(where [let* binding]
(. file.lexical call)
(sym? let* :let)
(fennel.sequence? binding)
(= 0 (length binding)))
(diagnostic {:range (message.ast->range server file binding)
:message "use do instead of let with no bindings"
:severity message.severity.WARN
:code :empty-let}
#[(let [{: start} (message.ast->range server file let*)
{: end} (message.ast->range server file binding)]
{:range {: start : end}
:newText "do"})])))
(λ add-lint-diagnostics [server file]
"fill up the file.diagnostics table with linting things"
(let [lints server.configuration.lints
@ -272,6 +288,8 @@ the `file.diagnostics` field, filling it with diagnostics."
(table.insert diagnostics (op-with-no-arguments server file head call)))
(when lints.no-decreasing-comparison
(table.insert diagnostics (no-decreasing-comparison server file head call)))
(when lints.empty-let
(table.insert diagnostics (empty-let server file head call)))
;; argument lints
;; every argument to a special or a function call

View File

@ -9,10 +9,11 @@
(: :close))
(let [output-file (io.popen (.. "./fennel-ls --lint "
input-file-name)
:r)]
:r)
contents (output-file:read :*a)]
(os.remove input-file-name)
(faith.= (.. input-file-name ":1:7: warning: unused definition: x\n")
(output-file:read :*a))
(os.remove input-file-name))
contents))
nil))
{: test-lint}

View File

@ -7,18 +7,19 @@
(accumulate [result nil
i d (ipairs diagnostics)
&until result]
(if (and (or (= e.message nil)
(if (= (type e.message) "function")
(e.message d.message)
(= e.message d.message)))
(or (= e.code nil)
(= e.code d.code))
(or (= e.range nil)
(and (= e.range.start.line d.range.start.line)
(= e.range.start.character d.range.start.character)
(= e.range.end.line d.range.end.line)
(= e.range.end.character d.range.end.character))))
i)))
(let [d (or d.self d)]
(if (and (or (= e.message nil)
(if (= (type e.message) "function")
(e.message d.message)
(= e.message d.message)))
(or (= e.code nil)
(= e.code d.code))
(or (= e.range nil)
(and (= e.range.start.line d.range.start.line)
(= e.range.start.character d.range.start.character)
(= e.range.end.line d.range.end.line)
(= e.range.end.character d.range.end.character))))
i))))
(fn check [file-contents expected ?unexpected]
(let [{: diagnostics} (create-client file-contents)]
@ -32,8 +33,8 @@
(let [i (find diagnostics e)]
(faith.is i (.. "No lint matching " (view e) "\n"
"from: " (view file-contents) "\n"
(view diagnostics {:empty-as-sequence? true
:escape-newlines? true})))
"possible matches: " (view diagnostics {:empty-as-sequence? true
:escape-newlines? true})))
(table.remove diagnostics i)))))
(fn assert-ok [file-contents]
@ -257,12 +258,21 @@
(assert-ok "(and false 1)")
(assert-ok "(and nil 1)")
(check "(and)"
{:message "write true instead of (and)"
:code :op-with-no-arguments
:range {:start {:characer 0 :line 0}
:end {:character 5 :line 0}}})
[{:message "write true instead of (and)"
:code :op-with-no-arguments
:range {:start {:character 0 :line 0}
:end {:character 5 :line 0}}}])
nil)
(fn test-empty-let []
(assert-ok "(let [x 1] x)")
(check "(let [] print)"
[{:message "use do instead of let with no bindings"
:code :empty-let
:range {:start {:character 5 :line 0}
:end {:character 7 :line 0}}}])
(assert-ok "(-> [] (let print))"))
;; TODO lints:
;; duplicate keys in kv table
;; (tset <sym> <any>) --> (set (. <sym> <any>)) (might be wanted for compat?)
@ -286,4 +296,5 @@
: test-match-should-case
: test-unpack-into-op
: test-unpack-in-middle
: test-op-with-no-arguments}
: test-op-with-no-arguments
: test-empty-let}

View File

@ -30,6 +30,11 @@
{: position
:textDocument {:uri file}})))
(fn completion-item-resolve [self completion-item]
(dispatch.handle* self.server
(message.create-request (next-id! self) :completionItem/resolve
completion-item)))
(fn definition [self file position]
(dispatch.handle* self.server
(message.create-request (next-id! self) :textDocument/definition
@ -87,6 +92,7 @@
{:__index {: open-file!
: pretend-this-file-exists!
: completion
: completion-item-resolve
: definition
: hover
: references