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

Infer the class of string and coll literals #107

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### master (unreleased)

- Infer the class string and coll literals, giving more accurate completions for those.

### 0.4.1 (2023-08-23)

- [#33](https://github.com/alexander-yakushev/compliment/issues/33): Demunge
Expand Down
8 changes: 5 additions & 3 deletions src/compliment/sources/class_members.clj
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,11 @@
(:tag (meta (get (set (bindings-from-context context ns)) form))))]
;; We have a tag - try to resolve the class from it.
(resolve-class ns tag)
;; Otherwise, try to resolve symbol to a Var.
;; Otherwise, try to resolve symbol to a Var,
;; or literal to class.
(or (utils/var->class ns form)
(utils/invocation-form->class ns form))))))
(utils/invocation-form->class ns form)
(utils/literal->class form))))))

(defn members-candidates
"Returns a list of Java non-static fields and methods candidates."
Expand Down Expand Up @@ -222,7 +224,7 @@
(if (static? c)
(let [full-name (.getName c)]
(if (cache (.getName c))
(recur (update-in cache [full-name] conj c) r)
(recur (update cache full-name conj c) r)
(recur (assoc cache full-name [c]) r)))
(recur cache r))
(swap! static-members-cache assoc class cache))))
Expand Down
3 changes: 2 additions & 1 deletion src/compliment/sources/local_bindings.clj
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
(when bound-to
(when-let [found (or (-> bound-to meta :tag)
(utils/var->class ns bound-to)
(utils/invocation-form->class ns bound-to))]
(utils/invocation-form->class ns bound-to)
(utils/literal->class bound-to))]
(if (class? found)
(-> ^Class found .getName symbol)
found))))
Expand Down
8 changes: 8 additions & 0 deletions src/compliment/utils.clj
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,11 @@ Note that should always have the same value, regardless of OS."
(ns-resolve ns (first form)))]
(when (var? var-from-invocation)
(-> var-from-invocation meta :tag))))

(defn literal->class
"Extracts the class from a literal.
This is meant to support interop on strings and Clojure collections."
[form]
(when (or (string? form)
(coll? form))
(class form)))
25 changes: 25 additions & 0 deletions test/compliment/sources/t_class_members.clj
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,28 @@

(fact "static class members have docs"
(src/static-member-doc "Integer/parseInt" (-ns)) => (checker string?)))

(deftest literals-inference-test
(fact "Has around 19 candidates (give or take, varies per JDK),
which indicates that the members are an exact match against the class of `[]`"
(let [c (count (src/members-candidates "." (-ns) (ctx/cache-context
"(__prefix__ [])")))]
(< 17 c 21))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose testing for something exact. Let's say, check that when completing .in, only .indexOf is suggested when context is present, and more than one candidate are suggested without context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally did a bit of both, LMK what you think

=>
truthy)


(fact "A docstring is offered for the previous query"
(src/members-doc ".assocN" (-ns)) => (checker string?))

(fact "Has around 50 candidates (give or take, varies per JDK),
which indicates that the members are an exact match against the class of `\"\"`"
(let [c (count (src/members-candidates "." (-ns) (ctx/cache-context
"(__prefix__ \"\")")))]
(< 34 c 52))
=>
truthy)

(fact "A docstring is offered for the previous query"
(src/members-doc ".codePointBefore" (-ns))
=> (checker string?)))
14 changes: 13 additions & 1 deletion test/compliment/sources/t_local_bindings.clj
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,19 @@
(map (comp :tag meta)
(src/bindings-from-context (ctx/parse-context '(let [a (string/trim "a")] __prefix__))
(-ns)))
=> (just [`String])))
=> (just [`String]))

(fact "The class of a given binding can be identified by the class of a string literal"
(map (comp :tag meta)
(src/bindings-from-context (ctx/parse-context '(let [a ""] __prefix__))
(-ns)))
=> (just [`String]))

(fact "The class of a given binding can be identified by the class of a vector literal"
(map (comp :tag meta)
(src/bindings-from-context (ctx/parse-context '(let [a []] __prefix__))
(-ns)))
=> (just ['clojure.lang.PersistentVector])))

(deftest local-bindings
(defmacro ^{:completion/locals :let} like-let [& _])
Expand Down