add lint that (let [] ...) should be (do ...)
This commit is contained in:
parent
e355534d8d
commit
6f946c76ea
@ -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 "")})
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user