diff --git a/cases/testcases/unusednsimport/consumer1.clj b/cases/testcases/unusednsimport/consumer1.clj new file mode 100644 index 00000000..82b4e2c5 --- /dev/null +++ b/cases/testcases/unusednsimport/consumer1.clj @@ -0,0 +1,7 @@ +(ns testcases.unusednsimport.consumer1 + ;; This require is needed to properly import the record below + (:require [testcases.unusednsimport.defrecord]) + (:import (testcases.unusednsimport.defrecord A))) + +;; Exercises top-level forms: +(A. 1) diff --git a/cases/testcases/unusednsimport/consumer2.clj b/cases/testcases/unusednsimport/consumer2.clj new file mode 100644 index 00000000..5f72de3f --- /dev/null +++ b/cases/testcases/unusednsimport/consumer2.clj @@ -0,0 +1,8 @@ +(ns testcases.unusednsimport.consumer2 + ;; This require is needed to properly import the record below + (:require [testcases.unusednsimport.defrecord]) + (:import (testcases.unusednsimport.defrecord A))) + +;; Should be deemed unused: +(comment + (A. 1)) diff --git a/cases/testcases/unusednsimport/consumer3.clj b/cases/testcases/unusednsimport/consumer3.clj new file mode 100644 index 00000000..cd9c3c78 --- /dev/null +++ b/cases/testcases/unusednsimport/consumer3.clj @@ -0,0 +1,9 @@ +(ns testcases.unusednsimport.consumer3 + ;; This require is needed to properly import the record below + (:require [testcases.unusednsimport.defrecord]) + (:import (testcases.unusednsimport.defrecord A))) + +;; Exercises forms nested deep into arbitrary code: +(defn sample [] + (for [x [(A. 1)]] + x)) diff --git a/cases/testcases/unusednsimport/consumer4.clj b/cases/testcases/unusednsimport/consumer4.clj new file mode 100644 index 00000000..b37513e8 --- /dev/null +++ b/cases/testcases/unusednsimport/consumer4.clj @@ -0,0 +1,9 @@ +(ns testcases.unusednsimport.consumer4 + ;; This require is needed to properly import the record below + (:require [testcases.unusednsimport.defrecord]) + (:import (testcases.unusednsimport.defrecord A))) + +;; Exercises metadata: +(defn ^A sample [] + ;; return nil (and not `(A.)` so that we are certain that only metadata is being exercised) + nil) diff --git a/cases/testcases/unusednsimport/consumer5.clj b/cases/testcases/unusednsimport/consumer5.clj new file mode 100644 index 00000000..67c736f7 --- /dev/null +++ b/cases/testcases/unusednsimport/consumer5.clj @@ -0,0 +1,7 @@ +(ns testcases.unusednsimport.consumer5 + ;; This require is needed to properly import the record below + (:require [testcases.unusednsimport.defrecord]) + (:import (testcases.unusednsimport.defrecord A))) + +;; Exercises simple defs: +(def thing (A. 1)) diff --git a/cases/testcases/unusednsimport/defrecord.clj b/cases/testcases/unusednsimport/defrecord.clj new file mode 100644 index 00000000..d993feb5 --- /dev/null +++ b/cases/testcases/unusednsimport/defrecord.clj @@ -0,0 +1,3 @@ +(ns testcases.unusednsimport.defrecord) + +(defrecord A [a]) diff --git a/src/eastwood/linters/unused.clj b/src/eastwood/linters/unused.clj index a1728733..c590e437 100644 --- a/src/eastwood/linters/unused.clj +++ b/src/eastwood/linters/unused.clj @@ -63,6 +63,19 @@ (str/replace #"\.[^\.]+$" "") symbol)) +(defn classes-used [asts] + (let [simple-tags (->> asts + (mapcat ast/nodes) + (keep :o-tag)) + tags-from-meta (->> asts + (mapcat ast/nodes) + (keep (comp :tag meta :result))) + tags (into simple-tags tags-from-meta)] + + (into #{} + (remove nil?) + tags))) + (defn protocols-used [asts] (->> asts (mapcat ast/nodes) @@ -267,6 +280,7 @@ Example: (all-suffixes [1 2 3]) used-keywords (keywords-used asts) used-macros (macros-invoked asts) used-protocols (protocols-used asts) + used-classes (classes-used asts) ;; _ (do ;; (println "dbg: required namespaces:") ;; (pp/pprint required) @@ -302,7 +316,8 @@ Example: (all-suffixes [1 2 3]) (map symbol)) (keep #(if-let [n (namespace %)] (symbol n)) used-macros) - (map namespace-for used-protocols)))] + (map namespace-for used-protocols) + (map namespace-for used-classes)))] (for [ns (set/difference required used-namespaces)] {:loc loc :unused-namespace-sym ns diff --git a/test/eastwood/test/linters_test.clj b/test/eastwood/test/linters_test.clj index b6cdf7d1..9b296925 100644 --- a/test/eastwood/test/linters_test.clj +++ b/test/eastwood/test/linters_test.clj @@ -1708,6 +1708,23 @@ the next." :line 164, :column 1} 1, }) + ;; No faults expected: + (lint-test 'testcases.unusednsimport.consumer1 [:unused-namespaces] default-opts {}) + ;; Fault expected (since the refered type is in a `comment` form): + (lint-test 'testcases.unusednsimport.consumer2 + [:unused-namespaces] + default-opts + {{:linter :unused-namespaces + :msg "Namespace testcases.unusednsimport.defrecord is never used in testcases.unusednsimport.consumer2" + :file "testcases/unusednsimport/consumer2.clj" + :line 1 + :column 1} 1}) + ;; No faults expected: + (lint-test 'testcases.unusednsimport.consumer3 [:unused-namespaces] default-opts {}) + ;; No faults expected: + (lint-test 'testcases.unusednsimport.consumer4 [:unused-namespaces] default-opts {}) + ;; No faults expected: + (lint-test 'testcases.unusednsimport.consumer5 [:unused-namespaces] default-opts {}) (lint-test 'testcases.unusednss [:unused-namespaces :unused-locals]