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)
|
:var-never-set (option true)
|
||||||
:op-with-no-arguments (option true)
|
:op-with-no-arguments (option true)
|
||||||
:multival-in-middle-of-call (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 {})
|
:libraries (option {})
|
||||||
:extra-globals (option "")})
|
:extra-globals (option "")})
|
||||||
|
|
||||||
|
|||||||
@ -242,6 +242,22 @@ the `file.diagnostics` field, filling it with diagnostics."
|
|||||||
:severity message.severity.WARN
|
:severity message.severity.WARN
|
||||||
:code :inline-unpack}))
|
: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]
|
(λ add-lint-diagnostics [server file]
|
||||||
"fill up the file.diagnostics table with linting things"
|
"fill up the file.diagnostics table with linting things"
|
||||||
(let [lints server.configuration.lints
|
(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)))
|
(table.insert diagnostics (op-with-no-arguments server file head call)))
|
||||||
(when lints.no-decreasing-comparison
|
(when lints.no-decreasing-comparison
|
||||||
(table.insert diagnostics (no-decreasing-comparison server file head call)))
|
(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
|
;; argument lints
|
||||||
;; every argument to a special or a function call
|
;; every argument to a special or a function call
|
||||||
|
|||||||
@ -9,10 +9,11 @@
|
|||||||
(: :close))
|
(: :close))
|
||||||
(let [output-file (io.popen (.. "./fennel-ls --lint "
|
(let [output-file (io.popen (.. "./fennel-ls --lint "
|
||||||
input-file-name)
|
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")
|
(faith.= (.. input-file-name ":1:7: warning: unused definition: x\n")
|
||||||
(output-file:read :*a))
|
contents))
|
||||||
(os.remove input-file-name))
|
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
{: test-lint}
|
{: test-lint}
|
||||||
|
|||||||
@ -7,18 +7,19 @@
|
|||||||
(accumulate [result nil
|
(accumulate [result nil
|
||||||
i d (ipairs diagnostics)
|
i d (ipairs diagnostics)
|
||||||
&until result]
|
&until result]
|
||||||
(if (and (or (= e.message nil)
|
(let [d (or d.self d)]
|
||||||
(if (= (type e.message) "function")
|
(if (and (or (= e.message nil)
|
||||||
(e.message d.message)
|
(if (= (type e.message) "function")
|
||||||
(= e.message d.message)))
|
(e.message d.message)
|
||||||
(or (= e.code nil)
|
(= e.message d.message)))
|
||||||
(= e.code d.code))
|
(or (= e.code nil)
|
||||||
(or (= e.range nil)
|
(= e.code d.code))
|
||||||
(and (= e.range.start.line d.range.start.line)
|
(or (= e.range nil)
|
||||||
(= e.range.start.character d.range.start.character)
|
(and (= e.range.start.line d.range.start.line)
|
||||||
(= e.range.end.line d.range.end.line)
|
(= e.range.start.character d.range.start.character)
|
||||||
(= e.range.end.character d.range.end.character))))
|
(= e.range.end.line d.range.end.line)
|
||||||
i)))
|
(= e.range.end.character d.range.end.character))))
|
||||||
|
i))))
|
||||||
|
|
||||||
(fn check [file-contents expected ?unexpected]
|
(fn check [file-contents expected ?unexpected]
|
||||||
(let [{: diagnostics} (create-client file-contents)]
|
(let [{: diagnostics} (create-client file-contents)]
|
||||||
@ -32,8 +33,8 @@
|
|||||||
(let [i (find diagnostics e)]
|
(let [i (find diagnostics e)]
|
||||||
(faith.is i (.. "No lint matching " (view e) "\n"
|
(faith.is i (.. "No lint matching " (view e) "\n"
|
||||||
"from: " (view file-contents) "\n"
|
"from: " (view file-contents) "\n"
|
||||||
(view diagnostics {:empty-as-sequence? true
|
"possible matches: " (view diagnostics {:empty-as-sequence? true
|
||||||
:escape-newlines? true})))
|
:escape-newlines? true})))
|
||||||
(table.remove diagnostics i)))))
|
(table.remove diagnostics i)))))
|
||||||
|
|
||||||
(fn assert-ok [file-contents]
|
(fn assert-ok [file-contents]
|
||||||
@ -257,12 +258,21 @@
|
|||||||
(assert-ok "(and false 1)")
|
(assert-ok "(and false 1)")
|
||||||
(assert-ok "(and nil 1)")
|
(assert-ok "(and nil 1)")
|
||||||
(check "(and)"
|
(check "(and)"
|
||||||
{:message "write true instead of (and)"
|
[{:message "write true instead of (and)"
|
||||||
:code :op-with-no-arguments
|
:code :op-with-no-arguments
|
||||||
:range {:start {:characer 0 :line 0}
|
:range {:start {:character 0 :line 0}
|
||||||
:end {:character 5 :line 0}}})
|
:end {:character 5 :line 0}}}])
|
||||||
nil)
|
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:
|
;; TODO lints:
|
||||||
;; duplicate keys in kv table
|
;; duplicate keys in kv table
|
||||||
;; (tset <sym> <any>) --> (set (. <sym> <any>)) (might be wanted for compat?)
|
;; (tset <sym> <any>) --> (set (. <sym> <any>)) (might be wanted for compat?)
|
||||||
@ -286,4 +296,5 @@
|
|||||||
: test-match-should-case
|
: test-match-should-case
|
||||||
: test-unpack-into-op
|
: test-unpack-into-op
|
||||||
: test-unpack-in-middle
|
: test-unpack-in-middle
|
||||||
: test-op-with-no-arguments}
|
: test-op-with-no-arguments
|
||||||
|
: test-empty-let}
|
||||||
|
|||||||
@ -30,6 +30,11 @@
|
|||||||
{: position
|
{: position
|
||||||
:textDocument {:uri file}})))
|
: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]
|
(fn definition [self file position]
|
||||||
(dispatch.handle* self.server
|
(dispatch.handle* self.server
|
||||||
(message.create-request (next-id! self) :textDocument/definition
|
(message.create-request (next-id! self) :textDocument/definition
|
||||||
@ -87,6 +92,7 @@
|
|||||||
{:__index {: open-file!
|
{:__index {: open-file!
|
||||||
: pretend-this-file-exists!
|
: pretend-this-file-exists!
|
||||||
: completion
|
: completion
|
||||||
|
: completion-item-resolve
|
||||||
: definition
|
: definition
|
||||||
: hover
|
: hover
|
||||||
: references
|
: references
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user