fix imports

14 views
Skip to first unread message

Martin DeMello

unread,
Nov 27, 2008, 7:29:21 PM11/27/08
to Clojure
I've done a bit of Java programming, and one of the reasons I use an
IDE (netbeans) rather than plain vim is that I can write code without
having to bother about where every class I use comes from, then click
'fix imports' and have netbeans statically examine the code and add
import statements. I've missed this in clojure - is it possible in
theory to examine a clojure program and a classpath, and generate the
import statements needed to make it compile? It needn't do a perfect
job, of course, but just handling the common case would be very useful
- as it is, I have to constantly go looking up the java docs to find
out what package provides every class I use.

martin

Paul Drummond

unread,
Nov 28, 2008, 3:03:49 AM11/28/08
to clo...@googlegroups.com
Hi Martin,

Well, this is the sort of feature provided by IDEs rather than editors as you say, so it's not a "clojure" specific issue.  It's whether your chosen IDE supports the feature you require.

FYI, there is a NetBeans plugin (http://enclojure.org/) and a Eclipse plugin (http://code.google.com/p/clojure-dev/) in development.  I'm sure this kind of feature is either supported now or on the todo-list.  I can't say for sure however as I haven't tried them.

Paul.

2008/11/28 Martin DeMello <martin...@gmail.com>



--
Iode Software Ltd, registered in England No. 6299803.

Registered Office Address: 12 Sancroft Drive, Houghton-le-Spring, Tyne & Wear, DH5 8NE.

This message is intended only for the use of the person(s) ("the intended recipient(s)") to whom it is addressed. It may contain information which is privileged and confidential within the meaning of applicable law. If you are not the intended recipient, please contact the sender as soon as possible. The views expressed in this communication may not necessarily be the views held by The Company.

lpetit

unread,
Nov 28, 2008, 7:41:58 AM11/28/08
to Clojure
Hello,

This is certainly possible, I think.
The "fix import" action could try to resolve an unknown symbol by
first searching the symbol in one of the classpath available
namespaces, and then search for java classes in the classpath.
It could then add an import/require command for each found resolution
(and if several resolutions found, ad all, letting the user solve
manually the conflict).

This could be provided as an IDE action, and also, I think, as a
clojure function that could work directly on files.

I've added this to the wishlist of clojure-dev.

--
Laurent

On Nov 28, 9:03 am, "Paul Drummond" <paul.drumm...@iode.co.uk> wrote:
> Hi Martin,
>
> Well, this is the sort of feature provided by IDEs rather than editors as
> you say, so it's not a "clojure" specific issue.  It's whether your chosen
> IDE supports the feature you require.
>
> FYI, there is a NetBeans plugin (http://enclojure.org/) and a Eclipse plugin
> (http://code.google.com/p/clojure-dev/) in development.  I'm sure this kind
> of feature is either supported now or on the todo-list.  I can't say for
> sure however as I haven't tried them.
>
> Paul.
>
> 2008/11/28 Martin DeMello <martindeme...@gmail.com>

Martin DeMello

unread,
Nov 28, 2008, 1:44:18 PM11/28/08
to Clojure
On Nov 28, 12:03 am, "Paul Drummond" <paul.drumm...@iode.co.uk> wrote:
> Hi Martin,
>
> Well, this is the sort of feature provided by IDEs rather than editors as
> you say, so it's not a "clojure" specific issue.  It's whether your chosen
> IDE supports the feature you require.

No, I'd be perfectly happy with a command line tool that could analyse
my clojure program and tell me what imports I'm missing - I just don't
want to have to tediously go through the javadocs one by one and see,
for instance, that I need java.awt.Polygon but java.awt.geom.Point2D.
The reason I wondered if this were clojure-specific is that java
programs might well be easier to statically analyse than clojure ones.

martin

Paul Drummond

unread,
Dec 1, 2008, 6:15:40 AM12/1/08
to clo...@googlegroups.com
2008/11/28 Martin DeMello <martin...@gmail.com>
No, I'd be perfectly happy with a command line tool that could analyse
my clojure program and tell me what imports I'm missing - I just don't
want to have to tediously go through the javadocs one by one and see,
for instance, that I need java.awt.Polygon but java.awt.geom.Point2D.
The reason I wondered if this were clojure-specific is that java
programs might well be easier to statically analyse than clojure ones.

Ah, I see.   Well, I am not sure how you would go about writing something like this but surely if all you are interested in is a list of missing imports, you will get that when you try to evaluate your code, right?  For instance, for this script:

(def d Date)
(def r Random)

I get the following when I send the forms to the REPL:

java.lang.Exception: Unable to resolve symbol: Date in this context (NO_SOURCE_FILE:1)
java.lang.Exception: Unable to resolve symbol: Random in this context (NO_SOURCE_FILE:2)

Paul.





Michael Wood

unread,
Dec 1, 2008, 8:26:11 AM12/1/08
to clo...@googlegroups.com

I think his point is that if he gets an "Unable to resolve symbol:
Polygon" error and also an "Unable to resolve symbol: Point2D" error
then he still has to figure out which one is in java.awt and which is
in java.awt.geom. He wants a tool to spit out the list of required
imports so he doesn't have to remember exactly where they all are. If
there are conflicts, then the tool wouldn't have to guess. It could
just note the conflict for manual resolution.

--
Michael Wood <esio...@gmail.com>

Paul Drummond

unread,
Dec 1, 2008, 8:45:56 AM12/1/08
to clo...@googlegroups.com
2008/12/1 Michael Wood <esio...@gmail.com>
I think his point is that if he gets an "Unable to resolve symbol:
Polygon" error and also an "Unable to resolve symbol: Point2D" error
then he still has to figure out which one is in java.awt and which is
in java.awt.geom.  He wants a tool to spit out the list of required
imports so he doesn't have to remember exactly where they all are.  If
there are conflicts, then the tool wouldn't have to guess.  It could
just note the conflict for manual resolution.

Yeah, I realise my crude example isn't really what Martin was after.

I was thinking about how you would do this sort of thing in Clojure via analysing ns-interns and ns-imports, then I realised there won't be any vars in ns-interns where the class of the var being defined is unresolved! 

So how would you write such a tool in Clojure?   Hook into the exception maybe?  Hmm, I'm not sure...

Paul.

Stuart Sierra

unread,
Dec 1, 2008, 3:23:38 PM12/1/08
to Clojure
On Nov 28, 7:41 am, lpetit <laurent.pe...@gmail.com> wrote:
> The "fix import" action could try to resolve an unknown symbol by
> first searching the symbol in one of the classpath available
> namespaces, and then search for java classes in the classpath.
> It could then add an import/require command for each found resolution
> (and if several resolutions found, ad all, letting the user solve
> manually the conflict).
>
> This could be provided as an IDE action, and also, I think, as a
> clojure function that could work directly on files.

JDEE <http://jdee.sourceforge.net/> does this, for Java source code.

-S

Vijay Lakshminarayanan

unread,
Dec 3, 2008, 1:59:44 PM12/3/08
to clo...@googlegroups.com

This is far from complete and should be expanded but I got this from a
few hours of hacking:

(import '(java.util.jar JarFile JarEntry)
'(java.io File IOException))

(defn find-all
"(for [x coll :when (test-fn item (key-fn x))] x)"
([item coll test-fn key-fn]
(filter #(test-fn item (key-fn %)) coll))
([item coll test-fn]
(find-all item coll test-fn #'identity))
([item coll]
(find-all item coll #'= #'identity)))

(defn find-reg-in-seq
([reg coll key]
(find-all reg coll #'re-find key))
([reg coll]
(find-reg-in-seq reg coll #'identity)))

(defn dir-or-jar->seq
[path-entity]
(cond (instance? File path-entity)
(if (.isDirectory #^File path-entity)
(file-seq path-entity)
(throw (IOException. "Cannot search within a file.")))
(instance? JarFile path-entity)
(enumeration-seq (.entries #^JarFile path-entity))
true
(throw (UnsupportedOperationException.
(str "Cannot handle " (class path-entity))))))

(defn find-re-in-path-entity [reg path-entity]
(find-reg-in-seq reg
(dir-or-jar->seq path-entity)
#(.getName %)))

(defn find-class-in-path-entity [class-name path-entity]
(find-re-in-path-entity (re-pattern (str #"[^A-Za-z0-9$]" class-name
".class$"))
path-entity))

(def *rt-jar* (.toString
(File.
(File. (.getProperty System "java.home") "lib") "rt.jar")))

(defn find-java-class-in-classpath [class-name]
(let [cpath (cons *rt-jar* (.split (.getProperty System "java.class.path")
(.getProperty System "path.separator")))]
(mapcat #'identity
(filter #(not (nil? %))
(for [#^String path cpath]
(find-class-in-path-entity class-name
(if (.endsWith path ".jar")
(JarFile. path)
(File. path))))))))

(defn find-java-class [class-name]
(map (fn [o] (let [#^String s (.toString #^Object o)
l (.length s)]
(.. s (substring 0 (- l 6)) (replace "/" "."))))
(find-java-class-in-classpath class-name)))

;;; *eof*

It looks inside all jar files and at all .class files inside
directories in the classpath and rt.jar -- the java runtime library
and returns the list of classes that exist on the classpath.

I haven't written it inside a namespace etc. It's saved in a file
named "stuff.clj" because I couldnt' think of a good name.

user> (load "stuff")
nil
user> (find-java-class "List")
("com.sun.xml.internal.bind.v2.schemagen.xmlschema.List"
"java.awt.List" "java.util.List")
user> (find-java-class "URL")
("java.net.URL")
user> (find-java-class "NonExistent")
("com.sun.corba.se.impl.protocol.NonExistent")
user> (find-java-class "NonExistentClass")
nil

;; I never expected there'd be a class named "NonExistent" ;-)

The above code is released under public domain so anyone may do what
they wish with it.

Cheers
Vijay

Martin DeMello

unread,
Dec 5, 2008, 1:59:36 AM12/5/08
to Clojure
On Dec 3, 11:59 pm, "Vijay Lakshminarayanan" <liyer.vi...@gmail.com>
wrote:
>
> This is far from complete and should be expanded but I got this from a
> few hours of hacking:

Good stuff, thanks!

martin
Reply all
Reply to author
Forward
0 new messages