[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] scratch/javaimp-wip fe080eb: wip
From: |
Filipp Gunbin |
Subject: |
[elpa] scratch/javaimp-wip fe080eb: wip |
Date: |
Tue, 3 Aug 2021 10:53:20 -0400 (EDT) |
branch: scratch/javaimp-wip
commit fe080eba615ed90586a03f5e5c0b2515ddaab729
Author: Filipp Gunbin <fgunbin@fastmail.fm>
Commit: Filipp Gunbin <fgunbin@fastmail.fm>
wip
---
javaimp-parse.el | 120 ++++++++-------
javaimp-tests.el | 272 ++++++++++++++++++----------------
javaimp.el | 3 +-
testdata/test-get-file-classes-1.java | 60 --------
testdata/test1-misc-classes.java | 117 +++++++++++++++
5 files changed, 331 insertions(+), 241 deletions(-)
diff --git a/javaimp-parse.el b/javaimp-parse.el
index 55c89f2..1a46b65 100644
--- a/javaimp-parse.el
+++ b/javaimp-parse.el
@@ -33,13 +33,20 @@ present."
:type 'function)
(cl-defstruct javaimp-scope
- type ; one of anonymous-class, class, interface, enum, local-class,
- ; method, statement, simple-statement, array, unknown
+ type ; see javaimp--parse-all-scope-types
name
start
open-brace
parent)
+(defconst javaimp--parse-named-scope-types
+ '(class interface enum local-class method))
+
+(defconst javaimp--parse-all-scope-types
+ (append
+ '(anonymous-class statement simple-statement array unknown)
+ javaimp--parse-named-scope-types))
+
(defconst javaimp--parse-classlike-keywords
'("class" "interface" "enum"))
(defconst javaimp--parse-stmt-keywords
@@ -48,8 +55,9 @@ present."
))
(defsubst javaimp--parse-is-classlike (scope)
- (member (symbol-name (javaimp-scope-type scope))
- javaimp--parse-classlike-keywords))
+ (when scope
+ (member (symbol-name (javaimp-scope-type scope))
+ javaimp--parse-classlike-keywords)))
(defvar javaimp--arglist-syntax-table
(let ((st (make-syntax-table java-mode-syntax-table))) ;TODO don't depend
@@ -61,7 +69,8 @@ present."
(defvar-local javaimp--parse-dirty-pos nil
"Buffer position after which all parsed information should be
-considered as stale. Usually set by modification change hooks.")
+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))
@@ -425,20 +434,21 @@ nil then goes all the way up. Examines and sets property
res))
(defun javaimp--parse-all-scopes ()
- "Parses all scopes in this buffer, but only after
-`javaimp--parse-dirty-pos' if it is non-nil."
+ "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
- (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))))
- (setq javaimp--parse-dirty-pos nil))
+ '(javaimp-parse-scope nil))
+ (goto-char (point-max))
+ (let ((parse-sexp-ignore-comments t) ; FIXME remove with major mode
+ (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))))
+ (setq javaimp--parse-dirty-pos nil)))
@@ -450,19 +460,41 @@ nil then goes all the way up. Examines and sets property
"^\\s-*package\\s-+\\([^;\n]+\\)\\s-*;" nil t 1)
(match-string 1)))
-(defun javaimp--parse-get-file-classes ()
- (javaimp--parse-all-scopes)
- (goto-char (point-max))
- (let (match res)
- (while (setq match (text-property-search-backward
- 'javaimp-parse-scope nil nil))
- (when (javaimp--parse-is-classlike (prop-match-value match))
- (push (mapconcat #'javaimp-scope-name
- (javaimp--parse-scopes nil)
- ".")
- res)))))
+(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))
+ (javaimp--parse-get-all-scopes reparse
#'javaimp--parse-is-classlike)))
+
+(defun javaimp--parse-get-forest-for-imenu (&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))))))
+ (classes (javaimp--parse-get-all-scopes
+ nil ;no need to reparse
+ #'javaimp--parse-is-classlike))
+ (top-classes (mapcar (lambda (s)
+ (null (javaimp-scope-parent s)))
+ classes)))
+ (mapcar
+ (lambda (class)
+ (message "Building tree for top-level class-like scope: %s"
+ (javaimp-scope-name class))
+ (javaimp--build-tree class (concat methods classes)
+ (lambda (el tested)
+ (equal el (javaimp-scope-parent tested)))))
+ top-classes)))
-(defun javaimp--parse-get-all-scopes (&optional reparse)
+(defun javaimp--parse-get-all-scopes (&optional reparse pred)
+ "Return all scopes in the current buffer for which PRED (if
+given) returns non-nil. If REPARSE is non-nil then full
+reparsing is done."
(when reparse
(setq javaimp--parse-dirty-pos (point-min)))
(javaimp--parse-all-scopes)
@@ -470,35 +502,11 @@ nil then goes all the way up. Examines and sets property
(let (match res)
(while (setq match (text-property-search-backward
'javaimp-parse-scope nil nil))
- (push (prop-match-value match) res))
+ (when (or (null pred)
+ (funcall pred (prop-match-value match)))
+ (push (prop-match-value match) res)))
res))
-(defun javaimp--parse-get-forest-for-imenu ()
- (javaimp--parse-all-scopes)
- (goto-char (point-max))
- (let (match methods classes top-classes)
- (while (setq match (text-property-search-backward
- 'javaimp-parse-scope nil nil))
- (let* ((scope (prop-match-value match))
- (parent (javaimp-scope-parent scope)))
- (cond (;; all methods
- (and (eq (javaimp-scope-type scope) 'method)
- (and parent (javaimp--parse-is-classlike parent)))
- (push scope methods))
- (;; all classes
- (javaimp--parse-is-classlike scope)
- (push scope classes)
- (when (not (javaimp-scope-parent scope))
- (push scope top-classes))))))
- (mapcar
- (lambda (class)
- (message "Building tree for top-level class: %s"
- (javaimp-scope-name class))
- (javaimp--build-tree class (concat methods classes)
- (lambda (el tested)
- (equal el (javaimp-scope-parent tested)))))
- top-classes)))
-
(defun javaimp--parse-update-dirty-pos (beg _end _old-len)
"Function to add to `after-change-functions' hook."
(when (or (not javaimp--parse-dirty-pos)
diff --git a/javaimp-tests.el b/javaimp-tests.el
index 0ca4593..7bb63b5 100644
--- a/javaimp-tests.el
+++ b/javaimp-tests.el
@@ -8,119 +8,7 @@
(require 'ert)
(require 'javaimp)
-;; (ert-deftest javaimp-test--maven-projects-from-xml--project ()
-;; (with-temp-buffer
-;; (insert "<project/>")
-;; (let ((projects (javaimp--maven-projects-from-xml
-;; (xml-parse-region (point-min) (point-max)))))
-;; (should (eql (length projects) 1)))))
-
-;; (ert-deftest javaimp-test--maven-projects-from-xml--projects ()
-;; (with-temp-buffer
-;; (insert "<projects><project/><project/></projects>")
-;; (let ((projects (javaimp--maven-projects-from-xml
-;; (xml-parse-region (point-min) (point-max)))))
-;; (should (eql (length projects) 2)))))
-
-
-(defun javaimp-test--check-scope (parse-hook &rest test-items)
- (declare (indent 1))
- (dolist (item test-items)
- (with-temp-buffer
- (insert (nth 0 item))
- (java-mode)
- (let* ((parse-sexp-ignore-comments t) ;FIXME remove with major mode
- (parse-sexp-lookup-properties nil)
- (javaimp--parse-scope-hook parse-hook)
- (scope (car (javaimp--parse-scopes 1))))
- (should-not (null scope))
- (should (eq (javaimp-scope-type scope) (nth 1 item)))
- (should (equal (javaimp-scope-name scope) (nth 2 item)))))))
-
-(ert-deftest javaimp-test--parse-scope-class ()
- (javaimp-test--check-scope #'javaimp--parse-scope-class
- '("class Foo {"
- class "Foo")
- '("class Foo extends Bar {"
- class "Foo")
- '("class Foo implements Bar {"
- class "Foo")
- '("class Foo implements Bar, Baz {"
- class "Foo")
- '("public class Foo extends Bar implements Baz1 , Baz2 {"
- class "Foo")
- `(,(subst-char-in-string
- ? ?\n
- "public class Foo extends Bar implements Baz1 , Baz2 {")
- class "Foo")
- '("class Foo<Bar, Baz> extends FooSuper<Bar, Baz> \
-implements Interface1<Bar, Baz>, Interface2 {"
- class "Foo")
- '("class Foo<E extends Bar> {"
- class "Foo")
- '("class Foo<Enum<?>> {"
- class "Foo")
- '("class Foo<T extends Baz<? extends Baz2>> \
-extends Bar<? extends Baz<? extends Baz2>> {"
- class "Foo")
- '("interface Foo<Bar, Baz> {"
- interface "Foo")
- '("private enum Foo {"
- enum "Foo")))
-
-(ert-deftest javaimp-test--parse-scope-anonymous-class ()
- (javaimp-test--check-scope #'javaimp--parse-scope-anonymous-class
- '(" = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {"
- anonymous-class "Object")
- `(,(subst-char-in-string
- ? ?\n
- " = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {")
- anonymous-class "Object")
- '(" = (obj.getField()).new Object<Class1, Class2>(1, baz) {"
- anonymous-class "Object")
- '(" = obj.new Object<>(1, baz) {"
- anonymous-class "Object")))
-
-(ert-deftest javaimp-test--parse-scope-method-or-stmt ()
- (javaimp-test--check-scope #'javaimp--parse-scope-method-or-stmt
- '("static void foo_bar ( String a , int b ) {"
- method "foo_bar(String a, int b)")
- `(,(subst-char-in-string
- ? ?\n
- "static void foo_bar ( String a , int b ) {")
- method "foo_bar(String a, int b)")
- '("void foo_bar(String a, int b) throws E1, E2 {"
- method "foo_bar(String a, int b) throws E1, E2")
- '("void foo_bar()
-throws E1 {"
- method "foo_bar() throws E1")
- '("if (foo_bar(a, b) < 2) {"
- statement "if")))
-
-(ert-deftest javaimp-test--parse-scope-simple-stmt ()
- (javaimp-test--check-scope #'javaimp--parse-scope-simple-stmt
- '(" try {"
- simple-statement "try")
- `(,(subst-char-in-string ? ?\n " try {")
- simple-statement "try")
- ;; static initializer
- '("static {"
- simple-statement "static")
- ;; lambda
- '("it -> {"
- simple-statement "lambda")
- '("(x, y) -> {"
- simple-statement "lambda")
- ))
-
-(ert-deftest javaimp-test--parse-scope-array ()
- (javaimp-test--check-scope #'javaimp--parse-scope-array
- '("new String[] {"
- array "")
- '("new Object[][] { {"
- array "")
- '("new int[] {{1, 2}, {"
- array "")))
+;; Low-level helpers of scope parsers.
(ert-deftest javaimp-test--parse-arglist ()
(dolist (data '(("")
@@ -175,6 +63,113 @@ Exception4<? super Exception5>>")
(cdr data))))))
+
+;; Tests for scope parsers, which should be in
+;; `javaimp--parse-scope-hook'.
+
+(ert-deftest javaimp-test--parse-scope-class ()
+ (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-class))
+ (javaimp-test--check-single-scope
+ '("class Foo {"
+ class "Foo")
+ '("class Foo extends Bar {"
+ class "Foo")
+ '("class Foo implements Bar {"
+ class "Foo")
+ '("class Foo implements Bar, Baz {"
+ class "Foo")
+ '("public class Foo extends Bar implements Baz1 , Baz2 {"
+ class "Foo")
+ `(,(subst-char-in-string
+ ? ?\n
+ "public class Foo extends Bar implements Baz1 , Baz2 {")
+ class "Foo")
+ '("class Foo<Bar, Baz> extends FooSuper<Bar, Baz> \
+implements Interface1<Bar, Baz>, Interface2 {"
+ class "Foo")
+ '("class Foo<E extends Bar> {"
+ class "Foo")
+ '("class Foo<Enum<?>> {"
+ class "Foo")
+ '("class Foo<T extends Baz<? extends Baz2>> \
+extends Bar<? extends Baz<? extends Baz2>> {"
+ class "Foo")
+ '("interface Foo<Bar, Baz> {"
+ interface "Foo")
+ '("private enum Foo {"
+ enum "Foo"))))
+
+(ert-deftest javaimp-test--parse-scope-anonymous-class ()
+ (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-anonymous-class))
+ (javaimp-test--check-single-scope
+ '(" = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {"
+ anonymous-class "Object")
+ `(,(subst-char-in-string
+ ? ?\n
+ " = new Object < Class1 , Class2 > ( 1 + 1 , baz ) {")
+ anonymous-class "Object")
+ '(" = (obj.getField()).new Object<Class1, Class2>(1, baz) {"
+ anonymous-class "Object")
+ '(" = obj.new Object<>(1, baz) {"
+ anonymous-class "Object"))))
+
+(ert-deftest javaimp-test--parse-scope-method-or-stmt ()
+ (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-method-or-stmt))
+ (javaimp-test--check-single-scope
+ '("static void foo_bar ( String a , int b ) {"
+ method "foo_bar(String a, int b)")
+ `(,(subst-char-in-string
+ ? ?\n
+ "static void foo_bar ( String a , int b ) {")
+ method "foo_bar(String a, int b)")
+ '("void foo_bar(String a, int b) throws E1, E2 {"
+ method "foo_bar(String a, int b) throws E1, E2")
+ '("void foo_bar()
+throws E1 {"
+ method "foo_bar() throws E1")
+ '("if (foo_bar(a, b) < 2) {"
+ statement "if"))))
+
+(ert-deftest javaimp-test--parse-scope-simple-stmt ()
+ (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-simple-stmt))
+ (javaimp-test--check-single-scope
+ '(" try {"
+ simple-statement "try")
+ `(,(subst-char-in-string ? ?\n " try {")
+ simple-statement "try")
+ ;; static initializer
+ '("static {"
+ simple-statement "static")
+ ;; lambda
+ '("it -> {"
+ simple-statement "lambda")
+ '("(x, y) -> {"
+ simple-statement "lambda")
+ )))
+
+(ert-deftest javaimp-test--parse-scope-array ()
+ (let ((javaimp--parse-scope-hook #'javaimp--parse-scope-array))
+ (javaimp-test--check-single-scope
+ '("new String[] {"
+ array "")
+ '("new Object[][] { {"
+ array "")
+ '("new int[] {{1, 2}, {"
+ array ""))))
+
+(defun javaimp-test--check-single-scope (&rest test-items)
+ (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)))
+ (should (equal (javaimp-scope-name scope) (nth 2 item)))))))
+
+
+;; Tests for javaimp-parse.el "package-private" API.
+
(ert-deftest javaimp-test--parse-get-package ()
(with-temp-buffer
(insert "//package org.commented1;
@@ -182,17 +177,46 @@ Exception4<? super Exception5>>")
package org.foo;")
(should (equal (javaimp--parse-get-package) "org.foo"))))
+(ert-deftest javaimp-test--parse-get-all-classlikes ()
+ (with-temp-buffer
+ (insert-file-contents
+ (concat javaimp--basedir "testdata/test1-misc-classes.java"))
+ (should (equal (javaimp--parse-get-all-classlikes t)
+ '("Top"
+ "Top.CInner1"
+ "Top.CInner1.CInner1_CInner1"
+ "Top.IInner1"
+ "Top.IInner1.IInner1_CInner1"
+ "Top.IInner1.IInner1_IInner1"
+ "Top.EInner1"
+ "Top.EInner1.EInner1_EInner1")))))
+
+(ert-deftest javaimp-test--parse-get-forest-for-imenu ()
+ ;; TODO
+ )
+
+
+(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-scopes (javaimp--parse-get-all-scopes t))
+ ;; reparse half buffer
+ (setq javaimp--parse-dirty-pos (/ (- (point-max) (point-min)) 2))
+ (javaimp-test--check-scopes (javaimp--parse-get-all-scopes))
+ ;; use cache
+ (javaimp-test--check-scopes (javaimp--parse-get-all-scopes))))
+
+(defun javaimp--test-check-scopes (scopes)
+ ;; TODO check positions of first / most nested / last
+
+ '((class "Top"))
+ '((class "CInner1") (class "Top"))
+ '((method "foo") (class "CInner1") (class "Top"))
+
+ )
+
-(ert-deftest javaimp-test--get-file-classes ()
- (should (equal (javaimp--get-file-classes
- (concat javaimp--basedir
"testdata/test-get-file-classes-1.java"))
- '("org.foo.Top"
- "org.foo.Top.CInner1"
- "org.foo.Top.CInner1.CInner1_CInner1"
- "org.foo.Top.IInner1"
- "org.foo.Top.IInner1.IInner1_IInner1"
- "org.foo.Top.IInner1.IInner1_CInner1"
- "org.foo.Top.EInner1"
- "org.foo.Top.EInner1.EInner1_EInner1"))))
(provide 'javaimp-tests)
diff --git a/javaimp.el b/javaimp.el
index dade07e..5d9ef9d 100644
--- a/javaimp.el
+++ b/javaimp.el
@@ -449,7 +449,7 @@ prefix arg is given, don't do this filtering."
(mapcar (lambda (class)
(if package
(concat package "." class)))
- (javaimp--parse-get-file-classes)))))
+ (javaimp--parse-get-all-classlikes)))))
;; Organizing imports
@@ -573,6 +573,7 @@ is `ordinary' or `static'. Interactively, NEW-IMPORTS is
nil."
;;;###autoload
(defun javaimp-imenu-create-index ()
+ "Function to use as `imenu-create-index-function'."
(let ((forest (save-excursion
(javaimp--parse-get-forest-for-imenu))))
(cond ((not javaimp-imenu-group-methods)
diff --git a/testdata/test-get-file-classes-1.java
b/testdata/test-get-file-classes-1.java
deleted file mode 100644
index ba36d31..0000000
--- a/testdata/test-get-file-classes-1.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.foo;
-
-public class Top {
- public static class CInner1<T, S> {
- public void foo_bar() {
- if (true) {
- class CInner1_CLocal1 implements Serializable {
- void foo_bar() {
- System.out.println("");
- if (true) {
- class CInner1_CLocal1_CLocal1 extends Object {
- public void foo_bar() {
- System.out.println("");
- }
- }
- }
- }
- }
- }
-
- class CInner1_CLocal2 extends Object {
- void foo_bar() {
- System.out.println("");
- }
- }
- }
-
- private Object obj = new Object();
- class CInner1_CInner1 {
- }
- }
-
- interface IInner1 {
- interface IInner1_IInner1 extends A<B, C>, Serializable {
- void foo_bar();
- }
-
- static class IInner1_CInner1 {
- public void foo_bar() {
- if (true) {
- System.out.println("");
- }
- }
- }
- }
-
- enum EInner1 {
- A("a"),
- B("b");
- private EInner1() {
- }
- public void foo_bar() {
- System.out.println("");
- }
-
- enum EInner1_EInner1 {
- C, D
- }
- }
-}
diff --git a/testdata/test1-misc-classes.java b/testdata/test1-misc-classes.java
new file mode 100644
index 0000000..436d057
--- /dev/null
+++ b/testdata/test1-misc-classes.java
@@ -0,0 +1,117 @@
+package org.foo;
+
+public class Top {
+ public static class CInner1<T, S> {
+ public void foo() {
+ if (true) {
+ class CInner1_CLocal1 implements Serializable {
+ void foo() {
+ System.out.println("");
+ if (true) {
+ class CInner1_CLocal1_CLocal1 extends Object {
+ public void foo() {
+ System.out.println("");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ class CInner1_CLocal2 extends Object {
+ void foo() {
+ System.out.println("");
+ }
+ }
+ }
+
+ private Object obj = new Object();
+ private Object obj = new Object() {
+ @Override
+ public String toString() {
+ return "asdf";
+ }
+ };
+ abstract class CInner1_CInner1 {
+ public void foo() {
+ }
+
+ abstract void abstract_method();
+
+ public void bar() {
+ System.out.println("");
+ }
+
+ abstract void baz();
+ }
+ }
+
+ // public class LineCommentedClass {
+ // }
+
+ /*
+ public class BlockCommentedClass {
+ }
+ */
+
+ /*
+ * public class BlockCommentedClass2 {
+ * }
+ */
+
+ /**
+ * public class JavadocCommentedClass {
+ * }
+ */
+
+
+ interface IInner1 {
+ static void foo() {
+ if (true) {
+ System.out.println("");
+ }
+ }
+
+ String bar(String arg1, String arg2);
+
+ static class IInner1_CInner1 {
+ public void foo() {
+ if (true) {
+ System.out.println("");
+ }
+ }
+ }
+
+ void baz();
+
+ default void defaultMethod() {
+ System.out.println("");
+ }
+
+ interface IInner1_IInner1 extends A<B, C>, Serializable {
+ void foo();
+
+ default String defaultMethod() {
+ System.out.println("");
+ }
+
+ void baz();
+ }
+ }
+
+ enum EnumInner1 {
+ A("a"),
+ B("b");
+
+ private EnumInner1() {
+ }
+
+ public void foo() {
+ System.out.println("");
+ }
+
+ enum EnumInner1_EInner1 {
+ C, D
+ }
+ }
+}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] scratch/javaimp-wip fe080eb: wip,
Filipp Gunbin <=