branch: externals/phpinspect
commit bb04e9a0f80c284a92896b8bfaccb877d0be9f88
Author: Hugo Thunnissen <de...@hugot.nl>
Commit: Hugo Thunnissen <de...@hugot.nl>

    Implement strategy pattern for phpinspect-eldoc-function
---
 phpinspect-class.el          |  12 ++-
 phpinspect-eldoc.el          | 200 +++++++++++++++++++++++++++++++++++++++++++
 phpinspect-parser.el         |   2 +-
 phpinspect-project.el        |   4 -
 phpinspect-resolvecontext.el |   5 ++
 phpinspect-util.el           |  75 +++++++++-------
 phpinspect.el                | 107 ++---------------------
 test/phpinspect-test.el      |   1 +
 test/test-eldoc.el           |  88 +++++++++++++++++++
 test/test-util.el            |   9 +-
 10 files changed, 363 insertions(+), 140 deletions(-)

diff --git a/phpinspect-class.el b/phpinspect-class.el
index 3fa10abf5b..1e51bdf5e7 100644
--- a/phpinspect-class.el
+++ b/phpinspect-class.el
@@ -98,9 +98,16 @@
 (cl-defmethod phpinspect--class-get-method ((class phpinspect--class) 
method-name)
   (gethash method-name (phpinspect--class-methods class)))
 
