Skip to content

Commit

Permalink
Fix clj-kondo#2448: redundant nested call in hook gen'ed code (clj-ko…
Browse files Browse the repository at this point in the history
  • Loading branch information
borkdude authored Dec 3, 2024
1 parent 0d0b669 commit 4bac9e2
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ For a list of breaking changes, check [here](#breaking-changes).
- [#2431](https://github.com/clj-kondo/clj-kondo/issues/2431): only apply redundant-nested-call linter for nested exprs
- Relax `:redundant-nested-call` for `comp`, `concat`, `every-pred` and `some-fn` since it may affect performance
- [#2446](https://github.com/clj-kondo/clj-kondo/issues/2446): false positive `:redundant-ignore`
- [#2448](https://github.com/clj-kondo/clj-kondo/issues/2448): redundant nested call in hook gen'ed code

## 2024.11.14

Expand Down
4 changes: 4 additions & 0 deletions corpus/issue-2448/.clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{:hooks {:analyze-call {ductile.util/if+ hooks/ifplus-hook
ductile.util/when+ hooks/whenplus-hook
ductile.util/cond+ hooks/condplus-hook}}
:linters {:redundant-nested-call {:level :warning}}}
93 changes: 93 additions & 0 deletions corpus/issue-2448/.clj-kondo/hooks.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
(ns hooks
(:require
[clj-kondo.hooks-api :as api]))

(defn transform-conds [cond-forms body-form]
(if (empty? cond-forms)
body-form
(let [cond-form (first cond-forms)]
(if (and (api/keyword-node? cond-form) (= :let (:k cond-form)))
(api/list-node
(list
(api/token-node 'let)
(second cond-forms)
(transform-conds (nnext cond-forms) body-form)))
(api/list-node
(list
(api/token-node 'when)
cond-form
(transform-conds (next cond-forms) body-form)))))))

(defn ifplus-hook [form]
(let [[_ cond-form then-form else-form] (:children (:node form))
new-node (or
(when (api/list-node? cond-form)
(let [[f & conds] (:children cond-form)]
(when (and (api/token-node? f)
(= 'and (:value f)))
(api/list-node
(list
(api/token-node 'or)
(transform-conds conds then-form)
else-form)))))
(api/list-node
(list
(api/token-node 'if)
cond-form
then-form
else-form)))]
{:node
new-node}))

(defn whenplus-hook [form]
(let [[_ cond-form & body-forms] (:children (:node form))]
{:node
(api/list-node
(list
(api/token-node 'ductile.util/if+)
cond-form
(api/list-node
(list*
(api/token-node 'do)
body-forms))
(api/token-node nil)))}))

(defn condplus-hook [form]
(let [[_ test expr & rest] (:children (:node form))
tail (if rest
(api/list-node
(list*
(api/token-node 'ductile.util/cond+)
rest))
(api/coerce nil))
new-node (cond
(and (api/keyword-node? test) (= :do (:k test)))
(api/list-node
(list
(api/token-node 'do)
expr
tail))

(and (api/keyword-node? test) (= :let (:k test)))
(api/list-node
(list
(api/token-node 'let)
expr
tail))

(and (api/keyword-node? test) (= :some (:k test)))
(api/list-node
(list
(api/token-node 'or)
expr
tail))

:else
(api/list-node
(list
(api/token-node 'ductile.util/if+)
test
expr
tail)))]
{:node new-node}))

13 changes: 13 additions & 0 deletions corpus/issue-2448/src/foobar.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(ns foobar
(:require [ductile.util :as util]))

(util/cond+
false 1
(and true
:let [x 2]
(= 3 x)) 4
(and true
:let [x 3]
(= 3 x)) x)

(or (or 1 2) 2)
7 changes: 4 additions & 3 deletions src/clj_kondo/impl/linters.clj
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@
(defn lint-redundant-nested-call
"Lints calls of variadic functions/macros when nested."
[call]
(let [[[call-ns call-name :as c] parent] (:callstack call)]
(let [[[call-ns call-name :as c] parent] (:callstack call)
mc (meta c)]
(when (and (utils/one-of call-ns [clojure.core cljs.core])
(utils/one-of call-name [* *' + +'
and or
Expand All @@ -231,8 +232,8 @@
)
(= [call-ns call-name] parent)
;; Exclude instances of nesting when directly inside threading macros
(let [mc (meta c)
{call-row :row
(not (:derived-location mc))
(let [{call-row :row
call-col :col} mc
{parent-row :row
parent-col :col} (meta parent)]
Expand Down
11 changes: 11 additions & 0 deletions test/clj_kondo/hooks_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,14 @@ my-ns/special-map \"
(lint! (fs/file "corpus" "issue-2446" "src" "foobar.clj")
"--config" (slurp (fs/file "corpus" "issue-2446" ".clj-kondo" "config.edn"))
"--config-dir" (fs/file "corpus" "issue-2446" ".clj-kondo"))))

(deftest issue-2448-hooks-redundant-nested-call-test
(assert-submaps2
[{:file "corpus/issue-2448/src/foobar.clj",
:row 13,
:col 5,
:level :warning,
:message "Redundant nested call: or"}]
(lint! (fs/file "corpus" "issue-2448" "src" "foobar.clj")
"--config" (slurp (fs/file "corpus" "issue-2448" ".clj-kondo" "config.edn"))
"--config-dir" (fs/file "corpus" "issue-2448" ".clj-kondo"))))

0 comments on commit 4bac9e2

Please sign in to comment.