Skip to content

Commit b5d0393

Browse files
[Fix #184] Squashed commit of the following:
commit ff5c4612b8a7eb816905a4c412b6d3f574d47b71 Merge: 10089ca fe6b355 Author: Benedek Fazekas <[email protected]> Date: Sun Jan 22 21:04:59 2017 +0000 Merge branch 'eager-find-classes' of git://github.com/plexus/refactor-nrepl into plexus-eager-find-classes commit fe6b355 Author: Arne Brasseur <[email protected]> Date: Sun Jan 22 12:35:01 2017 +0100 Cleanup: replace pre-1.2 metadata, prefer reify over proxy FileNameFilter is an interface, so reify does the job just fine, no need for proxy. commit 9e8531a Author: Arne Brasseur <[email protected]> Date: Sun Jan 22 12:34:19 2017 +0100 Add CHANGELOG entry for #184 commit c1838f1 Author: Arne Brasseur <[email protected]> Date: Fri Jan 20 21:19:38 2017 +0100 Remove laziness in Slamhound's "get-available-classes" Once the classpath gets big enough, this would cause a stack overflow, which from clj-refactor simply shows up as a timeout. Instead use transducers over lists as much as possible. Since the collection of available classes is only ever traversed sequentially, this provides the best performance as well.
1 parent 10089ca commit b5d0393

File tree

2 files changed

+41
-37
lines changed

2 files changed

+41
-37
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
* [#185](https://github.com/clojure-emacs/refactor-nrepl/issues/185) Report throwables of type `Error` instead of swallowing them.
88
* [#186](https://github.com/clojure-emacs/refactor-nrepl/issues/186) Make sure `resolve-missing` still works, even if a candidate class has missing dependencies.
9+
* [#184](https://github.com/clojure-emacs/refactor-nrepl/pull/184) In `resolve-missing`, prevent classpaths with many entries from causing a stack overflow.
910
* [clojure-emacs/clj-refactor.el#330](https://github.com/clojure-emacs/clj-refactor.el/issues/332) `clean-ns` removes imported inner inner classes.
1011
* [clojure-emacs/clj-refactor.el#330](https://github.com/clojure-emacs/clj-refactor.el/issues/330) `clean-ns` ignores namespaced keywords.
1112
* [#160](https://github.com/clojure-emacs/refactor-nrepl/issues/160) Make `resolve-missing` find newly defined vars and types (clj). Because of a stale cache, newly added vars or types would not be found. This fix takes into account vars/types added by eval-ing code (rescan affected namespace), and by hotloading dependencies (reset the cache).

src/refactor_nrepl/ns/slam/hound/search.clj

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
(defn expand-wildcard
4242
"Expands a wildcard path entry to its matching .jar files (JDK 1.6+).
4343
If not expanding, returns the path entry as a single-element vector."
44-
[#^String path]
44+
[^String path]
4545
(let [f (File. path)]
4646
(if (= (.getName f) "*")
4747
(.. f getParentFile (list jar-filter))
@@ -55,70 +55,73 @@
5555
(.replace path ".class" ""))
5656
(.replace File/separator ".")))
5757

58-
(def path-class-files nil)
5958
(defmulti path-class-files
6059
"Returns a list of classes found on the specified path location
6160
(jar or directory), each comprised of a map with the following keys:
6261
:name Java class or Clojure namespace name
6362
:loc Classpath entry (directory or jar) on which the class is located
6463
:file Path of the class file, relative to :loc"
65-
(fn [#^File f _]
66-
(cond (.isDirectory f) :dir
67-
(jar? f) :jar
64+
(fn [^File f _]
65+
(cond (.isDirectory f) :dir
66+
(jar? f) :jar
6867
(class-file? (.getName f)) :class)))
6968

70-
(defmethod path-class-files :default
71-
[& _] [])
69+
(defmethod path-class-files :default [& _] [])
7270

7371
(defmethod path-class-files :jar
7472
;; Build class info for all jar entry class files.
75-
[#^File f #^File loc]
73+
[^File f ^File loc]
7674
(let [lp (.getPath loc)]
7775
(try
78-
(map class-or-ns-name
79-
(filter class-file?
80-
(map #(.getName #^JarEntry %)
81-
(enumeration-seq (.entries (JarFile. f))))))
76+
(into ()
77+
(comp
78+
(map #(.getName ^JarEntry %))
79+
(filter class-file?)
80+
(map class-or-ns-name))
81+
(enumeration-seq (.entries (JarFile. f))))
8282
(catch Exception e [])))) ; fail gracefully if jar is unreadable
8383

8484
(defmethod path-class-files :dir
8585
;; Dispatch directories and files (excluding jars) recursively.
86-
[#^File d #^File loc]
87-
(let [fs (.listFiles d (proxy [FilenameFilter] []
88-
(accept [d n] (not (jar? (file n))))))]
89-
(reduce concat (for [f fs] (path-class-files f loc)))))
86+
[^File d ^File loc]
87+
(let [fs (.listFiles d (reify FilenameFilter
88+
(accept [_ dir name]
89+
(-> name file jar? not))))]
90+
(into () (mapcat #(path-class-files % loc)) fs)))
9091

9192
(defmethod path-class-files :class
9293
;; Build class info using file path relative to parent classpath entry
9394
;; location. Make sure it decends; a class can't be on classpath directly.
94-
[#^File f #^File loc]
95+
[^File f ^File loc]
9596
(let [fp (str f), lp (str loc)
9697
loc-pattern (re-pattern (Pattern/quote (str "^" loc)))]
9798
(if (re-find loc-pattern fp) ; must be descendent of loc
9899
(let [fpr (.substring fp (inc (count lp)))]
99100
[(class-or-ns-name fpr)])
100101
[])))
101102

102-
(defn scan-paths
103-
"Takes one or more classpath strings, scans each classpath entry location, and
104-
returns a list of all class file paths found, each relative to its parent
105-
directory or jar on the classpath."
106-
([cp]
107-
(if cp
108-
(let [entries (enumeration-seq
109-
(StringTokenizer. cp File/pathSeparator))
110-
locs (mapcat expand-wildcard entries)]
111-
(mapcat #(path-class-files % %) locs))
112-
())))
113-
114-
(defn- get-available-classes
115-
[]
116-
(->> (mapcat scan-paths (concat (map #(System/getProperty %) ["sun.boot.class.path"
117-
"java.ext.dirs"
118-
"java.class.path"])
119-
(map #(.getName %) (cp/classpath-jarfiles))))
120-
(remove clojure-fn-file?)
121-
(map symbol)))
103+
(defn path-entries-seq
104+
"Split a string on the 'path separator', i.e. ':'. Used for splitting multiple
105+
classpath entries."
106+
[path-str]
107+
(enumeration-seq
108+
(StringTokenizer. path-str File/pathSeparator)))
109+
110+
(defn all-classpath-entries []
111+
(into (map #(System/getProperty %) ["sun.boot.class.path"
112+
"java.ext.dirs"
113+
"java.class.path"])
114+
(map #(.getName %) (cp/classpath-jarfiles))))
115+
116+
(defn- get-available-classes []
117+
(into ()
118+
(comp (mapcat path-entries-seq)
119+
(mapcat expand-wildcard)
120+
(mapcat #(path-class-files % %))
121+
(remove clojure-fn-file?)
122+
(distinct)
123+
(map symbol))
124+
(all-classpath-entries)))
122125

123126
(def available-classes
124127
(get-available-classes))

0 commit comments

Comments
 (0)