emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/javaimp 21c5c8355f: Parsing fixes and improvements


From: Filipp Gunbin
Subject: [elpa] externals/javaimp 21c5c8355f: Parsing fixes and improvements
Date: Tue, 17 May 2022 16:48:49 -0400 (EDT)

branch: externals/javaimp
commit 21c5c8355ffdeab860af3380ae5e4a32ac45693d
Author: Filipp Gunbin <fgunbin@fastmail.fm>
Commit: Filipp Gunbin <fgunbin@fastmail.fm>

    Parsing fixes and improvements
---
 javaimp-parse.el | 305 ++++++++++++++++++++++++++++++++-----------------------
 javaimp.el       |  61 +++++------
 tests/imenu.el   |  42 ++++----
 tests/parse.el   | 147 +++++++++++++--------------
 4 files changed, 300 insertions(+), 255 deletions(-)

diff --git a/javaimp-parse.el b/javaimp-parse.el
index f1f45a43d9..bf2a453f1a 100644
--- a/javaimp-parse.el
+++ b/javaimp-parse.el
@@ -22,39 +22,54 @@
 (require 'cl-lib)
 (require 'seq)
 
+
 (cl-defstruct javaimp-scope
-  type
+  (type
+   nil
+   :documentation "Scope type, a symbol.  See `javaimp-scope-all-types'.")
   name
   start
   open-brace
-  parent)
-
+  (parent
+   nil
+   :documentation "Reference to parent scope struct."))
 
-(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))
+ '(anon-class
+    array-init
+    class
+    enum
+    interface
+    local-class
+    method
+    simple-statement
+    statement)
+  "All known scope types.")
+
+(defconst javaimp-parse--class-keywords-regexp
+  (regexp-opt (mapcar #'symbol-name
+                      '(class interface enum)) 'symbols))
 
 
-(defconst javaimp-parse--classlike-keywords
-  (mapcar #'symbol-name
-          javaimp-scope-classlike-types))
-
 (defconst javaimp-parse--stmt-keywords
-  '("if" "else" "for" "while" "do" "switch" "try" "catch" "finally"
-    "static"                            ; static initializer block
+  '("if" "else" "for" "while" "do" "switch"
+    "try" "catch" "finally"
+    ;; synchronized block (not method modifier)
+    "synchronized"
+    ;; static initializer block (not field modifier)
+    "static"
     ))
+(defconst javaimp-parse--stmt-keywords-regexp
+  (regexp-opt javaimp-parse--stmt-keywords 'words))
 (defconst javaimp-parse--stmt-keyword-maxlen
   (seq-max (mapcar #'length javaimp-parse--stmt-keywords)))
 
+(defsubst javaimp-parse--scope-type-defun-p (s)
+  (and (javaimp-scope-type s)
+       (not (memq (javaimp-scope-type s)
+                  '(array-init simple-statement statement)))))
+
 
 (defun javaimp-parse--directive-regexp (directive)
   "Return regexp suitable for matching package-like DIRECTIVE, a
@@ -170,7 +185,8 @@ skipping further backwards is done by the caller."
       (error "Cannot parse argument type"))))
 
 (defun javaimp-parse--skip-back-until (&optional stop-p)
-  "Goes backwards until position at which STOP-P returns non-nil, or reaching 
bob.
+  "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
 non-ws thing skipped: LAST-WHAT (symbol - either 'list' or
@@ -255,8 +271,7 @@ is unchanged."
   "Attempt to parse defun declaration prefix backwards from
 point (but not farther than BOUND).  Matches inside comments /
 strings are skipped.  Return the beginning of the match (then the
-point is also at that position) or nil (then the point is left
-unchanged)."
+point is also at that position) or nil."
   (javaimp-parse--skip-back-until)
   ;; If we skip a previous scope (including unnamed initializers), or
   ;; reach enclosing scope start, we'll fail the check in the below
@@ -279,7 +294,8 @@ unchanged)."
                   (or (not bound) (>= pos bound))
                   (or (memql (char-after pos)
                              '(?@ ?\(   ;annotation type / args
-                                  ?<))  ;generic type
+                                  ?<    ;generic type
+                                  ?\[)) ;array
                       ;; keyword / identifier first char
                       (= (syntax-class (syntax-after pos)) 2))) ;word
         (goto-char (setq res pos))))
@@ -298,16 +314,15 @@ unchanged)."
       (setq tmp (javaimp-scope-parent tmp)))
     res))
 
