Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tab completion with Leiningen REPL after typing a period in a namespace triggers an NPE #2380

Closed
venantius opened this issue Dec 22, 2017 · 10 comments · Fixed by #2398
Closed

Comments

@venantius
Copy link
Contributor

Bit of an oddly specific bug, I know.

TL;DR - if I type clojure.co and then try to tab-complete, an NPE is triggered. Tab-completion works fine if I hit tab at cloj or at clojure.core/, but after that first period and before the slash I'll get NPE'd. I ran into this on a project and then was able to reproduce outside of a project context.

Now the expected behavior would be for tab completion to work the way it did when I hit tab at cloj, i.e. to show me the list of namespaces that are potential results for what I've typed so far.

Full command history and stacktrace:

▸ lein repl
nREPL server started on port 55883 on host 127.0.0.1 - nrepl://127.0.0.1:55883
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
Java HotSpot(TM) 64-Bit Server VM 9.0.1+11
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> clojure.corNullPointerException   complete.core/fn--632/iter--624--633/fn--634 (core.clj:66)


CompilerException java.lang.ClassNotFoundException: clojure.cor, compiling:(null:0:0)
user=> (pst)
clojure.lang.Compiler$CompilerException: java.lang.ClassNotFoundException: clojure.cor, compiling:(null:0:0)
                                Compiler.java:6688 clojure.lang.Compiler.analyze
                                Compiler.java:6625 clojure.lang.Compiler.analyze
                                Compiler.java:6931 clojure.lang.Compiler.eval
                                Compiler.java:6890 clojure.lang.Compiler.eval
                                     core.clj:3105 clojure.core/eval
                                     core.clj:3101 clojure.core/eval
                                      main.clj:240 clojure.main/repl[fn]
                                      main.clj:240 clojure.main/repl[fn]
                                      main.clj:258 clojure.main/repl[fn]
                                      main.clj:258 clojure.main/repl
                                      main.clj:174 clojure.main/repl
                                  RestFn.java:1523 clojure.lang.RestFn.invoke
                         interruptible_eval.clj:87 clojure.tools.nrepl.middleware.interruptible-eval/evaluate[fn]
                                      AFn.java:152 clojure.lang.AFn.applyToHelper
                                      AFn.java:144 clojure.lang.AFn.applyTo
                                      core.clj:646 clojure.core/apply
                                     core.clj:1881 clojure.core/with-bindings*
                                     core.clj:1881 clojure.core/with-bindings*
                                   RestFn.java:425 clojure.lang.RestFn.invoke
                         interruptible_eval.clj:85 clojure.tools.nrepl.middleware.interruptible-eval/evaluate
                         interruptible_eval.clj:55 clojure.tools.nrepl.middleware.interruptible-eval/evaluate
                        interruptible_eval.clj:224 clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval[fn]
                        interruptible_eval.clj:192 clojure.tools.nrepl.middleware.interruptible-eval/run-next[fn]
                                       AFn.java:22 clojure.lang.AFn.run
                      ThreadPoolExecutor.java:1167 java.util.concurrent.ThreadPoolExecutor.runWorker
                       ThreadPoolExecutor.java:641 java.util.concurrent.ThreadPoolExecutor$Worker.run
                                   Thread.java:844 java.lang.Thread.run
Caused by: java.lang.ClassNotFoundException: clojure.cor
                           URLClassLoader.java:466 java.net.URLClassLoader.findClass
                        DynamicClassLoader.java:69 clojure.lang.DynamicClassLoader.findClass
                              ClassLoader.java:563 java.lang.ClassLoader.loadClass
                        DynamicClassLoader.java:77 clojure.lang.DynamicClassLoader.loadClass
                              ClassLoader.java:496 java.lang.ClassLoader.loadClass
                                  (Unknown Source) java.lang.Class.forName0
                                    Class.java:375 java.lang.Class.forName
                                      RT.java:2168 clojure.lang.RT.classForName
                                      RT.java:2177 clojure.lang.RT.classForName
                                Compiler.java:7145 clojure.lang.Compiler.resolveIn
                                Compiler.java:7108 clojure.lang.Compiler.resolve
                                Compiler.java:7069 clojure.lang.Compiler.analyzeSymbol
                                Compiler.java:6648 clojure.lang.Compiler.analyze
nil
user=>
@technomancy
Copy link
Owner

technomancy commented Dec 22, 2017 via email

@venantius
Copy link
Contributor Author

Great, I've opened an issue over there.

@tirkarthi
Copy link
Contributor

I tried reproducing this but it works fine for me. I tried a test on clojure-complete

