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

    Reindex dynamically resolved property types after change in imported types
---
 phpinspect-buffer.el           | 84 +++++++++++++++++++++++++++++++++---------
 phpinspect-resolve.el          |  5 +--
 phpinspect-resolvecontext.el   |  4 +-
 test/phpinspect-test-env.el    |  8 ++++
 test/test-buffer-indexation.el | 11 ++++--
 5 files changed, 85 insertions(+), 27 deletions(-)

diff --git a/phpinspect-buffer.el b/phpinspect-buffer.el
index 3f1338a84d..d407f92188 100644
--- a/phpinspect-buffer.el
+++ b/phpinspect-buffer.el
@@ -60,6 +60,7 @@ emacs buffer."
   (-tokens nil)
   (last-change nil :type phpinspect-change)
   (token-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
+  (reindex-after-import (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
   (-project nil
             :type phpinspect-project))
 
@@ -260,8 +261,6 @@ tokens that have been deleted from a buffer."
         (phpinspect-buffer-token-index buffer)
         (make-hash-table :test 'eq :size 100 :rehash-size 1.5)))
 
-
-
 (defun phpinspect-buffer-state (buffer)
   (interactive (list (or phpinspect-current-buffer
                          (error "Not a phpinspect buffer"))))
@@ -504,6 +503,12 @@ DECLARATION must be an object of type `phpinspect-meta'."
                      (phpinspect-buffer-get-resolvecontext
                       buffer (phpinspect-meta-start statement-end)))))
 
+          ;; When type is unknown, a change of local imports could result in a
+          ;; properly resolved type. Register token for reindexation upon index
+          ;; change.
+          (when (phpinspect--type= phpinspect--unknown-type type)
+            (puthash (phpinspect-meta-token this) this 
(phpinspect-buffer-reindex-after-import buffer)))
+
           (if-let ((prop (phpi-typedef-get-property typedef accessor-name)))
               (progn
                 (setf (phpi-prop-type prop) type)
@@ -524,9 +529,6 @@ DECLARATION must be an object of type `phpinspect-meta'."
             (phpinspect-buffer-set-index-reference-for-token buffer 
(phpinspect-meta-token this) index-ref)
             (phpinspect-buffer-set-index-reference-for-token buffer 
(phpinspect-meta-token accessor) index-ref)))))))
 
-
-
-
 (defun phpinspect-buffer--index-class-variable (buffer var)
   (let ((class (phpinspect-buffer-find-token-ancestor-matching buffer var 
#'phpinspect-class-p))
         scope static comment-before)
@@ -731,6 +733,14 @@ If provided, PROJECT must be an instance of 
`phpinspect-project'."
   (-deletions nil :type list)
   (-additions (make-hash-table :test #'eq) :type hash-table))
 
+(cl-defstruct (phpinspect-index-context
+               (:constructor phpi-make-sidc)
+               (:conc-name phpi-sidc-))
+  (imports-changed nil
+                   :documentation
+                   "Set to `t' when new/deleted imports were encountered during
+indexation"))
+
 (defun phpi--append-token-metadata-to-hash-table (table metadata)
   (dolist (meta metadata)
     (puthash (phpinspect-meta-token meta) meta table)))
@@ -883,13 +893,33 @@ If provided, PROJECT must be an instance of 
`phpinspect-project'."
                            class #'phpinspect-class-declaration-p)))
     (phpinspect-buffer--index-class-declaration buffer declaration 'force)))
 
-(defun phpi-shadow-process-deletions (shadow)
+(defun phpi-process-index-deletion (buffer deletion)
+  (pcase (phpinspect-meta-token deletion)
+    ((pred phpinspect--can-delete-buffer-index-for-token)
+     (phpinspect-buffer-delete-index-for-token
+      buffer (phpinspect-meta-token deletion)))
+
+    ((pred phpinspect-use-trait-p)
+     (phpi--handle-use-trait-deletion buffer deletion))))
+
+(defun phpi-shadow-process-deletions (shadow ctx)
+  "Process token deletions for SHADOW using CTX state.
+
+CTX should be an instance of `phpinspect-shadow-index-context'.
+SHADOW should be an instance of `phpinspect-shadow'."
   (let ((buffer (phpi-shadow-origin shadow))
         (additions (phpi-shadow--additions shadow)))
     ;; Process deleted tokens
     (dolist (deletion (phpi-shadow--deletions shadow))
       (phpi-progn
        (let ((token (phpinspect-meta-token deletion)))
+         ;; No need to reindex a deleted token
+         (remhash token (phpinspect-buffer-reindex-after-import buffer))
+
+         ;; An import was deleted, make context aware
+         (when (phpinspect-use-p token)
+           (setf (phpi-sidc-imports-changed ctx) t))
+
          (if (gethash token additions)
              ;; Token was deleted before it could be indexed, remove and
              ;; continue
@@ -897,14 +927,9 @@ If provided, PROJECT must be an instance of 
`phpinspect-project'."
 
            (progn
              ;; Token was indexed but has been deleted, update index 
accordingly
-             (pcase (phpinspect-meta-token deletion)
-               ((pred phpinspect--can-delete-buffer-index-for-token)
-                (phpinspect-buffer-delete-index-for-token
-                 buffer (phpinspect-meta-token deletion)))
-
-               ((pred phpinspect-use-trait-p)
-                (phpi--handle-use-trait-deletion buffer deletion)))
+             (phpi-process-index-deletion buffer deletion)
 
+             ;; Delete token reference
              (remhash (phpinspect-meta-token deletion) 
(phpinspect-buffer--tokens buffer)))))))
 
     (setf (phpi-shadow--deletions shadow) nil)))
