Add unnecessary-tset, unnecessary-do, and redundant-do lints.
"Redundant" means that it's a `do` in a context where there's already an implicit `do`, as defined by fennel.syntax indicating body-form? is true. Unnecessary means it only has one argument.
This commit is contained in:
parent
a27f42bfa4
commit
b5dbeb28fe
@ -23,6 +23,9 @@ There are no global settings. They're all stored in the `server` object.
|
||||
:lints {:unused-definition (option true)
|
||||
:unknown-module-field (option true)
|
||||
:unnecessary-method (option true)
|
||||
:unnecessary-tset (option true)
|
||||
:unnecessary-do (option true)
|
||||
:redundant-do (option true)
|
||||
:match-should-case (option true)
|
||||
:bad-unpack (option true)
|
||||
:var-never-set (option true)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
Provides the function (check server file), which goes through a file and mutates
|
||||
the `file.diagnostics` field, filling it with diagnostics."
|
||||
|
||||
(local {: sym? : list? : table? : view} (require :fennel))
|
||||
(local {: sym? : list? : table? : view &as fennel} (require :fennel))
|
||||
(local analyzer (require :fennel-ls.analyzer))
|
||||
(local message (require :fennel-ls.message))
|
||||
(local utils (require :fennel-ls.utils))
|
||||
@ -81,6 +81,48 @@ the `file.diagnostics` field, filling it with diagnostics."
|
||||
:code 303
|
||||
:codeDescription "unnecessary-method"}))))
|
||||
|
||||
(λ unnecessary-tset [server file head call]
|
||||
(if (and (sym? head :tset) (sym? (. call 2))
|
||||
(= :string (type (. call 3))) (. file.lexical call))
|
||||
(diagnostic {:range (message.ast->range server file call)
|
||||
:message (string.format "unnecessary %s" head)
|
||||
:severity message.severity.WARN
|
||||
:code 309
|
||||
:codeDescription "unnecessary-tset"}
|
||||
#[{:range (message.ast->range server file call)
|
||||
:newText (string.format "(set %s.%s %s)"
|
||||
(. call 2) (. call 3)
|
||||
(view (. call 4)))}])))
|
||||
|
||||
(λ unnecessary-do-values [server file head call]
|
||||
(if (and (or (sym? head :do) (sym? head :values))
|
||||
(= nil (. call 3)) (. file.lexical call))
|
||||
(diagnostic {:range (message.ast->range server file call)
|
||||
:message (string.format "unnecessary %s" head)
|
||||
:severity message.severity.WARN
|
||||
:code 310
|
||||
:codeDescription "unnecessary-do-values"}
|
||||
#[{:range (message.ast->range server file call)
|
||||
:newText (view (. call 2))}])))
|
||||
|
||||
(local implicit-do-forms (collect [form {: body-form?} (pairs (fennel.syntax))]
|
||||
(values form body-form?)))
|
||||
|
||||
(λ redundant-do [server file head call]
|
||||
(let [last-body (. call (length call))]
|
||||
(if (and (. implicit-do-forms (tostring head)) (. file.lexical call)
|
||||
(list? last-body) (sym? (. last-body 1) :do))
|
||||
(diagnostic {:range (message.ast->range server file last-body)
|
||||
:message "redundant do"
|
||||
:severity message.severity.WARN
|
||||
:code 311
|
||||
:codeDescription "redundant-do"}
|
||||
#[{:range (message.ast->range server file last-body)
|
||||
:newText (table.concat
|
||||
(fcollect [i 2 (length last-body)]
|
||||
(view (. last-body i)))
|
||||
" ")}]))))
|
||||
|
||||
(λ bad-unpack [server file op call]
|
||||
"an unpack call leading into an operator"
|
||||
(let [last-item (. call (length call))]
|
||||
@ -185,6 +227,9 @@ the `file.diagnostics` field, filling it with diagnostics."
|
||||
(when head
|
||||
(if lints.bad-unpack (table.insert diagnostics (bad-unpack server file head call)))
|
||||
(if lints.unnecessary-method (table.insert diagnostics (unnecessary-method server file head call)))
|
||||
(if lints.unnecessary-do (table.insert diagnostics (unnecessary-do-values server file head call)))
|
||||
(if lints.unnecessary-tset (table.insert diagnostics (unnecessary-tset server file head call)))
|
||||
(if lints.redundant-do (table.insert diagnostics (redundant-do server file head call)))
|
||||
(if lints.op-with-no-arguments (table.insert diagnostics (op-with-no-arguments server file head call)))
|
||||
|
||||
;; argument lints
|
||||
|
||||
@ -177,6 +177,47 @@
|
||||
[] [{:code 307}])
|
||||
nil)
|
||||
|
||||
(fn test-unnecessary-tset []
|
||||
;; valid, if you're targeting older Fennels
|
||||
(check "(local [tbl key] [{} :k]) (tset tbl key 249)" [] [{}])
|
||||
;; never a good use of tset
|
||||
(check "(local tbl {}) (tset tbl :key 9)"
|
||||
[{:code 309
|
||||
:codeDescription "unnecessary-tset"
|
||||
:message "unnecessary tset"
|
||||
:range {:start {:character 15 :line 0}
|
||||
:end {:character 32 :line 0}}}] []))
|
||||
|
||||
(fn test-unnecessary-do []
|
||||
;; multi-arg do
|
||||
(check "(do (print :x) 11)" [] [{}])
|
||||
;; unnecessary do
|
||||
(check "(do 9)" [{:message "unnecessary do"
|
||||
:code 310
|
||||
:codeDescription "unnecessary-do-values"
|
||||
:range {:start {:character 0 :line 0}
|
||||
:end {:character 6 :line 0}}}] [])
|
||||
;; unnecessary values
|
||||
(check "(print :hey (values :lol))"
|
||||
[{:code 310
|
||||
:codeDescription "unnecessary-do-values"
|
||||
:message "unnecessary values"
|
||||
:range {:start {:character 12 :line 0}
|
||||
:end {:character 25 :line 0}}}]
|
||||
[]))
|
||||
|
||||
(fn test-redundant-do []
|
||||
;; good do
|
||||
(check "(case 134 x (do (print :x x) 11))" [] [{}])
|
||||
;; unnecessary one
|
||||
(set _G.dbg true)
|
||||
(check "(let [x 29] (do (print 9) x))"
|
||||
[{:code 311
|
||||
:codeDescription "redundant-do"
|
||||
:message "redundant do"
|
||||
:range {:start {:character 12 :line 0}
|
||||
:end {:character 28 :line 0}}}] []))
|
||||
|
||||
(fn test-match-should-case []
|
||||
;; OK: most basic pinning
|
||||
(check "(let [x 99] (match 99 x :yep!))" [] [{}])
|
||||
@ -207,16 +248,12 @@
|
||||
:end {:character 6 :line 0}}}] []))
|
||||
|
||||
;; TODO lints:
|
||||
;; unnecessary (do) in body position
|
||||
;; duplicate keys in kv table
|
||||
;; (tset <sym> <str>) --> (set <sym>.<str>)
|
||||
;; (tset <sym> <any>) --> (set (. <sym> <any>))
|
||||
;; (tset <sym> <any>) --> (set (. <sym> <any>)) (might be wanted for compat?)
|
||||
;; {&as x} and [&as x] pattern with no other matches
|
||||
;; Unused variables / fields (maybe difficult)
|
||||
;; discarding results to various calls, such as unpack, values, etc
|
||||
;; unnecessary `do`/`values` with only one inner form
|
||||
;; `pairs` or `ipairs` call in a (for) binding table
|
||||
;; mark when unification is happening on a `match` pattern (may be difficult)
|
||||
;; steal as many lints as possible from cargo
|
||||
;; unnecessary parens around single multival destructure
|
||||
|
||||
@ -226,6 +263,9 @@
|
||||
: test-ampersand
|
||||
: test-unknown-module-field
|
||||
: test-unnecessary-colon
|
||||
: test-unnecessary-tset
|
||||
: test-unnecessary-do
|
||||
: test-redundant-do
|
||||
: test-unset-var
|
||||
: test-match-should-case
|
||||
: test-unpack-into-op
|
||||
|
||||
Loading…
Reference in New Issue
Block a user