➜  foo-2380 lein repl
nREPL server started on port 50500 on host 127.0.0.1 - nrepl://127.0.0.1:50500
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_102-b14
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> clojure.core
clojure.core                            clojure.core.ArrayChunk                 clojure.core.ArrayManager               clojure.core.Eduction                   clojure.core.IVecImpl
clojure.core.Vec                        clojure.core.VecNode                    clojure.core.VecSeq                     clojure.core.protocols                  clojure.core.protocols.CollReduce
clojure.core.protocols.IKVReduce        clojure.core.protocols.InternalReduce   clojure.core.server
user=> clojure.core
➜  foo-2380 lein -v
Leiningen 2.8.0 on Java 1.8.0_102 Java HotSpot(TM) 64-Bit Server VM

clojure-complete test

(is (= '("clojure.core" "clojure.core.ArrayChunk" "clojure.core.ArrayManager" "clojure.core.IVecImpl" "clojure.core.Vec" "clojure.core.VecNode" "clojure.core.VecSeq" "clojure.core.protocols" "clojure.core.protocols.InternalReduce") (completions "clojure.co")))

@venantius
Copy link
Contributor Author

Thanks for the follow-up - I noticed you're running Java 8 and that seems to be the trigger factor here (I'm on JDK 9). I tested it out with Java 8 and the bug did not reproduce so there's got to be some change in Java 9's classloading behavior that's causing this.

@tirkarthi
Copy link
Contributor

tirkarthi commented Jan 11, 2018

@venantius Can confirm on Java 9 on Ubuntu

$ lein repl
nREPL server started on port 38202 on host 127.0.0.1 - nrepl://127.0.0.1:38202
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
OpenJDK 64-Bit Server VM 9-internal+0-2016-04-14-195246.buildd.src
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> clojure.coNullPointerException   complete.core/fn--647/iter--639--648/fn--649 (core.clj:66)

CompilerException java.lang.ClassNotFoundException: clojure.co, compiling:(null:0:0)

user=>

As @technomancy mentioned it's a problem with upstream clojure-complete on Java 9. I tried the test which passed on Java 8, it fails on Java 9 as below :

Test case :

(is (= '("clojure.core" "clojure.core.ArrayChunk" "clojure.core.ArrayManager" "clojure.core.IVecImpl" "clojure.core.Vec" "clojure.core.VecNode" "clojure.core.VecSeq" "clojure.core.protocols" "clojure.core.protocols.InternalReduce") (completions "clojure.co")))
ubuntu@ip-172-31-23-26:~/clojure-complete$ lein test

lein test complete.core-test

lein test :only complete.core-test/completions-test

ERROR in (completions-test) (FutureTask.java:123)
expected: (= (quote ("clojure.core" "clojure.core.ArrayChunk" "clojure.core.ArrayManager" "clojure.core.IVecImpl" "clojure.core.Vec" "clojure.core.VecNode" "clojure.core.VecSeq" "clojure.core.protocols" "clojure.core.protocols.InternalReduce")) (completions "clojure.co"))
  actual: java.util.concurrent.ExecutionException: java.lang.NullPointerException
 at java.util.concurrent.FutureTask.report (FutureTask.java:123)
    java.util.concurrent.FutureTask.get (FutureTask.java:193)
    clojure.core$future_call$reify__5684.deref (core.clj:6054)
    clojure.core$deref.invoke (core.clj:2078)
    complete.core$eval384$fn__385.invoke (core.clj:112)
    clojure.lang.MultiFn.invoke (MultiFn.java:167)
    complete.core$completions.invoke (core.clj:128)
    complete.core$completions.invoke (core.clj:126)
    complete.core_test$fn__407$fn__420.invoke (core_test.clj:15)
    complete.core_test/fn (core_test.clj:14)
    clojure.test$test_var$fn__6484.invoke (test.clj:693)
    clojure.test$test_var.invoke (test.clj:693)
    clojure.test$test_all_vars$fn__6488$fn__6495.invoke (test.clj:709)
    clojure.test$default_fixture.invoke (test.clj:663)
    clojure.test$test_all_vars$fn__6488.invoke (test.clj:709)
    clojure.test$default_fixture.invoke (test.clj:663)
    clojure.test$test_all_vars.invoke (test.clj:705)
    clojure.test$test_ns.invoke (test.clj:728)
    user$eval77$fn__126.invoke (form-init265966808124094054.clj:1)
    clojure.lang.AFn.applyToHelper (AFn.java:163)
    clojure.lang.AFn.applyTo (AFn.java:151)
    clojure.core$apply.invoke (core.clj:602)
    leiningen.core.injected$compose_hooks$fn__15.doInvoke (form-init265966808124094054.clj:1)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invoke (core.clj:600)
    leiningen.core.injected$run_hooks.invoke (form-init265966808124094054.clj:1)
    leiningen.core.injected$prepare_for_hooks$fn__20$fn__21.doInvoke (form-init265966808124094054.clj:1)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$map$fn__3811.invoke (core.clj:2432)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1607)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:602)
    clojure.test$run_tests.doInvoke (test.clj:743)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invoke (core.clj:600)
    user$eval77$fn__136$fn__167.invoke (form-init265966808124094054.clj:1)
    user$eval77$fn__136$fn__137.invoke (form-init265966808124094054.clj:1)
    user$eval77$fn__136.invoke (form-init265966808124094054.clj:1)
    user$eval77.invoke (form-init265966808124094054.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:6465)
    clojure.lang.Compiler.eval (Compiler.java:6455)
    clojure.lang.Compiler.load (Compiler.java:6902)
    clojure.lang.Compiler.loadFile (Compiler.java:6863)
    clojure.main$load_script.invoke (main.clj:282)
    clojure.main$init_opt.invoke (main.clj:287)
    clojure.main$initialize.invoke (main.clj:315)
    clojure.main$null_opt.invoke (main.clj:348)
    clojure.main$main.doInvoke (main.clj:426)
    clojure.lang.RestFn.invoke (RestFn.java:421)
    clojure.lang.Var.invoke (Var.java:405)
    clojure.lang.AFn.applyToHelper (AFn.java:163)
    clojure.lang.Var.applyTo (Var.java:518)
    clojure.main.main (main.java:37)
Caused by: java.lang.NullPointerException: null
 at complete.core$fn__307$iter__299__308$fn__309.invoke (core.clj:66)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:466)
    clojure.core$seq.invoke (core.clj:133)
    complete.core$fn__334$iter__335__339$fn__340.invoke (core.clj:76)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:466)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$dorun.invoke (core.clj:2723)
    clojure.core$doall.invoke (core.clj:2739)
    complete.core/fn (core.clj:76)
    clojure.core$binding_conveyor_fn$fn__3713.invoke (core.clj:1817)
    clojure.lang.AFn.call (AFn.java:18)
    java.util.concurrent.FutureTask.run (FutureTask.java:266)
    java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1158)
    java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:632)
    java.lang.Thread.run (Thread.java:804)

