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

    WIP: Index every possibly required type ahead of time.
    
    - Changed project and after-save-action implementation to include imports in
      opened files. This way any types that are used in a file will have 
completion
      available for it ahead of time.
    - Extra attributes have been added to phpinspect--class to check whether or 
not
      its file has been indexed/is queued for indexation yet.
    - Misc: Fixed eldoc function bug that was caused by a previous commit
---
 phpinspect-class.el   |  19 +++++-
 phpinspect-index.el   | 163 +++++++++++++++++++++++++++-----------------------
 phpinspect-project.el |  86 +++++++++++++++-----------
 phpinspect-type.el    |  10 ++--
 phpinspect.el         |  35 +++++++----
 5 files changed, 187 insertions(+), 126 deletions(-)

diff --git a/phpinspect-class.el b/phpinspect-class.el
index 7b6e12be0c..dba40450df 100644
--- a/phpinspect-class.el
+++ b/phpinspect-class.el
@@ -56,7 +56,17 @@
                  :documentation
                  "A list of subscription functions that should be
                  called whenever anything about this class is
-                 updated"))
+                 updated")
+  (initial-index nil
+                 :type bool
+                 :documentation
+                 "A boolean indicating whether or not this class
+                 has been indexed yet.")
+  (index-queued nil
+                :type bool
+                :documentation
+                "A boolean indicating whether the class type has
+                been queued for indexation"))
 
 (cl-defmethod phpinspect--class-trigger-update ((class phpinspect--class))
   (dolist (sub (phpinspect--class-subscriptions class))
@@ -64,6 +74,7 @@
 
 (cl-defmethod phpinspect--class-set-index ((class phpinspect--class)
                                            (index (head 
phpinspect--indexed-class)))
+  (setf (phpinspect--class-initial-index class) t)
   (setf (phpinspect--class-index class) index)
   (dolist (method (alist-get 'methods index))
     (phpinspect--class-update-method class method))
@@ -124,6 +135,12 @@
     (when method
       (phpinspect--function-return-type method))))
 
+(cl-defmethod phpinspect--class-get-static-method-return-type
+  ((class phpinspect--class) (method-name symbol))
+  (let ((method (phpinspect--class-get-static-method class method-name)))
+    (when method
+      (phpinspect--function-return-type method))))
+
 (cl-defmethod phpinspect--class-get-method-list ((class phpinspect--class))
   (let ((methods))
     (maphash (lambda (key method)
diff --git a/phpinspect-index.el b/phpinspect-index.el
index cfa642d94f..4cb4b6179a 100644
--- a/phpinspect-index.el
+++ b/phpinspect-index.el
@@ -46,10 +46,10 @@
         (arg-list (cl-copy-list arg-list)))
     (while (setq current-token (pop arg-list))
       (cond ((and (phpinspect-word-p current-token)
-               (phpinspect-variable-p (car arg-list)))
-          (push `(,(cadr (pop arg-list))
-                  ,(funcall type-resolver (phpinspect--make-type :name (cadr 
current-token))))
-                arg-index))
+                  (phpinspect-variable-p (car arg-list)))
+             (push `(,(cadr (pop arg-list))
+                     ,(funcall type-resolver (phpinspect--make-type :name 
(cadr current-token))))
+                   arg-index))
             ((phpinspect-variable-p (car arg-list))
              (push `(,(cadr (pop arg-list))
                      nil)
@@ -71,8 +71,8 @@
     ;; @return annotation. When dealing with a collection, we want to store the
     ;; type of its members.
     (let* ((is-collection
-           (when type
-             (member (phpinspect--type-name type) 
phpinspect-collection-types)))
+            (when type
+              (member (phpinspect--type-name type) 
phpinspect-collection-types)))
            (return-annotation-type
             (when (or (phpinspect--should-prefer-return-annotation type) 
is-collection)
               (cadadr
@@ -139,7 +139,7 @@
                             (cadr class-token))))
     (cadr subtoken)))
 
-(defun phpinspect--index-class (type-resolver class)
+(defun phpinspect--index-class (imports type-resolver class)
   "Create an alist with relevant attributes of a parsed class."
   (phpinspect--log "INDEXING CLASS")
   (let ((methods)
@@ -247,9 +247,9 @@
     ;; TODO: actually check the types of the variables assigned to object 
attributes
     (let* ((constructor-sym (phpinspect-intern-name "__construct"))
            (constructor (seq-find (lambda (method)
-                                   (eq (phpinspect--function-name-symbol 
method)
-                                            constructor-sym))
-                                 methods)))
+                                    (eq (phpinspect--function-name-symbol 
method)
+                                        constructor-sym))
+                                  methods)))
       (when constructor
         (phpinspect--log "Constructor was found")
         (dolist (variable variables)
@@ -267,6 +267,7 @@
     (let ((class-name (funcall type-resolver (phpinspect--make-type :name 
class-name))))
       `(,class-name .
                     (phpinspect--indexed-class
+                     (imports . ,imports)
                      (methods . ,methods)
                      (class-name . ,class-name)
                      (static-methods . ,static-methods)
@@ -283,22 +284,26 @@ Accounts for namespaces that are defined with '{}' 
blocks."
       (cdaddr namespace)
     (cdr namespace)))
 
-(defun phpinspect--index-classes (types classes &optional namespace indexed)
-  "Index the class tokens in `classes`, using the types in `types`
+(defun phpinspect--index-classes (imports classes &optional namespace indexed)
+  "Index the class tokens in `classes`, using the imports in `imports`
 as Fully Qualified names. `namespace` will be assumed the root
 namespace if not provided"
   (if classes
       (let ((class (pop classes)))
         (push (phpinspect--index-class
-               (phpinspect--make-type-resolver types class namespace)
+               imports
+               (phpinspect--make-type-resolver imports class namespace)
                class)
               indexed)
-        (phpinspect--index-classes types classes namespace indexed))
+        (phpinspect--index-classes imports classes namespace indexed))
     (nreverse indexed)))
 
 (defun phpinspect--use-to-type (use)
   (let* ((fqn (cadr (cadr use)))
-         (type (phpinspect--make-type :name fqn :fully-qualified t))
+         (type (phpinspect--make-type :name (if (string-match "^\\\\" fqn)
+                                                fqn
+                                              (concat "\\" fqn))
+                                      :fully-qualified t))
          (type-name (if (and (phpinspect-word-p (caddr use))
                              (string= "as" (cadr (caddr use))))
                         (cadr (cadddr use))
@@ -327,16 +332,18 @@ namespace if not provided"
 
 (defun phpinspect--index-tokens (tokens)
   "Index TOKENS as returned by `phpinspect--parse-current-buffer`."
-  `(phpinspect--root-index
-    ,(append
-      (append '(classes)
-              (phpinspect--index-namespaces (seq-filter 
#'phpinspect-namespace-p tokens))
-              (phpinspect--index-classes
-               (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p 
tokens))
-               (seq-filter #'phpinspect-class-p tokens))))
-    (functions))
-  ;; TODO: Implement function indexation
-  )
+  (let ((imports (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p 
tokens))))
+    `(phpinspect--root-index
+      (imports . ,imports)
+      ,(append
+        (append '(classes)
+                (phpinspect--index-namespaces (seq-filter 
#'phpinspect-namespace-p tokens))
+                (phpinspect--index-classes
+                 imports
+                 (seq-filter #'phpinspect-class-p tokens))))
+      (functions))
+    ;; TODO: Implement function indexation
+    ))
 
 (defun phpinspect-index-file (file-name)
   (phpinspect--index-tokens (phpinspect-parse-file file-name)))
@@ -377,43 +384,45 @@ namespace if not provided"
                 enqueued."))
 
 (defsubst phpinspect--make-queue (&optional subscription)
-    (phpinspect--make-queue-item :subscription subscription))
+  (phpinspect--make-queue-item :subscription subscription))
 
+;; Recursion causes max-eval-depth error here for long queues. Hence the loop
+;; implementation for these two functions.
 (cl-defmethod phpinspect--queue-last ((item phpinspect--queue-item))
-  (if (phpinspect--queue-item-next item)
-      (phpinspect--queue-last (phpinspect--queue-item-next item))
-    item))
+  (while (phpinspect--queue-item-next item)
+    (setq item (phpinspect--queue-item-next item)))
+  item)
 
 (cl-defmethod phpinspect--queue-first ((item phpinspect--queue-item))
-  (if (phpinspect--queue-item-previous item)
-      (phpinspect--queue-first (phpinspect--queue-item-previous item))
-    item))
+  (while (phpinspect--queue-item-previous item)
+      (setq item (phpinspect--queue-item-previous item)))
+  item)
 
 (cl-defmethod phpinspect--queue-enqueue ((item phpinspect--queue-item) thing)
-    (let ((last (phpinspect--queue-last item)))
-      (if (not (phpinspect--queue-item-thing last))
-          (setf (phpinspect--queue-item-thing last) thing)
-        (setf (phpinspect--queue-item-next last)
-              (phpinspect--make-queue-item
-               :previous last
-               :thing thing
-               :subscription (phpinspect--queue-item-subscription item)))))
-    (funcall (phpinspect--queue-item-subscription item)))
+  (let ((last (phpinspect--queue-last item)))
+    (if (not (phpinspect--queue-item-thing last))
+        (setf (phpinspect--queue-item-thing last) thing)
+      (setf (phpinspect--queue-item-next last)
+            (phpinspect--make-queue-item
+             :previous last
+             :thing thing
+             :subscription (phpinspect--queue-item-subscription item)))))
+  (funcall (phpinspect--queue-item-subscription item)))
 
 (cl-defmethod phpinspect--queue-dequeue ((item phpinspect--queue-item))
-    (let* ((first (phpinspect--queue-first item))
-           (thing (phpinspect--queue-item-thing first))
-           (next (phpinspect--queue-item-next first)))
-      (when next (setf (phpinspect--queue-item-previous next) nil))
-      (cond ((and (eq item first) (not next))
-             (setf (phpinspect--queue-item-thing item)
-                   nil))
-            ((eq item first)
-             (setf (phpinspect--queue-item-thing item)
-                   (phpinspect--queue-item-thing next))
-             (setf (phpinspect--queue-item-next item)
-                   (phpinspect--queue-item-next next))))
-      thing))
+  (let* ((first (phpinspect--queue-first item))
+         (thing (phpinspect--queue-item-thing first))
+         (next (phpinspect--queue-item-next first)))
+    (when next (setf (phpinspect--queue-item-previous next) nil))
+    (cond ((and (eq item first) (not next))
+           (setf (phpinspect--queue-item-thing item)
+                 nil))
+          ((eq item first)
+           (setf (phpinspect--queue-item-thing item)
+                 (phpinspect--queue-item-thing next))
+           (setf (phpinspect--queue-item-next item)
+                 (phpinspect--queue-item-next next))))
+    thing))
 
 (cl-defmethod phpinspect--queue-find
   ((item phpinspect--queue-item) thing comparison-func)
@@ -478,10 +487,10 @@ namespace if not provided"
                       ;; and skipped, as we haven't done any intensive work 
that
                       ;; may cause hangups.
                       (setq skip-pause t))
-                  (let ((type-index (phpinspect--index-type
-                                     project
-                                     (phpinspect--index-task-type task))))
-                    (when type-index (phpinspect--project-add-class project 
type-index))))))
+                  (let* ((type (phpinspect--index-task-type task))
+                         (root-index (phpinspect--index-type-file project 
type)))
+                    (when root-index
+                      (phpinspect--project-add-index project root-index))))))
 
           ;; else: join with the main thread until wakeup is signaled
           (thread-join main-thread))
@@ -535,23 +544,27 @@ namespace if not provided"
 (defsubst phpinspect--make-index-task (project-root type)
   (list project-root type))
 
-(cl-defmethod phpinspect--index-type ((project phpinspect--project)
-                                      (type phpinspect--type))
-  (let* ((class-file (with-temp-buffer
-                       (cd (phpinspect--project-root project))
-                       (phpinspect-type-filepath type)))
-         (visited-buffer (when class-file (find-buffer-visiting class-file)))
-         (new-index)
-         (class-index))
-    (when class-file
-      (if visited-buffer
-          (setq new-index (with-current-buffer visited-buffer
-                            (phpinspect--index-current-buffer)))
-        (setq new-index (phpinspect-index-file class-file)))
-            (alist-get type (alist-get 'classes new-index)
-                       nil
-                       nil
-                       #'phpinspect--type=))))
+(cl-defmethod phpinspect--index-type-file ((project phpinspect--project)
+                                           (type phpinspect--type))
+  (condition-case error
+      (let* ((class-file (with-temp-buffer
+                           (cd (phpinspect--project-root project))
+                           (phpinspect-type-filepath type)))
+             (visited-buffer (when class-file (find-buffer-visiting 
class-file)))
+             (new-index)
+             (class-index))
+        (when class-file
+          (if visited-buffer
+              (with-current-buffer visited-buffer 
(phpinspect--index-current-buffer))
+            (phpinspect-index-file class-file))))
+    (file-missing
+     (phpinspect--log "Failed to find file for type %s:  %s" type error)
+     nil)))
+
+(defsubst phpinspect--index-thread-enqueue (task)
+  (phpinspect--queue-enqueue-noduplicate phpinspect--index-queue
+                                         task
+                                         #'phpinspect--index-task=))
 
 (provide 'phpinspect-index)
 ;;; phpinspect-index.el ends here
diff --git a/phpinspect-project.el b/phpinspect-project.el
index 313dc07f4a..372ce96089 100644
--- a/phpinspect-project.el
+++ b/phpinspect-project.el
@@ -44,22 +44,30 @@ indexed classes in the project")
 (cl-defmethod phpinspect--project-add-return-types-to-index-queueue
   ((project phpinspect--project) methods)
   (dolist (method methods)
-    (when (not (phpinspect--project-get-class project 
(phpinspect--function-return-type method)))
-      (phpinspect--queue-enqueue-noduplicate phpinspect--index-queue
-                                             (phpinspect--make-index-task
-                                              (phpinspect--project-root 
project)
-                                              
(phpinspect--function-return-type method))
-                                             #'phpinspect--index-task=))))
+    (when (phpinspect--function-return-type method)
+      (phpinspect--project-enqueue-if-not-present
+       project
+       (phpinspect--function-return-type method)))))
 
 (cl-defmethod phpinspect--project-add-variable-types-to-index-queue
   ((project phpinspect--project) variables)
   (dolist (var variables)
     (when (phpinspect--variable-type var)
-      (phpinspect--queue-enqueue-noduplicate phpinspect--index-queue
-                                             (phpinspect--make-index-task
-                                              (phpinspect--project-root 
project)
-                                              (phpinspect--variable-type var))
-                                             #'phpinspect--index-task=))))
+      (phpinspect--project-enqueue-if-not-present project 
(phpinspect--variable-type var)))))
+
+(cl-defmethod phpinspect--project-enqueue-if-not-present
+  ((project phpinspect--project) (type phpinspect--type))
+  (let ((class (phpinspect--project-get-class project type)))
+    (when (or (not class)
+              (not (or (phpinspect--class-initial-index class)
+                       (phpinspect--class-index-queued class))))
+      (when (not class)
+        (setq class (phpinspect--project-create-class project type)))
+      (phpinspect--log "Adding unpresent class %s to index queue" type)
+      (setf (phpinspect--class-index-queued class) t)
+      (phpinspect--index-thread-enqueue (phpinspect--make-index-task
+                                         (phpinspect--project-root project)
+                                         type)))))
 
 (cl-defmethod phpinspect--project-add-class-attribute-types-to-index-queue
   ((project phpinspect--project) (class phpinspect--class))
@@ -73,43 +81,53 @@ indexed classes in the project")
    project
    (phpinspect--class-variables class)))
 
+(cl-defmethod phpinspect--project-add-index
+  ((project phpinspect--project) (index (head phpinspect--root-index)))
+  (dolist (indexed-class (alist-get 'classes (cdr index)))
+    (phpinspect--project-add-class project (cdr indexed-class))))
+
+(cl-defmethod phpinspect--project-enqueue-imports
+  ((project phpinspect--project) imports)
+  (dolist (import imports)
+    (when import
+      (phpinspect--log "Adding import to index queue: %s" import)
+      (phpinspect--project-enqueue-if-not-present project (cdr import)))))
 
 (cl-defmethod phpinspect--project-add-class
   ((project phpinspect--project) (indexed-class (head 
phpinspect--indexed-class)))
   (let* ((class-name (phpinspect--type-name-symbol
                       (alist-get 'class-name (cdr indexed-class))))
-         (existing-class (gethash class-name
-                                  (phpinspect--project-class-index project))))
-    (if existing-class
-        (progn
-          (phpinspect--class-set-index existing-class indexed-class)
-          (phpinspect--project-add-class-attribute-types-to-index-queue
-           project
-           existing-class))
-      (let ((new-class (phpinspect--make-class-generated :project project)))
-        (phpinspect--class-set-index new-class indexed-class)
-        (puthash class-name new-class (phpinspect--project-class-index 
project))
-        (phpinspect--project-add-class-attribute-types-to-index-queue
-         project
-         new-class)))))
+         (class (gethash class-name
+                         (phpinspect--project-class-index project))))
+    (unless class
+      (setq class (phpinspect--make-class-generated :project project)))
+
+    (phpinspect--class-set-index class indexed-class)
+    (puthash class-name class (phpinspect--project-class-index project))
+    (phpinspect--project-add-class-attribute-types-to-index-queue project 
class)))
 
 (cl-defgeneric phpinspect--project-get-class
     ((project phpinspect--project) (class-fqn phpinspect--type))
   "Get indexed class by name of CLASS-FQN stored in PROJECT.")
 
+(cl-defmethod phpinspect--project-set-class
+  ((project phpinspect--project) (class-fqn phpinspect--type) (class 
phpinspect--class))
+  (puthash (phpinspect--type-name-symbol class-fqn)
+           class
+           (phpinspect--project-class-index project)))
+
+(cl-defmethod phpinspect--project-create-class
+  ((project phpinspect--project) (class-fqn phpinspect--type))
+  (let ((class (phpinspect--make-class-generated :project project)))
+    (phpinspect--project-set-class project class-fqn class)
+    class))
+
 (cl-defmethod phpinspect--project-get-class-create
   ((project phpinspect--project) (class-fqn phpinspect--type))
   (let ((class (phpinspect--project-get-class project class-fqn)))
     (unless class
-      (setq class (phpinspect--make-class-generated :project project))
-      (puthash (phpinspect--type-name-symbol class-fqn)
-               class
-               (phpinspect--project-class-index project))
-      (phpinspect--queue-enqueue-noduplicate
-       phpinspect--index-queue
-       (phpinspect--make-index-task (phpinspect--project-root project)
-                                    class-fqn)
-       #'phpinspect--index-task=))
+      (setq class (phpinspect--project-create-class project class-fqn))
+      (phpinspect--project-enqueue-if-not-present project class-fqn))
     class))
 
 (defalias 'phpinspect--project-add-class-if-missing 
#'phpinspect--project-get-class-create)
diff --git a/phpinspect-type.el b/phpinspect-type.el
index 2cfa88cf2d..7f55d4234b 100644
--- a/phpinspect-type.el
+++ b/phpinspect-type.el
@@ -122,11 +122,11 @@ NAMESPACE may be nil, or a string with a namespace FQN."
 
         ;; Clas|interface|trait name
         (t (let ((from-types (assoc-default (phpinspect-intern-name type) 
types #'eq)))
-             (concat "\\" (cond (from-types
-                                 (phpinspect--type-name from-types))
-                                (namespace
-                                 (concat namespace "\\" type))
-                                (t type)))))))
+             (cond (from-types
+                    (phpinspect--type-name from-types))
+                   (namespace
+                    (concat "\\" namespace "\\" type))
+                   (t (concat "\\" type)))))))
 
 (cl-defmethod phpinspect--type-resolve (types namespace (type 
phpinspect--type))
   (unless (phpinspect--type-fully-qualified type)
diff --git a/phpinspect.el b/phpinspect.el
index 226288ffa2..be0872f55b 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -353,12 +353,13 @@ TODO:
       (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-methods (phpinspect-get-cached-project-class-methods
-                            (phpinspect--resolvecontext-project-root 
resolvecontext)
-                            type-of-previous-statement
-                            static))
-             (method (and class-methods
-                          (phpinspect-find-function-in-list method-name 
class-methods))))
+             (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
+                       (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)
@@ -716,8 +717,8 @@ more recent"
   (eldoc-add-command 'c-electric-paren)
   (eldoc-add-command 'c-electric-backspace)
 
-  (phpinspect--after-save-action)
   (phpinspect--ensure-index-thread)
+  (phpinspect--after-save-action)
 
   (add-hook 'after-save-hook #'phpinspect--after-save-action nil 'local))
 
@@ -732,10 +733,22 @@ keeps the cache valid.  If changes are made outside of 
Emacs,
 users will have to use \\[phpinspect-purge-cache]."
   (when (and (boundp 'phpinspect-mode) phpinspect-mode)
     (setq phpinspect--buffer-index (phpinspect--index-current-buffer))
-    (dolist (class (alist-get 'classes phpinspect--buffer-index))
-      (when class
-        (phpinspect-cache-project-class (phpinspect-project-root)
-                                        (cdr class))))))
+    (let ((imports (alist-get 'imports phpinspect--buffer-index))
+          (project (phpinspect--cache-get-project-create
+                    (phpinspect--get-or-create-global-cache)
+                    (phpinspect-project-root))))
+
+      (dolist (class (alist-get 'classes phpinspect--buffer-index))
+        (when class
+          (phpinspect--project-add-class project (cdr class))
+
+          (let ((imports (alist-get 'imports (cdr class))))
+            (when imports
+              (phpinspect--project-enqueue-imports project imports)))))
+
+
+      (when imports (phpinspect--project-enqueue-imports project imports)))))
+
 
 (defun phpinspect--disable-mode ()
   "Clean up the buffer environment for the mode to be disabled."

Reply via email to