320 lines
7.3 KiB
Markdown
320 lines
7.3 KiB
Markdown
# unused-definition
|
|
## What it does
|
|
Marks bindings that aren't read. Completely overwriting a value doesn't count
|
|
as reading it. A variable that starts or ends with an `_` will not trigger this
|
|
lint. Use this to suppress the lint.
|
|
|
|
## Why is this bad?
|
|
Unused definitions can lead to bugs and make code harder to understand. Either
|
|
remove the binding, or add an `_` to the variable name.
|
|
|
|
## Example
|
|
```fnl
|
|
(var value 100)
|
|
(set value 10)
|
|
```
|
|
|
|
Instead, use the value, remove it, or add `_` to the variable name.
|
|
```fnl
|
|
(var value 100)
|
|
(set value 10)
|
|
;; use the value
|
|
(print value)
|
|
```
|
|
|
|
## Known limitations
|
|
Fennel's pattern matching macros also check for leading `_` for symbol names.
|
|
This means that adding an `_` can change the semantics of the code. In this
|
|
situation, add the `_` to the end of the symbol to disable the lint without
|
|
changing the pattern's meaning.
|
|
```fnl
|
|
(match [10 nil]
|
|
;; pattern works as intended, but triggers the lint
|
|
[a b] (print a "unintended")
|
|
_ (print "unintended"))
|
|
|
|
(match [10 nil]
|
|
;; pattern matches when we don't want it to
|
|
[a _b] (print a "unintended")
|
|
_ (print "unintended"))
|
|
|
|
(match [10 nil]
|
|
;; works as intended and doesn't trigger lint
|
|
[a b_] (print a "unintended")
|
|
_ (print "unintended"))
|
|
```
|
|
|
|
Think of it this way:
|
|
`identifier` - must be used, and should be non-`nil`
|
|
`?identifier` - must be used, and can be `nil`
|
|
`_identifier` - may be unused, and can be `nil`
|
|
`identifer_` - may be unused, but should be non-`nil`
|
|
|
|
# unknown-module-field
|
|
## What it does
|
|
Looks for module fields that can't be statically determined to exist. This only
|
|
triggers if the module is found, but there's no definition of the field inside
|
|
of the module.
|
|
|
|
## Why is this bad?
|
|
This is probably a typo, or a missing function in the module.
|
|
|
|
## Example
|
|
```fnl
|
|
;;; in `a.fnl`
|
|
{: print}
|
|
|
|
;;; in `b.fnl`
|
|
(local a (require :a))
|
|
(a.printtt 100)
|
|
```
|
|
Instead, use:
|
|
```fnl
|
|
;;; in `b.fnl`
|
|
(local a (require :a))
|
|
(a.print 100) ; typo fixed
|
|
```
|
|
|
|
## Known limitations
|
|
Fennel-ls doesn't have a full type system, so we're not able to check every
|
|
multisym statically, but as a heuristic, usually modules are able to be
|
|
evaluated statically. If you have a module that can't be figured out, please
|
|
let us know on the bug tracker.
|
|
|
|
# unnecessary-method
|
|
## What it does
|
|
Checks for unnecessary uses of the `:` method call syntax when a simple multisym
|
|
would work.
|
|
|
|
## Why is this bad?
|
|
Using the method call syntax unnecessarily adds complexity and can make code
|
|
harder to understand.
|
|
|
|
## Example
|
|
```fnl
|
|
(: alien :shoot-laser {:x 10 :y 20})
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(alien:shoot-laser {:x 10 :y 20})
|
|
```
|
|
|
|
# unnecessary-tset
|
|
## What it does
|
|
Identifies unnecessary uses of `tset` when a `set` with a multisym would be clearer.
|
|
|
|
## Why is this bad?
|
|
Using `tset` makes the code more verbose and harder to read when a simpler
|
|
alternative exists.
|
|
|
|
## Example
|
|
```fnl
|
|
(tset alien :health 1337)
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(set alien.health 1337)
|
|
```
|
|
|
|
# unnecessary-unary
|
|
## What it does
|
|
Warns about unnecessary `do` or `values` forms that only contain a single expression.
|
|
|
|
## Why is this bad?
|
|
Extra forms that don't do anything add syntactic noise.
|
|
|
|
## Example
|
|
```fnl
|
|
(do (print "hello"))
|
|
|
|
(values (+ 1 2))
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(print "hello")
|
|
|
|
(+ 1 2)
|
|
```
|
|
|
|
# redundant-do
|
|
## What it does
|
|
Identifies redundant `do` blocks within implicit do forms like `fn`, `let`, etc.
|
|
|
|
## Why is this bad?
|
|
Redundant `do` blocks add unnecessary nesting and make code harder to read.
|
|
|
|
## Example
|
|
```fnl
|
|
(fn [] (do
|
|
(print "first")
|
|
(print "second")))
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(fn []
|
|
(print "first")
|
|
(print "second"))
|
|
```
|
|
|
|
# bad-unpack
|
|
## What it does
|
|
Warns when `unpack` or `table.unpack` is used with operators that aren't
|
|
variadic at runtime.
|
|
|
|
## Why is this bad?
|
|
Fennel operators like `+`, `*`, etc. look like they should work with `unpack`,
|
|
but they don't actually accept a variable number of arguments at runtime.
|
|
|
|
## Example
|
|
```fnl
|
|
(+ 1 (unpack [2 3 4])) ; Only adds 1 and 2
|
|
(.. (unpack ["a" "b" "c"])) ; Only concatenates "a"
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
;; For concatenation:
|
|
(table.concat ["a" "b" "c"])
|
|
|
|
;; For other operators, use a loop:
|
|
(accumulate [sum 0 _ n (ipairs [1 2 3 4])]
|
|
(+ sum n))
|
|
```
|
|
|
|
# var-never-set
|
|
## What it does
|
|
Identifies variables declared with `var` that are never modified with `set`.
|
|
|
|
## Why is this bad?
|
|
If a `var` is never modified, it should be declared with `local` or `let` instead
|
|
for clarity.
|
|
|
|
## Example
|
|
```fnl
|
|
(var x 10)
|
|
(print x)
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(let [x 10]
|
|
(print x))
|
|
```
|
|
|
|
# op-with-no-arguments
|
|
## What it does
|
|
Warns when an operator is called with no arguments, which can be replaced with
|
|
an identity value.
|
|
|
|
## Why is this bad?
|
|
Calling operators with no arguments is less clear than using the identity value
|
|
directly.
|
|
|
|
## Example
|
|
```fnl
|
|
(+) ; Returns 0
|
|
(*) ; Returns 1
|
|
(..) ; Returns ""
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
0
|
|
1
|
|
""
|
|
```
|
|
|
|
## Note
|
|
This lint isn't actually very useful.
|
|
|
|
# no-decreasing-comparison (off by default)
|
|
## What it does
|
|
Suggests using increasing comparison operators (`<`, `<=`) instead of decreasing ones (`>`, `>=`).
|
|
|
|
## Why is this bad?
|
|
Consistency in comparison direction makes code more readable and maintainable,
|
|
especially in languages with lisp syntax. You can think of `<` as a function that
|
|
tests if the arguments are in sorted order.
|
|
|
|
## Example
|
|
```fnl
|
|
(> a b)
|
|
(>= x y z)
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(< b a)
|
|
(<= z y x)
|
|
```
|
|
|
|
# match-should-case
|
|
## What it does
|
|
Suggests using `case` instead of `match` when the meaning would not be altered.
|
|
|
|
## Why is this bad?
|
|
The `match` macro's meaning depends on the local variables in scope. When a
|
|
`match` call doesn't use the local variables, it can be replaced with the
|
|
`case` form.
|
|
|
|
## Example
|
|
```fnl
|
|
(match value
|
|
10 "ten"
|
|
20 "twenty"
|
|
_ "other")
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
(case value
|
|
10 "ten"
|
|
20 "twenty"
|
|
_ "other")
|
|
```
|
|
|
|
# inline-values
|
|
## What it does
|
|
Warns when multiple values from `values` or `unpack` are used in a non-final
|
|
position of a function call, where only the first value will be used.
|
|
|
|
## Why is this bad?
|
|
In Fennel (and Lua), multiple values are only preserved when they appear in the
|
|
final position of a function call. Using them elsewhere results in only the
|
|
first value being used. This is likely not what was intended, since the use of
|
|
`values` or `unpack` seems to imply that the code is interested in handling
|
|
multivals instead of discarding them.
|
|
|
|
## Example
|
|
```fnl
|
|
(print (values 1 2 3) 4) ; confusingly prints "1 4"
|
|
```
|
|
|
|
Instead, use:
|
|
```fnl
|
|
;; Try putting the multival at the end:
|
|
(print 4 (values 1 2 3))
|
|
|
|
;; Try writing the logic out manually instead of using multival
|
|
(let [(a b c) (values 1 2 3)]
|
|
(print a b c 4)
|
|
```
|
|
|
|
## Limitations
|
|
It doesn't make sense to flag *all* places where a multival is discarded, because
|
|
discarding extra values is common in Lua. For example, in the standard library
|
|
of Lua, `string.gsub` and `require` actually return two results, even though
|
|
most of the time, only the first one is what's wanted.
|
|
|
|
This lint specifically flags discarding multivals from `values` and `unpack`,
|
|
instead of flagging all discards, because these forms indicate that the user
|
|
*intends* for something to happen with multivals.
|
|
|
|
## Note
|
|
You find more information about Lua's multivals in [Benaiah's excellent post explaining Lua's multivals](https://benaiah.me/posts/everything-you-didnt-want-to-know-about-lua-multivals),
|
|
or by searching the word "adjust" in the [Lua Manual](https://www.lua.org/manual/5.4/manual.html#3.4.12).
|