lein test :only complete.core-test/completions-test

ERROR in (completions-test) (FutureTask.java:123)
expected: (= (quote ("complete.core" "complete.core-test")) (completions "complete.core"))
  actual: java.util.concurrent.ExecutionException: java.lang.NullPointerException
 at java.util.concurrent.FutureTask.report (FutureTask.java:123)
    java.util.concurrent.FutureTask.get (FutureTask.java:193)
    clojure.core$future_call$reify__5684.deref (core.clj:6054)
    clojure.core$deref.invoke (core.clj:2078)
    complete.core$eval384$fn__385.invoke (core.clj:112)
    clojure.lang.MultiFn.invoke (MultiFn.java:167)
    complete.core$completions.invoke (core.clj:128)
    complete.core$completions.invoke (core.clj:126)
    complete.core_test$fn__407$fn__424.invoke (core_test.clj:18)
    complete.core_test/fn (core_test.clj:17)
    clojure.test$test_var$fn__6484.invoke (test.clj:693)
    clojure.test$test_var.invoke (test.clj:693)
    clojure.test$test_all_vars$fn__6488$fn__6495.invoke (test.clj:709)
    clojure.test$default_fixture.invoke (test.clj:663)
    clojure.test$test_all_vars$fn__6488.invoke (test.clj:709)
    clojure.test$default_fixture.invoke (test.clj:663)
    clojure.test$test_all_vars.invoke (test.clj:705)
    clojure.test$test_ns.invoke (test.clj:728)
    user$eval77$fn__126.invoke (form-init265966808124094054.clj:1)
    clojure.lang.AFn.applyToHelper (AFn.java:163)
    clojure.lang.AFn.applyTo (AFn.java:151)
    clojure.core$apply.invoke (core.clj:602)
    leiningen.core.injected$compose_hooks$fn__15.doInvoke (form-init265966808124094054.clj:1)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invoke (core.clj:600)
    leiningen.core.injected$run_hooks.invoke (form-init265966808124094054.clj:1)
    leiningen.core.injected$prepare_for_hooks$fn__20$fn__21.doInvoke (form-init265966808124094054.clj:1)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$map$fn__3811.invoke (core.clj:2432)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1607)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:602)
    clojure.test$run_tests.doInvoke (test.clj:743)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invoke (core.clj:600)
    user$eval77$fn__136$fn__167.invoke (form-init265966808124094054.clj:1)
    user$eval77$fn__136$fn__137.invoke (form-init265966808124094054.clj:1)
    user$eval77$fn__136.invoke (form-init265966808124094054.clj:1)
    user$eval77.invoke (form-init265966808124094054.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:6465)
    clojure.lang.Compiler.eval (Compiler.java:6455)
    clojure.lang.Compiler.load (Compiler.java:6902)
    clojure.lang.Compiler.loadFile (Compiler.java:6863)
    clojure.main$load_script.invoke (main.clj:282)
    clojure.main$init_opt.invoke (main.clj:287)
    clojure.main$initialize.invoke (main.clj:315)
    clojure.main$null_opt.invoke (main.clj:348)
    clojure.main$main.doInvoke (main.clj:426)
    clojure.lang.RestFn.invoke (RestFn.java:421)
    clojure.lang.Var.invoke (Var.java:405)
    clojure.lang.AFn.applyToHelper (AFn.java:163)
    clojure.lang.Var.applyTo (Var.java:518)
    clojure.main.main (main.java:37)
