branch: scratch/javaimp-wip
commit dcc6bedf64189f7c4597f8382fea1abd84da8720
Author: Filipp Gunbin <fgun...@fastmail.fm>
Commit: Filipp Gunbin <fgun...@fastmail.fm>

    wip
---
 javaimp-parse.el                 | 128 ++++++++++++++--------
 javaimp-tests.el                 | 230 +++++++++++++++++++++------------------
 javaimp-util.el                  |  22 ++--
 javaimp.el                       |  60 ++++------
 testdata/test1-misc-classes.java |   9 +-
 5 files changed, 254 insertions(+), 195 deletions(-)

diff --git a/javaimp-parse.el b/javaimp-parse.el
index 061b18d..76da646 100644
--- a/javaimp-parse.el
+++ b/javaimp-parse.el
@@ -54,18 +54,12 @@ present."
     "static"                            ;static initializer block
     ))
 
-(defsubst javaimp--parse-is-classlike (scope)
-  (and scope
-       (member (symbol-name (javaimp-scope-type scope))
-               javaimp--parse-classlike-keywords)))
-
-(defsubst javaimp--parse-is-named (scope)
-  (and scope
-       (memq (javaimp-scope-type scope)
-             javaimp--parse-named-scope-types)))
+(defvar javaimp-syntax-table
+  (make-syntax-table java-mode-syntax-table) ;TODO don't depend
+  "Javaimp syntax table")
 
 (defvar javaimp--arglist-syntax-table
-  (let ((st (make-syntax-table java-mode-syntax-table))) ;TODO don't depend
+  (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
@@ -77,13 +71,16 @@ present."
 considered as stale.  Usually set by modification change hooks.
 Should be set to (point-min) in major mode hook.")
 
-(defmacro javaimp--parse-with-arglist-syntax (beg &rest body)
-  (declare (debug t))
+
+
+(defmacro javaimp--parse-with-syntax-table (syntax-table beg &rest body)
+  (declare (debug t)
+           (indent 2))
   (let ((begin (make-symbol "begin")))
     `(let ((,begin ,beg))
        (syntax-ppss-flush-cache ,begin)
        (unwind-protect
-           (with-syntax-table javaimp--arglist-syntax-table
+           (with-syntax-table ,syntax-table
              ,@body)
          (syntax-ppss-flush-cache ,begin)))))
 
@@ -93,6 +90,38 @@ Should be set to (point-min) in major mode hook.")
         (string-trim (substring str 0 end))
       str)))
 
+(defsubst javaimp--parse-is-classlike (scope)
+  (and scope
+       (member (symbol-name (javaimp-scope-type scope))
+               javaimp--parse-classlike-keywords)))
+
+(defsubst javaimp--parse-is-named (scope)
+  (and scope
+       (memq (javaimp-scope-type scope)
+             javaimp--parse-named-scope-types)))
+
+(defsubst javaimp--parse-is-imenu-included-method (scope)
+  (and (eq (javaimp-scope-type scope) 'method)
+       (javaimp--parse-is-classlike (javaimp-scope-parent scope))))
+
+(defun javaimp--parse-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--parse-concat-parent-names (scope)
+  (let (parents)
+    (while (setq scope (javaimp-scope-parent scope))
+      (push scope parents))
+    (mapconcat #'javaimp-scope-name parents ".")))
+
+
+
 (defun javaimp--parse-rsb-keyword (regexp &optional bound noerror count)
   "Like `re-search-backward', but count only occurences outside
 syntactic context as given by `syntax-ppss-context'.  Assumes
@@ -110,7 +139,7 @@ point is outside of any context initially."
   "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."
-  (javaimp--parse-with-arglist-syntax beg
+  (javaimp--parse-with-syntax-table javaimp--arglist-syntax-table beg
     (save-excursion
       (save-restriction
         (narrow-to-region beg end)
@@ -227,7 +256,7 @@ is unchanged."
     (catch 'found
       (while (javaimp--parse-rsb-keyword regexp bound t)
         (let ((scan-pos (match-end 0)))
-          (javaimp--parse-with-arglist-syntax scan-pos
+          (javaimp--parse-with-syntax-table javaimp--arglist-syntax-table 
scan-pos
             (while (and scan-pos (<= scan-pos (nth 1 state)))
               (if (ignore-errors
                     (= (scan-lists scan-pos 1 -1) ;As in 
javaimp--parse-preceding
@@ -419,7 +448,7 @@ nil then goes all the way up.  Examines and sets property
               (setq scope (run-hook-with-args-until-success
                            'javaimp--parse-scope-hook state))
               (put-text-property (point) (1+ (point))
-                                 'javaimp--parse-scope scope))
+                                 'javaimp-parse-scope scope))
             (push scope res)
             (if (javaimp-scope-start scope)
                 (goto-char (javaimp-scope-start scope)))))
@@ -439,20 +468,23 @@ nil then goes all the way up.  Examines and sets property
     res))
 
 (defun javaimp--parse-all-scopes ()
-  "Parses scopes in this buffer which are after
-`javaimp--parse-dirty-pos', if it is non-nil.  Resets this
-variable after parsing is done."
+  "Entry point to the scope parsing.  Parses scopes in this buffer
+which are after `javaimp--parse-dirty-pos', if it is non-nil.
+Resets this variable after parsing is done."
   (when javaimp--parse-dirty-pos
     (remove-text-properties javaimp--parse-dirty-pos (point-max)
                             '(javaimp-parse-scope nil))
     (goto-char (point-max))
-    (let ((parse-sexp-ignore-comments t)  ; FIXME remove with major mode
+    ;; FIXME With major mode we could set these, as well as syntax
+    ;; table, in mode function.
+    (let ((parse-sexp-ignore-comments t)
           (parse-sexp-lookup-properties nil))
-      (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))))
+      (javaimp--parse-with-syntax-table javaimp-syntax-table (point-min)
+        (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)))))
     (setq javaimp--parse-dirty-pos nil)))
 
 
@@ -462,27 +494,24 @@ variable after parsing is done."
 (defun javaimp--parse-get-package ()
   (goto-char (point-max))
   (when (javaimp--parse-rsb-keyword
-         "^\\s-*package\\s-+\\([^;\n]+\\)\\s-*;" nil t 1)
+         "^[ \t]*package[ \t]+\\([^;\n]+\\)[ \t]*;" nil t 1)
     (match-string 1)))
 
 (defun javaimp--parse-get-all-classlikes (&optional reparse)
   (mapcar (lambda (scope)
             (let ((name (javaimp-scope-name scope))
-                  (tmp scope))
-              (while (setq tmp (javaimp-scope-parent tmp))
-                (setq name (concat (javaimp-scope-name tmp) "." name)))
-              name))
+                  (parent-names (javaimp--parse-concat-parent-names scope)))
+              (if (string-empty-p parent-names)
+                  name
+                (concat parent-names "." name))))
           (javaimp--parse-get-all-scopes reparse 
#'javaimp--parse-is-classlike)))
 
-(defun javaimp--parse-get-forest-for-imenu (&optional reparse)
+(defun javaimp--parse-get-imenu-forest (&optional reparse)
   (let* ((methods
           (javaimp--parse-get-all-scopes
-           reparse
-           (lambda (s)
-             (and (eq (javaimp-scope-type s) 'method)
-                  (javaimp--parse-is-classlike (javaimp-scope-parent s))))))
+           reparse #'javaimp-imenu--included-method))
          (classes (javaimp--parse-get-all-scopes
-                   nil                  ; no need to reparse
+                   nil                  ; no need to reparse again
                    #'javaimp--parse-is-classlike))
          (top-classes (mapcar (lambda (s)
                                 (null (javaimp-scope-parent s)))
@@ -503,13 +532,26 @@ reparsing is done."
   (when reparse
     (setq javaimp--parse-dirty-pos (point-min)))
   (javaimp--parse-all-scopes)
-  (goto-char (point-max))
-  (let (match res)
-    (while (setq match (text-property-search-backward
-                        'javaimp-parse-scope nil nil))
-      (when (or (null pred)
-                (funcall pred (prop-match-value match)))
-        (push (prop-match-value match) res)))
+  (let ((pos (point-max))
+        scope res)
+    (while (setq pos (previous-single-property-change
+                      pos 'javaimp-parse-scope))
+      (setq scope (get-text-property pos 'javaimp-parse-scope))
+      (when (and scope
+                 (or (null pred)
+                     (funcall pred scope)))
+        (let* ((tmp (javaimp--parse-copy-scope scope))
+               (parent (javaimp-scope-parent tmp)))
+          (while (and tmp parent)
+            (if (funcall pred parent)
+                ;; go up
+                (setq parent (javaimp-scope-parent parent)
+                      tmp parent)
+              ;; skip this parent
+              (setq parent (javaimp-scope-parent parent))
+              (setf (javaimp-scope-parent tmp) parent)
+              (setq tmp parent)))
+          (push tmp res))))
     res))
 
 (defun javaimp--parse-update-dirty-pos (beg _end _old-len)
diff --git a/javaimp-tests.el b/javaimp-tests.el
index b4788e2..62d96a2 100644
--- a/javaimp-tests.el
+++ b/javaimp-tests.el
@@ -8,7 +8,7 @@
 (require 'ert)
 (require 'javaimp)
 
-;; Low-level helpers of scope parsers.
+;; Tests for low-level helpers of scope parsers.
 
 (ert-deftest javaimp-test--parse-arglist ()
   (dolist (data '(("")
@@ -34,7 +34,6 @@
                    ("String[][]" . "arr"))
                   ))
     (with-temp-buffer
-      (java-mode)
       (insert (car data))
       (should (equal (javaimp--parse-arglist (point-min) (point-max))
                      (cdr data))))))
@@ -57,7 +56,6 @@ Exception4<? super Exception5>>")
                    ("Exception6")
                    ("Exception7<Exception8>"))))
     (with-temp-buffer
-      (java-mode)
       (insert (car data))
       (should (equal (javaimp--parse-arglist (point-min) (point-max) t)
                      (cdr data))))))
@@ -114,7 +112,9 @@ extends Bar<? extends Baz<? extends Baz2>> {"
        anonymous-class "Object"))))
 
 (ert-deftest javaimp-test--parse-scope-method-or-stmt ()
-  (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-method-or-stmt))
+  (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-method-or-stmt)
+        (javaimp-parse-format-method-name
+         #'javaimp--parse-format-method-name-full))
     (javaimp-test--check-single-scope
      '("static void foo_bar ( String a , int b ) {"
        method "foo_bar(String a, int b)")
@@ -161,7 +161,6 @@ throws E1 {"
   (dolist (item test-items)
     (with-temp-buffer
       (insert (nth 0 item))
-      (java-mode)
       (let* ((scope (car (javaimp--parse-get-all-scopes t))))
         (should-not (null scope))
         (should (eq (javaimp-scope-type scope) (nth 1 item)))
@@ -188,27 +187,29 @@ throws E1 {"
                      "Top.IInner1"
                      "Top.IInner1.IInner1_CInner1"
                      "Top.IInner1.IInner1_IInner1"
-                     "Top.EInner1"
-                     "Top.EInner1.EInner1_EInner1"
+                     "Top.EnumInner1"
+                     "Top.EnumInner1.EnumInner1_EInner1"
                      "ColocatedTop")))))
 
 (ert-deftest javaimp-test--parse-get-all-scopes ()
   (with-temp-buffer
     (insert-file-contents
      (concat javaimp--basedir "testdata/test1-misc-classes.java"))
-    ;;
-    ;; parse full buffer
-    (javaimp-test--check-named-scopes
-     (javaimp--parse-get-all-scopes t #'javaimp--parse-is-named))
-    ;;
-    ;; reparse half of buffer
-    (setq javaimp--parse-dirty-pos (/ (- (point-max) (point-min)) 2))
-    (javaimp-test--check-named-scopes
-     (javaimp--parse-get-all-scopes nil #'javaimp--parse-is-named))
-    ;;
-    ;; use cache
-    (javaimp-test--check-named-scopes
-     (javaimp--parse-get-all-scopes nil #'javaimp--parse-is-named))))
+    (let ((javaimp-parse-format-method-name
+           #'javaimp--parse-format-method-name-types))
+      ;;
+      ;; parse full buffer
+      (javaimp-test--check-named-scopes
+       (javaimp--parse-get-all-scopes t #'javaimp--parse-is-named))
+      ;;
+      ;; reparse half of buffer
+      (setq javaimp--parse-dirty-pos (/ (- (point-max) (point-min)) 2))
+      (javaimp-test--check-named-scopes
+       (javaimp--parse-get-all-scopes nil #'javaimp--parse-is-named))
+      ;;
+      ;; use cache
+      (javaimp-test--check-named-scopes
+       (javaimp--parse-get-all-scopes nil #'javaimp--parse-is-named)))))
 
 (defun javaimp-test--check-named-scopes (scopes)
   (let ((actual
@@ -224,61 +225,66 @@ throws E1 {"
         (expected
          '(((class "Top"))
            ((class "CInner1") (class "Top"))
-           ((method "foo") (class "CInner1") (class "Top"))
+           ((method "foo()") (class "CInner1") (class "Top"))
            ((local-class "CInner1_CLocal1")
-            (method "foo") (class "CInner1") (class "Top"))
-           ((method "foo")
+            (method "foo()") (class "CInner1") (class "Top"))
+           ((method "foo()")
             (local-class "CInner1_CLocal1")
-            (method "foo") (class "CInner1") (class "Top"))
+            (method "foo()") (class "CInner1") (class "Top"))
            ((local-class "CInner1_CLocal1_CLocal1")
-            (method "foo")
+            (method "foo()")
             (local-class "CInner1_CLocal1")
-            (method "foo") (class "CInner1") (class "Top"))
-           ((method "foo")
+            (method "foo()") (class "CInner1") (class "Top"))
+           ((method "foo()")
             (local-class "CInner1_CLocal1_CLocal1")
-            (method "foo")
+            (method "foo()")
             (local-class "CInner1_CLocal1")
-            (method "foo") (class "CInner1") (class "Top"))
+            (method "foo()") (class "CInner1") (class "Top"))
 
            ((local-class "CInner1_CLocal2")
-            (method "foo") (class "CInner1") (class "Top"))
-           ((method "foo")
+            (method "foo()") (class "CInner1") (class "Top"))
+           ((method "foo()")
             (local-class "CInner1_CLocal2")
-            (method "foo") (class "CInner1") (class "Top"))
+            (method "foo()") (class "CInner1") (class "Top"))
 
-           ((class "CInner1_CInner") (class "CInner1") (class "Top"))
-           ((method "foo")
-            (class "CInner1_CInner") (class "CInner1") (class "Top"))
-           ((method "bar")
-            (class "CInner1_CInner") (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"))
+           ((method "foo()") (interface "IInner1") (class "Top"))
            ((class "IInner1_CInner1") (interface "IInner1") (class "Top"))
-           ((method "foo")
+           ((method "foo()")
             (class "IInner1_CInner1") (interface "IInner1") (class "Top"))
-           ((method "defaultMethod") (interface "IInner1") (class "Top"))
+           ((method "defaultMethod(String)")
+            (interface "IInner1") (class "Top"))
 
            ((interface "IInner1_IInner1") (interface "IInner1") (class "Top"))
-           ((method "defaultMethod")
+           ((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"))
+           ((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 "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 15 scopes) "Top.IInner1.IInner1_CInner1.foo" 1810 1816)
-           (,(nth 22 scopes) "Top.EnumInner1_EInner1" 2452 2476)
-           (,(nth 24 scopes) "ColocatedTop.foo" 2544 2550))))
+           (,(nth 15 scopes) "Top.IInner1.IInner1_CInner1.foo" 1798 1804)
+           (,(nth 22 scopes) "Top.EnumInner1_EInner1" 24574 2498)
+           (,(nth 24 scopes) "ColocatedTop.foo" 2566 2572))))
     (dolist (elt data)
       (let ((scope (nth 0 elt)))
         (should (equal (nth 1 elt) (javaimp-scope-name scope)))
@@ -291,77 +297,95 @@ throws E1 {"
 
 (ert-deftest javaimp-test--imenu-group ()
   (let* ((javaimp-imenu-group-methods t)
-         (actual (javaimp-test--imenu-get-index)))
+         (javaimp-parse-format-method-name
+          #'javaimp--parse-format-method-name-types)
+         (actual
+          (javaimp-test--imenu-simplify-entries
+           (with-temp-buffer
+             (insert-file-contents
+              (concat javaimp--basedir "testdata/test1-misc-classes.java"))
+             (javaimp-imenu-create-index)))))
     (should
      (equal
       actual
       '(("Top"
          ("CInner1"
-          ("foo" . 98)
+          ("foo()" . 98)
           ("CInner1_CInner1"
-           ("foo" . 1099)
-           ("bar" . 1192)))
+           ("foo()" . 1099)
+           ("bar()" . 1192)))
          ("IInner1"
-          ("foo" . 1603)
+          ("foo()" . 1603)
           ("IInner1_CInner1"
-           ("foo" . 1810))
-          ("defaultMethod" . 1975)
+           ("foo()" . 1810))
+          ("defaultMethod(String)" . 1975)
           ("IInner1_IInner1"
-           ("defaultMethod" . 2158)))
+           ("defaultMethod(String)" . 2169)))
          ("EnumInner1"
-          ("EnumInner1" . 2343)
-          ("foo" . 2389)
-          ;; "EnumInner1_EInner1" empty - omitted
+          ("EnumInner1()" . 2365)
+          ("foo()" . 2411)
+          ;; "EnumInner1_EInner1" omitted because no methods inside
           ))
         ("ColocatedTop"
-         ("foo" . 2544)))))))
-
-(ert-deftest javaimp-test--imenu-simple ()
-  (let* ((javaimp-imenu-group-methods nil)
-         (actual (javaimp-test--imenu-get-index)))
-    (should
-     (equal
-      actual
-      '(("foo (Top.CInner1)" . 98)
-        ("foo (Top.CInner1.CInner1_CInner1)" . 1099)
-        ("bar" . 1192)
-        ("foo (Top.IInner1)" . 1603)
-        ("foo (Top.IInner1.IInner1_CInner1)" . 1810)
-        ("defaultMethod (Top.IInner1)" . 1975)
-        ("defaultMethod (Top.IInner1.IInner1_IInner1)" . 2158)
-        ("EnumInner1" . 2343)
-        ("foo (Top.EnumInner1)" . 2389)
-        ("foo (ColocatedTop)" . 2544))))))
-
-(ert-deftest javaimp-test--imenu-qualified ()
-  (let* ((javaimp-imenu-group-methods 'qualified)
-         (actual
-          (mapcar (lambda (entry)
+         ("foo()" . 2566)
+         ("bar(String, String)" . 2578)))))))
 
-          (javaimp-test--imenu-get-index)))
-    (should
-     (equal
+(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)))))
 
-      (lambda (s)
-       (cons (javaimp-scope-name entry) (javaimp-scope-start entry)))
 
+(ert-deftest javaimp-test--imenu-simple ()
+  (let ((javaimp-parse-format-method-name
+         #'javaimp--parse-format-method-name-types)
+        (javaimp-imenu-group-methods nil))
+    (javaimp-test--imenu-method-list 0)))
 
-      actual
-      '(("Top.CInner1.foo" . 98)
-        ("Top.CInner1.CInner1_CInner1.foo" . 1099)
-        ("Top.CInner1.CInner1_CInner1.bar" . 1192)
-        ("Top.IInner1.foo" . 1603)
-        ("Top.IInner1.IInner1_CInner1.foo" . 1810)
-        ("Top.IInner1.defaultMethod" . 1975)
-        ("Top.IInner1.IInner1_IInner1.defaultMethod" . 2158)
-        ("Top.EnumInner1.EnumInner1" . 2343)
-        ("Top.EnumInner1.foo" . 2389)
-        ("ColocatedTop.foo" . 2544))))))
-
-(defun javaimp-test--imenu-get-index ()
-  (with-temp-buffer
-    (insert-file-contents
-     (concat javaimp--basedir "testdata/test1-misc-classes.java"))
-    (javaimp-imenu-create-index)))
+(ert-deftest javaimp-test--imenu-qualified ()
+  (let ((javaimp-parse-format-method-name
+         #'javaimp--parse-format-method-name-types)
+        (javaimp-imenu-group-methods 'qualified))
+    (javaimp-test--imenu-method-list 1)))
+
+(defun javaimp-test--imenu-method-list (exp-name-idx)
+  (let* ((actual
+          (with-temp-buffer
+            (insert-file-contents
+             (concat javaimp--basedir "testdata/test1-misc-classes.java"))
+            (javaimp-imenu-create-index)))
+         (expected
+          '(("foo() [Top.CInner1]"
+             "Top.CInner1.foo()" 98)
+            ("foo() [Top.CInner1.CInner1_CInner1]"
+             "Top.CInner1.CInner1_CInner1.foo()" 1099)
+            ("bar()"
+             "Top.CInner1.CInner1_CInner1.bar()" 1192)
+            ("foo() [Top.IInner1]"
+             "Top.IInner1.foo()" 1603)
+            ("foo() [Top.IInner1.IInner1_CInner1]"
+             "Top.IInner1.IInner1_CInner1.foo()" 1810)
+            ("defaultMethod(String) [Top.IInner1]"
+             "Top.IInner1.defaultMethod(String)" 1975)
+            ("defaultMethod(String) [Top.IInner1.IInner1_IInner1]"
+             "Top.IInner1.IInner1_IInner1.defaultMethod(String)" 2169)
+            ("EnumInner1()"
+             "Top.EnumInner1.EnumInner1()" 2365)
+            ("foo() [Top.EnumInner1]"
+             "Top.EnumInner1.foo()" 2411)
+            ("foo() [ColocatedTop]"
+             "ColocatedTop.foo()" 2566)
+            ("bar(String, String)"
+             "ColocatedTop.bar(String, String)" 2578))))
+    (should (= (length expected) (length actual)))
+    (dotimes (i (length expected))
+      (let ((exp (nth i expected))
+            (act (nth i actual)))
+        ;; name
+        (should (equal (nth exp-name-idx exp) (nth 0 act)))
+        ;; pos
+        (should (= (nth 2 exp) (nth 1 act)))))))
 
 (provide 'javaimp-tests)
diff --git a/javaimp-util.el b/javaimp-util.el
index 1bf2a79..25dd12d 100644
--- a/javaimp-util.el
+++ b/javaimp-util.el
@@ -160,9 +160,9 @@ PARENT-NODE is indented for recursive calls."
 (defun javaimp--find-node (pred forest &optional unwrap)
   (catch 'found
     (dolist (tree forest)
-      (javaimp--find-node-in-tree-1 tree pred unwrap))))
+      (javaimp--find-node-in-tree tree pred unwrap))))
 
-(defun javaimp--find-node-in-tree-1 (tree pred unwrap)
+(defun javaimp--find-node-in-tree (tree pred unwrap)
   (when tree
     (if (funcall pred (javaimp-node-contents tree))
        (throw 'found
@@ -170,23 +170,25 @@ PARENT-NODE is indented for recursive calls."
                    (javaimp-node-contents tree)
                  tree)))
     (dolist (child (javaimp-node-children tree))
-      (javaimp--find-node-in-tree-1 child pred unwrap))))
+      (javaimp--find-node-in-tree child pred unwrap))))
 
 
 (defun javaimp--collect-nodes (pred forest)
   (apply #'seq-concatenate 'list
         (mapcar (lambda (tree)
-                  (javaimp--collect-nodes-from-tree tree pred))
+                   (delq nil
+                        (javaimp--collect-nodes-from-tree tree pred)))
                 forest)))
 
 (defun javaimp--collect-nodes-from-tree (tree pred)
   (when tree
-    (append (when (funcall pred (javaimp-node-contents tree))
-             (list (javaimp-node-contents tree)))
-           (apply #'seq-concatenate 'list
-                  (mapcar (lambda (child)
-                            (javaimp--collect-nodes-from-tree child pred))
-                          (javaimp-node-children tree))))))
+    (cons (and (funcall pred (javaimp-node-contents tree))
+               (javaimp-node-contents tree))
+         (apply #'seq-concatenate 'list
+                (mapcar (lambda (child)
+                           (delq nil
+                                (javaimp--collect-nodes-from-tree child pred)))
+                        (javaimp-node-children tree))))))
 
 
 (defun javaimp--map-nodes (mapper pred forest)
diff --git a/javaimp.el b/javaimp.el
index 86b16cd..2bd4d2f 100644
--- a/javaimp.el
+++ b/javaimp.el
@@ -571,32 +571,33 @@ is `ordinary' or `static'.  Interactively, NEW-IMPORTS is 
nil."
 (defun javaimp-imenu-create-index ()
   "Function to use as `imenu-create-index-function'."
   (let ((forest (save-excursion
-                  (javaimp--parse-get-forest-for-imenu))))
+                  (javaimp--parse-get-imenu-forest))))
     (cond ((not javaimp-imenu-group-methods)
            ;; plain list of methods
-           (let ((entries (mapcar #'javaimp-imenu--make-entry
-                                  (javaimp--collect-nodes
-                                   #'javaimp-imenu--included-method forest))))
+           (let ((entries
+                  (mapcar #'javaimp-imenu--make-entry
+                          (javaimp--collect-nodes
+                           #'javaimp--parse-is-imenu-included-method forest))))
              (mapcar (lambda (entry)
-                       ;; disambiguate similar method names
+                       ;; disambiguate same method names
                        (when (assoc (car entry) entries)
                          (setcar entry
-                                 (format "%s (%s)"
+                                 (format "%s [%s]"
                                          (car entry)
-                                         (javaimp-imenu--concat-parent-names
+                                         (javaimp--parse-concat-parent-names
                                           (nth 3 entry))))))
                      entries)))
           ((eq javaimp-imenu-group-methods 'qualified)
            ;; list of qualified methods
            (mapcar (lambda (entry)
                      ;; prepend parents to name
-                     (setcar entry (concat (javaimp-imenu--concat-parent-names
+                     (setcar entry (concat (javaimp--parse-concat-parent-names
                                             (nth 3 entry))
                                            "."
                                            (car entry))))
-                   (mapcar #'javaimp-imenu-make-entry
+                   (mapcar #'javaimp-imenu--make-entry
                            (javaimp--collect-nodes
-                            #'javaimp-imenu--included-method forest))))
+                            #'javaimp--parse-is-imenu-included-method 
forest))))
 
           (t
            ;; group methods inside their enclosing class
@@ -605,46 +606,21 @@ is `ordinary' or `static'.  Interactively, NEW-IMPORTS is 
nil."
               (cond ((javaimp--parse-is-classlike scope)
                      ;; this will be a sub-alist's car
                      (javaimp-scope-name scope))
-                    ((javaimp-imenu--included-method scope)
+                    ((javaimp--parse-is-imenu-included-method scope)
                      (javaimp-imenu--make-entry scope))))
             #'cdr                ;don't include empty container scopes
             forest)))))
 
-(defsubst javaimp-imenu--included-method (scope)
-  (and (eq (javaimp-scope-type scope) 'method)
-       (javaimp--parse-is-classlike (javaimp-scope-parent scope))))
-
 (defsubst javaimp-imenu--make-entry (scope)
   (list (javaimp-scope-name scope)
         (javaimp-scope-start scope)
         #'javaimp-imenu--go
         scope))
 
-(defun javaimp-imenu--concat-parent-names (scope)
-  (let (parents)
-    (while (setq scope (javaimp-scope-parent scope))
-      (push scope parents))
-    (mapconcat #'javaimp-scope-name parents ".")))
-
-
 (defun javaimp-imenu--go (scope)
   (goto-char (javaimp-scope-start scope))
   (back-to-indentation))
 
-
-
-;; Misc
-
-(defun javaimp-reset (arg)
-  "Forget loaded trees state.  With prefix arg, also reset jars
-cache."
-  (interactive "P")
-  (setq javaimp-project-forest nil
-        javaimp--jdk-classes 'need-init)
-  (when arg
-    (setq javaimp-cached-jars nil)))
-
-
 
 ;; Help
 
@@ -713,6 +689,18 @@ scopes cache."
       (setq buffer-read-only t))
     (display-buffer buf)))
 
+
+;; Misc
+
+(defun javaimp-reset (arg)
+  "Forget loaded trees state.  With prefix arg, also reset jars
+cache."
+  (interactive "P")
+  (setq javaimp-project-forest nil
+        javaimp--jdk-classes 'need-init)
+  (when arg
+    (setq javaimp-cached-jars nil)))
+
 (provide 'javaimp)
 
 ;;; javaimp.el ends here
diff --git a/testdata/test1-misc-classes.java b/testdata/test1-misc-classes.java
index d916221..c010604 100644
--- a/testdata/test1-misc-classes.java
+++ b/testdata/test1-misc-classes.java
@@ -72,7 +72,7 @@ public class Top {
             }
         }
 
-        String bar(String arg1, String arg2);
+        String abstract_method();
 
         static class IInner1_CInner1 {
             public void foo() {
@@ -84,14 +84,14 @@ public class Top {
 
         void baz();
 
-        default void defaultMethod() {
+        default void defaultMethod(String arg1) {
             System.out.println("");
         }
 
         interface IInner1_IInner1 extends A<B, C>, Serializable {
             void foo();
 
-            default String defaultMethod() {
+            default String defaultMethod(String arg2) {
                 System.out.println("");
             }
 
@@ -119,4 +119,7 @@ public class Top {
 class ColocatedTop {
     void foo() {
     }
+
+    void bar(String arg1, String arg2) {
+    }
 }

Reply via email to