-(defun javaimp-scope-filter-parents (scope pred)
+(defun javaimp-scope-filter-parents (pred scope)
   "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))))))
+    (if-let ((parent (javaimp-scope-parent scope))
+             ((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)
@@ -323,17 +338,21 @@ left."
       (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)))))
+(defun javaimp-scope-defun-p (&optional include-also)
+  "Return predicate which matches defun scopes, which are usually
+type definitions.  If INCLUDE-ALSO is 'method' then also include
+ methods.  If INCLUDE-ALSO is t, include methods, as well as
+ local / anonymous classes and their methods."
+  (let ((leaf-types
+         (append '(class interface enum)
+                 (when include-also
+                   '(method))
+                 (when (eq include-also t)
+                   '(anon-class local-class))))
+        (parent-types
+         (if (eq include-also t)
+             javaimp-scope-all-types
+           '(class interface enum))))
     (lambda (s)
       (javaimp-scope-test-type s leaf-types parent-types))))
 
@@ -349,27 +368,30 @@ parents may be anonymous classes."
 
 ;; Scope parsing
 
+(defsubst javaimp-parse--wrap-parser (parser)
+  (lambda (arg)
+    (save-excursion
+      (funcall parser arg))))
+
 (defvar javaimp-parse--scope-hook
-  (mapcar (lambda (parser)
-            (lambda (arg)
-              (save-excursion
-                (funcall parser arg))))
-          '(javaimp-parse--scope-array
-            ;; anon-class should be before method/stmt because it
-            ;; looks similar, but with "new" in front
+  (mapcar #'javaimp-parse--wrap-parser
+          '(;; 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
+            ;; Should be after simple/stmt, and preferably last
+            javaimp-parse--scope-array-init
             ))
   "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)
-  "Attempts to parse 'class' / 'interface' / 'enum' scope."
+  "Attempts to parse class scope."
   (when (javaimp-parse--preceding
-         (regexp-opt javaimp-parse--classlike-keywords 'symbols)
+         javaimp-parse--class-keywords-regexp
          brace-pos
          ;; closest preceding closing paren is a good bound
          ;; because there _will be_ such char in frequent case
@@ -397,20 +419,21 @@ brace.")
 (defun javaimp-parse--scope-simple-stmt (_brace-pos)
   "Attempts to parse 'simple-statement' scope.  Currently block
 lambdas are also recognized as such."
-  (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))
-       (make-javaimp-scope
-        :type 'simple-statement
-        :name (or (match-string 1)
-                  "lambda")
-        :start (or (match-beginning 1)
-                   (- (point) 2)))))
+  (javaimp-parse--skip-back-until)
+  (cond ((looking-back "->" (- (point) 2))
+         (make-javaimp-scope
+          :type 'simple-statement
+          :name "lambda"
+          :start (- (point) 2)))
+        ((looking-back javaimp-parse--stmt-keywords-regexp
+                       (- (point) javaimp-parse--stmt-keyword-maxlen) nil)
+         (make-javaimp-scope
+          :type 'simple-statement
+          :name (match-string 1)
+          :start (match-beginning 1)))))
 
 (defun javaimp-parse--scope-anon-class (brace-pos)
-  "Attempts to parse 'anon-class' scope."
+  "Attempts to parse anonymous class scope."
   ;; skip arg-list and ws
   (when (and (progn
                  (javaimp-parse--skip-back-until)
@@ -474,13 +497,20 @@ lambdas are also recognized as such."
                        name)
                :start (point)))))))))
 
-(defun javaimp-parse--scope-array (_brace-pos)
-  "Attempts to parse 'array' scope."
-  (and (javaimp-parse--skip-back-until)
-       (member (char-before) '(?, ?\]))
-       (make-javaimp-scope :type 'array
-                           :name ""
-                           :start nil)))
+(defun javaimp-parse--scope-array-init (_brace-pos)
+  "Attempts to parse 'array-init' scope."
+  (javaimp-parse--skip-back-until)
+  (let (decl-prefix-beg)
+    (when (or
+           ;; Special case for array-valued single-element annotation
+           (= (preceding-char) ?\()
+           ;; This will be non-nil for "top-level" array initializer.
+           ;; Nested array initializers are handled by a special rule
+           ;; in `javaimp-parse--scopes'.
+           (setq decl-prefix-beg (javaimp-parse--decl-prefix)))
+      (make-javaimp-scope :type 'array-init
+                          :name ""
+                          :start decl-prefix-beg))))
 
 
 (defun javaimp-parse--scopes (count)
@@ -490,10 +520,15 @@ 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
-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.
+`javaimp-parse--scope-hook' return non-nil then a dummy scope is
+created, with `javaimp-scope-type' set to nil.
+
+A couple of additional special rules, which may apply only when
+we have full chain of scope nesting:
+- If a `class' is nested in `method' (possibly within
+statements), then it's changed to `local-class'.
+- If an unrecognized scope (with nil type) is nested directly in
+`array-init' then it's changed to `array-init'.
 
 If point is inside of any comment/string then this function does
 nothing."
@@ -503,41 +538,47 @@ nothing."
       (while (and (nth 1 state)
                   (or (not count)
                       (>= (setq count (1- count)) 0)))
-        ;; find innermost enclosing open-bracket
+        ;; Find innermost enclosing open-bracket
         (goto-char (nth 1 state))
         (when (= (char-after) ?{)
           (let ((scope (get-text-property (point) 'javaimp-parse-scope)))
             (unless scope
-              (setq scope (run-hook-with-args-until-success
-                           'javaimp-parse--scope-hook (point)))
-              (if scope
-                  (setf (javaimp-scope-open-brace scope) (point))
-                (setq scope 'unknown))
+              (setq scope (or (run-hook-with-args-until-success
+                               'javaimp-parse--scope-hook (point))
+                              (make-javaimp-scope)))
+              (setf (javaimp-scope-open-brace scope) (point))
               (put-text-property (point) (1+ (point))
                                  'javaimp-parse-scope scope))
             (push scope res)
-            (when (and (javaimp-scope-p scope)
-                       (javaimp-scope-start scope))
+            (when (javaimp-scope-start scope)
               (goto-char (javaimp-scope-start scope)))))
         (setq state (syntax-ppss))))
-    (let (parent reset-tail)
+    (let (curr parent in-method)
       (while res
-        (if reset-tail
-            ;; overwrite property value with `unknown'
-            (when (javaimp-scope-p (car res))
-              (let ((pos (javaimp-scope-open-brace (car res))))
-                (put-text-property pos (1+ pos) 'javaimp-parse-scope 
'unknown)))
-          (if (javaimp-scope-p (car res))
-              (progn
-                (setf (javaimp-scope-parent (car res)) parent)
-                (setq parent (car res)))
-            ;; Just reset remaining scopes, and return nil
-            (setq reset-tail t)
-            (setq parent nil)))
-        (setq res (cdr res)))
+        (setq curr (car res))
+        ;; Additional special rules.  Note that we modify the object
+        ;; which is the value of text property, so this will work only
+        ;; once.
+        (cond ((and (eq 'class (javaimp-scope-type curr))
+                    in-method)
+               ;; Class nested in method is "local class"
+               (setf (javaimp-scope-type curr) 'local-class))
+              ((and parent
+                    (eq 'array-init (javaimp-scope-type parent))
+                    (not (javaimp-scope-type curr)))
+               (setf (javaimp-scope-type curr) 'array-init)))
+        (if (eq 'method (javaimp-scope-type curr))
+            (setq in-method t)
+          (if (memq (javaimp-scope-type curr)
+                    ;; all non-method defuns
+                    '(anon-class class enum interface local-class))
+              (setq in-method nil)))
+        ;;
+        (setf (javaimp-scope-parent curr) parent)
+        (setq parent curr
+              res (cdr res)))
       parent)))
 
-
 (defun javaimp-parse--all-scopes ()
   "Parse all scopes in this buffer which are after
 `javaimp-parse--dirty-pos', if it points anywhere.  Makes it
@@ -573,18 +614,18 @@ call this function first."
   (catch 'found
     (let ((state (syntax-ppss)))
       (while t
-        (let ((res (save-excursion
-                     (javaimp-parse--scopes nil))))
-          (when (and (javaimp-scope-p res)
-                     (or (null pred)
-                         (funcall pred res)))
-            (throw 'found res))
-          ;; Go up until we get something
-          (if (nth 1 state)
-              (progn
-                (goto-char (nth 1 state))
-                (setq state (syntax-ppss)))
-            (throw 'found nil)))))))
+        (when-let* ((res (save-excursion
+                           (javaimp-parse--scopes nil)))
+                    ((javaimp-scope-type res))
+                    ((or (null pred)
+                         (funcall pred res))))
+          (throw 'found res))
+        ;; Go up
+        (if (nth 1 state)
+            (progn
+              (goto-char (nth 1 state))
+              (setq state (syntax-ppss)))
+          (throw 'found nil))))))
 
 (defun javaimp-parse--class-abstract-methods ()
   (goto-char (point-max))
@@ -599,8 +640,8 @@ call this function first."
             (backward-char)        ;skip semicolon
             ;; now parse as normal method scope
             (when-let ((scope (javaimp-parse--scope-method-or-stmt (point)))
-                       ;; note that an abstract method with no
-                       ;; parents will be ignored
+                       ;; note that an abstract method with no parents
+                       ;; will be ignored
                        (parent (javaimp-parse--scopes nil)))
               (setf (javaimp-scope-parent scope) (javaimp-scope-copy parent))
               (push scope res))))))
@@ -660,14 +701,19 @@ 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 no-filter)
   "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
-should move point.  Note that parents may be outside of region
-given by BEG and END.  BEG is the LIMIT argument to
+and END, both exclusive, optionally filtering them with PRED.
+PRED should not 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."
+defaults to end of accessible portion of the buffer.
+
+The returned objects are copies, and so may be freely modified.
+
+Scope parents are filtered according to
+`javaimp-parse--scope-type-defun-p', but if NO-FILTER is non-nil
+then no filtering is done."
   (javaimp-parse--all-scopes)
   (let ((pos (or end (point-max)))
         scope res)
@@ -676,24 +722,32 @@ defaults to end of accessible portion of the buffer."
                 (or (not beg)
                     (/= pos beg)))
       (setq scope (get-text-property pos 'javaimp-parse-scope))
-      (when (and (javaimp-scope-p scope)
+      (when (and scope
+                 (javaimp-scope-type scope)
                  (or (null pred)
                      (funcall pred scope)))
         (setq scope (javaimp-scope-copy scope))
-        (when parent-pred
-          (javaimp-scope-filter-parents scope parent-pred))
+        (unless no-filter
+          (javaimp-scope-filter-parents
+           #'javaimp-parse--scope-type-defun-p scope))
         (push scope res)))
     res))
 
-(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."
+(defun javaimp-parse-get-enclosing-scope (&optional pred)
+  "Return innermost enclosing scope at point.  If PRED is non-nil
+then the scope must satisfy it, otherwise the next outer scope is
+tried.
+
+The returned objects are copies, and so may be freely modified.
+
+Scope parents are filtered according to
+`javaimp-parse--scope-type-defun-p'."
   (save-excursion
     (javaimp-parse--all-scopes))
   (when-let ((scope (javaimp-parse--enclosing-scope pred)))
     (setq scope (javaimp-scope-copy scope))
-    (when parent-pred
-      (javaimp-scope-filter-parents scope parent-pred))
+    (javaimp-scope-filter-parents
+     #'javaimp-parse--scope-type-defun-p scope)
     scope))
 
 (defun javaimp-parse-get-defun-decl-start (&optional bound)
@@ -712,11 +766,12 @@ outside paren constructs like arg-list."
 
 (defun javaimp-parse-get-interface-abstract-methods ()
   "Return all scopes which are abstract methods in interfaces."
+  (javaimp-parse--all-scopes)
   (let ((interfaces (javaimp-parse-get-all-scopes
                      nil nil
                      (lambda (s)
                        (javaimp-scope-test-type s
-                         '(interface) javaimp-scope-classlike-types)))))
+                         '(interface) '(class interface enum))))))
     (seq-mapcat #'javaimp-parse--interface-abstract-methods
                 interfaces)))
 
diff --git a/javaimp.el b/javaimp.el
index 5e9b2fb7f5..2480744bd4 100644
--- a/javaimp.el
+++ b/javaimp.el
@@ -238,15 +238,6 @@ 
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")))
 
 
 ;; Subroutines
@@ -805,9 +796,9 @@ in a major mode hook."
         (javaimp-tree-map-nodes
          (lambda (scope)
            (if (eq (javaimp-scope-type scope) 'method)
-               ;; entry
+               ;; leaf entry for method
                (cons nil (javaimp-imenu--make-entry scope))
-             ;; sub-alist
+             ;; sub-alist for class-like
              (cons t (javaimp-scope-name scope))))
          (lambda (res)
            (or (functionp (nth 2 res))  ; imenu entry
@@ -825,8 +816,8 @@ in a major mode hook."
                 (setf (alist-get (car entry) alist 0 nil #'equal)
                       (1+ (alist-get (car entry) alist 0 nil #'equal))))
               entries)
+        ;; Append parents to equal names to disambiguate them
         (mapc (lambda (entry)
-                ;; disambiguate same method names
                 (when (> (alist-get (car entry) alist 0 nil #'equal) 1)
                   (setcar entry
                           (format "%s [%s]"
@@ -836,27 +827,29 @@ in a major mode hook."
               entries)))))
 
 (defun javaimp-imenu--get-forest ()
-  (let* ((defun-scopes
-          (javaimp-parse-get-all-scopes
-           nil nil (javaimp-scope-defun-p '(method))))
-         (methods (seq-filter
-                   (lambda (scope)
-                     (eq (javaimp-scope-type scope) 'method))
-                   defun-scopes))
-         (classes (seq-filter
-                   (lambda (scope)
-                     (not (eq (javaimp-scope-type scope) 'method)))
-                   defun-scopes))
-         (top-classes (seq-filter (lambda (s)
-                                    (null (javaimp-scope-parent s)))
-                                  classes))
+  "Subroutine of `javaimp-imenu-create-index'."
+  (let* ((scopes
+          (javaimp-parse-get-all-scopes nil nil
+                                        (javaimp-scope-defun-p 'method)))
          (abstract-methods (append
                             (javaimp-parse-get-class-abstract-methods)
-                            (javaimp-parse-get-interface-abstract-methods))))
+                            (javaimp-parse-get-interface-abstract-methods)))
+
+         methods classes top-classes)
+    (dolist (s scopes)
+      (if (eq (javaimp-scope-type s) 'method)
+          (push s methods)
+        (push s classes)
+        (when (null (javaimp-scope-parent s))
+          (push s top-classes))))
+    (setq methods (nreverse methods)
+          classes (nreverse classes)
+          top-classes (nreverse top-classes))
     (mapcar
      (lambda (top-class)
        (when javaimp-verbose
-         (message "Building tree for top-level class-like scope: %s"
+         (message "Building tree for top-level %s %s"
+                  (javaimp-scope-type top-class)
                   (javaimp-scope-name top-class)))
        (javaimp-tree-build top-class
                            (append methods
@@ -884,7 +877,7 @@ in a major mode hook."
 (defun javaimp-xref--backend () 'javaimp)
 
 (defun javaimp-xref--ident-completion-table ()
-  (let ((scope-pred (javaimp-scope-defun-p '(method)))
+  (let ((scope-pred (javaimp-scope-defun-p 'method))
         (module (javaimp--detect-module)))
     (if module
         (nconc
@@ -995,7 +988,7 @@ buffer."
              (save-restriction
                (widen)
                (javaimp-parse-get-all-scopes
-                nil nil (javaimp-scope-defun-p '(method anon-class)))))))
+                nil nil (javaimp-scope-defun-p t))))))
         (default-dir
          (with-current-buffer source-buf
            default-directory))
@@ -1024,8 +1017,8 @@ buffer."
                              (with-current-buffer source-buf
                                (line-number-at-pos (javaimp-scope-start 
scope)))
                              depth
-                             (cdr (assq (javaimp-scope-type scope)
-                                        javaimp-show-scopes-type-abbrevs))
+                             (substring (symbol-name (javaimp-scope-type 
scope))
+                                        0 2)
                              (make-string (* 2 depth) ? )
                              (javaimp-scope-name scope))
                      'mouse-face 'highlight
@@ -1126,7 +1119,7 @@ PREV-INDEX gives the index of the method itself."
     (save-restriction
       (widen)
       (let* ((pos (point))
-             (defun-pred (javaimp-scope-defun-p '(method anon-class)))
+             (defun-pred (javaimp-scope-defun-p t))
              (enc (javaimp-parse-get-enclosing-scope defun-pred))
              (parent
               (if (and enc (eq (javaimp-scope-type enc) 'method))
@@ -1196,7 +1189,7 @@ PREV-INDEX gives the index of the method itself."
     (save-restriction
       (widen)
       (let ((s (javaimp-parse-get-enclosing-scope
-                (javaimp-scope-defun-p '(method anon-class))))
+                (javaimp-scope-defun-p 'method)))
             names)
         (while s
           (push (javaimp-scope-name s) names)
diff --git a/tests/imenu.el b/tests/imenu.el
index cbf7fb3639..0ae4f3c64d 100644
--- a/tests/imenu.el
+++ b/tests/imenu.el
@@ -13,14 +13,13 @@
   (dolist (elt alist)
     (if (and (= (length elt) 4)
              (functionp (nth 2 elt)))
-        (setcdr elt (nth 1 elt))
+        (setcdr elt nil)
       (javaimp-test-imenu--simplify-entries (cdr elt)))))
 
 
 (ert-deftest javaimp-imenu-create-index ()
   (let ((actual (javaimp-with-temp-buffer "test1.java"
-                  (let ((imenu-use-markers nil))
-                    (javaimp-imenu-create-index))))
+                  (javaimp-imenu-create-index)))
         (expected-names
          '("foo() [Top.CInner1]"
            "foo() [Top.CInner1.CInner1_CInner1]"
@@ -45,36 +44,35 @@
 
 (ert-deftest javaimp-imenu-create-index-use-sub-alists ()
   (let ((actual (javaimp-with-temp-buffer "test1.java"
-                  (let ((imenu-use-markers nil)
-                        (javaimp-imenu-use-sub-alists t))
+                  (let ((javaimp-imenu-use-sub-alists t))
                     (javaimp-imenu-create-index))))
         (expected
          '(("Top"
             ("CInner1"
-             ("foo()" . 98)
+             ("foo()")
              ("CInner1_CInner1"
-              ("foo()" . 1099)
-              ("abstract_method()" . 1148)
-              ("bar()" . 1192)
-              ("baz()" . 1281)))
+              ("foo()")
+              ("abstract_method()")
+              ("bar()")
+              ("baz()")))
             ("IInner1"
-             ("foo()" . 1603)
-             ("abstract_method()" . 1715)
+             ("foo()")
+             ("abstract_method()")
              ("IInner1_CInner1"
-              ("foo()" . 1798))
-             ("baz()" . 1934)
-             ("defaultMethod(String)" . 1963)
+              ("foo()"))
+             ("baz()")
+             ("defaultMethod(String)")
              ("IInner1_IInner1"
-              ("foo()" . 2122)
-              ("defaultMethod(String)" . 2157)
-              ("baz()" . 2258)))
+              ("foo()")
+              ("defaultMethod(String)")
+              ("baz()")))
             ("EnumInner1"
-             ("EnumInner1()" . 2353)
-             ("foo()" . 2399)
+             ("EnumInner1()")
+             ("foo()")
              ;; "EnumInner1_EInner1" omitted because no methods inside
              ))
            ("ColocatedTop"
-            ("foo()" . 2554)
-            ("bar(String,String)" . 2578)))))
+            ("foo()")
+            ("bar(String,String)")))))
     (javaimp-test-imenu--simplify-entries actual)
     (should (equal expected actual))))
diff --git a/tests/parse.el b/tests/parse.el
index 86f8820c0f..d023005d46 100644
--- a/tests/parse.el
+++ b/tests/parse.el
@@ -103,6 +103,9 @@ Exception4<? super Exception5>>")
                   ;; don't go into incomplete generic
                   ("S> T " . 4)
 
+                  ;; array
+                  ("String[] " . 1)
+
                   ;; don't go over semicolon
                   ("foo(); void " . 8)))
     (javaimp-with-temp-buffer nil
@@ -119,104 +122,106 @@ Exception4<? super Exception5>>")
   (dolist (item test-items)
     (javaimp-with-temp-buffer nil
       (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)))))))
-
+      (let* ((javaimp-parse--scope-hook (javaimp-parse--wrap-parser parser))
+             (scopes (mapcar #'javaimp-test-parse--simplify-scope
+                             (javaimp-parse-get-all-scopes nil nil nil t))))
+        (should (equal (cdr item) scopes))))))
 
 (ert-deftest javaimp-parse-scope-class ()
   (javaimp-test-parse--scope #'javaimp-parse--scope-class
     '("class Foo {"
-      class "Foo")
+      ((class "Foo")))
     '("class Foo extends Bar {"
-      class "Foo")
-    '("class Foo implements Bar {"
-      class "Foo")
-    '("class Foo implements Bar, Baz {"
-      class "Foo")
+      ((class "Foo")))
     '("public class Foo extends Bar implements Baz1 , Baz2 {"
-      class "Foo")
+      ((class "Foo")))
     `(,(subst-char-in-string
         ?  ?\n
         "public class Foo extends Bar implements Baz1 , Baz2 {")
-      class "Foo")
+      ((class "Foo")))
     '("class Foo<Bar, Baz> extends FooSuper<Bar, Baz> \
 implements Interface1<Bar, Baz>, Interface2 {"
-      class "Foo")
+      ((class "Foo")))
     '("class Foo<E extends Bar> {"
-      class "Foo")
+      ((class "Foo")))
+    ;; enum is also a keyword
     '("class Foo<Enum<?>> {"
-      class "Foo")
+      ((class "Foo")))
     '("class Foo<T extends Baz<? extends Baz2>> \
 extends Bar<? extends Baz<? extends Baz2>> {"
-      class "Foo")
+      ((class "Foo")))
     '("interface Foo<Bar, Baz> {"
-      interface "Foo")
+      ((interface "Foo")))
     '("private enum Foo {"
-      enum "Foo")
+      ((enum "Foo")))
     ))
 
 (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")
+      ((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")
+      ((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")
+      ((anon-class "<anon>Object")))
     ))
 
 (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)")
+      ((method "foo_bar(String,int)")))
     `(,(subst-char-in-string
         ?  ?\n
         "static void foo_bar ( String a , int b ) {")
-      method "foo_bar(String,int)")
+      ((method "foo_bar(String,int)")))
     '("void foo_bar(String a, int b) throws E1, E2 {"
-      method "foo_bar(String,int)")
+      ((method "foo_bar(String,int)")))
     '("void foo_bar()
 throws E1 {"
-      method "foo_bar()")
+      ((method "foo_bar()")))
     '("if (foo_bar(a, b) < 2) {"
-      statement "if")
+      ((statement "if")))
     ))
 
 (ert-deftest javaimp-parse-scope-simple-stmt ()
   (javaimp-test-parse--scope #'javaimp-parse--scope-simple-stmt
     '(" try {"
-      simple-statement "try")
+      ((simple-statement "try")))
     `(,(subst-char-in-string ?  ?\n " try {")
-      simple-statement "try")
-    ;; static initializer
+      ((simple-statement "try")))
     '("static {"
-      simple-statement "static")
-    ;; lambda
+      ((simple-statement "static")))
     '("it -> {"
-      simple-statement "lambda")
+      ((simple-statement "lambda")))
     '("(x, y) -> {"
-      simple-statement "lambda")
+      ((simple-statement "lambda")))
     ))
 
-(ert-deftest javaimp-parse-scope-array ()
-  (javaimp-test-parse--scope #'javaimp-parse--scope-array
+(ert-deftest javaimp-parse-scope-array-init ()
+  (javaimp-test-parse--scope #'javaimp-parse--scope-array-init
     '("new String[] {"
-      array "")
-    ;; TODO fix
-    ;; '("new Object[][] { {"
-    ;;   array "")
-    ;; '("new int[] {{1, 2}, {"
-    ;;   array "")
+      ((array-init "")))
+    '("new Object[i][] { {"
+      ((array-init ""))
+      ((array-init nil) (array-init "")))
+    '("new int[] {{1, 2}, {"
+      ((array-init ""))
+      ((array-init nil) (array-init ""))
+      ((array-init nil) (array-init "")))
+    '("new int[] {{{1,"
+      ((array-init ""))
+      ((array-init nil) (array-init ""))
+      ((array-init nil) (array-init nil) (array-init "")))
+    `(,(subst-char-in-string ?  ?\n "new int[] {{1, 2}, {")
+      ((array-init ""))
+      ((array-init nil) (array-init ""))
+      ((array-init nil) (array-init "")))
+    '("@FooContainer( {"
+      ((array-init "")))
     ))
 
 
@@ -225,13 +230,7 @@ throws E1 {"
 
 (defun javaimp-test-parse--get-all-scopes-defuns ()
   (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)))))
+                  nil nil (javaimp-scope-defun-p t)))
          (actual (mapcar #'javaimp-test-parse--simplify-scope scopes))
          (expected
           '(((class "Top"))
@@ -240,34 +239,37 @@ throws E1 {"
 
             ((method "foo()") (class "CInner1") (class "Top"))
 
-            ((class "CInner1_CLocal1")
+            ((local-class "CInner1_CLocal1")
              (method "foo()") (class "CInner1") (class "Top"))
 
             ((method "foo()")
-             (class "CInner1_CLocal1")
+             (local-class "CInner1_CLocal1")
              (method "foo()") (class "CInner1") (class "Top"))
 
-            ((class "CInner1_CLocal1_CLocal1")
+            ((local-class "CInner1_CLocal1_CLocal1")
              (method "foo()")
-             (class "CInner1_CLocal1")
+             (local-class "CInner1_CLocal1")
              (method "foo()") (class "CInner1") (class "Top"))
 
             ((method "foo()")
-             (class "CInner1_CLocal1_CLocal1")
+             (local-class "CInner1_CLocal1_CLocal1")
              (method "foo()")
-             (class "CInner1_CLocal1")
+             (local-class "CInner1_CLocal1")
              (method "foo()") (class "CInner1") (class "Top"))
 
-            ((class "CInner1_CLocal2")
+            ((local-class "CInner1_CLocal2")
              (method "foo()") (class "CInner1") (class "Top"))
 
             ((method "foo()")
-             (class "CInner1_CLocal2")
+             (local-class "CInner1_CLocal2")
              (method "foo()") (class "CInner1") (class "Top"))
 
-            ((method "toString()")
+            ((anon-class "<anon>Object")
              (class "CInner1") (class "Top"))
 
+            ((method "toString()")
+             (anon-class "<anon>Object") (class "CInner1") (class "Top"))
+
             ((class "CInner1_CInner1") (class "CInner1") (class "Top"))
 
             ((method "foo()")
@@ -309,18 +311,19 @@ throws E1 {"
     (should (= (length expected) (length actual)))
     (dotimes (i (length expected))
       (should (equal (nth i expected) (nth i actual))))
-    ;; selectively check positions
+    ;; Selectively check positions
     (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))))
+             (,(nth 17 scopes) "foo()" 1798 1804)
+             (,(nth 24 scopes) "EnumInner1_EInner1" 2462 2486)
+             (,(nth 26 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))))))))
 
+
 (defun javaimp-test-parse--simplify-scope (s)
   (let (res)
     (while s
@@ -380,6 +383,7 @@ import static some_class.fun_2; // comment
     ;; don't reparse
     (javaimp-test-parse--get-all-scopes-defuns)))
 
+
 (ert-deftest javaimp-parse-get-enclosing-scope ()
   (let ((testcases
          '(;; bob
@@ -416,9 +420,4 @@ import static some_class.fun_2; // comment
          (equal (cdr testcase)
                 (javaimp-test-parse--simplify-scope
                  (javaimp-parse-get-enclosing-scope
-                  (lambda (s)
-                    (memq (javaimp-scope-type s)
-                          '(class interface enum method)))
-                  (lambda (s)
-                    (memq (javaimp-scope-type s)
-                          '(class interface enum method)))))))))))
+                  (javaimp-scope-defun-p 'method)))))))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]