@@ -931,7 +956,11 @@ If provided, PROJECT must be an instance of 
`phpinspect-project'."
          ((pred phpinspect-class-variable-p)
           (phpinspect-buffer--update-class-variable-fqn-type buffer token 
type)))))))
 
-(defun phpi-shadow-process-additions (shadow)
+(defun phpi-shadow-process-additions (shadow ctx)
+  "Process newly added tokens for SHADOW using CTX state.
+
+CTX should be an instance of `phpinspect-shadow-index-context'.
+SHADOW should be an instance of `phpinspect-shadow'."
   ;; Process newly parsed tokens
   (when-let ((additions (phpi-shadow--additions shadow))
              (buffer (phpi-shadow-origin shadow)))
@@ -948,7 +977,8 @@ If provided, PROJECT must be an instance of 
`phpinspect-project'."
           ((pred phpinspect-this-p)
            (phpinspect-buffer--index-this buffer addition))
           ((pred (phpinspect-use-p))
-           (phpinspect-buffer--index-use buffer addition))
+           (phpinspect-buffer--index-use buffer addition)
+           (setf (phpi-sidc-imports-changed ctx) t))
           ((or (pred phpinspect-class-variable-p)
                (pred phpinspect-const-p))
            (phpinspect-buffer--index-class-variable buffer addition)))))