-(cl-defmethod phpinspect--class-get-static-method ((class phpinspect--class) 
method-name)
+(cl-defmethod phpinspect--class-get-static-method ((class phpinspect--class) 
(method-name symbol))
   (gethash method-name (phpinspect--class-static-methods class)))
 
+(cl-defmethod phpinspect--class-get-variable
+  ((class phpinspect--class) (variable-name string))
+  (catch 'found
+    (dolist (variable (phpinspect--class-variables class))
+      (when (string= variable-name (phpinspect--variable-name variable))
+        (throw 'found variable)))))
+
 (cl-defmethod phpinspect--add-method-copy-to-map
   ((map hash-table)
    (class-name phpinspect--type)
@@ -179,7 +186,8 @@
 (cl-defmethod phpinspect--class-update-method ((class phpinspect--class)
                                                (method phpinspect--function))
   (let* ((existing (gethash (phpinspect--function-name-symbol method)
-                           (phpinspect--class-methods class))))
+                            (phpinspect--class-methods class))))
+
     (if existing
         (phpinspect--merge-method
          (alist-get 'class-name (phpinspect--class-index class))
diff --git a/phpinspect-eldoc.el b/phpinspect-eldoc.el
new file mode 100644
index 0000000000..fef7b69d91
--- /dev/null
+++ b/phpinspect-eldoc.el
@@ -0,0 +1,200 @@
+;;; phpinspect-eldoc.el --- PHP parsing and completion package  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021  Free Software Foundation, Inc
+
+;; Author: Hugo Thunnissen <de...@hugot.nl>
+;; Keywords: php, languages, tools, convenience
+;; Version: 0
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+
+
+(cl-defstruct (phpinspect-eldoc-query (:constructor 
phpinspect-make-eldoc-query))
+  (point 0
+         :type integer
+         :documentation "Position in buffer for which to provide hints")
+  (buffer nil
+          :type phpinspect-buffer))
+
+(cl-defmethod phpinspect-eldoc-query-execute ((query phpinspect-eldoc-query))
+  (let* ((buffer (phpinspect-eldoc-query-buffer query))
+         (point (phpinspect-eldoc-query-point query))
+         (buffer-map (phpinspect-buffer-parse-map buffer))
+         (rctx (phpinspect-get-resolvecontext buffer-map point)))
+    (catch 'matched
+      (dolist (strategy phpinspect-eldoc-strategies)
+        (when (phpinspect-eld-strategy-supports strategy query rctx)
+          (throw 'matched (phpinspect-eld-strategy-execute strategy query 
rctx)))))))
+
+(cl-defgeneric phpinspect-eld-strategy-supports (strategy (query 
phpinspect-eldoc-query) (context phpinspect--resolvecontext))
+  "Should return non-nil if STRATEGY should be deployed for QUERY
+and CONTEXT. All strategies must implement this method.")
+
+(cl-defgeneric phpinspect-eld-strategy-execute (strategy (query 
phpinspect-eldoc-query) (context phpinspect--resolvecontext))
+  "Should return an object for which `phpinspect-eldoc-string' is 
implemented.")
+
+(cl-defgeneric phpinspect-eldoc-string (response)
+  "Should return a string to be displayed by eldoc. This needs to
+be implemented for return values of `phpinspect-eld-strategy-execute'")
+
+(cl-defstruct (phpinspect-eld-attribute (:constructor 
phpinspect-make-eld-attribute))
+  "Eldoc strategy for object attributes.")
+
+(cl-defmethod phpinspect-eld-strategy-supports
+  ((strat phpinspect-eld-attribute) (q phpinspect-eldoc-query) (rctx 
phpinspect--resolvecontext))
+  (phpinspect-attrib-p (car (last (phpinspect--resolvecontext-subject rctx)))))
+
+;; (cl-defmethod phpinspect-eld-strategy-execute
+;;   ((strat phpinspect-eld-attribute) (q phpinspect-eldoc-query) (rctx 
phpinspect--resolvecontext))
+;;   (let ((attrib (car (last (phpinspect--resolvecontext-subject rctx))))
+;;         type-before)
+;;     (setf (phpinspect--resolvecontext-subject rctx) (butlast 
(phpinspect--resolvecontext-subject rctx)))
+;;     (setq type-before (phpinspect-resolve-type-from-context rctx))
+
+;;     (when type-before
+;;       (let ((class (phpinspect-project-get-class-create
+;;                     (phpinspect--resolvecontext-project rctx)
+;;                     type-before))
+;;             attribute)
+;;         (cond ((phpinspect-static-attrib-p attrib)
+;;                (setq attribute (or (phpinspect--class-get-variable
+
+
+(cl-defstruct (phpinspect-eld-function-args (:constructor 
phpinspect-make-eld-function-args))
+  "Eldoc strategy for function arguments.")
+
+(cl-defmethod phpinspect-eld-strategy-supports
+  ((strat phpinspect-eld-function-args) (q phpinspect-eldoc-query) (rctx 
phpinspect--resolvecontext))
+  (let ((parent-token (car (phpinspect--resolvecontext-enclosing-tokens 
rctx))))
+    ;; When our subject is inside a list, it is probably an argument of a
+    ;; function/method call, which is what this strategy provides information 
for.
+    (or (phpinspect-list-p parent-token)
+
+        ;; When our subject IS a list, we're probably in an empty/incomplete
+        ;; argument list.
+        (and (= 1 (length (phpinspect--resolvecontext-subject rctx)))
+             (phpinspect-list-p
+              (car (last (phpinspect--resolvecontext-subject rctx)))))
+
+        ;; When the last token in our subject is an incomplete list, we're
+        ;; probably at the end of the buffer in an unfinished argument list.
+        (phpinspect-incomplete-list-p
+         (car (last (phpinspect--resolvecontext-subject rctx)))))))
+
+(cl-defmethod phpinspect-eld-strategy-execute
+  ((strat phpinspect-eld-function-args) (q phpinspect-eldoc-query) (rctx 
phpinspect--resolvecontext))
+  (let* ((token-map (phpinspect-buffer-parse-map 
(phpinspect-eldoc-query-buffer q)))
+         (enclosing-token (cadr (phpinspect--resolvecontext-enclosing-tokens
+                                 rctx)))
+         (statement (phpinspect-find-statement-before-point
+                     token-map (phpinspect-bmap-token-meta token-map 
enclosing-token)
+                     (phpinspect-eldoc-query-point q)))
+         match-result static arg-list arg-pos)
+
+    (when enclosing-token
+      (cond
+       ;; Method call
+       ((setq match-result (phpinspect--match-sequence (last statement 2)
+                             :f #'phpinspect-attrib-p
+                             :f #'phpinspect-list-p))
+
+        (setq arg-list (car (last match-result))
+              static (phpinspect-static-attrib-p (car match-result))
+              arg-pos (seq-reduce
+                       (lambda (count token)
+                         (if (and (phpinspect-comma-p token)
+                                  (> (phpinspect-eldoc-query-point q)
+                                     (phpinspect-meta-end
+                                      (phpinspect-bmap-token-meta token-map 
token))))
+                             (+ count 1)
+                           count))
+                       arg-list 0))
+
+        ;; Set resolvecontext subject to the statement minus the method
+        ;; name. Point is likely to be at a location inside a method call like
+        ;; "$a->b->doSomething(". The resulting subject should be "$a->b".
+        (setf (phpinspect--resolvecontext-subject rctx) (butlast statement 2))
+
+        (let* ((type-of-previous-statement
+                (phpinspect-resolve-type-from-context rctx))
+               (method-name-sym (phpinspect-intern-name (car (cdadar 
match-result))))
+               (class (phpinspect-project-get-class-create
+                       (phpinspect--resolvecontext-project rctx)
+                       type-of-previous-statement))
+               (method (when class
+                         (if static
+                             (phpinspect--class-get-static-method class 
method-name-sym)
+                           (phpinspect--class-get-method class 
method-name-sym)))))
+          (when method
+            (phpinspect-make-function-doc :fn method :arg-pos arg-pos))))))))
+
+(cl-defstruct (phpinspect-function-doc (:constructor 
phpinspect-make-function-doc))
+  (fn nil
+      :type phpinspect--function)
+  (arg-pos nil))
+
+(cl-defmethod phpinspect-eldoc-string ((doc phpinspect-function-doc))
+  (let ((fn (phpinspect-function-doc-fn doc))
+        (arg-pos (phpinspect-function-doc-arg-pos doc))
+        (arg-count 0))
+    (concat (truncate-string-to-width
+             (phpinspect--function-name fn) phpinspect-eldoc-word-width) ": ("
+             (mapconcat
+              (lambda (arg)
+                (let ((doc-string
+                       (concat "$" (truncate-string-to-width
+                                    (car arg) phpinspect-eldoc-word-width)
+                               (if (cadr arg) " " "")
+                               (phpinspect--format-type-name (or (cadr arg) 
"")))))
+                  (when (and arg-pos (= arg-count arg-pos))
+                    (setq doc-string
+                          (propertize
+                           doc-string 'face 
'eldoc-highlight-function-argument)))
+                  (setq arg-count (+ arg-count 1))
+                  doc-string))
+              (phpinspect--function-arguments fn)
+              ", ")
+             "): "
+             (phpinspect--format-type-name
+              (phpinspect--function-return-type fn)))))
+
+(defvar phpinspect-eldoc-strategies (list ;;(phpinspect-make-eld-attribute)
+                                          (phpinspect-make-eld-function-args))
+  "The eldoc strategies that phpinspect is currently allowed to
+employ. Strategies are queried in the order of this list. See
+also `phpinspect-eldoc-query-execute'.")
+
+(defun phpinspect-eldoc-function ()
+  "An `eldoc-documentation-function` implementation for PHP files.
+
+Ignores `eldoc-argument-case` and `eldoc-echo-area-use-multiline-p`.
+
+TODO:
+ - Respect `eldoc-echo-area-use-multiline-p`
+"
+  (catch 'phpinspect-parse-interrupted
+    (let ((resp (phpinspect-eldoc-query-execute
+                 (phpinspect-make-eldoc-query
+                  :buffer phpinspect-current-buffer
+                  :point (phpinspect--determine-completion-point)))))
+      (when resp
+        (phpinspect-eldoc-string resp)))))
+
+
+(provide 'phpinspect-eldoc)
diff --git a/phpinspect-parser.el b/phpinspect-parser.el
index 9aab4d32c9..4d75d06a7e 100644
--- a/phpinspect-parser.el
+++ b/phpinspect-parser.el
@@ -911,7 +911,7 @@ static keywords with the same meaning as in a class block."
          (continue-condition (lambda ()
                                (not (and (char-equal (char-after) ?})
                                          (setq complete-block t)))))
-         (parsed (funcall parser (current-buffer) max-point 
continue-condition)))
+         (parsed (funcall parser (current-buffer) max-point continue-condition 
'root)))
     (if complete-block
         (forward-char)
       (setcar parsed :incomplete-block))
diff --git a/phpinspect-project.el b/phpinspect-project.el
index 39410c11ea..a90ac7d0ed 100644
--- a/phpinspect-project.el
+++ b/phpinspect-project.el
@@ -95,10 +95,6 @@ Projects get purged when they are removed from the global 
cache.")
                  :documentation "All active file watchers in this project,
 indexed by the absolute paths of the files they're watching."))
 
-(cl-defgeneric phpinspect-project-add-class
-    ((project phpinspect-project) (class (head phpinspect--indexed-class)))
-  "Add an indexed CLASS to PROJECT.")
-
 (cl-defmethod phpinspect-project-purge ((project phpinspect-project))
   "Disable all background processes for project and put it in a `purged` 
state."
   (maphash (lambda (_ watcher) (file-notify-rm-watch watcher))
diff --git a/phpinspect-resolvecontext.el b/phpinspect-resolvecontext.el
index 5eaded16df..c6e4382705 100644
--- a/phpinspect-resolvecontext.el
+++ b/phpinspect-resolvecontext.el
@@ -121,6 +121,11 @@
      :enclosing-tokens (nreverse enclosing-tokens)
      :project-root (phpinspect-current-project-root))))
 
+(defun phpinspect--resolvecontext-project (rctx)
+  (phpinspect--cache-get-project-create
+   (phpinspect--get-or-create-global-cache)
+   (phpinspect--resolvecontext-project-root rctx)))
+
 (defun phpinspect--get-resolvecontext (token &optional resolvecontext)
   "Find the deepest nested incomplete token in TOKEN.
 If RESOLVECONTEXT is nil, it is created.  Returns RESOLVECONTEXT
diff --git a/phpinspect-util.el b/phpinspect-util.el
index c5f4722da2..7edab54174 100644
--- a/phpinspect-util.el
+++ b/phpinspect-util.el
@@ -72,20 +72,22 @@ pattern. See `phpinspect--match-sequence'."
         :type list
         :documentation "The original code list used to create this pattern"))
 
-(defsubst phpinspect--make-pattern (&rest pattern)
-  (phpinspect--make-pattern-generated
-   :matcher (apply #'phpinspect--match-sequence-lambda pattern)
-   :code pattern))
+(defmacro phpinspect--make-pattern (&rest pattern)
+  `(phpinspect--make-pattern-generated
+    :matcher (phpinspect--match-sequence-lambda ,@pattern)
+    :code  (list ,@(mapcar (lambda (part) (if (eq '* part) `(quote ,part) 
part))
+                           pattern))))
 
-(defun phpinspect--match-sequence-lambda (&rest pattern)
-  (lambda (sequence)
-    (apply #'phpinspect--match-sequence sequence pattern)))
+(defmacro phpinspect--match-sequence-lambda (&rest pattern)
+  (let ((sequence-sym (gensym)))
+    `(lambda (,sequence-sym)
+       (phpinspect--match-sequence ,sequence-sym ,@pattern))))
 
 (cl-defmethod phpinspect--pattern-match ((pattern phpinspect--pattern) 
sequence)
   "Match SEQUENCE to PATTERN."
   (funcall (phpinspect--pattern-matcher pattern) sequence))
 
-(defun phpinspect--match-sequence (sequence &rest pattern)
+(defmacro phpinspect--match-sequence (sequence &rest pattern)
   "Match SEQUENCE to positional matchers defined in PATTERN.
 
 PATTERN is a plist with the allowed keys being :m and :f. Each
@@ -107,30 +109,43 @@ element at this position in SEQUENCE.
 the function provided as value. The function is executed with the
 list element as argument, and will be considered as matching if
 it evaluates to a non-nil value."
+  (declare (indent 1))
   (let* ((pattern-length (length pattern))
-         (count 0)
+         (sequence-length (/ pattern-length 2))
          (sequence-pos 0)
-         (sequence-length (/ pattern-length 2)))
-
-    (and (= sequence-length (length sequence))
-         (catch 'found
-           (while (< count pattern-length)
-             (let ((key (elt pattern count))
-                   (value (elt pattern (+ count 1))))
-               (unless (keywordp key)
-                 (error (format "Invalid, expected keyword, got %s" key)))
-
-               (cond ((eq key :m)
-                      (unless (eq value '*)
-                        (unless (equal value (elt sequence sequence-pos))
-                          (throw 'found nil))))
-                     ((eq key :f)
-                      (unless (funcall value (elt sequence sequence-pos))
-                        (throw 'found nil)))
-                     (t (error (format "Invalid keyword: %s" key))))
-               (setq count (+ count 2)
-                     sequence-pos (+ sequence-pos 1))))
-           (throw 'found t)))))
+         (sequence-sym (gensym))
+         (match-sym (gensym))
+         checkers key value)
+
+    (while (setq key (pop pattern))
+      (unless (keywordp key)
+        (error "Invalid pattern argument, expected keyword, got: %s" key))
+
+      (unless (setq value (pop pattern))
+        (error "No value for key %s" key))
+
+      (cond ((eq key :m)
+             (unless (eq value '*)
+               (setq checkers
+                     (nconc checkers (list `(equal ,value (elt ,sequence-sym 
,sequence-pos)))))))
+            ((eq key :f)
+             (setq checkers
+                   (nconc
+                    checkers (list
+                              (if (symbolp value)
+                                  `(,value (elt ,sequence-sym ,sequence-pos))
+                                `(funcall ,value (elt ,sequence-sym 
,sequence-pos)))))))
+            (t (error "Invalid keyword: %s" key)))
+
+      (setq checkers (nconc checkers (list `(setq ,match-sym (nconc ,match-sym 
(list (elt ,sequence-sym ,sequence-pos)))))))
+
+      (setq sequence-pos (+ sequence-pos 1)))
+
+    `(let ((,sequence-sym ,sequence)
+           ,match-sym)
+       (and (= ,sequence-length (length ,sequence))
+            ,@checkers)
+       ,match-sym)))
 
 (defun phpinspect--pattern-concat (pattern1 pattern2)
   (let* ((pattern1-sequence-length (/ (length (phpinspect--pattern-code 
pattern1)) 2)))
diff --git a/phpinspect.el b/phpinspect.el
index 55f73b652d..e9e367c54d 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -42,6 +42,7 @@
 (require 'phpinspect-imports)
 (require 'phpinspect-buffer)
 (require 'phpinspect-resolvecontext)
+(require 'phpinspect-eldoc)
 
 (defvar phpinspect-auto-reindex nil
   "Whether or not phpinspect should automatically search for new
@@ -179,12 +180,9 @@ candidate. Candidates can be indexed functions and 
variables.")
                    project-root class-fqn variable-name)
   (when project-root
     (let ((found-variable
-           (seq-find (lambda (variable)
-                       (string= (phpinspect--variable-name variable) 
variable-name))
-                     (phpinspect--class-variables
-                      (phpinspect-get-or-create-cached-project-class
-                       project-root
-                       class-fqn)))))
+           (phpinspect--class-get-variable
+            (phpinspect-get-or-create-cached-project-class project-root 
class-fqn)
+            variable-name)))
       (when found-variable
         (phpinspect--variable-type found-variable)))))
 
@@ -281,98 +279,6 @@ context for completion."
     (forward-char)
     (point)))
 
-(defun phpinspect-eldoc-function ()
-  "An `eldoc-documentation-function` implementation for PHP files.
-
-Ignores `eldoc-argument-case` and `eldoc-echo-area-use-multiline-p`.
-
-TODO:
- - Respect `eldoc-echo-area-use-multiline-p`
- - This function is too big and has repetitive code. Split up and simplify.
-"
-  (catch 'phpinspect-parse-interrupted
-    (let* ((token-map (phpinspect-buffer-parse-map phpinspect-current-buffer))
-           (resolvecontext (phpinspect-get-resolvecontext token-map 
(phpinspect--determine-completion-point)))
-           (parent-token (car (phpinspect--resolvecontext-enclosing-tokens
-                               resolvecontext)))
-           (enclosing-token (cadr (phpinspect--resolvecontext-enclosing-tokens
-                                   resolvecontext)))
-           (statement (phpinspect--resolvecontext-subject resolvecontext))
-           (arg-list)
-           (type-resolver (phpinspect--make-type-resolver-for-resolvecontext
-                           resolvecontext))
-           (static))
-
-      (phpinspect--log  "Eldoc statement before checking outside list: %s" 
statement)
-      (when (and (phpinspect-list-p parent-token) enclosing-token)
-        (setq statement
-              (phpinspect-find-statement-before-point
-               token-map (phpinspect-bmap-token-meta token-map enclosing-token)
-               (phpinspect-meta-end
-                (phpinspect-bmap-token-meta token-map parent-token)))))
-
-      (phpinspect--log "Enclosing token: %s" enclosing-token)
-      (phpinspect--log  "Eldoc statement: %s" statement)
-
-      (setq arg-list (seq-find #'phpinspect-list-p (reverse statement)))
-
-      (when (and (phpinspect-list-p arg-list)
-                 enclosing-token
-                 (or (phpinspect-object-attrib-p (car (last statement 2)))
-                     (setq static (phpinspect-static-attrib-p (car (last 
statement 2))))))
-
-        ;; Set resolvecontext subject to the last statement in the enclosing 
token, minus
-        ;; the method name. The last enclosing token is an incomplete list, so 
point is
-        ;; likely to be at a location inside a method call like 
"$a->b->doSomething(". The
-        ;; resulting subject would be "$a->b".
-        (setf (phpinspect--resolvecontext-subject resolvecontext)
-              (phpinspect--get-last-statement-in-token (butlast statement 2)))
-
-        (let* ((type-of-previous-statement
-                (phpinspect-resolve-type-from-context resolvecontext 
type-resolver))
-               (method-name-sym (phpinspect-intern-name (cadr (cadar (last 
statement 2)))))
-               (class (phpinspect-project-get-class-create
-                       (phpinspect--cache-get-project-create
-                        (phpinspect--get-or-create-global-cache)
-                        (phpinspect--resolvecontext-project-root 
resolvecontext))
-                       type-of-previous-statement))
-               (method (when class
-                         (if static
-                             (phpinspect--class-get-static-method class 
method-name-sym)
-                           (phpinspect--class-get-method class 
method-name-sym)))))
-          (phpinspect--log "Eldoc method name: %s" method-name-sym)
-          (phpinspect--log "Eldoc type of previous statement: %s"
-                           type-of-previous-statement)
-          (phpinspect--log "Eldoc method: %s" method)
-          (when method
-            (let ((arg-count -1)
-                  (comma-count
-                   (length (seq-filter #'phpinspect-comma-p arg-list))))
-              (concat (truncate-string-to-width
-                       (phpinspect--function-name method) 
phpinspect-eldoc-word-width) ": ("
-                       (mapconcat
-                        (lambda (arg)
-                          (setq arg-count (+ arg-count 1))
-                          (if (= arg-count comma-count)
-                              (propertize (concat
-                                           "$"
-                                           (truncate-string-to-width
-                                            (car arg)
-                                            phpinspect-eldoc-word-width)
-                                           " "
-                                           (phpinspect--format-type-name (or 
(cadr arg) "")))
-                                          'face 
'eldoc-highlight-function-argument)
-                            (concat "$"
-                                    (truncate-string-to-width (car arg)
-                                                              
phpinspect-eldoc-word-width)
-                                    (if (cadr arg) " " "")
-                                    (phpinspect--format-type-name (or (cadr 
arg) "")))))
-                        (phpinspect--function-arguments method)
-                        ", ")
-                       "): "
-                       (phpinspect--format-type-name
-                        (phpinspect--function-return-type method))))))))))
-
 (cl-defstruct (phpinspect--assignment
                (:constructor phpinspect--make-assignment))
   (to nil
@@ -700,7 +606,10 @@ EXPRESSION."
                                                     function-arg-list)))))
 
 
-(defun phpinspect-resolve-type-from-context (resolvecontext type-resolver)
+(defun phpinspect-resolve-type-from-context (resolvecontext &optional 
type-resolver)
+  (unless type-resolver
+    (setq type-resolver
+          (phpinspect--make-type-resolver-for-resolvecontext resolvecontext)))
   (phpinspect--log "Looking for type of statement: %s in nested token"
                    (phpinspect--resolvecontext-subject resolvecontext))
   ;; Find all enclosing tokens that aren't classes. Classes do not contain 
variable
diff --git a/test/phpinspect-test.el b/test/phpinspect-test.el
index 6547d69a03..426838883c 100644
--- a/test/phpinspect-test.el
+++ b/test/phpinspect-test.el
@@ -599,6 +599,7 @@ class Thing
 
 (load-file (concat phpinspect-test-directory "/test-worker.el"))
 (load-file (concat phpinspect-test-directory "/test-autoload.el"))
+(load-file (concat phpinspect-test-directory "/test-eldoc.el"))
 (load-file (concat phpinspect-test-directory "/test-fs.el"))
 (load-file (concat phpinspect-test-directory "/test-project.el"))
 (load-file (concat phpinspect-test-directory "/test-buffer.el"))
diff --git a/test/test-eldoc.el b/test/test-eldoc.el
new file mode 100644
index 0000000000..f384ffbda7
--- /dev/null
+++ b/test/test-eldoc.el
@@ -0,0 +1,88 @@
+;;; test-eldoc.el --- Unit tests for phpinspect.el  -*- lexical-binding: t; -*-
+
+(require 'phpinspect)
+(require 'phpinspect-eldoc)
+
+(ert-deftest phpinspect-eld-method-call ()
+  (with-temp-buffer
+    (let* ((php-code "
+class Thing
+{
+
+    function getThis(\\DateTime $moment, Thing $thing, $other): static
+    {
+        return $this;
+    }
+
+    function doStuff()
+    {
+        $this->getThis(new \\DateTime(), bla)")
+           (tokens (phpinspect-parse-string php-code))
+           (index (phpinspect--index-tokens tokens))
+           (phpinspect-project-root-function (lambda () "phpinspect-test"))
+           (phpinspect-eldoc-word-width 100)
+           (buffer (phpinspect-make-buffer :buffer (current-buffer)))
+           second-arg-pos first-arg-pos)
+      (phpinspect-ensure-worker)
+      (phpinspect-purge-cache)
+      (phpinspect-cache-project-class
+       (phpinspect-current-project-root)
+       (cdar (alist-get 'classes (cdr index))))
+
+      (insert php-code)
+      (backward-char)
+      (setq second-arg-pos (point))
+      (backward-char 6)
+      (setq first-arg-pos (point))
+
+      (let ((result (phpinspect-eldoc-query-execute
+                     (phpinspect-make-eldoc-query :point second-arg-pos 
:buffer buffer))))
+        (should (phpinspect-function-doc-p result))
+        (should (= 1 (phpinspect-function-doc-arg-pos result)))
+        (should (string= "getThis" (phpinspect--function-name 
(phpinspect-function-doc-fn result))))
+
+        (setq result (phpinspect-eldoc-query-execute
+                      (phpinspect-make-eldoc-query :point first-arg-pos 
:buffer buffer)))
+        (should (phpinspect-function-doc-p result))
+        (should (= 0 (phpinspect-function-doc-arg-pos result)))
+        (should (string= "getThis" (phpinspect--function-name 
(phpinspect-function-doc-fn result))))))))
+
+;; (ert-deftest phpinspect-eld-attribute ()
+;;   (with-temp-buffer
+;;     (let* ((php-code "
+;; class Thing
+;; {
+;;     /** @var \\DateTime **/
+;;     public $banana;
+
+;;     function getThis(\\DateTime $moment, Thing $thing, $other): static
+;;     {
+;;         return $this;
+;;     }
+
+;;     function doStuff()
+;;     {
+;;         $this->banana;
+;;         $this->getThis(new \\DateTime(), bla)")
+;;            (tokens (phpinspect-parse-string php-code))
+;;            (index (phpinspect--index-tokens tokens))
+;;            (phpinspect-project-root-function (lambda () "phpinspect-test"))
+;;            (phpinspect-eldoc-word-width 100)
+;;            (buffer (phpinspect-make-buffer :buffer (current-buffer)))
+;;            getThis-pos banana-pos)
+
+;;       (insert php-code)
+;;       (backward-char 28)
+;;       (setq getThis-pos (point))
+;;       (backward-char 22)
+;;       (setq banana-pos (point))
+
+;;       (phpinspect-ensure-worker)
+;;       (phpinspect-purge-cache)
+;;       (phpinspect-cache-project-class
+;;        (phpinspect-current-project-root)
+;;        (cdar (alist-get 'classes (cdr index))))
+
+;;       (let ((result (phpinspect-eldoc-query-execute
+;;                      (phpinspect-make-eldoc-query :point getThis-pos 
:buffer buffer))))
+;;         (message "Result: %s" result)))))
diff --git a/test/test-util.el b/test/test-util.el
index 8a61fa1b6f..3b6111b554 100644
--- a/test/test-util.el
+++ b/test/test-util.el
@@ -25,21 +25,22 @@
 
 (ert-deftest phpinspect--pattern ()
   (let* ((a "a")
-         (pattern1 (phpinspect--make-pattern :m `(,a) :m '* :m "b"))
-         (pattern2 (phpinspect--make-pattern :f #'listp :m '* :m "b")))
+         (pattern1 (phpinspect--make-pattern :m `(,a) :m * :m "b"))
+         (pattern2 (phpinspect--make-pattern :f #'listp :m * :m "b")))
 
     (should (equal '(:m ("a") :m * :m "b") (phpinspect--pattern-code 
pattern1)))
     (should (equal '(:f listp :m * :m "b") (phpinspect--pattern-code 
pattern2)))
 
     (dolist (pattern `(,pattern1 ,pattern2))
       (should (phpinspect--pattern-match pattern '(("a") "c" "b")))
+      (should (equal '(("a") "c" "b") (phpinspect--pattern-match pattern 
'(("a") "c" "b"))))
       (should (phpinspect--pattern-match pattern '(("a") nil "b")))
       (should-not (phpinspect--pattern-match pattern '(1 nil "b")))
       (should-not (phpinspect--pattern-match pattern '(("a") nil "b" "c"))))))
 
 (ert-deftest phpinspect--pattern-concat ()
-  (let* ((pattern1 (phpinspect--make-pattern :m "a" :m '* :m "b"))
-         (pattern2 (phpinspect--make-pattern :f #'stringp :m '* :m "D"))
+  (let* ((pattern1 (phpinspect--make-pattern :m "a" :m * :m "b"))
+         (pattern2 (phpinspect--make-pattern :f #'stringp :m * :m "D"))
          (result (phpinspect--pattern-concat pattern1 pattern2)))
 
     (should (equal '(:m "a" :m * :m "b" :f stringp :m * :m "D") 
(phpinspect--pattern-code result)))

Reply via email to