[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)))))))))
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] externals/javaimp 21c5c8355f: Parsing fixes and improvements,
Filipp Gunbin <=