Caused by: java.lang.NullPointerException: null
 at complete.core$fn__307$iter__299__308$fn__309.invoke (core.clj:66)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:466)
    clojure.core$seq.invoke (core.clj:133)
    complete.core$fn__334$iter__335__339$fn__340.invoke (core.clj:76)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:466)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$dorun.invoke (core.clj:2723)
    clojure.core$doall.invoke (core.clj:2739)
    complete.core/fn (core.clj:76)
    clojure.core$binding_conveyor_fn$fn__3713.invoke (core.clj:1817)
    clojure.lang.AFn.call (AFn.java:18)
    java.util.concurrent.FutureTask.run (FutureTask.java:266)
    java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1158)
    java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:632)
    java.lang.Thread.run (Thread.java:804)
$ clj
Clojure 1.9.0
user=> (import [java.io File])
java.io.File
user=> (for [prop ["sun.boot.class.path" "java.ext.dirs" "java.class.path"]
      path (.split (System/getProperty prop) File/pathSeparator)] path)
NullPointerException   user/eval171/iter--165--172/fn--173 (NO_SOURCE_FILE:5)
user=> (.split (System/getProperty "sun.boot.class.path") File/pathSeparator)
NullPointerException   user/eval192 (NO_SOURCE_FILE:7)
user=> (.split (System/getProperty "java.ext.dirs") File/pathSeparator)
NullPointerException   user/eval194 (NO_SOURCE_FILE:8)
user=> (.split (System/getProperty "java.class.path") File/pathSeparator)
#object["[Ljava.lang.String;" 0x78de58ea "[Ljava.lang.String;@78de58ea"]

@venantius
Copy link
Contributor Author

While we've merged a fix to clojure-complete, @ninjudd has warned us that the library is no longer maintained. I don't yet have deploy rights to Clojars, so I don't have a way of actually releasing the fix.

It would seem to me that an alternative approach here would be to migrate Leiningen's dependency off of clojure-complete to https://github.com/alexander-yakushev/compliment, which is actively maintained.

@tirkarthi
Copy link
Contributor

@venantius I think leiningen uses reply for repl which in turn uses clojure-complete. I couldn't see clojure-complete being used directly in leiningen. The issue of deprecation is already an issue in clojure-complete repo. I think it will be better if we can bump the release with the help of @ninjudd and to have reply and leiningen to migrate to compliment in the long term since they may take significant changes. I will open an issue in reply to migrate to compliment.

@venantius
Copy link
Contributor Author

@tirkarthi Agree that's the right thing to do short and long term. I took a quick look at what would need changing in reply and it looks like a fair bit of work, otherwise I would have tried to fix it this afternoon. Opening an issue with them is a good start.

@tirkarthi
Copy link
Contributor

tirkarthi commented Feb 3, 2018

@venantius I have opened up an issue in reply trptcolin/reply#176 . There is already an issue in clojure-complete about deprecation ninjudd/clojure-complete#18 . I will take a stab at migrating reply to compliment over the weekend 👍

@tirkarthi
Copy link
Contributor

@venantius Seems like there is already a three year old PR to replace clojure-complete with compliment : trptcolin/reply#153

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants