Permalink
Browse files

Second attempt at unused-locals

  • Loading branch information...
1 parent 86f62da commit e3a2f8e9b13ba38bee8ab1d31f8b01ffad7691ae @jonase committed Jan 16, 2012
Showing with 72 additions and 36 deletions.
  1. +7 −7 project.clj
  2. +63 −27 src/eastwood/linters/unused.clj
  3. +2 −2 src/eastwood/util.clj
View
@@ -4,24 +4,24 @@
[analyze "0.1.3-SNAPSHOT"]
;; clojure.data.json OK
- #_[org.clojure/data.json "0.1.1"]
+ [org.clojure/data.json "0.1.1"]
;; clojure.core.match: lots of reflection warnings -- eastwood fault
- #_[org.clojure/core.match "0.2.0-alpha8"]
+ [org.clojure/core.match "0.2.0-alpha8"]
;; clojure.core.logic: 2x misplaced docstrings, subst? never used + lots of reflection
- #_[org.clojure/core.logic "0.6.7"]
+ [org.clojure/core.logic "0.6.7"]
;; clojure.data.finger-tree: lots of reflection
- #_[org.clojure/data.finger-tree "0.0.1"]
+ [org.clojure/data.finger-tree "0.0.1"]
;; clojure.tools.logging: OK
- #_[org.clojure/tools.logging "0.2.3"]
+ [org.clojure/tools.logging "0.2.3"]
;; clojure.java.jdbc: using deprecated replicate + naked use.
;; clojure.java.jdbc.internal: reflection getCause
- #_[org.clojure/java.jdbc "0.1.1"]
+ [org.clojure/java.jdbc "0.1.1"]
;; clojure.data.csv: OK
- #_[org.clojure/data.csv "0.1.0"]
+ [org.clojure/data.csv "0.1.0"]
])
@@ -1,41 +1,49 @@
(ns eastwood.linters.unused
(:require [clojure.set :as set]
- [eastwood.util :as util])
+ #_[eastwood.util :as util])
(:use analyze.core analyze.util))
-(defn unused-locals* [binding-expr]
- (let [lbs (util/local-bindings binding-expr)
- free (apply set/union (map util/free-locals
- (:children binding-expr)))]
- (set/difference lbs free)))
-
(defn binding-expr? [expr]
(#{:let :let-fn :fn-method} (:op expr)))
-(defmulti report (fn [expr locals] (:op expr)))
+(defn locals-used [expr]
+ (set (->> (expr-seq expr)
+ (filter #(= (:op %) :local-binding-expr))
+ (map #(-> % :local-binding :LocalBinding-obj)))))
-(defmethod report :let [expr locals]
- (if (> (count locals) 1)
- (println "Unused let-locals:" locals)
- (println "Unused let-local:" (first locals))))
+(defn local-bindings [expr]
+ (condp = (:op expr)
+ :fn-method (if-let [rest-param (:rest-param expr)]
+ (conj (set (map :LocalBinding-obj (:required-params expr)))
+ (:LocalBinding-obj rest-param))
+ (set (map :LocalBinding-obj (:required-params expr))))
+ :let (set (map #(-> % :local-binding :LocalBinding-obj)
+ (:binding-inits expr)))
+ :let-fn (set (map #(-> % :local-binding :LocalBinding-obj)
+ (:binding-inits expr)))))
-(defmethod report :let-fn [expr locals]
- (if (> (count locals) 1)
- (println "Unused letfn arguments:" locals)
- (println "Unused letfn argument:" (first locals))))
+(defn report [expr locals]
+ (let [msg (condp = (:op expr)
+ :let "let-local"
+ :let-fn "letfn argument"
+ :fn-method "fn argument")]
+ (if (> (count locals) 1)
+ (let [msg (str msg "s:")]
+ (apply println "Unused" msg locals))
+ (let [msg (str msg ":")]
+ (println "Unused" msg (first locals))))))
-(defmethod report :fn-method [expr locals]
- (if (> (count locals) 1)
- (println "Unused fn arguments:" locals)
- (println "Unused fn argument:" (first locals))))
+(def ^:dynamic *ignore-locals* #{'_ '&form '&env})
+;; NOTE: destructured loop-locals are reported as unused
(defn unused-locals [exprs]
- (doseq [expr (mapcat expr-seq exprs)]
- (when (binding-expr? expr)
- (when-let [ul (seq (for [{sym :sym} (unused-locals* expr)
- :when (not= '_ sym)]
- sym))]
- (report expr ul)))))
+ (doseq [expr (mapcat expr-seq exprs)
+ :when (binding-expr? expr)]
+ (let [dl (local-bindings expr)
+ lu (locals-used expr)
+ diff (map #(.sym %) (set/difference dl lu))]
+ (when (seq (remove *ignore-locals* diff))
+ (report expr diff)))))
;; Unused private vars
(defn- private-defs [exprs]
@@ -44,7 +52,7 @@
(-> % :var meta :private)
(-> % :var meta :macro not))) ;; skip private macros
(map :var)))
-
+
(defn- var-freq [exprs]
(->> (mapcat expr-seq exprs)
(filter #(= :var (:op %)))
@@ -57,3 +65,31 @@
(doseq [pvar pdefs
:when (nil? (vfreq pvar))]
(println "Private var" pvar "is never used"))))
+
+
+(comment
+
+ (def src '(loop [[a] []] a))
+ (def analyzed (analyze-one {:ns {:name 'user} :context :eval}
+ src))
+
+ (unused-locals [analyzed])
+
+ (print-expr (analyze-one {:ns {:name 'user} :context :eval}
+ '(let [a 0])))
+
+ (def expr (first (drop-while #(not= (:op %) :let)
+ (expr-seq analyzed))))
+
+ (print-expr expr
+ :children
+ :env)
+
+ (locals-used expr)
+
+ (local-bindings expr)
+
+ (set/difference (local-bindings expr)
+ (locals-used expr))
+
+ )
View
@@ -15,9 +15,9 @@
(defn free-locals [expr]
(if (= (:op expr) :local-binding-expr)
- #{(:local-binding expr)}
+ #{(:sym (:local-binding expr))}
(set/difference (apply set/union (map free-locals
- (:children expr)))
+ (:children expr))))
(local-bindings expr))))

0 comments on commit e3a2f8e

Please sign in to comment.