@@ -956,11 +986,29 @@ If provided, PROJECT must be an instance of 
`phpinspect-project'."
 
     (setf (phpi-shadow--additions shadow) nil)))
 
+(defun phpi-process-reindex-after-import (buffer)
+  (let ((reindex-table (phpinspect-buffer-reindex-after-import buffer)))
+    ;; Reset reindex queue
+    (setf (phpinspect-buffer-reindex-after-import buffer)
+          (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
+
+  (maphash
+   (lambda (token token-meta)
+     ;; reindexation is only supported for "this" tokens now
+     (when (phpinspect-this-p token)
+       (phpi-process-index-deletion buffer token-meta)
+       (phpinspect-buffer--index-this buffer token-meta)))
+   reindex-table)))
+
 (defun phpi-shadow-update-project-index (shadow)
-  (let ((change (phpi-shadow--last-change shadow)))
+  (let ((change (phpi-shadow--last-change shadow))
+        (ctx (phpi-make-sidc)))
     (when (phpinspect-buffer-project (phpi-shadow-origin shadow))
-      (phpi-shadow-process-deletions shadow)
-      (phpi-shadow-process-additions shadow)
+      (phpi-shadow-process-deletions shadow ctx)
+      (phpi-shadow-process-additions shadow ctx)
+
+      (when (phpi-sidc-imports-changed ctx)
+        (phpi-process-reindex-after-import (phpi-shadow-origin shadow)))
 
       (setf (phpi-shadow--indexed-change shadow) change))))
 
diff --git a/phpinspect-resolve.el b/phpinspect-resolve.el
index 4cdc2708db..2dfde7399f 100644
--- a/phpinspect-resolve.el
+++ b/phpinspect-resolve.el
@@ -150,9 +150,6 @@ Destructively removes tokens from the end of 
ASSIGNMENT-TOKENS."
     (pop statement))
   statement)
 
-(defsubst phpinspect-get-cached-project-class (rctx class-fqn)
-  (phpinspect-project-get-typedef-or-extra (phpinspect--resolvecontext-project 
rctx) class-fqn))
-
 (defun phpinspect-get-cached-project-typedef-methods (rctx class-fqn &optional 
static)
     (phpinspect--log "Getting cached project class methods for %s"
                      class-fqn)
@@ -281,7 +278,7 @@ value/type of ->bar must be derived from the type of $foo. 
So
             ((and type-before (phpinspect-array-p current-token))
              (setq type-before
                    (phpinspect--type-contains type-before)))
-            ((t (setq type-before nil)))))
+            (t (setq type-before nil))))
     (phpinspect--log "Found derived type: %s" type-before)
     ;; Make sure to always return a FQN
     (if type-before
diff --git a/phpinspect-resolvecontext.el b/phpinspect-resolvecontext.el
index fc3ade61df..e480f400f4 100644
--- a/phpinspect-resolvecontext.el
+++ b/phpinspect-resolvecontext.el
@@ -219,10 +219,10 @@ accompanied by all of its enclosing tokens."
 
     resolvecontext)))
 
-(defun phpinspect-rctx-get-typedef (rctx class-fqn &optional no-enqueue)
+(defun phpinspect-rctx-get-typedef (rctx class-fqn &optional _ignored)
   (cl-assert (phpinspect--resolvecontext-p rctx))
   (let ((project (phpinspect--resolvecontext-project rctx)))
-    (phpinspect-project-get-typedef-extra-or-create project class-fqn 
no-enqueue)))
+    (phpinspect-project-get-typedef-extra-or-create project class-fqn 
'no-enqueue)))
 
 (defun phpinspect-rctx-get-function-return-type (rctx function-name)
   (cl-assert (phpinspect--resolvecontext-p rctx))
diff --git a/test/phpinspect-test-env.el b/test/phpinspect-test-env.el
index 912daba08f..4d560971a1 100644
--- a/test/phpinspect-test-env.el
+++ b/test/phpinspect-test-env.el
@@ -96,4 +96,12 @@
   (phpinspect-parse-file
    (concat phpinspect-test-php-file-directory "/" name ".php")))
 
+(ert-deftest phpinspect-test-env-dummy-project-indexation ()
+  (let ((project (phpinspect--make-dummy-composer-project-with-code))
+        typedef)
+
+    (should (setq typedef (phpinspect-project-get-typedef-create project 
(phpinspect--make-type :name "\\App\\Barry") 'no-enqueue)))
+    (should (phpi-typedef-get-methods typedef))))
+
+
 (provide 'phpinspect-test-env)
diff --git a/test/test-buffer-indexation.el b/test/test-buffer-indexation.el
index a1b583a662..1e4cb23366 100644
--- a/test/test-buffer-indexation.el
+++ b/test/test-buffer-indexation.el
@@ -88,7 +88,7 @@ class ReportTest extends TestCase
 (ert-deftest phpinspect-index-this ()
   (with-temp-buffer
     (let ((buffer (phpinspect-claim-buffer
-                   (current-buffer) (phpinspect--make-dummy-project))))
+                   (current-buffer) 
(phpinspect--make-dummy-composer-project-with-code))))
 
       (insert "<?php
 
@@ -123,10 +123,15 @@ class A
 
         (should (setq property (phpi-typedef-get-property typedef "harry")))
 
-        (should (phpinspect--type= phpinspect--unknown-type (phpi-prop-type 
property)))))))
-
+        (should (phpinspect--type= phpinspect--unknown-type (phpi-prop-type 
property)))
 
+        ;; Adds import for "Barry"
+        (phpinspect-fix-imports)
+        (phpinspect-buffer-update-project-index buffer)
 
+        (should (setq property (phpi-typedef-get-property typedef "harry")))
+        (should (phpinspect--type= (phpinspect--make-type :name "\\App\\Harry")
+                                   (phpi-prop-type property)))))))
 
 
 (provide 'test-buffer-indexation)

Reply via email to