branch: externals/javaimp
commit a434ee966015752c65dc503de5159046c1edac42
Author: Filipp Gunbin <[email protected]>
Commit: Filipp Gunbin <[email protected]>
Reorganize project structure
---
.elpaignore | 4 +
Makefile | 25 ++
javaimp-gradle.el | 49 +--
javaimp-maven.el | 79 +++--
javaimp-parse.el | 343 +++++++++++-------
javaimp-tests.el | 424 +----------------------
javaimp-util.el | 155 ++-------
javaimp.el | 150 ++++----
{testdata => tests/data}/gradle-multi.tar.gz | Bin
{testdata => tests/data}/maven-multi.tar.gz | Bin
{testdata => tests/data}/maven-single.tar.gz | Bin
{testdata => tests/data}/test1-misc-classes.java | 0
javaimp-tests-gradle.el => tests/gradle.el | 46 ++-
tests/imenu.el | 85 +++++
javaimp-tests-maven.el => tests/maven.el | 51 ++-
javaimp-tests.el => tests/parse.el | 293 +++++-----------
tests/tests.el | 24 ++
17 files changed, 672 insertions(+), 1056 deletions(-)
diff --git a/.elpaignore b/.elpaignore
new file mode 100644
index 0000000000..c7946ef938
--- /dev/null
+++ b/.elpaignore
@@ -0,0 +1,4 @@
+.gitignore
+Makefile
+tests
+javaimp-tests.el
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..6c8f3ec3e9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,25 @@
+# -*- Makefile -*-
+
+# "make check" by default runs non-expensive tests. To run all tests,
+# use "make check SELECTOR=t".
+
+EMACS = emacs -Q -batch -L .
+SRCS = javaimp-util.el javaimp-gradle.el javaimp-maven.el javaimp-parse.el
javaimp.el
+TESTS = $(wildcard tests/*.el)
+OBJS = $(SRCS:.el=.elc) $(TESTS:.el=.elc)
+SELECTOR ?= (not (tag :expensive))
+
+.PHONY: all check test clean
+
+%.elc: %.el
+ ${EMACS} -f batch-byte-compile $^
+
+all: $(OBJS)
+
+check test: all
+ ${EMACS} \
+ $(addprefix -l ,$(OBJS)) \
+ -eval '(ert-run-tests-batch-and-exit (quote ${SELECTOR}))'
+
+clean:
+ $(RM) -f $(OBJS)
diff --git a/javaimp-gradle.el b/javaimp-gradle.el
index e3b801a5be..bed838d712 100644
--- a/javaimp-gradle.el
+++ b/javaimp-gradle.el
@@ -20,30 +20,37 @@
(require 'javaimp-util)
-(defun javaimp--gradle-visit (file)
+(defcustom javaimp-gradle-program "gradle"
+ "Path to the `gradle' program. If the visited project has local
+gradlew (Gradle wrapper), it is used in preference."
+ :type 'string
+ :group 'javaimp)
+
+
+(defun javaimp-gradle-visit (file)
"Calls gradle on FILE to get various project information.
Passes specially crafted init file as -I argument to gradle and
invokes task contained in it. This task outputs all needed
information."
(message "Visiting Gradle build file %s..." file)
- (let* ((alists (javaimp--gradle-call file #'javaimp--gradle-handler))
+ (let* ((alists (javaimp-gradle--call file #'javaimp-gradle--handler))
(modules (mapcar (lambda (alist)
- (javaimp--gradle-module-from-alist alist file))
+ (javaimp-gradle--module-from-alist alist file))
alists)))
;; first module is always root
(message "Building tree for root: %s"
(javaimp-print-id (javaimp-module-id (car modules))))
(list
- (javaimp--build-tree (car modules) modules
- ;; more or less reliable way to find children
- ;; is to look for modules with "this" as the
- ;; parent
- (lambda (el tested)
- (equal (javaimp-module-parent-id tested)
- (javaimp-module-id el)))))))
-
-(defun javaimp--gradle-handler ()
+ (javaimp-tree-build (car modules) modules
+ ;; more or less reliable way to find children
+ ;; is to look for modules with "this" as the
+ ;; parent
+ (lambda (el tested)
+ (equal (javaimp-module-parent-id tested)
+ (javaimp-module-id el)))))))
+
+(defun javaimp-gradle--handler ()
"Parse current buffer into list of project descriptors, each of
which is an alist of attributes (NAME . VALUE). Each attribute
occupies one line, and is of the form 'NAME=VALUE'. See file
@@ -65,12 +72,12 @@ descriptor."
(push alist res))
(nreverse res)))
-(defun javaimp--gradle-module-from-alist (alist file-orig)
+(defun javaimp-gradle--module-from-alist (alist file-orig)
"Make `javaimp-module' structure out of attribute alist ALIST."
(make-javaimp-module
- :id (javaimp--gradle-id-from-semi-separated
+ :id (javaimp-gradle--id-from-semi-separated
(cdr (assq 'id alist)))
- :parent-id (javaimp--gradle-id-from-semi-separated
+ :parent-id (javaimp-gradle--id-from-semi-separated
(cdr (assq 'parent-id alist)))
:file (cdr (assq 'file alist))
:file-orig file-orig
@@ -87,10 +94,10 @@ descriptor."
(cdr (assq 'build-dir alist))))
:dep-jars (javaimp--split-native-path (cdr (assq 'dep-jars alist)))
:load-ts (current-time)
- :dep-jars-fetcher #'javaimp--gradle-fetch-dep-jars
+ :dep-jars-fetcher #'javaimp-gradle--fetch-dep-jars
:raw nil))
-(defun javaimp--gradle-id-from-semi-separated (str)
+(defun javaimp-gradle--id-from-semi-separated (str)
(when str
(let ((parts (split-string str ";" t))
artifact)
@@ -106,8 +113,8 @@ descriptor."
:artifact artifact
:version (nth 2 parts)))))
-(defun javaimp--gradle-fetch-dep-jars (module ids)
- (javaimp--gradle-call
+(defun javaimp-gradle--fetch-dep-jars (module ids)
+ (javaimp-gradle--call
;; Always invoke on orig file (which is root build script) because
;; module's own file may not exist, even if reported by Gradle as
;; project.buildFile. Furthermore, we use that file's directory to
@@ -120,7 +127,7 @@ descriptor."
(unless (string-empty-p mod-path)
(format ":%s:" mod-path)))))
-(defun javaimp--gradle-call (file handler &optional mod-path)
+(defun javaimp-gradle--call (file handler &optional mod-path)
(let* (;; There is (was) "-b" switch for specifying build file,
;; however it became deprecated in Gradle 7, so we try to run
;; in build file directory.
@@ -142,7 +149,7 @@ descriptor."
"-Dorg.gradle.java.compile-classpath-packaging=true"
"-I" (javaimp-cygpath-convert-maybe
(expand-file-name "javaimp-init-script.gradle"
- (concat javaimp--basedir
+ (concat javaimp-basedir
(file-name-as-directory "support"))))
(concat mod-path "javaimpTask"))))
diff --git a/javaimp-maven.el b/javaimp-maven.el
index c4b7269550..fafaad3d00 100644
--- a/javaimp-maven.el
+++ b/javaimp-maven.el
@@ -23,26 +23,33 @@
(require 'javaimp-util)
-(defun javaimp--maven-visit (file)
+(defcustom javaimp-mvn-program "mvn"
+ "Path to the `mvn' program. If the visited project has local
+mvnw (Maven wrapper), it is used in preference."
+ :type 'string
+ :group 'javaimp)
+
+
+(defun javaimp-maven-visit (file)
"Calls \"mvn help:effective-pom\" on FILE,
reads project structure from the output and records which files
belong to which modules and other module information. Returns
resulting module trees."
(message "Visiting Maven POM file %s..." file)
- (let* ((xml-tree (javaimp--maven-call
+ (let* ((xml-tree (javaimp-maven--call
file
- #'javaimp--maven-effective-pom-handler
+ #'javaimp-maven--effective-pom-handler
"help:effective-pom"))
(projects (or (if (assq 'project xml-tree)
(list (assq 'project xml-tree))
- (javaimp--xml-children (assq 'projects xml-tree)
'project))
+ (javaimp-xml-children (assq 'projects xml-tree)
'project))
(user-error "No projects found")))
(modules (mapcar (lambda (proj-elt)
- (javaimp--maven-module-from-xml proj-elt file))
+ (javaimp-maven--module-from-xml proj-elt file))
projects)))
;; Set :file slots in a separate step because Maven doesn't give
;; pom.xml file location for each subproject.
- (javaimp--maven-fill-modules-files file modules)
+ (javaimp-maven--fill-modules-files file modules)
(when-let ((without-files (seq-filter (lambda (m)
(null (javaimp-module-file m)))
modules)))
@@ -71,7 +78,7 @@ resulting module trees."
(mapcar (lambda (root)
(message "Building tree for root: %s"
(javaimp-print-id (javaimp-module-id root)))
- (javaimp--build-tree
+ (javaimp-tree-build
root modules
;; more or less reliable way to find children is to
;; look for modules with "this" as the parent
@@ -80,7 +87,7 @@ resulting module trees."
(javaimp-module-id el)))))
roots))))
-(defun javaimp--maven-effective-pom-handler ()
+(defun javaimp-maven--effective-pom-handler ()
(let ((start
(save-excursion
(progn
@@ -97,46 +104,46 @@ resulting module trees."
(match-end 0)))))
(xml-parse-region start end)))
-(defun javaimp--maven-module-from-xml (elt file-orig)
- (let ((build-elt (javaimp--xml-child 'build elt)))
+(defun javaimp-maven--module-from-xml (elt file-orig)
+ (let ((build-elt (javaimp-xml-child 'build elt)))
(make-javaimp-module
- :id (javaimp--maven-id-from-xml elt)
- :parent-id (javaimp--maven-id-from-xml (javaimp--xml-child 'parent elt))
+ :id (javaimp-maven--id-from-xml elt)
+ :parent-id (javaimp-maven--id-from-xml (javaimp-xml-child 'parent elt))
;; <project> element does not contain pom file path, so we set this slot
- ;; later, see javaimp--maven-fill-modules-files
+ ;; later, see javaimp-maven--fill-modules-files
:file nil
:file-orig file-orig
;; jar/war supported
- :final-name (let ((packaging (or (javaimp--xml-first-child
- (javaimp--xml-child 'packaging elt))
+ :final-name (let ((packaging (or (javaimp-xml-first-child
+ (javaimp-xml-child 'packaging elt))
"jar")))
(when (member packaging '("jar" "war"))
- (concat (javaimp--xml-first-child
- (javaimp--xml-child 'finalName build-elt))
+ (concat (javaimp-xml-first-child
+ (javaimp-xml-child 'finalName build-elt))
"." packaging)))
:source-dirs (list (file-name-as-directory
(javaimp-cygpath-convert-maybe
- (javaimp--xml-first-child
- (javaimp--xml-child 'sourceDirectory build-elt))))
+ (javaimp-xml-first-child
+ (javaimp-xml-child 'sourceDirectory build-elt))))
(file-name-as-directory
(javaimp-cygpath-convert-maybe
- (javaimp--xml-first-child
- (javaimp--xml-child 'testSourceDirectory
build-elt)))))
+ (javaimp-xml-first-child
+ (javaimp-xml-child 'testSourceDirectory
build-elt)))))
:build-dir (file-name-as-directory
(javaimp-cygpath-convert-maybe
- (javaimp--xml-first-child (javaimp--xml-child 'directory
build-elt))))
+ (javaimp-xml-first-child (javaimp-xml-child 'directory
build-elt))))
:dep-jars nil ; dep-jars is initialized lazily on demand
:load-ts (current-time)
- :dep-jars-fetcher #'javaimp--maven-fetch-dep-jars
+ :dep-jars-fetcher #'javaimp-maven--fetch-dep-jars
:raw elt)))
-(defun javaimp--maven-id-from-xml (elt)
+(defun javaimp-maven--id-from-xml (elt)
(make-javaimp-id
- :group (javaimp--xml-first-child (javaimp--xml-child 'groupId elt))
- :artifact (javaimp--xml-first-child (javaimp--xml-child 'artifactId elt))
- :version (javaimp--xml-first-child (javaimp--xml-child 'version elt))))
+ :group (javaimp-xml-first-child (javaimp-xml-child 'groupId elt))
+ :artifact (javaimp-xml-first-child (javaimp-xml-child 'artifactId elt))
+ :version (javaimp-xml-first-child (javaimp-xml-child 'version elt))))
-(defun javaimp--maven-fill-modules-files (file modules)
+(defun javaimp-maven--fill-modules-files (file modules)
"Reads <module> ids from FILE, looks up corresponding modules in
MODULES, sets their :file slot, then recurses for each of them.
A submodule file path is constructed by appending relative path
@@ -147,7 +154,7 @@ are somewhat arbitrary."
(insert-file-contents file)
(xml-parse-region (point-min) (point-max))))
(project-elt (assq 'project xml-tree))
- (this-id (javaimp--maven-id-from-xml project-elt))
+ (this-id (javaimp-maven--id-from-xml project-elt))
(module (seq-find
(lambda (m)
(let ((mid (javaimp-module-id m)))
@@ -175,20 +182,20 @@ are somewhat arbitrary."
;; help:effective-pom because Maven can extend the list in the
;; file with elements from profiles
(let* ((submodules-elt
- (javaimp--xml-child 'modules (javaimp-module-raw module)))
- (submodules (javaimp--xml-children submodules-elt 'module))
- (rel-paths (mapcar #'javaimp--xml-first-child submodules)))
+ (javaimp-xml-child 'modules (javaimp-module-raw module)))
+ (submodules (javaimp-xml-children submodules-elt 'module))
+ (rel-paths (mapcar #'javaimp-xml-first-child submodules)))
;; recurse into each submodule
(dolist (rel-path rel-paths)
- (javaimp--maven-fill-modules-files
+ (javaimp-maven--fill-modules-files
(concat (file-name-directory file)
(mapconcat #'file-name-as-directory
(split-string rel-path "[/\\\\]+" t) nil)
"pom.xml")
modules)))))
-(defun javaimp--maven-fetch-dep-jars (module _ids)
- (javaimp--maven-call
+(defun javaimp-maven--fetch-dep-jars (module _ids)
+ (javaimp-maven--call
;; always invoke for this module's pom.xml
(javaimp-module-file module)
(lambda ()
@@ -200,7 +207,7 @@ are somewhat arbitrary."
;; build tool wrapper.
(file-name-directory (javaimp-module-file-orig module))))
-(defun javaimp--maven-call (file handler task &optional dir)
+(defun javaimp-maven--call (file handler task &optional dir)
(let* ((default-directory (or dir (file-name-directory file)))
;; Prefer local mvn wrapper
(local-mvnw (if (memq system-type '(cygwin windows-nt))
diff --git a/javaimp-parse.el b/javaimp-parse.el
index fd3b2ae305..ee7b28eaca 100644
--- a/javaimp-parse.el
+++ b/javaimp-parse.el
@@ -18,20 +18,45 @@
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-(require 'javaimp-util)
+(require 'cc-mode) ;for java-mode-syntax-table
+(require 'cl-lib)
+(require 'seq)
-(defconst javaimp--parse-classlike-keywords
+(cl-defstruct javaimp-scope
+ type
+ name
+ start
+ open-brace
+ parent)
+
+
+(defconst javaimp-scope-classlike-types
+ '(class interface enum))
+
+(defconst javaimp-scope-all-types
+ (append
+ '(anon-class
+ array
+ method
+ simple-statement
+ statement
+ array)
+ javaimp-scope-classlike-types))
+
+
+(defconst javaimp-parse--classlike-keywords
(mapcar #'symbol-name
- javaimp--classlike-scope-types))
+ javaimp-scope-classlike-types))
-(defconst javaimp--parse-stmt-keywords
+(defconst javaimp-parse--stmt-keywords
'("if" "else" "for" "while" "do" "switch" "try" "catch" "finally"
"static" ; static initializer block
))
-(defconst javaimp--parse-stmt-keyword-maxlen
- (seq-max (mapcar #'length javaimp--parse-stmt-keywords)))
+(defconst javaimp-parse--stmt-keyword-maxlen
+ (seq-max (mapcar #'length javaimp-parse--stmt-keywords)))
-(defun javaimp--directive-regexp (directive)
+
+(defun javaimp-parse--directive-regexp (directive)
"Return regexp suitable for matching package-like DIRECTIVE, a
regexp. First group is directive, second group is identifier."
(rx bol (* space)
@@ -39,25 +64,40 @@ regexp. First group is directive, second group is
identifier."
(group (+ (any alnum ?_)) (* ?. (+ (any alnum ?_ ?*))))
(* space) ?\;))
-(defconst javaimp--parse-package-regexp
- (javaimp--directive-regexp "package"))
-(defconst javaimp--parse-import-regexp
- (javaimp--directive-regexp "import\\(?:[[:space:]]+static\\)?"))
+(defconst javaimp-parse--package-regexp
+ (javaimp-parse--directive-regexp "package"))
+(defconst javaimp-parse--import-regexp
+ (javaimp-parse--directive-regexp "import\\(?:[[:space:]]+static\\)?"))
+
+
+(defvar javaimp-syntax-table
+ (make-syntax-table java-mode-syntax-table) ;TODO don't depend on cc-mode
+ "Javaimp syntax table")
+
+(defvar javaimp--arglist-syntax-table
+ (let ((st (make-syntax-table javaimp-syntax-table)))
+ (modify-syntax-entry ?< "(>" st)
+ (modify-syntax-entry ?> ")<" st)
+ (modify-syntax-entry ?. "_" st) ; separates parts of fully-qualified type
+ st)
+ "Enables parsing angle brackets as lists")
+
-(defvar-local javaimp--parse-dirty-pos nil
+(defvar-local javaimp-parse--dirty-pos nil
"Marker which points to a buffer position after which all parsed
information should be considered as stale. Usually set by
modification change hooks. Nil value means we haven't yet parsed
anything in the buffer. A marker pointing nowhere means
everything's up-to-date.")
-(defsubst javaimp--parse-substr-before-< (str)
+
+(defsubst javaimp-parse--substr-before-< (str)
(let ((end (string-search "<" str)))
(if end
(string-trim (substring str 0 end))
str)))
-(defun javaimp--parse-rsb-keyword (regexp &optional bound noerror count)
+(defun javaimp-parse--rsb-keyword (regexp &optional bound noerror count)
"Like `re-search-backward', but count only occurences which start
outside any syntactic context as given by `syntax-ppss-context'.
Assumes point is outside of any context initially."
@@ -70,7 +110,7 @@ Assumes point is outside of any context initially."
(syntax-ppss-context (syntax-ppss)))))
res))
-(defun javaimp--parse-arglist (beg end &optional only-type)
+(defun javaimp-parse--arglist (beg end &optional only-type)
"Parse arg list between BEG and END, of the form 'TYPE NAME,
...'. Return list of conses (TYPE . NAME). If ONLY-TYPE is
non-nil, then name parsing is skipped."
@@ -81,24 +121,24 @@ non-nil, then name parsing is skipped."
(ignore-errors
(let (res)
(while (progn
- (javaimp--parse-skip-back-until)
+ (javaimp-parse--skip-back-until)
(not (bobp)))
- (push (javaimp--parse-arglist-one-arg only-type) res)
+ (push (javaimp-parse--arglist-one-arg only-type) res)
;; move back to the previous argument, if any
- (when (javaimp--parse-skip-back-until
+ (when (javaimp-parse--skip-back-until
(lambda (_last-what _last-pos)
(and (not (bobp))
(= (char-before) ?,))))
(backward-char))) ; skip comma
res))))))
-(defun javaimp--parse-arglist-one-arg (only-type)
+(defun javaimp-parse--arglist-one-arg (only-type)
"Parse one argument as type and name backwards starting from
point and return it in the form (TYPE . NAME). Name is skipped
if ONLY-TYPE is non-nil. Leave point at where the job is done:
skipping further backwards is done by the caller."
(let ((limit (progn
- (javaimp--parse-skip-back-until)
+ (javaimp-parse--skip-back-until)
(point)))
name)
;; Parse name
@@ -106,12 +146,12 @@ skipping further backwards is done by the caller."
(if (= 0 (skip-syntax-backward "w_"))
(error "Cannot parse argument name")
(setq name (buffer-substring-no-properties (point) limit))
- (javaimp--parse-skip-back-until)
+ (javaimp-parse--skip-back-until)
(setq limit (point))))
;; Parse type: allow anything, but stop at the word boundary which
;; is not inside list (this is presumably the type start..)
(if-let ((last-skip
- (javaimp--parse-skip-back-until
+ (javaimp-parse--skip-back-until
(lambda (_last-what last-pos)
(save-excursion
(if last-pos (goto-char last-pos))
@@ -125,7 +165,7 @@ skipping further backwards is done by the caller."
(cons type name)))
(error "Cannot parse argument type"))))
-(defun javaimp--parse-skip-back-until (&optional stop-p)
+(defun javaimp-parse--skip-back-until (&optional stop-p)
"Goes backwards until position at which STOP-P returns non-nil, or reaching
bob.
STOP-P is invoked with two arguments which describe the last
@@ -167,20 +207,20 @@ function is to just skip whitespace / comments."
(setq last-what 'char
last-pos (point)))))))))
-(defun javaimp--parse-preceding (regexp scope-start &optional bound skip-count)
+(defun javaimp-parse--preceding (regexp scope-start &optional bound skip-count)
"Returns non-nil if a match for REGEXP is found before point,
but not before BOUND. Matches inside comments / strings are
skipped. Potential match is checked to be SKIP-COUNT lists away
from the SCOPE-START (1 is for scope start itself, so if you want
to skip one additional list, use 2 etc.). If a match is found,
then match-data is set, as for `re-search-backward'."
- (and (javaimp--parse-rsb-keyword regexp bound t)
+ (and (javaimp-parse--rsb-keyword regexp bound t)
(ignore-errors
;; Does our match belong to the right block?
(= (scan-lists (match-end 0) (or skip-count 1) -1)
(1+ scope-start)))))
-(defun javaimp--parse-decl-suffix (regexp brace-pos &optional bound)
+(defun javaimp-parse--decl-suffix (regexp brace-pos &optional bound)
"Attempts to parse declaration suffix backwards from point (but
not farther than BOUND), returning non-nil on success. More
precisely, the value is the end of the match for REGEXP. Point
@@ -188,14 +228,14 @@ is left before the match. Otherwise, the result is nil
and point
is unchanged."
(let ((pos (point)))
(catch 'found
- (while (javaimp--parse-rsb-keyword regexp bound t)
+ (while (javaimp-parse--rsb-keyword regexp bound t)
(let ((scan-pos (match-end 0)))
(with-syntax-table javaimp--arglist-syntax-table
;; Skip over any number of lists, which may be exceptions
;; in "throws", or something like that
(while (and scan-pos (<= scan-pos brace-pos))
(if (ignore-errors
- (= (scan-lists scan-pos 1 -1) ;As in
javaimp--parse-preceding
+ (= (scan-lists scan-pos 1 -1) ;As in
javaimp-parse--preceding
(1+ brace-pos)))
(progn
(goto-char (match-beginning 0))
@@ -209,58 +249,119 @@ is unchanged."
;;; Scopes
-(defvar javaimp--parse-scope-hook
+(defun javaimp-scope-copy (scope)
+ "Recursively copies SCOPE and its parents."
+ (let* ((res (copy-javaimp-scope scope))
+ (tmp res)
+ orig-parent)
+ (while (setq orig-parent (javaimp-scope-parent tmp))
+ (setf (javaimp-scope-parent tmp) (copy-javaimp-scope orig-parent))
+ (setq tmp (javaimp-scope-parent tmp)))
+ res))
+
+(defun javaimp-scope-filter-parents (scope pred)
+ "Rewrite SCOPE's parents so that only those matching PRED are
+left."
+ (while scope
+ (let ((parent (javaimp-scope-parent scope)))
+ (if (and parent
+ (not (funcall pred parent)))
+ ;; leave out this parent
+ (setf (javaimp-scope-parent scope) (javaimp-scope-parent parent))
+ (setq scope (javaimp-scope-parent scope))))))
+
+(defun javaimp-scope-concat-parents (scope)
+ (let (parents)
+ (while (setq scope (javaimp-scope-parent scope))
+ (push scope parents))
+ (mapconcat #'javaimp-scope-name parents ".")))
+
+(defsubst javaimp-scope-test-type (scope leaf-types parent-types)
+ (declare (indent 1))
+ (let ((res (memq (javaimp-scope-type scope) leaf-types)))
+ (while (and res
+ (setq scope (javaimp-scope-parent scope)))
+ (setq res (memq (javaimp-scope-type scope) parent-types)))
+ res))
+
+(defun javaimp-scope-defun-p (&optional additional)
+ "Return predicate which matches scopes in
+`javaimp-scope-classlike-types'. ADDITIONAL is a list of scope
+types. If it includes `method', then also method leafs are
+included. If it includes `anon-class', then also leafs and
+parents may be anonymous classes."
+ (let ((leaf-types (append javaimp-scope-classlike-types
+ (when (memq 'method additional) '(method))
+ (when (memq 'anon-class additional)
'(anon-class))))
+ (parent-types (append javaimp-scope-classlike-types
+ (when (memq 'anon-class additional)
'(anon-class)))))
+ (lambda (s)
+ (javaimp-scope-test-type s leaf-types parent-types))))
+
+(defun javaimp-scope-same-parent-p (parent)
+ (if parent
+ (lambda (s)
+ (and (javaimp-scope-parent s)
+ (= (javaimp-scope-open-brace (javaimp-scope-parent s))
+ (javaimp-scope-open-brace parent))))
+ (lambda (s)
+ (not (javaimp-scope-parent s)))))
+
+
+;; Scope parsing
+
+(defvar javaimp-parse--scope-hook
(mapcar (lambda (parser)
(lambda (arg)
(save-excursion
(funcall parser arg))))
- '(javaimp--parse-scope-array
+ '(javaimp-parse--scope-array
;; anon-class should be before method/stmt because it
;; looks similar, but with "new" in front
- javaimp--parse-scope-anon-class
- javaimp--parse-scope-class
- javaimp--parse-scope-simple-stmt
- javaimp--parse-scope-method-or-stmt
+ javaimp-parse--scope-anon-class
+ javaimp-parse--scope-class
+ javaimp-parse--scope-simple-stmt
+ javaimp-parse--scope-method-or-stmt
))
"List of parser functions, each of which is called in
`save-excursion' and with one argument, the position of opening
brace.")
-(defun javaimp--parse-scope-class (brace-pos)
+(defun javaimp-parse--scope-class (brace-pos)
"Attempts to parse 'class' / 'interface' / 'enum' scope."
- (when (javaimp--parse-preceding
- (regexp-opt javaimp--parse-classlike-keywords 'symbols)
+ (when (javaimp-parse--preceding
+ (regexp-opt javaimp-parse--classlike-keywords 'symbols)
brace-pos
;; closest preceding closing paren is a good bound
;; because there _will be_ such char in frequent case
;; of method/stmt
(save-excursion
- (when (javaimp--parse-rsb-keyword ")" nil t 1)
+ (when (javaimp-parse--rsb-keyword ")" nil t 1)
(1+ (point)))))
(let* ((keyword-start (match-beginning 1))
(keyword-end (match-end 1))
arglist)
(goto-char brace-pos)
- (or (javaimp--parse-decl-suffix "\\_<extends\\_>" brace-pos keyword-end)
- (javaimp--parse-decl-suffix "\\_<implements\\_>" brace-pos
keyword-end)
- (javaimp--parse-decl-suffix "\\_<permits\\_>" brace-pos keyword-end))
+ (or (javaimp-parse--decl-suffix "\\_<extends\\_>" brace-pos keyword-end)
+ (javaimp-parse--decl-suffix "\\_<implements\\_>" brace-pos
keyword-end)
+ (javaimp-parse--decl-suffix "\\_<permits\\_>" brace-pos keyword-end))
;; we either skipped back over the valid declaration
;; suffix(-es), or there wasn't any
- (setq arglist (javaimp--parse-arglist keyword-end (point) t))
+ (setq arglist (javaimp-parse--arglist keyword-end (point) t))
(when (= (length arglist) 1)
(make-javaimp-scope :type (intern
(buffer-substring-no-properties
keyword-start keyword-end))
- :name (javaimp--parse-substr-before-< (caar
arglist))
+ :name (javaimp-parse--substr-before-< (caar
arglist))
:start keyword-start)))))
-(defun javaimp--parse-scope-simple-stmt (_brace-pos)
+(defun javaimp-parse--scope-simple-stmt (_brace-pos)
"Attempts to parse 'simple-statement' scope."
- (and (javaimp--parse-skip-back-until)
+ (and (javaimp-parse--skip-back-until)
(or (and (= (char-before (1- (point))) ?-) ; ->
(= (char-before) ?>))
- (looking-back (regexp-opt javaimp--parse-stmt-keywords 'words)
- (- (point) javaimp--parse-stmt-keyword-maxlen) nil))
+ (looking-back (regexp-opt javaimp-parse--stmt-keywords 'words)
+ (- (point) javaimp-parse--stmt-keyword-maxlen) nil))
(make-javaimp-scope
:type 'simple-statement
:name (or (match-string 1)
@@ -268,42 +369,42 @@ brace.")
:start (or (match-beginning 1)
(- (point) 2)))))
-(defun javaimp--parse-scope-anon-class (brace-pos)
+(defun javaimp-parse--scope-anon-class (brace-pos)
"Attempts to parse 'anon-class' scope."
;; skip arg-list and ws
(when (and (progn
- (javaimp--parse-skip-back-until)
+ (javaimp-parse--skip-back-until)
(= (char-before) ?\)))
(ignore-errors
(goto-char
(scan-lists (point) -1 0))))
(let ((end (point))
start arglist)
- (when (javaimp--parse-preceding "\\_<new\\_>" brace-pos nil 2)
+ (when (javaimp-parse--preceding "\\_<new\\_>" brace-pos nil 2)
(setq start (match-beginning 0)
- arglist (javaimp--parse-arglist (match-end 0) end t))
+ arglist (javaimp-parse--arglist (match-end 0) end t))
(when (= (length arglist) 1)
(make-javaimp-scope :type 'anon-class
:name
(concat "<anon>"
- (javaimp--parse-substr-before-< (caar
arglist)))
+ (javaimp-parse--substr-before-< (caar
arglist)))
:start start))))))
-(defun javaimp--parse-scope-method-or-stmt (brace-pos)
+(defun javaimp-parse--scope-method-or-stmt (brace-pos)
"Attempts to parse 'method' or 'statement' scope."
(let (;; take the closest preceding closing paren as the bound
(throws-search-bound (save-excursion
- (when (javaimp--parse-rsb-keyword ")" nil t 1)
+ (when (javaimp-parse--rsb-keyword ")" nil t 1)
(1+ (point))))))
(when throws-search-bound
(let ((throws-args
- (when-let ((pos (javaimp--parse-decl-suffix
+ (when-let ((pos (javaimp-parse--decl-suffix
"\\_<throws\\_>" brace-pos throws-search-bound)))
- (or (javaimp--parse-arglist pos brace-pos t)
+ (or (javaimp-parse--arglist pos brace-pos t)
t))))
(when (and (not (eq throws-args t))
(progn
- (javaimp--parse-skip-back-until)
+ (javaimp-parse--skip-back-until)
(= (char-before) ?\)))
(ignore-errors
;; for method this is arglist
@@ -313,42 +414,44 @@ brace.")
(arglist-region (cons (1+ (point))
(1- (scan-lists (point) 1 0))))
(count (progn
- (javaimp--parse-skip-back-until)
+ (javaimp-parse--skip-back-until)
(skip-syntax-backward "w_")))
(name (and (< count 0)
(buffer-substring-no-properties
(point) (+ (point) (abs count)))))
(type (when name
- (if (and (member name javaimp--parse-stmt-keywords)
+ (if (and (member name javaimp-parse--stmt-keywords)
(not throws-args))
'statement 'method))))
(when type
(make-javaimp-scope
:type type
:name (if (eq type 'method)
- (let ((args (javaimp--parse-arglist
+ (let ((args (javaimp-parse--arglist
(car arglist-region)
(cdr arglist-region))))
(concat name "(" (mapconcat #'car args ",") ")"))
name)
:start (point)))))))))
-(defun javaimp--parse-scope-array (_brace-pos)
+(defun javaimp-parse--scope-array (_brace-pos)
"Attempts to parse 'array' scope."
- (and (javaimp--parse-skip-back-until)
+ (and (javaimp-parse--skip-back-until)
(member (char-before) '(?, ?\]))
(make-javaimp-scope :type 'array
:name ""
:start nil)))
-(defun javaimp--parse-scopes (count)
+
+
+(defun javaimp-parse--scopes (count)
"Attempts to parse COUNT enclosing scopes at point.
Returns most nested one, with its parents sets accordingly. If
COUNT is nil then goes all the way up.
Examines and sets property 'javaimp-parse-scope' at each scope's
open brace. If neither of functions in
-`javaimp--parse-scope-hook' return non-nil then the property
+`javaimp-parse--scope-hook' return non-nil then the property
value is set to the symbol `unknown'. Additionally, if a scope
is recognized, but any of its parents is 'unknown', then it's set
to 'unknown' too.
@@ -367,7 +470,7 @@ nothing."
(let ((scope (get-text-property (point) 'javaimp-parse-scope)))
(unless scope
(setq scope (run-hook-with-args-until-success
- 'javaimp--parse-scope-hook (point)))
+ 'javaimp-parse--scope-hook (point)))
(if scope
(setf (javaimp-scope-open-brace scope) (point))
(setq scope 'unknown))
@@ -395,36 +498,36 @@ nothing."
(setq res (cdr res)))
parent)))
-(defun javaimp--parse-all-scopes ()
+(defun javaimp-parse--all-scopes ()
"Parses all scopes in this buffer which are after
-`javaimp--parse-dirty-pos', if it points anywhere. Makes it
+`javaimp-parse--dirty-pos', if it points anywhere. Makes it
point nowhere when done."
- (unless javaimp--parse-dirty-pos ;init on first use
- (setq javaimp--parse-dirty-pos (point-min-marker))
- (javaimp--parse-setup-buffer))
- (when (marker-position javaimp--parse-dirty-pos)
+ (unless javaimp-parse--dirty-pos ;init on first use
+ (setq javaimp-parse--dirty-pos (point-min-marker))
+ (javaimp-parse--setup-buffer))
+ (when (marker-position javaimp-parse--dirty-pos)
(with-silent-modifications ;we update only private props
- (remove-text-properties javaimp--parse-dirty-pos (point-max)
+ (remove-text-properties javaimp-parse--dirty-pos (point-max)
'(javaimp-parse-scope nil))
(goto-char (point-max))
(let ((parse-sexp-ignore-comments t)
;; Can be removed when we no longer rely on cc-mode
(parse-sexp-lookup-properties nil))
(with-syntax-table javaimp-syntax-table
- (while (javaimp--parse-rsb-keyword "{" javaimp--parse-dirty-pos t)
+ (while (javaimp-parse--rsb-keyword "{" javaimp-parse--dirty-pos t)
(save-excursion
(forward-char)
;; Set props at this brace and all the way up
- (javaimp--parse-scopes nil))))))
- (set-marker javaimp--parse-dirty-pos nil)))
+ (javaimp-parse--scopes nil))))))
+ (set-marker javaimp-parse--dirty-pos nil)))
-(defun javaimp--parse-setup-buffer ()
+(defun javaimp-parse--setup-buffer ()
;; FIXME This may be done in major/minor mode setup
(setq syntax-ppss-table javaimp-syntax-table)
(setq-local multibyte-syntax-as-symbol t)
- (add-hook 'after-change-functions #'javaimp--parse-update-dirty-pos))
+ (add-hook 'after-change-functions #'javaimp-parse--update-dirty-pos))
-(defun javaimp--parse-enclosing-scope (&optional pred)
+(defun javaimp-parse--enclosing-scope (&optional pred)
"Return innermost enclosing scope matching PRED."
(with-syntax-table javaimp-syntax-table
(let ((state (syntax-ppss)))
@@ -435,7 +538,7 @@ point nowhere when done."
(catch 'found
(while t
(let ((res (save-excursion
- (javaimp--parse-scopes nil))))
+ (javaimp-parse--scopes nil))))
(when (and (javaimp-scope-p res)
(or (null pred)
(funcall pred res)))
@@ -447,27 +550,27 @@ point nowhere when done."
(setq state (syntax-ppss)))
(throw 'found nil))))))))
-(defun javaimp--parse-class-abstract-methods ()
+(defun javaimp-parse--class-abstract-methods ()
(goto-char (point-max))
(let (res)
- (while (javaimp--parse-rsb-keyword "\\_<abstract\\_>" nil t)
+ (while (javaimp-parse--rsb-keyword "\\_<abstract\\_>" nil t)
(save-excursion
(let ((enclosing (nth 1 (syntax-ppss))))
(when (and enclosing
- (javaimp--parse-rsb-keyword ";" nil t -1)
+ (javaimp-parse--rsb-keyword ";" nil t -1)
;; are we in the same nest?
(= (nth 1 (syntax-ppss)) enclosing))
(backward-char) ;skip semicolon
;; now parse as normal method scope
- (when-let ((scope (javaimp--parse-scope-method-or-stmt (point)))
+ (when-let ((scope (javaimp-parse--scope-method-or-stmt (point)))
;; note that an abstract method with no
;; parents will be ignored
- (parent (javaimp--parse-scopes nil)))
- (setf (javaimp-scope-parent scope) (javaimp--copy-scope parent))
+ (parent (javaimp-parse--scopes nil)))
+ (setf (javaimp-scope-parent scope) (javaimp-scope-copy parent))
(push scope res))))))
res))
-(defun javaimp--parse-interface-abstract-methods (int-scope)
+(defun javaimp-parse--interface-abstract-methods (int-scope)
(let ((start (1+ (javaimp-scope-open-brace int-scope)))
(end (ignore-errors
(1- (scan-lists (javaimp-scope-open-brace int-scope) 1 0))))
@@ -475,49 +578,49 @@ point nowhere when done."
(when (and start end)
(goto-char end)
(while (and (> (point) start)
- (javaimp--parse-rsb-keyword ";" start t))
+ (javaimp-parse--rsb-keyword ";" start t))
;; are we in the same nest?
(if (= (nth 1 (syntax-ppss)) (javaimp-scope-open-brace int-scope))
(save-excursion
;; now parse as normal method scope
- (when-let ((scope (javaimp--parse-scope-method-or-stmt (point))))
+ (when-let ((scope (javaimp-parse--scope-method-or-stmt (point))))
(setf (javaimp-scope-parent scope) int-scope)
(push scope res)))
;; we've entered another nest, go back to its start
(goto-char (nth 1 (syntax-ppss))))))
res))
-(defun javaimp--parse-update-dirty-pos (beg _end _old-len)
+(defun javaimp-parse--update-dirty-pos (beg _end _old-len)
"Function to add to `after-change-functions' hook."
- (when (and javaimp--parse-dirty-pos
- (or (not (marker-position javaimp--parse-dirty-pos))
- (< beg javaimp--parse-dirty-pos)))
- (set-marker javaimp--parse-dirty-pos beg)))
+ (when (and javaimp-parse--dirty-pos
+ (or (not (marker-position javaimp-parse--dirty-pos))
+ (< beg javaimp-parse--dirty-pos)))
+ (set-marker javaimp-parse--dirty-pos beg)))
;; Functions intended to be called from other parts of javaimp. They
;; do not preserve excursion / restriction - it's the caller's
;; responsibility.
-(defun javaimp--parse-get-package ()
+(defun javaimp-parse-get-package ()
"Return the package declared in the current file. Leaves point
at the end of directive."
- (javaimp--parse-all-scopes)
+ (javaimp-parse--all-scopes)
(goto-char (point-max))
- (when (javaimp--parse-rsb-keyword javaimp--parse-package-regexp nil t 1)
+ (when (javaimp-parse--rsb-keyword javaimp-parse--package-regexp nil t 1)
(goto-char (match-end 0))
(match-string 2)))
-(defun javaimp--parse-get-imports ()
+(defun javaimp-parse-get-imports ()
"Parse import directives in the current buffer and return (REGION
. CLASS-ALIST). REGION, a cons of two positions, spans from bol
of first import to eol of last import. CLASS-ALIST contains
elements (CLASS . TYPE), where CLASS is a string and TYPE is
either of symbols `normal' or 'static'."
- (javaimp--parse-all-scopes)
+ (javaimp-parse--all-scopes)
(goto-char (point-max))
(let (start-pos end-pos class-alist)
- (while (javaimp--parse-rsb-keyword javaimp--parse-import-regexp nil t)
+ (while (javaimp-parse--rsb-keyword javaimp-parse--import-regexp nil t)
(setq start-pos (line-beginning-position))
(unless end-pos
(setq end-pos (line-end-position)))
@@ -528,7 +631,7 @@ either of symbols `normal' or 'static'."
(cons (and start-pos end-pos (cons start-pos end-pos))
class-alist)))
-(defun javaimp--parse-get-all-scopes (&optional beg end pred parent-pred)
+(defun javaimp-parse-get-all-scopes (&optional beg end pred parent-pred)
"Return all scopes in the current buffer between positions BEG
and END, both exclusive, optionally filtering them with PRED, and
their parents with PARENT-PRED. Neither of PRED or PARENT-PRED
@@ -536,7 +639,7 @@ should move point. Note that parents may be outside of
region
given by BEG and END. BEG is the LIMIT argument to
`previous-single-property-change', and so may be nil. END
defaults to end of accessible portion of the buffer."
- (javaimp--parse-all-scopes)
+ (javaimp-parse--all-scopes)
(let ((pos (or end (point-max)))
scope res)
(while (and (setq pos (previous-single-property-change
@@ -547,46 +650,46 @@ defaults to end of accessible portion of the buffer."
(when (and (javaimp-scope-p scope)
(or (null pred)
(funcall pred scope)))
- (setq scope (javaimp--copy-scope scope))
+ (setq scope (javaimp-scope-copy scope))
(when parent-pred
- (javaimp--filter-scope-parents scope parent-pred))
+ (javaimp-scope-filter-parents scope parent-pred))
(push scope res)))
res))
-(defun javaimp--parse-get-enclosing-scope (&optional pred parent-pred)
+(defun javaimp-parse-get-enclosing-scope (&optional pred parent-pred)
"Return innermost enclosing scope at point, optionally checking
it with PRED, and its parents with PARENT-PRED."
(save-excursion
- (javaimp--parse-all-scopes))
- (when-let ((scope (javaimp--parse-enclosing-scope pred)))
- (setq scope (javaimp--copy-scope scope))
+ (javaimp-parse--all-scopes))
+ (when-let ((scope (javaimp-parse--enclosing-scope pred)))
+ (setq scope (javaimp-scope-copy scope))
(when parent-pred
- (javaimp--filter-scope-parents scope parent-pred))
+ (javaimp-scope-filter-parents scope parent-pred))
scope))
-(defun javaimp--parse-get-class-abstract-methods ()
- (javaimp--parse-all-scopes)
- (javaimp--parse-class-abstract-methods))
+(defun javaimp-parse-get-class-abstract-methods ()
+ (javaimp-parse--all-scopes)
+ (javaimp-parse--class-abstract-methods))
-(defun javaimp--parse-get-interface-abstract-methods ()
- (let ((interfaces (javaimp--parse-get-all-scopes
+(defun javaimp-parse-get-interface-abstract-methods ()
+ (let ((interfaces (javaimp-parse-get-all-scopes
nil nil
(lambda (s)
- (javaimp-test-scope-type s
- '(interface) javaimp--classlike-scope-types)))))
- (seq-mapcat #'javaimp--parse-interface-abstract-methods
+ (javaimp-scope-test-type s
+ '(interface) javaimp-scope-classlike-types)))))
+ (seq-mapcat #'javaimp-parse--interface-abstract-methods
interfaces)))
-(defmacro javaimp--parse-without-hook (&rest body)
+(defmacro javaimp-parse-without-hook (&rest body)
"Execute BODY, temporarily removing
-`javaimp--parse-update-dirty-pos' from `after-change-functions'
+`javaimp-parse--update-dirty-pos' from `after-change-functions'
hook."
(declare (debug t) (indent 0))
`(unwind-protect
(progn
- (remove-hook 'after-change-functions
#'javaimp--parse-update-dirty-pos)
+ (remove-hook 'after-change-functions
#'javaimp-parse--update-dirty-pos)
,@body)
- (add-hook 'after-change-functions #'javaimp--parse-update-dirty-pos)))
+ (add-hook 'after-change-functions #'javaimp-parse--update-dirty-pos)))
(provide 'javaimp-parse)
diff --git a/javaimp-tests.el b/javaimp-tests.el
index 42b5daa069..165eef1ec2 100644
--- a/javaimp-tests.el
+++ b/javaimp-tests.el
@@ -1,431 +1,19 @@
-;;; javaimp-tests.el --- javaimp tests -*- lexical-binding: t; -*-
+;;; javaimp-tests.el --- javaimp test util -*- lexical-binding: t; -*-
-;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
+;; Copyright (C) 2022-2022 Free Software Foundation, Inc.
;; Author: Filipp Gunbin <[email protected]>
;; Maintainer: Filipp Gunbin <[email protected]>
-(require 'ert)
-(require 'javaimp)
-
-;; Use this selector to run all tests which do not invoke build tool:
-;;
-;; (and "^javaimp-" (not (tag :runs-build-tool)))
-;;
-
-;; Tests for low-level helpers of scope parsers.
-
-(ert-deftest javaimp-test--parse-arglist ()
- (dolist (data '(("")
- (" ")
- ("int i"
- ("int" . "i"))
- ("\nint\ni\n,\nint\nj\n"
- ("int" . "i")
- ("int" . "j"))
- (" List<? extends Comparable<? super T>> list, T... elements"
- ("List<? extends Comparable<? super T>>" . "list")
- ("T..." . "elements"))
- ("org.foo.Map <? extends K, \n? extends V> m, String []
array, int i"
- ;; TODO remove extra ws within
- ("org.foo.Map <? extends K, ? extends V>" . "m")
- ("String []" . "array")
- ("int" . "i"))
- (" Bi_Function<? super K, ? super V, ? extends V> function "
- ("Bi_Function<? super K, ? super V, ? extends V>" .
"function"))
- ("@Annotation1 final int i,
[email protected]_2(value_1 = \"value1 , (){}\", value2 = -2.3) String[][]
arr"
- ("int" . "i")
- ("String[][]" . "arr"))
- ))
- (with-temp-buffer
- (insert (car data))
- (should (equal (javaimp--parse-arglist (point-min) (point-max))
- (cdr data))))))
-
-(ert-deftest javaimp-test--parse-arglist-throws ()
- (dolist (data '(("")
- (" ")
- ("Exception1"
- ("Exception1"))
- ("\nEx1\n,\nEx2\n"
- ("Ex1")
- ("Ex2"))
- (" Exception1 , org.foo_bar_3.Exception_2 "
- ("Exception1")
- ("org.foo_bar_3.Exception_2"))
- ("Exception_1<? extends org.foo.Exception_2<? super
Exception3>,
- Exception4<? super Exception5>>, \nException6,Exception7<Exception8>"
- ("Exception_1<? extends org.foo.Exception_2<? super
Exception3>, \
-Exception4<? super Exception5>>")
- ("Exception6")
- ("Exception7<Exception8>"))))
- (with-temp-buffer
- (insert (car data))
- (should (equal (javaimp--parse-arglist (point-min) (point-max) t)
- (cdr data))))))
-
-
-
-;; Tests for single scope parsers, which should be in
-;; `javaimp--parse-scope-hook'.
-
-(ert-deftest javaimp-test--parse-scope-class ()
- (javaimp-test--single-parser #'javaimp--parse-scope-class
- '("class Foo {"
- class "Foo")
- '("class Foo extends Bar {"
- class "Foo")
- '("class Foo implements Bar {"
- class "Foo")
- '("class Foo implements Bar, Baz {"
- class "Foo")
- '("public class Foo extends Bar implements Baz1 , Baz2 {"
- class "Foo")
- `(,(subst-char-in-string
- ? ?\n
- "public class Foo extends Bar implements Baz1 , Baz2 {")
- class "Foo")
- '("class Foo<Bar, Baz> extends FooSuper<Bar, Baz> \
-implements Interface1<Bar, Baz>, Interface2 {"
- class "Foo")
- '("class Foo<E extends Bar> {"
- class "Foo")
- '("class Foo<Enum<?>> {"
- class "Foo")
- '("class Foo<T extends Baz<? extends Baz2>> \
-extends Bar<? extends Baz<? extends Baz2>> {"
- class "Foo")
- '("interface Foo<Bar, Baz> {"
- interface "Foo")
- '("private enum Foo {"
- enum "Foo")
- ))
-
-(ert-deftest javaimp-test--parse-scope-anon-class ()
- (javaimp-test--single-parser #'javaimp--parse-scope-anon-class
- '(" = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {"
- anon-class "<anon>Object")
- `(,(subst-char-in-string
- ? ?\n
- " = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {")
- anon-class "<anon>Object")
- '(" = (obj.getField()).new Object<Class1, Class2>(1, baz) {"
- anon-class "<anon>Object")
- '(" = obj.new Object<>(1, baz) {"
- anon-class "<anon>Object")
- ))
-
-(ert-deftest javaimp-test--parse-scope-method-or-stmt ()
- (javaimp-test--single-parser #'javaimp--parse-scope-method-or-stmt
- '("static void foo_bar ( String a , int b ) {"
- method "foo_bar(String,int)")
- `(,(subst-char-in-string
- ? ?\n
- "static void foo_bar ( String a , int b ) {")
- method "foo_bar(String,int)")
- '("void foo_bar(String a, int b) throws E1, E2 {"
- method "foo_bar(String,int)")
- '("void foo_bar()
-throws E1 {"
- method "foo_bar()")
- '("if (foo_bar(a, b) < 2) {"
- statement "if")
- ))
-
-(ert-deftest javaimp-test--parse-scope-simple-stmt ()
- (javaimp-test--single-parser #'javaimp--parse-scope-simple-stmt
- '(" try {"
- simple-statement "try")
- `(,(subst-char-in-string ? ?\n " try {")
- simple-statement "try")
- ;; static initializer
- '("static {"
- simple-statement "static")
- ;; lambda
- '("it -> {"
- simple-statement "lambda")
- '("(x, y) -> {"
- simple-statement "lambda")
- ))
-
-(ert-deftest javaimp-test--parse-scope-array ()
- (javaimp-test--single-parser #'javaimp--parse-scope-array
- '("new String[] {"
- array "")
- ;; TODO fix
- ;; '("new Object[][] { {"
- ;; array "")
- ;; '("new int[] {{1, 2}, {"
- ;; array "")
- ))
-
-(defun javaimp-test--single-parser (parser &rest test-items)
- (declare (indent 1))
- (dolist (item test-items)
- (with-temp-buffer
- (insert (nth 0 item))
- (let* ((javaimp--parse-scope-hook
- (lambda (arg)
- (save-excursion
- (funcall parser arg))))
- (scopes (javaimp--parse-get-all-scopes)))
- (should (= 1 (length scopes)))
- (should (eq (javaimp-scope-type (car scopes)) (nth 1 item)))
- (should (equal (javaimp-scope-name (car scopes)) (nth 2 item)))))))
-
-
-;; Tests for parse "api"
-
-(ert-deftest javaimp-test--parse-get-package ()
- (with-temp-buffer
- (insert "
- package foo.bar.baz ;
-//package commented.line;
-/*
-package commented.block;
-*/
-")
- (should (equal (javaimp--parse-get-package) "foo.bar.baz"))))
-
-(ert-deftest javaimp-test--parse-get-imports ()
- (with-temp-buffer
- (insert "
- import some.class1 ;
-import static some.class.fun1;
-//import commented.line;
-/*
-import static commented.block;
-*/
-import someclass2;
-import my.package.* ;
-
-import static some_class.fun_2; // comment
-// comment outside
-")
- (should (equal
- (javaimp--parse-get-imports)
- '((2 . 206)
- ("some.class1" . normal)
- ("some.class.fun1" . static)
- ("someclass2" . normal)
- ("my.package.*" . normal)
- ("some_class.fun_2" . static))))))
-
-(ert-deftest javaimp-test--parse-get-all-scopes ()
- (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir "testdata/test1-misc-classes.java"))
- (should-not javaimp--parse-dirty-pos)
- ;;
- ;; parse full buffer
- (javaimp-test--check-named-scopes)
- (should javaimp--parse-dirty-pos)
- (should-not (marker-position javaimp--parse-dirty-pos))
- ;;
- ;; reparse half of the buffer
- (set-marker javaimp--parse-dirty-pos (/ (- (point-max) (point-min)) 2))
- (javaimp-test--check-named-scopes)
- (should-not (marker-position javaimp--parse-dirty-pos))
- ;;
- ;; don't reparse
- (javaimp-test--check-named-scopes)))
-
-(defun javaimp-test--check-named-scopes ()
- (let* ((scopes (javaimp--parse-get-all-scopes
- nil nil
- (lambda (s)
- (memq (javaimp-scope-type s) '(class interface enum
method)))
- (lambda (s)
- (memq (javaimp-scope-type s) '(class interface enum
method)))))
- (actual (mapcar
- (lambda (s)
- (let (res)
- (while s
- (push (list (javaimp-scope-type s)
- (javaimp-scope-name s))
- res)
- (setq s (javaimp-scope-parent s)))
- (nreverse res)))
- scopes))
- (expected
- '(((class "Top"))
- ((class "CInner1") (class "Top"))
- ((method "foo()") (class "CInner1") (class "Top"))
- ((class "CInner1_CLocal1")
- (method "foo()") (class "CInner1") (class "Top"))
- ((method "foo()")
- (class "CInner1_CLocal1")
- (method "foo()") (class "CInner1") (class "Top"))
- ((class "CInner1_CLocal1_CLocal1")
- (method "foo()")
- (class "CInner1_CLocal1")
- (method "foo()") (class "CInner1") (class "Top"))
- ((method "foo()")
- (class "CInner1_CLocal1_CLocal1")
- (method "foo()")
- (class "CInner1_CLocal1")
- (method "foo()") (class "CInner1") (class "Top"))
-
- ((class "CInner1_CLocal2")
- (method "foo()") (class "CInner1") (class "Top"))
- ((method "foo()")
- (class "CInner1_CLocal2")
- (method "foo()") (class "CInner1") (class "Top"))
-
- ((method "toString()")
- (class "CInner1") (class "Top"))
-
- ((class "CInner1_CInner1") (class "CInner1") (class "Top"))
- ((method "foo()")
- (class "CInner1_CInner1") (class "CInner1") (class "Top"))
- ((method "bar()")
- (class "CInner1_CInner1") (class "CInner1") (class "Top"))
-
- ((interface "IInner1") (class "Top"))
- ((method "foo()") (interface "IInner1") (class "Top"))
- ((class "IInner1_CInner1") (interface "IInner1") (class "Top"))
- ((method "foo()")
- (class "IInner1_CInner1") (interface "IInner1") (class "Top"))
- ((method "defaultMethod(String)")
- (interface "IInner1") (class "Top"))
-
- ((interface "IInner1_IInner1") (interface "IInner1") (class "Top"))
- ((method "defaultMethod(String)")
- (interface "IInner1_IInner1") (interface "IInner1") (class "Top"))
-
- ((enum "EnumInner1") (class "Top"))
- ((method "EnumInner1()") (enum "EnumInner1") (class "Top"))
- ((method "foo()") (enum "EnumInner1") (class "Top"))
- ((enum "EnumInner1_EInner1") (enum "EnumInner1") (class "Top"))
-
- ((class "ColocatedTop"))
- ((method "foo()") (class "ColocatedTop"))
- ((method "bar(String,String)") (class "ColocatedTop")))))
- (should (= (length expected) (length actual)))
- (dotimes (i (length expected))
- (should (equal (nth i expected) (nth i actual))))
- ;;
- (let ((data
- `((,(nth 0 scopes) "Top" 26 36)
- (,(nth 16 scopes) "foo()" 1798 1804)
- (,(nth 23 scopes) "EnumInner1_EInner1" 2462 2486)
- (,(nth 25 scopes) "foo()" 2554 2560))))
- (dolist (elt data)
- (let ((scope (nth 0 elt)))
- (should (equal (nth 1 elt) (javaimp-scope-name scope)))
- (should (equal (nth 2 elt) (javaimp-scope-start scope)))
- (should (equal (nth 3 elt) (javaimp-scope-open-brace scope))))))))
-
-
-
-;; Tests for javaimp--get-buffer-classes
-
-(ert-deftest javaimp-test--get-buffer-classes ()
- (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir "testdata/test1-misc-classes.java"))
- (should (equal (javaimp--get-buffer-classes)
- '("org.foo.Top"
- "org.foo.Top.CInner1"
- "org.foo.Top.CInner1.CInner1_CInner1"
- "org.foo.Top.IInner1"
- "org.foo.Top.IInner1.IInner1_CInner1"
- "org.foo.Top.IInner1.IInner1_IInner1"
- "org.foo.Top.EnumInner1"
- "org.foo.Top.EnumInner1.EnumInner1_EInner1"
- "org.foo.ColocatedTop")))))
-
-
-;; Tests for imenu function
-
-(ert-deftest javaimp-test--imenu ()
- (let ((actual (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir
"testdata/test1-misc-classes.java"))
- (let ((imenu-use-markers nil))
- (javaimp-imenu-create-index))))
- (expected-names
- '("foo() [Top.CInner1]"
- "foo() [Top.CInner1.CInner1_CInner1]"
- "abstract_method() [Top.CInner1.CInner1_CInner1]"
- "bar()"
- "baz() [Top.CInner1.CInner1_CInner1]"
- "foo() [Top.IInner1]"
- "abstract_method() [Top.IInner1]"
- "foo() [Top.IInner1.IInner1_CInner1]"
- "baz() [Top.IInner1]"
- "defaultMethod(String) [Top.IInner1]"
- "foo() [Top.IInner1.IInner1_IInner1]"
- "defaultMethod(String) [Top.IInner1.IInner1_IInner1]"
- "baz() [Top.IInner1.IInner1_IInner1]"
- "EnumInner1()"
- "foo() [Top.EnumInner1]"
- "foo() [ColocatedTop]"
- "bar(String,String)")))
- (should (= (length expected-names) (length actual)))
- (dotimes (i (length expected-names))
- (should (equal (nth i expected-names) (car (nth i actual)))))))
-
-(ert-deftest javaimp-test--imenu-use-sub-alists ()
- (let ((actual (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir
"testdata/test1-misc-classes.java"))
- (let ((imenu-use-markers nil)
- (javaimp-imenu-use-sub-alists t))
- (javaimp-imenu-create-index))))
- (expected
- '(("Top"
- ("CInner1"
- ("foo()" . 98)
- ("CInner1_CInner1"
- ("foo()" . 1099)
- ("abstract_method()" . 1148)
- ("bar()" . 1192)
- ("baz()" . 1281)))
- ("IInner1"
- ("foo()" . 1603)
- ("abstract_method()" . 1715)
- ("IInner1_CInner1"
- ("foo()" . 1798))
- ("baz()" . 1934)
- ("defaultMethod(String)" . 1963)
- ("IInner1_IInner1"
- ("foo()" . 2122)
- ("defaultMethod(String)" . 2157)
- ("baz()" . 2258)))
- ("EnumInner1"
- ("EnumInner1()" . 2353)
- ("foo()" . 2399)
- ;; "EnumInner1_EInner1" omitted because no methods inside
- ))
- ("ColocatedTop"
- ("foo()" . 2554)
- ("bar(String,String)" . 2578)))))
- (javaimp-test--imenu-simplify-entries actual)
- (should (equal expected actual))))
-
-(defun javaimp-test--imenu-simplify-entries (alist)
- (dolist (elt alist)
- (if (and (= (length elt) 4)
- (functionp (nth 2 elt)))
- (setcdr elt (nth 1 elt))
- (javaimp-test--imenu-simplify-entries (cdr elt)))))
-
-
-;; Utility
-
-(defun javaimp-test--with-data (filename handler)
- "Untars testdata/FILENAME into temporary directory and runs
-HANDLER, supplying temp directory name as the only arg."
+(defun javaimp-call-with-data (filename handler)
+ "Untar FILENAME into temporary directory and call HANDLER,
+supplying that directory name as the only arg."
(let ((tmpdir (file-name-as-directory (make-temp-file "javaimp" t))))
(unwind-protect
(let ((rc (call-process
"tar" nil nil nil
"-x"
- "-f" (concat javaimp--basedir
- (file-name-as-directory "testdata")
- filename)
+ "-f" filename
"-C" tmpdir)))
(unless (= rc 0)
(error "Cannot untar test data %s: %d" filename rc))
diff --git a/javaimp-util.el b/javaimp-util.el
index 7105323768..8813b7afb6 100644
--- a/javaimp-util.el
+++ b/javaimp-util.el
@@ -21,34 +21,27 @@
;;; Code:
-(require 'xml)
(require 'cl-lib)
(require 'seq)
+(require 'xml)
+
+(defconst javaimp-basedir (file-name-directory load-file-name))
-(defconst javaimp--basedir (file-name-directory load-file-name))
-
-(defconst javaimp--classlike-scope-types
- '(class interface enum))
-
-(defconst javaimp--all-scope-types
- (append
- '(anon-class
- array
- method
- simple-statement
- statement
- array)
- javaimp--classlike-scope-types))
-
-(defconst javaimp--show-scopes-scope-type-abbrevs
- '((anon-class . "ac")
- (statement . "st")
- (simple-statement . "ss")
- (array . "ar")
- (method . "me")
- (class . "cl")
- (interface . "in")
- (enum . "en")))
+(defcustom javaimp-java-home
+ (let ((val (getenv "JAVA_HOME")))
+ (and val (not (string-blank-p val))
+ val))
+ "Path to the JDK. The directory given should contain
+subdirectory \"jre/lib\" (pre-JDK9) or just \"lib\". By default,
+it is initialized from the JAVA_HOME environment variable."
+ :type 'string
+ :group 'javaimp)
+
+(defcustom javaimp-cygpath-program
+ (if (eq system-type 'cygwin) "cygpath")
+ "Path to the `cygpath' program (Cygwin only)."
+ :type 'string
+ :group 'javaimp)
(defvar javaimp-tool-output-buf-name "*javaimp-tool-output*"
"Name of the buffer to which `javaimp--call-build-tool' copies
@@ -83,12 +76,6 @@ build tool output. Can be let-bound to nil to suppress
copying.")
(cl-defstruct javaimp-cached-file
file read-ts classes)
-(cl-defstruct javaimp-scope
- type ; see javaimp--all-scope-types
- name
- start
- open-brace
- parent)
(defsubst javaimp-print-id (id)
(format "%s:%s:%s"
@@ -99,87 +86,26 @@ build tool output. Can be let-bound to nil to suppress
copying.")
;; Xml
-(defun javaimp--xml-children (xml-tree child-name)
+(defun javaimp-xml-children (xml-tree child-name)
"Returns list of children of XML-TREE filtered by CHILD-NAME"
(seq-filter (lambda (child)
(and (consp child)
(eq (car child) child-name)))
(cddr xml-tree)))
-(defun javaimp--xml-child (name el)
+(defun javaimp-xml-child (name el)
"Returns a child of EL named by symbol NAME"
(assq name (cddr el)))
-(defun javaimp--xml-first-child (el)
+(defun javaimp-xml-first-child (el)
"Returns a first child of EL"
(car (cddr el)))
-;; Scopes
-
-(defun javaimp--copy-scope (scope)
- "Recursively copies SCOPE and its parents."
- (let* ((res (copy-javaimp-scope scope))
- (tmp res)
- orig-parent)
- (while (setq orig-parent (javaimp-scope-parent tmp))
- (setf (javaimp-scope-parent tmp) (copy-javaimp-scope orig-parent))
- (setq tmp (javaimp-scope-parent tmp)))
- res))
-
-(defun javaimp--filter-scope-parents (scope pred)
- "Rewrite SCOPE's parents so that only those matching PRED are
-left."
- (while scope
- (let ((parent (javaimp-scope-parent scope)))
- (if (and parent
- (not (funcall pred parent)))
- ;; leave out this parent
- (setf (javaimp-scope-parent scope) (javaimp-scope-parent parent))
- (setq scope (javaimp-scope-parent scope))))))
-
-(defun javaimp--concat-scope-parents (scope)
- (let (parents)
- (while (setq scope (javaimp-scope-parent scope))
- (push scope parents))
- (mapconcat #'javaimp-scope-name parents ".")))
-
-(defsubst javaimp-test-scope-type (scope leaf-types parent-types)
- (declare (indent 1))
- (let ((res (memq (javaimp-scope-type scope) leaf-types)))
- (while (and res
- (setq scope (javaimp-scope-parent scope)))
- (setq res (memq (javaimp-scope-type scope) parent-types)))
- res))
-
-(defun javaimp--defun-scope-pred (&optional additional)
- "Return predicate which matches scopes in
-`javaimp--classlike-scope-types'. ADDITIONAL is a list of scope
-types. If it includes `method', then also method leafs are
-included. If it includes `anon-class', then also leafs and
-parents may be anonymous classes."
- (let ((leaf-types (append javaimp--classlike-scope-types
- (when (memq 'method additional) '(method))
- (when (memq 'anon-class additional)
'(anon-class))))
- (parent-types (append javaimp--classlike-scope-types
- (when (memq 'anon-class additional)
'(anon-class)))))
- (lambda (s)
- (javaimp-test-scope-type s leaf-types parent-types))))
-
-(defun javaimp--scope-same-parent-pred (parent)
- (if parent
- (lambda (s)
- (and (javaimp-scope-parent s)
- (= (javaimp-scope-open-brace (javaimp-scope-parent s))
- (javaimp-scope-open-brace parent))))
- (lambda (s)
- (not (javaimp-scope-parent s)))))
-
-
;; Tree
-(defun javaimp--build-tree (this all child-p &optional parent-node sort-pred)
+(defun javaimp-tree-build (this all child-p &optional parent-node sort-pred)
"Recursively builds tree for element THIS and its children.
Children are those elements from ALL for which CHILD-P invoked
with this element and tested element returns non-nil. Children
@@ -195,20 +121,21 @@ recursive calls."
:contents this))
(child-nodes
(mapcar (lambda (child)
- (javaimp--build-tree
+ (javaimp-tree-build
child all child-p this-node sort-pred))
children)))
(setf (javaimp-node-children this-node) child-nodes)
this-node)))
-(defun javaimp--find-node (contents-pred forest &optional unwrap)
+
+(defun javaimp-tree-find-node (contents-pred forest &optional unwrap)
"Return first node for which CONTENTS-PRED returns non-nil. If
UNWRAP is non-nil, then node contents is returned."
(catch 'found
(dolist (tree forest)
- (javaimp--find-node-in-tree tree contents-pred unwrap))))
+ (javaimp-tree--find-node-1 tree contents-pred unwrap))))
-(defun javaimp--find-node-in-tree (tree contents-pred unwrap)
+(defun javaimp-tree--find-node-1 (tree contents-pred unwrap)
(when tree
(if (funcall contents-pred (javaimp-node-contents tree))
(throw 'found
@@ -216,30 +143,30 @@ UNWRAP is non-nil, then node contents is returned."
(javaimp-node-contents tree)
tree)))
(dolist (child (javaimp-node-children tree))
- (javaimp--find-node-in-tree child contents-pred unwrap))))
+ (javaimp-tree--find-node-1 child contents-pred unwrap))))
-(defun javaimp--collect-nodes (contents-pred forest)
+(defun javaimp-tree-collect-nodes (contents-pred forest)
"Return all nodes' contents for which CONTENTS-PRED returns
non-nil."
(apply #'seq-concatenate 'list
(mapcar (lambda (tree)
(delq nil
- (javaimp--collect-nodes-from-tree tree contents-pred)))
+ (javaimp-tree--collect-nodes-1 tree contents-pred)))
forest)))
-(defun javaimp--collect-nodes-from-tree (tree contents-pred)
+(defun javaimp-tree--collect-nodes-1 (tree contents-pred)
(when tree
(cons (and (funcall contents-pred (javaimp-node-contents tree))
(javaimp-node-contents tree))
(apply #'seq-concatenate 'list
(mapcar (lambda (child)
(delq nil
- (javaimp--collect-nodes-from-tree child
contents-pred)))
+ (javaimp-tree--collect-nodes-1 child
contents-pred)))
(javaimp-node-children tree))))))
-(defun javaimp--map-nodes (function pred forest)
+(defun javaimp-tree-map-nodes (function pred forest)
"Recursively applies FUNCTION to each node's contents in FOREST
and returns new tree. FUNCTION should return (t . VALUE) if the
result for this node should be made a list of the form (VALUE
@@ -248,10 +175,10 @@ this case children are discarded). The result for each
node is
additionally tested by PRED."
(delq nil
(mapcar (lambda (tree)
- (javaimp--map-nodes-from-tree tree function pred))
+ (javaimp-tree--map-nodes-1 tree function pred))
forest)))
-(defun javaimp--map-nodes-from-tree (tree function pred)
+(defun javaimp-tree--map-nodes-1 (tree function pred)
(when tree
(let* ((cell (funcall function (javaimp-node-contents tree)))
(res
@@ -259,7 +186,7 @@ additionally tested by PRED."
(let ((children
(delq nil
(mapcar (lambda (child)
- (javaimp--map-nodes-from-tree
+ (javaimp-tree--map-nodes-1
child function pred))
(javaimp-node-children tree)))))
(cons (cdr cell) children))
@@ -267,14 +194,9 @@ additionally tested by PRED."
(and (funcall pred res)
res))))
-(defun javaimp--get-root (node)
- (while (javaimp-node-parent node)
- (setq node (javaimp-node-parent node)))
- node)
-
-;; Files & caches
+;; Misc
(defsubst javaimp--get-file-ts (file)
(nth 5 (file-attributes file)))
@@ -307,9 +229,6 @@ error, the cache for FILE is cleared."
(signal (car err) (cdr err)))))
-
-;; System
-
;; TODO use functions `cygwin-convert-file-name-from-windows' and
;; `cygwin-convert-file-name-to-windows' when they are available
;; instead of calling `cygpath'. See
diff --git a/javaimp.el b/javaimp.el
index 4d42e4adb7..857c127cef 100644
--- a/javaimp.el
+++ b/javaimp.el
@@ -58,7 +58,7 @@
;; (setq javaimp-project forest nil)
;;
;; Project structure and dependency information is retrieved from the
-;; build tool, see `javaimp--maven-visit' and `javaimp--gradle-visit',
+;; build tool, see `javaimp-maven-visit' and `javaimp-gradle-visit',
;; and the `javaimp-handler-regexp-alist' variable. The output from
;; the build tool can be inspected in buffer named by
;; `javaimp-tool-output-buf-name' variable. If there exists
@@ -136,11 +136,11 @@
;;; Code:
+(require 'javaimp-util)
(require 'javaimp-maven)
(require 'javaimp-gradle)
(require 'javaimp-parse)
-(require 'javaimp-util)
-(require 'cc-mode) ;for java-mode-syntax-table
+
(require 'imenu)
@@ -170,15 +170,6 @@ The order of classes which were not matched is defined by
`javaimp-import-group-alist'"
:type 'integer)
-(defcustom javaimp-java-home
- (let ((val (getenv "JAVA_HOME")))
- (and val (not (string-blank-p val))
- val))
- "Path to the JDK. The directory given should contain
-subdirectory \"jre/lib\" (pre-JDK9) or just \"lib\". By default,
-it is initialized from the JAVA_HOME environment variable."
- :type 'string)
-
(defcustom javaimp-additional-source-dirs nil
"List of directories where additional (e.g. generated)
source files reside.
@@ -220,28 +211,13 @@ class)."
"Path to the `jmod' program used to read contents of jmod files."
:type 'string)
-(defcustom javaimp-cygpath-program
- (if (eq system-type 'cygwin) "cygpath")
- "Path to the `cygpath' program (Cygwin only)."
- :type 'string)
-
-(defcustom javaimp-mvn-program "mvn"
- "Path to the `mvn' program. If the visited project has local
-mvnw (Maven wrapper), it is used in preference."
- :type 'string)
-
-(defcustom javaimp-gradle-program "gradle"
- "Path to the `gradle' program. If the visited project has local
-gradlew (Gradle wrapper), it is used in preference."
- :type 'string)
-
;; Variables
(defvar javaimp-handler-regexp-alist
- `(("\\`build.gradle" . ,#'javaimp--gradle-visit)
- ("\\`pom.xml\\'" . ,#'javaimp--maven-visit))
+ `(("\\`build.gradle" . ,#'javaimp-gradle-visit)
+ ("\\`pom.xml\\'" . ,#'javaimp-maven-visit))
"Alist of file name patterns vs corresponding handler function.
A handler function takes one argument, a FILE.")
@@ -258,18 +234,6 @@ struct.")
is expanded file name and CACHED-FILE is javaimp-cached-file
struct.")
-(defvar javaimp-syntax-table
- (make-syntax-table java-mode-syntax-table) ;TODO don't depend on cc-mode
- "Javaimp syntax table")
-
-(defvar javaimp--arglist-syntax-table
- (let ((st (make-syntax-table javaimp-syntax-table)))
- (modify-syntax-entry ?< "(>" st)
- (modify-syntax-entry ?> ")<" st)
- (modify-syntax-entry ?. "_" st) ; separates parts of fully-qualified type
- st)
- "Enables parsing angle brackets as lists")
-
(defconst javaimp--jar-error-header
"There were errors when reading some of the dependency files,
they are listed below.
@@ -286,6 +250,16 @@
https://docs.gradle.org/current/userguide/java_library_plugin.html\
#sec:java_library_classes_usage
")
+(defconst javaimp-show-scopes-type-abbrevs
+ '((anon-class . "ac")
+ (statement . "st")
+ (simple-statement . "ss")
+ (array . "ar")
+ (method . "me")
+ (class . "cl")
+ (interface . "in")
+ (enum . "en")))
+
;;;###autoload
(defun javaimp-visit-project (file)
@@ -423,15 +397,15 @@ output."
(defun javaimp-find-module (predicate)
"Returns first module in `javaimp-project-forest' for which
PREDICATE returns non-nil."
- (javaimp--find-node predicate javaimp-project-forest t))
+ (javaimp-tree-find-node predicate javaimp-project-forest t))
(defun javaimp-collect-modules (predicate)
"Returns all modules in `javaimp-project-forest' for which
PREDICATE returns non-nil."
- (javaimp--collect-nodes predicate javaimp-project-forest))
+ (javaimp-tree-collect-nodes predicate javaimp-project-forest))
(defun javaimp-map-modules (function)
- (javaimp--map-nodes function #'always javaimp-project-forest))
+ (javaimp-tree-map-nodes function #'always javaimp-project-forest))
;;; Adding imports
@@ -458,7 +432,7 @@ current module or source tree, see
(interactive
(let* ((file (expand-file-name (or buffer-file-name
(error "Buffer is not visiting a
file!"))))
- (node (javaimp--find-node
+ (node (javaimp-tree-find-node
(lambda (m)
(seq-some (lambda (dir)
(string-prefix-p dir file))
@@ -544,7 +518,7 @@ If there's no such directive, then the last resort is just
(if-let ((package (save-excursion
(save-restriction
(widen)
- (javaimp--parse-get-package)))))
+ (javaimp-parse-get-package)))))
(string-remove-suffix
(mapconcat #'file-name-as-directory (split-string package "\\." t)
nil)
default-directory)
@@ -577,22 +551,22 @@ If there's no such directive, then the last resort is just
(insert-file-contents file)
;; We need only class-likes, and this is temp buffer, so for
;; efficiency avoid parsing anything else
- (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-class))
+ (let ((javaimp-parse--scope-hook #'javaimp-parse--scope-class))
(javaimp--get-buffer-classes))))
(defun javaimp--get-buffer-classes ()
"Return fully-qualified names of all class-like scopes in the
current buffer. Anonymous classes are not included."
- (let ((package (javaimp--parse-get-package))
- (scopes (javaimp--parse-get-all-scopes
- nil nil (javaimp--defun-scope-pred))))
+ (let ((package (javaimp-parse-get-package))
+ (scopes (javaimp-parse-get-all-scopes
+ nil nil (javaimp-scope-defun-p))))
(mapcar (lambda (class)
(if package
(concat package "." class)
class))
(mapcar (lambda (scope)
(let ((name (javaimp-scope-name scope))
- (parent-names (javaimp--concat-scope-parents
scope)))
+ (parent-names (javaimp-scope-concat-parents
scope)))
(if (string-empty-p parent-names)
name
(concat parent-names "." name))))
@@ -620,15 +594,15 @@ are assigned a default order defined by
Additionally, merge imports from ADD-ALIST, an alist of the same
form as CLASS-ALIST in return value of
-`javaimp--parse-get-imports'."
+`javaimp-parse-get-imports'."
(interactive)
(barf-if-buffer-read-only)
(save-excursion
(save-restriction
(widen)
- (let ((parsed (javaimp--parse-get-imports)))
+ (let ((parsed (javaimp-parse-get-imports)))
(when (or (cdr parsed) add-alist)
- (javaimp--parse-without-hook
+ (javaimp-parse-without-hook
(javaimp--position-for-insert-imports (car parsed))
(let ((with-order
(mapcar
@@ -664,7 +638,7 @@ form as CLASS-ALIST in return value of
(progn
(delete-region (car old-region) (cdr old-region))
(goto-char (car old-region)))
- (if (javaimp--parse-get-package)
+ (if (javaimp-parse-get-package)
(insert "\n\n")
;; As a last resort, go to bob and skip comments
(goto-char (point-min))
@@ -689,13 +663,22 @@ form as CLASS-ALIST in return value of
;; Imenu support
+(defsubst javaimp-imenu--make-entry (scope)
+ (list (javaimp-scope-name scope)
+ (if imenu-use-markers
+ (copy-marker (javaimp-scope-start scope))
+ (javaimp-scope-start scope))
+ #'javaimp-imenu--function
+ scope))
+
+
;;;###autoload
(defun javaimp-imenu-create-index ()
"Function to use as `imenu-create-index-function', can be set
in a major mode hook."
(let ((forest (javaimp-imenu--get-forest)))
(if javaimp-imenu-use-sub-alists
- (javaimp--map-nodes
+ (javaimp-tree-map-nodes
(lambda (scope)
(if (eq (javaimp-scope-type scope) 'method)
;; entry
@@ -709,7 +692,7 @@ in a major mode hook."
(let ((entries
(mapcar #'javaimp-imenu--make-entry
(seq-sort-by #'javaimp-scope-start #'<
- (javaimp--collect-nodes
+ (javaimp-tree-collect-nodes
(lambda (scope)
(eq (javaimp-scope-type scope) 'method))
forest))))
@@ -724,14 +707,14 @@ in a major mode hook."
(setcar entry
(format "%s [%s]"
(car entry)
- (javaimp--concat-scope-parents
+ (javaimp-scope-concat-parents
(nth 3 entry))))))
entries)))))
(defun javaimp-imenu--get-forest ()
(let* ((defun-scopes
- (javaimp--parse-get-all-scopes
- nil nil (javaimp--defun-scope-pred '(method))))
+ (javaimp-parse-get-all-scopes
+ nil nil (javaimp-scope-defun-p '(method))))
(methods (seq-filter
(lambda (scope)
(eq (javaimp-scope-type scope) 'method))
@@ -744,36 +727,29 @@ in a major mode hook."
(null (javaimp-scope-parent s)))
classes))
(abstract-methods (append
- (javaimp--parse-get-class-abstract-methods)
- (javaimp--parse-get-interface-abstract-methods))))
+ (javaimp-parse-get-class-abstract-methods)
+ (javaimp-parse-get-interface-abstract-methods))))
(mapcar
(lambda (top-class)
(message "Building tree for top-level class-like scope: %s"
(javaimp-scope-name top-class))
- (javaimp--build-tree top-class
- (append methods
- classes
- abstract-methods)
- (lambda (el tested)
- (equal el (javaimp-scope-parent tested)))
- nil
- (lambda (s1 s2)
- (< (javaimp-scope-start s1)
- (javaimp-scope-start s2)))))
+ (javaimp-tree-build top-class
+ (append methods
+ classes
+ abstract-methods)
+ (lambda (el tested)
+ (equal el (javaimp-scope-parent tested)))
+ nil
+ (lambda (s1 s2)
+ (< (javaimp-scope-start s1)
+ (javaimp-scope-start s2)))))
top-classes)))
-(defsubst javaimp-imenu--make-entry (scope)
- (list (javaimp-scope-name scope)
- (if imenu-use-markers
- (copy-marker (javaimp-scope-start scope))
- (javaimp-scope-start scope))
- #'javaimp-imenu--function
- scope))
-
(defun javaimp-imenu--function (_index-name index-position _scope)
(goto-char index-position)
(back-to-indentation))
+
;; Show scopes
@@ -829,8 +805,8 @@ opening brace."
(save-excursion
(save-restriction
(widen)
- (javaimp--parse-get-all-scopes
- nil nil (javaimp--defun-scope-pred '(method anon-class))))))
+ (javaimp-parse-get-all-scopes
+ nil nil (javaimp-scope-defun-p '(method anon-class))))))
(source-buf (current-buffer))
(source-default-dir default-directory)
(buf (get-buffer-create "*javaimp-scopes*")))
@@ -853,7 +829,7 @@ opening brace."
(line-number-at-pos (javaimp-scope-start
scope)))
depth
(cdr (assq (javaimp-scope-type scope)
-
javaimp--show-scopes-scope-type-abbrevs))
+ javaimp-show-scopes-type-abbrevs))
(make-string (* 2 depth) ? )
(javaimp-scope-name scope))
'mouse-face 'highlight
@@ -928,8 +904,8 @@ after this group of defuns."
(save-restriction
(widen)
(let* ((pos (point))
- (defun-pred (javaimp--defun-scope-pred '(method anon-class)))
- (enc (javaimp--parse-get-enclosing-scope defun-pred))
+ (defun-pred (javaimp-scope-defun-p '(method anon-class)))
+ (enc (javaimp-parse-get-enclosing-scope defun-pred))
(parent
(if (and enc (eq (javaimp-scope-type enc) 'method))
;; We're inside a method, and need to look at
@@ -945,9 +921,9 @@ after this group of defuns."
(ignore-errors
(scan-lists
(javaimp-scope-open-brace parent) 1 0))))
- (sibling-pred (javaimp--scope-same-parent-pred parent))
+ (sibling-pred (javaimp-scope-same-parent-p parent))
(siblings
- (javaimp--parse-get-all-scopes
+ (javaimp-parse-get-all-scopes
;; beg/end are not strictly needed, pred is enough, but
;; provide them for effectiveness
parent-beg parent-end
diff --git a/testdata/gradle-multi.tar.gz b/tests/data/gradle-multi.tar.gz
similarity index 100%
rename from testdata/gradle-multi.tar.gz
rename to tests/data/gradle-multi.tar.gz
diff --git a/testdata/maven-multi.tar.gz b/tests/data/maven-multi.tar.gz
similarity index 100%
rename from testdata/maven-multi.tar.gz
rename to tests/data/maven-multi.tar.gz
diff --git a/testdata/maven-single.tar.gz b/tests/data/maven-single.tar.gz
similarity index 100%
rename from testdata/maven-single.tar.gz
rename to tests/data/maven-single.tar.gz
diff --git a/testdata/test1-misc-classes.java
b/tests/data/test1-misc-classes.java
similarity index 100%
rename from testdata/test1-misc-classes.java
rename to tests/data/test1-misc-classes.java
diff --git a/javaimp-tests-gradle.el b/tests/gradle.el
similarity index 73%
rename from javaimp-tests-gradle.el
rename to tests/gradle.el
index 413c297939..f9e4e78e15 100644
--- a/javaimp-tests-gradle.el
+++ b/tests/gradle.el
@@ -1,4 +1,4 @@
-;;; javaimp-tests-gradle.el --- javaimp Gradle tests -*- lexical-binding: t;
-*-
+;;; tests/gradle.el --- javaimp Gradle tests -*- lexical-binding: t; -*-
;; Copyright (C) 2021-2021 Free Software Foundation, Inc.
@@ -6,34 +6,16 @@
;; Maintainer: Filipp Gunbin <[email protected]>
(require 'ert)
-(require 'javaimp)
+(require 'javaimp-gradle)
(require 'javaimp-tests)
-;; Tests for Gradle project parsing.
-;;
;; Note that you have to set up `javaimp-gradle-program' to point to
;; Gradle installation, which is rather untypical for Gradle projects
;; (most often, a "Gradle wrapper" is used, resulting in project-local
;; copy of Gradle).
-(ert-deftest javaimp-test--gradle-visit-multi ()
- :tags '(:runs-build-tool)
- (javaimp-test--with-data
- "gradle-multi.tar.gz"
- (lambda (tmpdir)
- (should
- (equal
- (javaimp-test--gradle-get-tree
- (concat tmpdir (file-name-as-directory "multi")))
- '((("<root>:org.example:1.0" . "build.gradle")
- (("child:org.example:1.0" . "child/build.gradle")
- (("child.grandchild:org.example:1.0" .
"child/grandchild/build.gradle")))
- ;; directory layout different from project layout
- (("non-direct-child:org.example:1.0" .
"foo/non-direct-child/build.gradle"))
- )))))))
-
-(defun javaimp-test--gradle-get-tree (project-dir)
- (javaimp--map-nodes
+(defun javaimp-test-gradle--get-tree (project-dir)
+ (javaimp-tree-map-nodes
(lambda (mod)
(cons t
(cons (javaimp-print-id (javaimp-module-id mod))
@@ -44,6 +26,22 @@
;; /var/ on macOS), so do it too
(file-truename project-dir)))))
#'always
- (javaimp--gradle-visit (concat project-dir "build.gradle"))))
+ (javaimp-gradle-visit (concat project-dir "build.gradle"))))
-(provide 'javaimp-tests-gradle)
+
+(ert-deftest javaimp-gradle-visit-multi ()
+ :tags '(:expensive)
+ (javaimp-call-with-data
+ (file-name-concat
+ javaimp-basedir "tests" "data" "gradle-multi.tar.gz")
+ (lambda (tmpdir)
+ (should
+ (equal
+ (javaimp-test-gradle--get-tree
+ (concat tmpdir (file-name-as-directory "multi")))
+ '((("<root>:org.example:1.0" . "build.gradle")
+ (("child:org.example:1.0" . "child/build.gradle")
+ (("child.grandchild:org.example:1.0" .
"child/grandchild/build.gradle")))
+ ;; directory layout different from project layout
+ (("non-direct-child:org.example:1.0" .
"foo/non-direct-child/build.gradle"))
+ )))))))
diff --git a/tests/imenu.el b/tests/imenu.el
new file mode 100644
index 0000000000..39c186f55a
--- /dev/null
+++ b/tests/imenu.el
@@ -0,0 +1,85 @@
+;;; tests/imenu.el --- javaimp Imenu tests -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022-2022 Free Software Foundation, Inc.
+
+;; Author: Filipp Gunbin <[email protected]>
+;; Maintainer: Filipp Gunbin <[email protected]>
+
+(require 'ert)
+(require 'javaimp)
+
+(defun javaimp-test-imenu--simplify-entries (alist)
+ (dolist (elt alist)
+ (if (and (= (length elt) 4)
+ (functionp (nth 2 elt)))
+ (setcdr elt (nth 1 elt))
+ (javaimp-test-imenu--simplify-entries (cdr elt)))))
+
+
+(ert-deftest javaimp-imenu-create-index ()
+ (let ((actual (with-temp-buffer
+ (insert-file-contents
+ (file-name-concat
+ javaimp-basedir "tests" "data" "test1-misc-classes.java"))
+ (let ((imenu-use-markers nil))
+ (javaimp-imenu-create-index))))
+ (expected-names
+ '("foo() [Top.CInner1]"
+ "foo() [Top.CInner1.CInner1_CInner1]"
+ "abstract_method() [Top.CInner1.CInner1_CInner1]"
+ "bar()"
+ "baz() [Top.CInner1.CInner1_CInner1]"
+ "foo() [Top.IInner1]"
+ "abstract_method() [Top.IInner1]"
+ "foo() [Top.IInner1.IInner1_CInner1]"
+ "baz() [Top.IInner1]"
+ "defaultMethod(String) [Top.IInner1]"
+ "foo() [Top.IInner1.IInner1_IInner1]"
+ "defaultMethod(String) [Top.IInner1.IInner1_IInner1]"
+ "baz() [Top.IInner1.IInner1_IInner1]"
+ "EnumInner1()"
+ "foo() [Top.EnumInner1]"
+ "foo() [ColocatedTop]"
+ "bar(String,String)")))
+ (should (= (length expected-names) (length actual)))
+ (dotimes (i (length expected-names))
+ (should (equal (nth i expected-names) (car (nth i actual)))))))
+
+(ert-deftest javaimp-imenu-create-index-use-sub-alists ()
+ (let ((actual (with-temp-buffer
+ (insert-file-contents
+ (file-name-concat
+ javaimp-basedir "tests" "data" "test1-misc-classes.java"))
+ (let ((imenu-use-markers nil)
+ (javaimp-imenu-use-sub-alists t))
+ (javaimp-imenu-create-index))))
+ (expected
+ '(("Top"
+ ("CInner1"
+ ("foo()" . 98)
+ ("CInner1_CInner1"
+ ("foo()" . 1099)
+ ("abstract_method()" . 1148)
+ ("bar()" . 1192)
+ ("baz()" . 1281)))
+ ("IInner1"
+ ("foo()" . 1603)
+ ("abstract_method()" . 1715)
+ ("IInner1_CInner1"
+ ("foo()" . 1798))
+ ("baz()" . 1934)
+ ("defaultMethod(String)" . 1963)
+ ("IInner1_IInner1"
+ ("foo()" . 2122)
+ ("defaultMethod(String)" . 2157)
+ ("baz()" . 2258)))
+ ("EnumInner1"
+ ("EnumInner1()" . 2353)
+ ("foo()" . 2399)
+ ;; "EnumInner1_EInner1" omitted because no methods inside
+ ))
+ ("ColocatedTop"
+ ("foo()" . 2554)
+ ("bar(String,String)" . 2578)))))
+ (javaimp-test-imenu--simplify-entries actual)
+ (should (equal expected actual))))
diff --git a/javaimp-tests-maven.el b/tests/maven.el
similarity index 77%
rename from javaimp-tests-maven.el
rename to tests/maven.el
index 4dad154ea2..ee83f63f88 100644
--- a/javaimp-tests-maven.el
+++ b/tests/maven.el
@@ -1,4 +1,4 @@
-;;; javaimp-tests-maven.el --- javaimp Maven tests -*- lexical-binding: t; -*-
+;;; tests/maven.el --- javaimp Maven tests -*- lexical-binding: t; -*-
;; Copyright (C) 2021-2021 Free Software Foundation, Inc.
@@ -6,12 +6,10 @@
;; Maintainer: Filipp Gunbin <[email protected]>
(require 'ert)
-(require 'javaimp)
+(require 'javaimp-maven)
(require 'javaimp-tests)
-;; Tests for Maven project parsing.
-
-;; "testdata" dir contains some archived Maven projects. If you need
+;; "data" dir contains some archived Maven projects. If you need
;; to run Maven on them manually, use this in the untarred directory:
;;
;; `mvn -U -s settings.xml -f <name>/pom.xml help:effective-pom'.
@@ -21,25 +19,37 @@
;; `<?xml version="1.0" encoding="UTF-8"?><settings/>'
;;
-(ert-deftest javaimp-test--maven-visit-single ()
- :tags '(:runs-build-tool)
- (javaimp-test--with-data
- "maven-single.tar.gz"
+(defun javaimp-test-maven--get-tree (project-dir)
+ (javaimp-tree-map-nodes
+ (lambda (mod)
+ (cons t
+ (cons (javaimp-print-id (javaimp-module-id mod))
+ (file-relative-name (javaimp-module-file mod) project-dir))))
+ #'always
+ (javaimp-maven-visit (concat project-dir "pom.xml"))))
+
+
+(ert-deftest javaimp-maven-visit-single ()
+ :tags '(:expensive)
+ (javaimp-call-with-data
+ (file-name-concat
+ javaimp-basedir "tests" "data" "maven-single.tar.gz")
(lambda (tmpdir)
(should
(equal
- (javaimp-test--maven-get-tree
+ (javaimp-test-maven--get-tree
(concat tmpdir (file-name-as-directory "single")))
'((("single:org.example:1.0.0" . "pom.xml"))))))))
-(ert-deftest javaimp-test--maven-visit-multi ()
- :tags '(:runs-build-tool)
- (javaimp-test--with-data
- "maven-multi.tar.gz"
+(ert-deftest javaimp-maven-visit-multi ()
+ :tags '(:expensive)
+ (javaimp-call-with-data
+ (file-name-concat
+ javaimp-basedir "tests" "data" "maven-multi.tar.gz")
(lambda (tmpdir)
(should
(equal
- (javaimp-test--maven-get-tree
+ (javaimp-test-maven--get-tree
(concat tmpdir (file-name-as-directory "multi")))
'(;; Main tree:
(("multi:org.example:1.0.0" . "pom.xml")
@@ -69,14 +79,3 @@
;; And "dangling-parent-link" project is not present at all,
;; because we have no way of knowing about it
))))))
-
-(defun javaimp-test--maven-get-tree (project-dir)
- (javaimp--map-nodes
- (lambda (mod)
- (cons t
- (cons (javaimp-print-id (javaimp-module-id mod))
- (file-relative-name (javaimp-module-file mod) project-dir))))
- #'always
- (javaimp--maven-visit (concat project-dir "pom.xml"))))
-
-(provide 'javaimp-tests-maven)
diff --git a/javaimp-tests.el b/tests/parse.el
similarity index 58%
copy from javaimp-tests.el
copy to tests/parse.el
index 42b5daa069..4cb16a47c2 100644
--- a/javaimp-tests.el
+++ b/tests/parse.el
@@ -1,21 +1,17 @@
-;;; javaimp-tests.el --- javaimp tests -*- lexical-binding: t; -*-
+;;; tests/parse.el --- javaimp parsing tests -*- lexical-binding: t; -*-
-;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
+;; Copyright (C) 2022-2022 Free Software Foundation, Inc.
;; Author: Filipp Gunbin <[email protected]>
;; Maintainer: Filipp Gunbin <[email protected]>
(require 'ert)
-(require 'javaimp)
+(require 'javaimp-parse)
+(require 'javaimp-util)
-;; Use this selector to run all tests which do not invoke build tool:
-;;
-;; (and "^javaimp-" (not (tag :runs-build-tool)))
-;;
+;; Tests for parse helpers
-;; Tests for low-level helpers of scope parsers.
-
-(ert-deftest javaimp-test--parse-arglist ()
+(ert-deftest javaimp-parse-arglist ()
(dolist (data '(("")
(" ")
("int i"
@@ -40,10 +36,10 @@
))
(with-temp-buffer
(insert (car data))
- (should (equal (javaimp--parse-arglist (point-min) (point-max))
+ (should (equal (javaimp-parse--arglist (point-min) (point-max))
(cdr data))))))
-(ert-deftest javaimp-test--parse-arglist-throws ()
+(ert-deftest javaimp-parse-arglist-throws ()
(dolist (data '(("")
(" ")
("Exception1"
@@ -62,16 +58,30 @@ Exception4<? super Exception5>>")
("Exception7<Exception8>"))))
(with-temp-buffer
(insert (car data))
- (should (equal (javaimp--parse-arglist (point-min) (point-max) t)
+ (should (equal (javaimp-parse--arglist (point-min) (point-max) t)
(cdr data))))))
-;; Tests for single scope parsers, which should be in
-;; `javaimp--parse-scope-hook'.
+;; Tests for scope parsers
+
+(defun javaimp-test-parse--scope (parser &rest test-items)
+ (declare (indent 1))
+ (dolist (item test-items)
+ (with-temp-buffer
+ (insert (nth 0 item))
+ (let* ((javaimp-parse--scope-hook
+ (lambda (arg)
+ (save-excursion
+ (funcall parser arg))))
+ (scopes (javaimp-parse-get-all-scopes)))
+ (should (= 1 (length scopes)))
+ (should (eq (javaimp-scope-type (car scopes)) (nth 1 item)))
+ (should (equal (javaimp-scope-name (car scopes)) (nth 2 item)))))))
+
-(ert-deftest javaimp-test--parse-scope-class ()
- (javaimp-test--single-parser #'javaimp--parse-scope-class
+(ert-deftest javaimp-parse-scope-class ()
+ (javaimp-test-parse--scope #'javaimp-parse--scope-class
'("class Foo {"
class "Foo")
'("class Foo extends Bar {"
@@ -102,8 +112,8 @@ extends Bar<? extends Baz<? extends Baz2>> {"
enum "Foo")
))
-(ert-deftest javaimp-test--parse-scope-anon-class ()
- (javaimp-test--single-parser #'javaimp--parse-scope-anon-class
+(ert-deftest javaimp-parse-scope-anon-class ()
+ (javaimp-test-parse--scope #'javaimp-parse--scope-anon-class
'(" = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {"
anon-class "<anon>Object")
`(,(subst-char-in-string
@@ -116,8 +126,8 @@ extends Bar<? extends Baz<? extends Baz2>> {"
anon-class "<anon>Object")
))
-(ert-deftest javaimp-test--parse-scope-method-or-stmt ()
- (javaimp-test--single-parser #'javaimp--parse-scope-method-or-stmt
+(ert-deftest javaimp-parse-scope-method-or-stmt ()
+ (javaimp-test-parse--scope #'javaimp-parse--scope-method-or-stmt
'("static void foo_bar ( String a , int b ) {"
method "foo_bar(String,int)")
`(,(subst-char-in-string
@@ -133,8 +143,8 @@ throws E1 {"
statement "if")
))
-(ert-deftest javaimp-test--parse-scope-simple-stmt ()
- (javaimp-test--single-parser #'javaimp--parse-scope-simple-stmt
+(ert-deftest javaimp-parse-scope-simple-stmt ()
+ (javaimp-test-parse--scope #'javaimp-parse--scope-simple-stmt
'(" try {"
simple-statement "try")
`(,(subst-char-in-string ? ?\n " try {")
@@ -149,8 +159,8 @@ throws E1 {"
simple-statement "lambda")
))
-(ert-deftest javaimp-test--parse-scope-array ()
- (javaimp-test--single-parser #'javaimp--parse-scope-array
+(ert-deftest javaimp-parse-scope-array ()
+ (javaimp-test-parse--scope #'javaimp-parse--scope-array
'("new String[] {"
array "")
;; TODO fix
@@ -160,79 +170,12 @@ throws E1 {"
;; array "")
))
-(defun javaimp-test--single-parser (parser &rest test-items)
- (declare (indent 1))
- (dolist (item test-items)
- (with-temp-buffer
- (insert (nth 0 item))
- (let* ((javaimp--parse-scope-hook
- (lambda (arg)
- (save-excursion
- (funcall parser arg))))
- (scopes (javaimp--parse-get-all-scopes)))
- (should (= 1 (length scopes)))
- (should (eq (javaimp-scope-type (car scopes)) (nth 1 item)))
- (should (equal (javaimp-scope-name (car scopes)) (nth 2 item)))))))
-;; Tests for parse "api"
-
-(ert-deftest javaimp-test--parse-get-package ()
- (with-temp-buffer
- (insert "
- package foo.bar.baz ;
-//package commented.line;
-/*
-package commented.block;
-*/
-")
- (should (equal (javaimp--parse-get-package) "foo.bar.baz"))))
-
-(ert-deftest javaimp-test--parse-get-imports ()
- (with-temp-buffer
- (insert "
- import some.class1 ;
-import static some.class.fun1;
-//import commented.line;
-/*
-import static commented.block;
-*/
-import someclass2;
-import my.package.* ;
-
-import static some_class.fun_2; // comment
-// comment outside
-")
- (should (equal
- (javaimp--parse-get-imports)
- '((2 . 206)
- ("some.class1" . normal)
- ("some.class.fun1" . static)
- ("someclass2" . normal)
- ("my.package.*" . normal)
- ("some_class.fun_2" . static))))))
+;; Tests for parse api
-(ert-deftest javaimp-test--parse-get-all-scopes ()
- (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir "testdata/test1-misc-classes.java"))
- (should-not javaimp--parse-dirty-pos)
- ;;
- ;; parse full buffer
- (javaimp-test--check-named-scopes)
- (should javaimp--parse-dirty-pos)
- (should-not (marker-position javaimp--parse-dirty-pos))
- ;;
- ;; reparse half of the buffer
- (set-marker javaimp--parse-dirty-pos (/ (- (point-max) (point-min)) 2))
- (javaimp-test--check-named-scopes)
- (should-not (marker-position javaimp--parse-dirty-pos))
- ;;
- ;; don't reparse
- (javaimp-test--check-named-scopes)))
-
-(defun javaimp-test--check-named-scopes ()
- (let* ((scopes (javaimp--parse-get-all-scopes
+(defun javaimp-test-parse--check-defuns ()
+ (let* ((scopes (javaimp-parse-get-all-scopes
nil nil
(lambda (s)
(memq (javaimp-scope-type s) '(class interface enum
method)))
@@ -318,118 +261,56 @@ import static some_class.fun_2; // comment
(should (equal (nth 3 elt) (javaimp-scope-open-brace scope))))))))
-
-;; Tests for javaimp--get-buffer-classes
-
-(ert-deftest javaimp-test--get-buffer-classes ()
+(ert-deftest javaimp-parse-get-package ()
(with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir "testdata/test1-misc-classes.java"))
- (should (equal (javaimp--get-buffer-classes)
- '("org.foo.Top"
- "org.foo.Top.CInner1"
- "org.foo.Top.CInner1.CInner1_CInner1"
- "org.foo.Top.IInner1"
- "org.foo.Top.IInner1.IInner1_CInner1"
- "org.foo.Top.IInner1.IInner1_IInner1"
- "org.foo.Top.EnumInner1"
- "org.foo.Top.EnumInner1.EnumInner1_EInner1"
- "org.foo.ColocatedTop")))))
-
-
-;; Tests for imenu function
-
-(ert-deftest javaimp-test--imenu ()
- (let ((actual (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir
"testdata/test1-misc-classes.java"))
- (let ((imenu-use-markers nil))
- (javaimp-imenu-create-index))))
- (expected-names
- '("foo() [Top.CInner1]"
- "foo() [Top.CInner1.CInner1_CInner1]"
- "abstract_method() [Top.CInner1.CInner1_CInner1]"
- "bar()"
- "baz() [Top.CInner1.CInner1_CInner1]"
- "foo() [Top.IInner1]"
- "abstract_method() [Top.IInner1]"
- "foo() [Top.IInner1.IInner1_CInner1]"
- "baz() [Top.IInner1]"
- "defaultMethod(String) [Top.IInner1]"
- "foo() [Top.IInner1.IInner1_IInner1]"
- "defaultMethod(String) [Top.IInner1.IInner1_IInner1]"
- "baz() [Top.IInner1.IInner1_IInner1]"
- "EnumInner1()"
- "foo() [Top.EnumInner1]"
- "foo() [ColocatedTop]"
- "bar(String,String)")))
- (should (= (length expected-names) (length actual)))
- (dotimes (i (length expected-names))
- (should (equal (nth i expected-names) (car (nth i actual)))))))
-
-(ert-deftest javaimp-test--imenu-use-sub-alists ()
- (let ((actual (with-temp-buffer
- (insert-file-contents
- (concat javaimp--basedir
"testdata/test1-misc-classes.java"))
- (let ((imenu-use-markers nil)
- (javaimp-imenu-use-sub-alists t))
- (javaimp-imenu-create-index))))
- (expected
- '(("Top"
- ("CInner1"
- ("foo()" . 98)
- ("CInner1_CInner1"
- ("foo()" . 1099)
- ("abstract_method()" . 1148)
- ("bar()" . 1192)
- ("baz()" . 1281)))
- ("IInner1"
- ("foo()" . 1603)
- ("abstract_method()" . 1715)
- ("IInner1_CInner1"
- ("foo()" . 1798))
- ("baz()" . 1934)
- ("defaultMethod(String)" . 1963)
- ("IInner1_IInner1"
- ("foo()" . 2122)
- ("defaultMethod(String)" . 2157)
- ("baz()" . 2258)))
- ("EnumInner1"
- ("EnumInner1()" . 2353)
- ("foo()" . 2399)
- ;; "EnumInner1_EInner1" omitted because no methods inside
- ))
- ("ColocatedTop"
- ("foo()" . 2554)
- ("bar(String,String)" . 2578)))))
- (javaimp-test--imenu-simplify-entries actual)
- (should (equal expected actual))))
-
-(defun javaimp-test--imenu-simplify-entries (alist)
- (dolist (elt alist)
- (if (and (= (length elt) 4)
- (functionp (nth 2 elt)))
- (setcdr elt (nth 1 elt))
- (javaimp-test--imenu-simplify-entries (cdr elt)))))
+ (insert "
+ package foo.bar.baz ;
+//package commented.line;
+/*
+package commented.block;
+*/
+")
+ (should (equal (javaimp-parse-get-package) "foo.bar.baz"))))
-
-;; Utility
+(ert-deftest javaimp-parse-get-imports ()
+ (with-temp-buffer
+ (insert "
+ import some.class1 ;
+import static some.class.fun1;
+//import commented.line;
+/*
+import static commented.block;
+*/
+import someclass2;
+import my.package.* ;
-(defun javaimp-test--with-data (filename handler)
- "Untars testdata/FILENAME into temporary directory and runs
-HANDLER, supplying temp directory name as the only arg."
- (let ((tmpdir (file-name-as-directory (make-temp-file "javaimp" t))))
- (unwind-protect
- (let ((rc (call-process
- "tar" nil nil nil
- "-x"
- "-f" (concat javaimp--basedir
- (file-name-as-directory "testdata")
- filename)
- "-C" tmpdir)))
- (unless (= rc 0)
- (error "Cannot untar test data %s: %d" filename rc))
- (funcall handler tmpdir))
- (delete-directory tmpdir t))))
+import static some_class.fun_2; // comment
+// comment outside
+")
+ (should (equal
+ (javaimp-parse-get-imports)
+ '((2 . 206)
+ ("some.class1" . normal)
+ ("some.class.fun1" . static)
+ ("someclass2" . normal)
+ ("my.package.*" . normal)
+ ("some_class.fun_2" . static))))))
-(provide 'javaimp-tests)
+(ert-deftest javaimp-parse-get-all-scopes ()
+ (with-temp-buffer
+ (insert-file-contents
+ (file-name-concat javaimp-basedir "tests" "data"
"test1-misc-classes.java"))
+ (should-not javaimp-parse--dirty-pos)
+ ;;
+ ;; parse full buffer
+ (javaimp-test-parse--check-defuns)
+ (should javaimp-parse--dirty-pos)
+ (should-not (marker-position javaimp-parse--dirty-pos))
+ ;;
+ ;; reparse half of the buffer
+ (set-marker javaimp-parse--dirty-pos (/ (- (point-max) (point-min)) 2))
+ (javaimp-test-parse--check-defuns)
+ (should-not (marker-position javaimp-parse--dirty-pos))
+ ;;
+ ;; don't reparse
+ (javaimp-test-parse--check-defuns)))
diff --git a/tests/tests.el b/tests/tests.el
new file mode 100644
index 0000000000..feab94b36a
--- /dev/null
+++ b/tests/tests.el
@@ -0,0 +1,24 @@
+;;; tests/tests.el --- javaimp tests -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022-2022 Free Software Foundation, Inc.
+
+;; Author: Filipp Gunbin <[email protected]>
+;; Maintainer: Filipp Gunbin <[email protected]>
+
+(require 'ert)
+(require 'javaimp)
+
+(ert-deftest javaimp-get-buffer-classes ()
+ (with-temp-buffer
+ (insert-file-contents
+ (file-name-concat javaimp-basedir "tests" "data"
"test1-misc-classes.java"))
+ (should (equal (javaimp--get-buffer-classes)
+ '("org.foo.Top"
+ "org.foo.Top.CInner1"
+ "org.foo.Top.CInner1.CInner1_CInner1"
+ "org.foo.Top.IInner1"
+ "org.foo.Top.IInner1.IInner1_CInner1"
+ "org.foo.Top.IInner1.IInner1_IInner1"
+ "org.foo.Top.EnumInner1"
+ "org.foo.Top.EnumInner1.EnumInner1_EInner1"
+ "org.foo.ColocatedTop")))))