Add diagnostic for var-never-set.
This uses the isvar field from the opts map of the destructure hook.
This commit is contained in:
parent
f25fd9fd60
commit
5055fd31ef
@ -83,7 +83,7 @@ later by fennel-ls.language to answer requests from the client."
|
|||||||
(when (or ?reference? (fennel.multi-sym? ast))
|
(when (or ?reference? (fennel.multi-sym? ast))
|
||||||
(reference ast scope)))
|
(reference ast scope)))
|
||||||
|
|
||||||
(λ define [?definition binding scope]
|
(λ define [?definition binding scope ?opts]
|
||||||
;; Add a definition to the definitions
|
;; Add a definition to the definitions
|
||||||
;; recursively explore the binding (which, in the general case, is a destructuring assignment)
|
;; recursively explore the binding (which, in the general case, is a destructuring assignment)
|
||||||
;; right now I'm not keeping track of *how* the symbol was destructured: just finding all the symbols for now.
|
;; right now I'm not keeping track of *how* the symbol was destructured: just finding all the symbols for now.
|
||||||
@ -96,7 +96,8 @@ later by fennel-ls.language to answer requests from the client."
|
|||||||
:referenced-by (or (?. definitions binding :referenced-by) [])
|
:referenced-by (or (?. definitions binding :referenced-by) [])
|
||||||
:keys (if (< 0 (length keys))
|
:keys (if (< 0 (length keys))
|
||||||
(fcollect [i 1 (length keys)]
|
(fcollect [i 1 (length keys)]
|
||||||
(. keys i)))}]
|
(. keys i)))
|
||||||
|
:var? (?. ?opts :isvar)}]
|
||||||
(tset (. definitions-by-scope scope) (tostring binding) definition)
|
(tset (. definitions-by-scope scope) (tostring binding) definition)
|
||||||
(tset definitions binding definition))
|
(tset definitions binding definition))
|
||||||
(list? binding)
|
(list? binding)
|
||||||
@ -104,7 +105,7 @@ later by fennel-ls.language to answer requests from the client."
|
|||||||
(= (length binding)
|
(= (length binding)
|
||||||
(- (length ?definition) 1)))
|
(- (length ?definition) 1)))
|
||||||
(for [i 1 (length binding)]
|
(for [i 1 (length binding)]
|
||||||
(define (. ?definition (+ i 1)) (. binding i) scope))
|
(define (. ?definition (+ i 1)) (. binding i) scope ?opts))
|
||||||
(recurse (. binding 1) keys))
|
(recurse (. binding 1) keys))
|
||||||
(table? binding)
|
(table? binding)
|
||||||
(accumulate [prev nil
|
(accumulate [prev nil
|
||||||
@ -135,10 +136,10 @@ later by fennel-ls.language to answer requests from the client."
|
|||||||
;; (fcollect [i 1 (length keys)]
|
;; (fcollect [i 1 (length keys)]
|
||||||
;; (. keys i)))}
|
;; (. keys i)))}
|
||||||
name (string.match (tostring binding) "[^%.:]+")]
|
name (string.match (tostring binding) "[^%.:]+")]
|
||||||
(when (multisym? binding)
|
(case (find-definition (tostring name) scope)
|
||||||
(case (find-definition (tostring name) scope)
|
target (if (multisym? binding)
|
||||||
target
|
(table.insert target.referenced-by binding)
|
||||||
(table.insert target.referenced-by binding))))
|
(set target.var-set true))))
|
||||||
(= :table (type binding))
|
(= :table (type binding))
|
||||||
(each [k v (iter binding)]
|
(each [k v (iter binding)]
|
||||||
(table.insert keys k)
|
(table.insert keys k)
|
||||||
@ -146,11 +147,11 @@ later by fennel-ls.language to answer requests from the client."
|
|||||||
(table.remove keys))))
|
(table.remove keys))))
|
||||||
(recurse binding []))
|
(recurse binding []))
|
||||||
|
|
||||||
(λ destructure [to from scope {:declaration ?declaration?}]
|
(λ destructure [to from scope {:declaration ?declaration? &as opts}]
|
||||||
;; I really don't understand symtype
|
;; I really don't understand symtype
|
||||||
;; I think I need an explanation
|
;; I think I need an explanation
|
||||||
(if ?declaration?
|
(if ?declaration?
|
||||||
(define to from scope)
|
(define to from scope opts)
|
||||||
(mutate to from scope)))
|
(mutate to from scope)))
|
||||||
|
|
||||||
(λ add-field [ast multisym scope]
|
(λ add-field [ast multisym scope]
|
||||||
|
|||||||
@ -73,6 +73,15 @@ Goes through a file and mutates the `file.diagnostics` field, filling it with di
|
|||||||
:code 304
|
:code 304
|
||||||
:codeDescription "bad-unpack"}))))
|
:codeDescription "bad-unpack"}))))
|
||||||
|
|
||||||
|
(λ var-never-set [self file]
|
||||||
|
(icollect [symbol definition (pairs file.definitions) &into file.diagnostics]
|
||||||
|
(if (and definition.var? (not definition.var-set))
|
||||||
|
{:range (message.ast->range self file symbol)
|
||||||
|
:message (.. "var is never set: " (tostring symbol))
|
||||||
|
:severity message.severity.WARN
|
||||||
|
:code 301
|
||||||
|
:codeDescription "var-never-set"})))
|
||||||
|
|
||||||
(λ check [self file]
|
(λ check [self file]
|
||||||
"fill up the file.diagnostics table with linting things"
|
"fill up the file.diagnostics table with linting things"
|
||||||
(if self.configuration.checks.unused-definition
|
(if self.configuration.checks.unused-definition
|
||||||
@ -82,6 +91,8 @@ Goes through a file and mutates the `file.diagnostics` field, filling it with di
|
|||||||
(if self.configuration.checks.unnecessary-method
|
(if self.configuration.checks.unnecessary-method
|
||||||
(unnecessary-method self file))
|
(unnecessary-method self file))
|
||||||
(if self.configuration.checks.bad-unpack
|
(if self.configuration.checks.bad-unpack
|
||||||
(bad-unpack self file)))
|
(bad-unpack self file))
|
||||||
|
(if self.configuration.checks.var-never-set
|
||||||
|
(var-never-set self file)))
|
||||||
|
|
||||||
{: check}
|
{: check}
|
||||||
|
|||||||
@ -96,7 +96,8 @@ in the \"self\" object."
|
|||||||
:checks {:unused-definition (option true)
|
:checks {:unused-definition (option true)
|
||||||
:unknown-module-field (option true)
|
:unknown-module-field (option true)
|
||||||
:unnecessary-method (option true)
|
:unnecessary-method (option true)
|
||||||
:bad-unpack (option true)}
|
:bad-unpack (option true)
|
||||||
|
:var-never-set (option true)}
|
||||||
:extra-globals (option "")})
|
:extra-globals (option "")})
|
||||||
|
|
||||||
(λ make-configuration [?c]
|
(λ make-configuration [?c]
|
||||||
|
|||||||
@ -81,6 +81,20 @@
|
|||||||
"not found")
|
"not found")
|
||||||
_ (error "did not match"))))
|
_ (error "did not match"))))
|
||||||
|
|
||||||
|
(it "warns about vars that are never set"
|
||||||
|
(let [self (create-client)
|
||||||
|
responses (self:open-file! filename "(var x nil) (print x)")]
|
||||||
|
(match responses
|
||||||
|
[{:params {: diagnostics}}]
|
||||||
|
(is (find [_ v (ipairs diagnostics)]
|
||||||
|
(match v
|
||||||
|
{:message "var is never set: x"
|
||||||
|
:range {:start {:character 5 :line 0}
|
||||||
|
:end {:character 6 :line 0}}}
|
||||||
|
v))
|
||||||
|
"not found")
|
||||||
|
_ (error "did not match"))))
|
||||||
|
|
||||||
(it "warns about unused functions"
|
(it "warns about unused functions"
|
||||||
(let [self (create-client)
|
(let [self (create-client)
|
||||||
responses (self:open-file! filename "(fn x [])")]
|
responses (self:open-file! filename "(fn x [])")]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user