emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/phpinspect 81919175ca 1/4: Implement stub index for bui


From: ELPA Syncer
Subject: [elpa] externals/phpinspect 81919175ca 1/4: Implement stub index for builtin functions and types
Date: Sun, 20 Aug 2023 12:58:38 -0400 (EDT)

branch: externals/phpinspect
commit 81919175cab362a4c403275f8ff013f698ca6e4b
Author: Hugo Thunnissen <devel@hugot.nl>
Commit: Hugo Thunnissen <devel@hugot.nl>

    Implement stub index for builtin functions and types
    
    Misc:
    - Removed Cask in favor of dependency install script
    - Rework makefile to provide simple build/install process
---
 .gitignore                   |   4 +-
 Cask                         |   4 -
 Makefile                     |  54 ++++++++---
 benchmarks/stubs.el          |  28 ++++++
 phpinspect-autoload.el       |  10 +-
 phpinspect-buffer.el         |  24 +++--
 phpinspect-cache.el          | 223 ++++++++++++++++++++++++++++++++++++------
 phpinspect-class-struct.el   |  18 +++-
 phpinspect-class.el          | 225 ++++++++++++++++++++-----------------------
 phpinspect-completion.el     |   2 +
 phpinspect-eldoc.el          |  12 ++-
 phpinspect-imports.el        |   4 +-
 phpinspect-project-struct.el |  25 ++++-
 phpinspect-project.el        | 213 +++++++++++++++++++++++++---------------
 phpinspect-resolve.el        |  12 +--
 phpinspect-serialize.el      |   6 ++
 phpinspect-suggest.el        |   9 +-
 phpinspect-type.el           |  19 +++-
 phpinspect-util.el           |  23 ++++-
 phpinspect-worker.el         |  14 ++-
 phpinspect.el                |  24 ++---
 scripts/install-deps.el      |  13 +++
 test/phpinspect-test.el      |  58 -----------
 test/test-buffer.el          |   6 +-
 test/test-eldoc.el           |  91 ++++++++++-------
 test/test-index.el           |   4 +-
 26 files changed, 717 insertions(+), 408 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8267c9df55..8e7c53117b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
 *.elc
 /benchmarks/profile.txt
-/.cask
+/.deps
+/data
+
 
 # ELPA-generated files
 /phpinspect-autoloads.el
diff --git a/Cask b/Cask
deleted file mode 100644
index 559671e53c..0000000000
--- a/Cask
+++ /dev/null
@@ -1,4 +0,0 @@
-(source gnu)
-(source melpa)
-
-(package-file "phpinspect.el")
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 8e0b8db854..aef4d3c0e5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,27 +1,49 @@
 export EMACS ?= $(shell which emacs)
 CASK_DIR := $(shell cask package-directory)
 
-$(CASK_DIR): Cask
-       cask install
-       @touch $(CASK_DIR)
+ELC_FILES = $(patsubst %.el, %.elc, $(shell ls -1 ./*.el ./test/*.el 
./benchmarks/*.el))
+DEP_DIRECTORY = $(CURDIR)/.deps
+RUN_EMACS := emacs -batch -L $(CURDIR) --eval '(package-initialize)'
 
-.PHONY: cask
-cask: $(CASK_DIR)
+export HOME = ${DEP_DIRECTORY}
+
+$(CURDIR): deps
+$(CURDIR):$(ELC_FILES)
+$(CURDIR): ./data/builtin-stubs-index.eld.gz
+
+./.deps: ./phpinspect.el
+./.deps:
+       emacs -batch -l ./scripts/install-deps.el
+
+./stubs/builtins.php: ./scripts/generate-builtin-stubs.php
+       mkdir -p ./stubs/
+       php ./scripts/generate-builtin-stubs.php > ./stubs/builtins.php
+
+./data/builtin-stubs-index.eld.gz: ./stubs/builtins.php | ./.deps
+       mkdir -p ./data/
+       $(RUN_EMACS) -l phpinspect-cache -f phpinspect-dump-stub-index
+
+%.elc: %.el
+       $(RUN_EMACS) --eval '(setq byte-compile-error-on-warn t)' -f 
batch-byte-compile $<
+
+.PHONY: deps
+deps: ./.deps
+
+.PHONY: stub-index
+stub-index: ./data/builtin-stubs-index.eld.gz
+
+.PHONY: clean
+clean:
+       rm -f $(ELC_FILES) ./stubs/builtins.php 
./data/builtin-stubs-index.eld.gz
 
 .PHONY: compile
-compile: cask
-compile: generate-stubs
-       bash ./scripts/compile.bash
+compile: ./.deps
+compile: $(ELC_FILES)
 
 .PHONY: compile-native
-compile-native: cask
-compile-native: generate-stubs
+compile-native: ./.deps
        bash ./scripts/native-compile.bash
 
-.PHONY: generate-stubs
-generate-stubs: cask
-       php ./scripts/generate-builtin-stubs.php > ./stubs/builtins.php
-
 .PHONY: test
-test: compile
-       cask emacs --batch -L . -L test -l ./test/phpinspect-test.el e -f 
ert-run-tests-batch
+test: deps
+       $(RUN_EMACS) -L ./test -l ./test/phpinspect-test e -f 
ert-run-tests-batch
diff --git a/benchmarks/stubs.el b/benchmarks/stubs.el
new file mode 100644
index 0000000000..ed2c4862a2
--- /dev/null
+++ b/benchmarks/stubs.el
@@ -0,0 +1,28 @@
+
+(require 'phpinspect-cache)
+
+(let (result)
+
+  (message "Building and loading stub cache")
+  (garbage-collect)
+  (setq result
+        (benchmark-run 1 (phpinspect-build-stub-cache)))
+  (message "Elapsed time: %f (%f in %d GC's)" (car result) (caddr result) 
(cadr result))
+
+  (message "Building stub cache")
+  (garbage-collect)
+  (setq result
+        (benchmark-run 1 (phpinspect-build-stub-index)))
+  (message "Elapsed time: %f (%f in %d GC's)" (car result) (caddr result) 
(cadr result))
+
+  (message "Building and dumping stub cache")
+  (garbage-collect)
+  (setq result
+        (benchmark-run 1 (phpinspect-dump-stub-index)))
+  (message "Elapsed time: %f (%f in %d GC's)" (car result) (caddr result) 
(cadr result))
+
+  (message "Loading stub cache")
+  (garbage-collect)
+  (setq result
+        (benchmark-run 1 (phpinspect-load-stub-index)))
+  (message "Elapsed time: %f (%f in %d GC's)" (car result) (caddr result) 
(cadr result)))
diff --git a/phpinspect-autoload.el b/phpinspect-autoload.el
index db57e9aedf..b95e560a59 100644
--- a/phpinspect-autoload.el
+++ b/phpinspect-autoload.el
@@ -167,9 +167,9 @@ bareword typenames."))
     (phpinspect-pipeline (phpinspect-files-list strat)
       :into (funcall :with-context indexer))))
 
-(cl-defmethod phpinspect-autoloader-put-type-bag ((al phpinspect-autoloader) 
(type-fqn symbol))
+(cl-defmethod phpinspect-autoloader-put-type-bag ((al phpinspect-autoloader) 
(type-fqn (head phpinspect-name)))
   (let* ((type-name (phpinspect-intern-name
-                     (car (last (split-string (symbol-name type-fqn) 
"\\\\")))))
+                     (car (last (split-string (phpinspect-name-string 
type-fqn) "\\\\")))))
          (bag (gethash type-name (phpinspect-autoloader-type-name-fqn-bags 
al))))
     (if bag
         (push type-fqn bag)
@@ -239,7 +239,7 @@ bareword typenames."))
 
 
 (cl-defmethod phpinspect-autoloader-resolve ((autoloader phpinspect-autoloader)
-                                             typename-symbol)
+                                             (typename (head phpinspect-name)))
   ;; Wait for pending refresh if not running in main thread.
   (unless (eq main-thread (current-thread))
     (when (and (phpinspect-autoloader-refresh-thread autoloader)
@@ -251,8 +251,8 @@ bareword typenames."))
       (phpinspect--log "Autoload refresh completed, continuing waiting thread 
%s"
                        (thread-name (current-thread)))))
 
-  (or (gethash typename-symbol (phpinspect-autoloader-own-types autoloader))
-      (gethash typename-symbol (phpinspect-autoloader-types autoloader))))
+  (or (gethash typename (phpinspect-autoloader-own-types autoloader))
+      (gethash typename (phpinspect-autoloader-types autoloader))))
 
 (cl-defmethod phpinspect-autoloader-refresh ((autoloader 
phpinspect-autoloader) &optional async-callback)
   "Refresh autoload definitions by reading composer.json files
diff --git a/phpinspect-buffer.el b/phpinspect-buffer.el
index 33a35cde97..abc81ec723 100644
--- a/phpinspect-buffer.el
+++ b/phpinspect-buffer.el
@@ -63,11 +63,17 @@ emacs buffer."
   (functions nil
              :type phpinspect-toc)
   (token-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
-  (project nil
-           :type phpinspect-project)
+  (-project nil
+            :type phpinspect-project)
   (edit-tracker (phpinspect-make-edtrack)
                 :type phpinspect-edtrack))
 
+(defun phpinspect-buffer-project (buffer)
+  (or (phpinspect-buffer--project buffer)
+      (with-current-buffer (phpinspect-buffer-buffer buffer)
+        (phpinspect--cache-get-project-create 
(phpinspect--get-or-create-global-cache)
+                                              
(phpinspect-current-project-root)))))
+
 (cl-defmethod phpinspect-buffer-parse ((buffer phpinspect-buffer) &optional 
no-interrupt)
   "Parse the PHP code in the the emacs buffer that this object is
 linked with."
@@ -96,8 +102,6 @@ linked with."
     (setq tree (phpinspect-buffer-tree buffer)))
   tree))
 
-
-
 (cl-defmethod phpinspect-buffer-get-index-for-token ((buffer 
phpinspect-buffer) token)
   (gethash token (phpinspect-buffer-token-index buffer)))
 
@@ -388,7 +392,8 @@ linked with."
                                                                
:enclosing-metadata (list class))))
               (setf (phpinspect--variable-type indexed)
                     (phpinspect-get-pattern-type-in-block
-                     rctx (phpinspect--make-pattern :m `(:variable "this") :m 
`(:object-attrib (:word ,(cadr var))))
+                     rctx (phpinspect--make-pattern :m `(:variable "this")
+                                                    :m `(:object-attrib (:word 
,(cadr (phpinspect-meta-token var)))))
                      (phpinspect-function-block (phpinspect--function-token 
constructor))
                      type-resolver
                      (phpinspect-function-argument-list 
(phpinspect--function-token constructor))))))
@@ -400,12 +405,17 @@ linked with."
            buffer (phpinspect-meta-token var)
            (cons (phpinspect--class-name class-obj) indexed)))))))
 
-(cl-defmethod phpinspect-buffer-reparse ((buffer phpinspect-buffer))
+(cl-defmethod phpinspect-buffer-reset ((buffer phpinspect-buffer))
   (setf (phpinspect-buffer-tree buffer) nil)
   (setf (phpinspect-buffer-map buffer) (phpinspect-make-bmap))
   (setf (phpinspect-buffer-declarations buffer) nil)
   (setf (phpinspect-buffer-imports buffer) nil)
-  (phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer))
+  (setf (phpinspect-buffer-token-index buffer)
+        (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
+  (phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer)))
+
+(cl-defmethod phpinspect-buffer-reparse ((buffer phpinspect-buffer))
+  (phpinspect-buffer-reset buffer)
   (phpinspect-buffer-parse buffer 'no-interrupt))
 
 (cl-defmethod phpinspect-buffer-update-project-index ((buffer 
phpinspect-buffer))
diff --git a/phpinspect-cache.el b/phpinspect-cache.el
index cc842bf18d..6287188c21 100644
--- a/phpinspect-cache.el
+++ b/phpinspect-cache.el
@@ -27,21 +27,110 @@
 (require 'phpinspect-autoload)
 (require 'phpinspect-worker)
 
+(defcustom phpinspect-load-stubs t
+  "If and when phpinspect should load code stubs."
+  :type '(choice
+          (const
+           :tag
+           "Load stubs on first mode init." t)
+          (const
+           :tag
+           "Never load stubs." nil))
+  :group 'phpinspect)
+
+(defvar phpinspect-buffers (make-hash-table :test #'eq)
+  "All buffers for which `phpinspect-mode' is currently active.
+
+Hash table with buffer (native emacs buffer object, `bufferp') as
+key, and a reset-function as value. The reset-function is called
+without arguments when the cache is purged (see
+`phpinspect-purge-cache'.")
+
+(defun phpinspect-register-current-buffer (reset-func)
+  (puthash (current-buffer) reset-func phpinspect-buffers))
+
+(defun phpinspect-unregister-current-buffer ()
+  (remhash (current-buffer) phpinspect-buffers))
+
+(defvar phpinspect-stub-cache nil
+  "An instance of `phpinspect--cache' containing an index of PHP
+functions and classes which phpinspect preloads. This index is
+not supposed to be mutated after initial creation.")
+
+(defmacro phpinspect--cache-edit (cache &rest body)
+  (declare (indent 1))
+  `(unless (phpinspect--cache-read-only-p ,cache)
+     ,@body))
+
 (defvar phpinspect-cache nil
   "An object used to store and access metadata of PHP projects.")
 
 (cl-defstruct (phpinspect--cache (:constructor phpinspect--make-cache))
+  (read-only-p nil
+               :type boolean
+               :documentation
+               "Whether this cache instance is read-only, meaning that it's 
data
+should never be changed.
+
+When the value of this slot is non-nil:
+
+- Actions that would normally mutate it's data should become
+no-ops.
+- All projects that are retrieved from it should be marked as read-only as 
well.")
+  (extra-class-retriever nil
+                         :type lambda
+                         :documentation
+                         "A function that should accept a `phpinspect--type' 
and return
+matching `phpinspect--class' instances or nil. Used to discover
+classes that are defined outside of code that this cache knows about.")
+  (extra-function-retriever nil
+                            :type lambda
+                            :documentation
+                            "A function that should accept a `phpinspect-name' 
(see
+`phpinspect-intern-name') and return matching
+`phpinspect--function' instances or nil. Used to discover
+functions that are defined outside of code that this cache knows
+about.")
   (projects (make-hash-table :test 'equal :size 10)
             :type hash-table
             :documentation
             "A `hash-table` with the root directories of projects
 as keys and project caches as values."))
 
+(defun phpinspect--get-stub-class (fqn)
+  (when phpinspect-stub-cache
+    (phpinspect--log "Getting stub class")
+    (catch 'return
+      (maphash (lambda (_name project)
+                 (when-let ((class (phpinspect-project-get-class project fqn)))
+                   (throw 'return class)))
+               (phpinspect--cache-projects phpinspect-stub-cache)))))
+
+(defun phpinspect--get-stub-function (name)
+  (when phpinspect-stub-cache
+    (if name
+        (catch 'return
+          (phpinspect--log "Getting stub function by name %s" name)
+          (maphash (lambda (_name project)
+                     (when-let ((class (phpinspect-project-get-function 
project name)))
+                       (throw 'return class)))
+                   (phpinspect--cache-projects phpinspect-stub-cache)))
+      (let* ((funcs (cons nil nil))
+             (funcs-rear funcs))
+        (phpinspect--log "Retrieving all stub functions for nil name")
+        (maphash (lambda (_name project)
+                   (setq funcs-rear (last (nconc funcs-rear 
(phpinspect-project-get-functions project)))))
+                 (phpinspect--cache-projects phpinspect-stub-cache))
+        (cdr funcs)))))
+
 (defun phpinspect--get-or-create-global-cache ()
   "Get `phpinspect-cache'.
 If its value is nil, it is created and then returned."
   (or phpinspect-cache
-      (setq phpinspect-cache (phpinspect--make-cache))))
+      (setq phpinspect-cache
+            (phpinspect--make-cache
+             :extra-class-retriever #'phpinspect--get-stub-class
+             :extra-function-retriever #'phpinspect--get-stub-function))))
 
 (defun phpinspect-purge-cache ()
   "Assign a fresh, empty cache object to `phpinspect-cache'.
@@ -54,54 +143,73 @@ currently opened projects."
                (phpinspect-project-purge project))
              (phpinspect--cache-projects phpinspect-cache)))
 
+
+  (maphash (lambda (buffer reset-hook)
+             (with-current-buffer buffer
+               (funcall reset-hook)))
+           phpinspect-buffers)
+
   ;; Assign a fresh cache object
-  (setq phpinspect-cache (phpinspect--make-cache)))
+  (setq phpinspect-cache (phpinspect--get-or-create-global-cache))
+  (setq phpinspect-names (phpinspect-make-name-hash))
+  (phpinspect-define-standard-types))
 
-(cl-defmethod phpinspect--cache-getproject
+(cl-defmethod phpinspect--cache-get-project
   ((cache phpinspect--cache) (project-root string))
-  (gethash project-root (phpinspect--cache-projects cache)))
+  (let ((project (gethash project-root (phpinspect--cache-projects cache))))
+    (when (and project (phpinspect--cache-read-only-p cache)
+               (not (phpinspect-project-read-only-p project)))
+      (setf (phpinspect-project-read-only-p project) t))
+
+    project))
 
 (defun phpinspect-get-or-create-cached-project-class (project-root class-fqn)
   (when project-root
     (let ((project (phpinspect--cache-get-project-create
                     (phpinspect--get-or-create-global-cache)
                     project-root)))
-      (phpinspect-project-get-class-create project class-fqn))))
+      (phpinspect-project-get-class-extra-or-create project class-fqn))))
 
 (cl-defmethod phpinspect--cache-get-project-create
   ((cache phpinspect--cache) (project-root string))
     "Get a project that is located in PROJECT-ROOT from CACHE.
 If no such project exists in the cache yet, it is created and
 then returned."
-  (let ((project (phpinspect--cache-getproject cache project-root)))
+  (let ((project (phpinspect--cache-get-project cache project-root)))
     (unless project
-      (setq project (puthash project-root
-                             (phpinspect--make-project
-                              :fs (phpinspect-make-fs)
-                              :root project-root
-                              :worker (phpinspect-make-dynamic-worker))
-                             (phpinspect--cache-projects cache)))
-      (let ((autoloader (phpinspect-make-autoloader
-                         :fs (phpinspect-project-fs project)
-                         :file-indexer (phpinspect-project-make-file-indexer 
project)
-                         :project-root-resolver 
(phpinspect-project-make-root-resolver project))))        (setf 
(phpinspect-project-autoload project) autoloader)
-        (phpinspect-autoloader-refresh autoloader)
-        (phpinspect-project-enqueue-include-dirs project)))
+      (phpinspect--cache-edit cache
+        (setq project
+              (puthash project-root
+                       (phpinspect--make-project
+                        :fs (phpinspect-make-fs)
+                        :root project-root
+                        :extra-class-retriever 
(phpinspect--cache-extra-class-retriever cache)
+                        :extra-function-retriever 
(phpinspect--cache-extra-function-retriever cache)
+                        :worker (phpinspect-make-dynamic-worker))
+                       (phpinspect--cache-projects cache)))
+        (let ((autoloader (phpinspect-make-autoloader
+                           :fs (phpinspect-project-fs project)
+                           :file-indexer (phpinspect-project-make-file-indexer 
project)
+                           :project-root-resolver 
(phpinspect-project-make-root-resolver project))))
+          (setf (phpinspect-project-autoload project) autoloader)
+          (phpinspect-autoloader-refresh autoloader)
+          (phpinspect-project-enqueue-include-dirs project))))
     project))
 
 (defun phpinspect-project-enqueue-include-dirs (project)
   (interactive (list (phpinspect--cache-get-project-create
                       (phpinspect--get-or-create-global-cache)
                       (phpinspect-current-project-root))))
-  (let ((dirs (alist-get 'include-dirs
-                         (alist-get (phpinspect-project-root project)
-                                    phpinspect-projects
-                                    nil nil #'string=))))
-    (dolist (dir dirs)
-      (message "enqueueing dir %s" dir)
-      (phpinspect-worker-enqueue
-       (phpinspect-project-worker project)
-       (phpinspect-make-index-dir-task :dir dir :project project)))))
+  (phpinspect-project-edit project
+    (let ((dirs (alist-get 'include-dirs
+                           (alist-get (phpinspect-project-root project)
+                                      phpinspect-projects
+                                      nil nil #'string=))))
+      (dolist (dir dirs)
+        (message "enqueueing dir %s" dir)
+        (phpinspect-worker-enqueue
+         (phpinspect-project-worker project)
+         (phpinspect-make-index-dir-task :dir dir :project project))))))
 
 (defun phpinspect-project-add-include-dir (dir)
   "Configure DIR as an include dir for the current project."
@@ -119,5 +227,64 @@ then returned."
                                             
(phpinspect--get-or-create-global-cache)
                                             
(phpinspect-current-project-root))))
 
-(provide 'phpinspect-cache)
+(defconst phpinspect-stub-directory
+  (expand-file-name  "stubs" (file-name-directory (macroexp-file-name)))
+  "Directory where PHP stub files are located.")
+
+(defconst phpinspect-data-directory
+  (expand-file-name  "data" (file-name-directory (macroexp-file-name)))
+  "Directory for data distributed with phpinspect.")
+
+(defconst phpinspect-stub-cache-file
+  (expand-file-name "builtin-stubs.eld" phpinspect-data-directory)
+  "")
+
+(defconst phpinspect-builtin-index-file
+  (expand-file-name (concat "builtin-stubs-index.eld" (if (zlib-available-p) 
".gz" ""))
+                    phpinspect-data-directory)
+  "")
+
+(defun phpinspect-build-stub-cache ()
+  (let* ((cache (phpinspect--make-cache))
+         (builtin-project (phpinspect--cache-get-project-create cache 
"builtins"))
+         (phpinspect-worker 'nil-worker))
+    (phpinspect-project-add-index builtin-project 
(phpinspect-build-stub-index))))
+
+(defun phpinspect-build-stub-index ()
+  (phpinspect--index-tokens (phpinspect-parse-file (expand-file-name 
"builtins.php" phpinspect-stub-directory))))
+
+(defun phpinspect-dump-stub-index ()
+  (interactive)
+  (let* ((phpinspect-names (phpinspect-make-name-hash))
+         (index (phpinspect-build-stub-index)))
+    (with-temp-buffer
+      (let ((print-length nil)
+            (print-level nil)
+            (print-circle t))
+
+        (prin1 (list (cons 'names phpinspect-names)
+                     (cons 'index index))
+               (current-buffer))
+        (write-file phpinspect-builtin-index-file)))))
+
+(defun phpinspect-load-stub-index ()
+  (interactive)
+  (unless (file-exists-p phpinspect-builtin-index-file)
+    (phpinspect-message "No stub index dump found, dumping stub index ...")
+    (phpinspect-dump-stub-index))
+
+  (let* ((data (with-temp-buffer
+                 (insert-file-contents phpinspect-builtin-index-file)
+                 (goto-char (point-min))
+                 (read (current-buffer))))
+         (project (phpinspect--make-project :worker 'nil-worker)))
+    (phpinspect-purge-cache)
+    (setq phpinspect-names (alist-get 'names data))
+    (phpinspect-define-standard-types)
+    (setq phpinspect-stub-cache (phpinspect--make-cache))
+    (phpinspect-project-add-index project (alist-get 'index data))
+    (puthash "builtins" project (phpinspect--cache-projects 
phpinspect-stub-cache))
+    (setf (phpinspect--cache-read-only-p phpinspect-stub-cache) t)))
+
 ;;; phpinspect.el ends here
+(provide 'phpinspect-cache)
diff --git a/phpinspect-class-struct.el b/phpinspect-class-struct.el
index bbfa1236a6..56057c69d2 100644
--- a/phpinspect-class-struct.el
+++ b/phpinspect-class-struct.el
@@ -25,10 +25,19 @@
 
 
 (cl-defstruct (phpinspect--class (:constructor 
phpinspect--make-class-generated))
-  (project nil
-           :type phpinspect-project
-           :documentaton
-           "The project that this class belongs to")
+  (class-retriever nil
+                   :type lambda
+                   :documentaton
+                   "A function that returns classes for types
+(should accept `phpinspect--type' as argument)")
+
+  (read-only-p nil
+               :type boolean
+               :documentation
+               "Whether this class instance is read-only, meaning that its data
+should never be changed. Methods and functions that are meant to
+manipulate class data should become no-ops when this slot has a
+non-nil value.")
   (index nil
          :type phpinspect--indexed-class
          :documentation
@@ -65,4 +74,5 @@
                  "A boolean indicating whether or not this class
                  has been indexed yet."))
 
+
 (provide 'phpinspect-class-struct)
diff --git a/phpinspect-class.el b/phpinspect-class.el
index 1144825537..2e18713783 100644
--- a/phpinspect-class.el
+++ b/phpinspect-class.el
@@ -24,85 +24,55 @@
 ;;; Code:
 
 (require 'phpinspect-type)
+(require 'phpinspect-class-struct)
 
-(cl-defstruct (phpinspect--class (:constructor 
phpinspect--make-class-generated))
-  (class-retriever nil
-                   :type lambda
-                   :documentaton
-                   "A function that returns classes for types
-(should accept `phpinspect--type' as argument)")
-  (index nil
-         :type phpinspect--indexed-class
-         :documentation
-         "The index that this class is derived from")
-  (methods (make-hash-table :test 'eq :size 20 :rehash-size 20)
-           :type hash-table
-           :documentation
-           "All methods, including those from extended classes.")
-  (static-methods (make-hash-table :test 'eq :size 20 :rehash-size 20)
-                  :type hash-table
-                  :documentation
-                  "All static methods this class provides,
-                  including those from extended classes.")
-  (name nil
-        :type phpinspect--type)
-  (variables nil
-             :type list
-             :documentation
-             "Variables that belong to this class.")
-  (extended-classes nil
-                    :type list
-                    :documentation
-                    "All extended/implemented classes.")
-  (subscriptions (make-hash-table :test #'eq :size 10 :rehash-size 1.5)
-                 :type hash-table
-                 :documentation
-                 "A list of subscription functions that should be
-                 called whenever anything about this class is
-                 updated")
-  (declaration nil)
-  (initial-index nil
-                 :type bool
-                 :documentation
-                 "A boolean indicating whether or not this class
-                 has been indexed yet."))
+(defmacro phpinspect--class-edit (class &rest body)
+  "Declare intent to edit CLASS in BODY.
+
+Conditionally executes BODY depending on
+`phpinspect--class-read-only-p' value."
+  (declare (indent 1))
+  `(unless (phpinspect--class-read-only-p ,class)
+     ,@body))
 
 (cl-defmethod phpinspect--class-trigger-update ((class phpinspect--class))
   (dolist (sub (hash-table-values (phpinspect--class-subscriptions class)))
     (funcall sub class)))
 
 (cl-defmethod phpinspect--class-update-extensions ((class phpinspect--class) 
extensions)
-  (setf (phpinspect--class-extended-classes class)
-        (seq-filter
-         #'phpinspect--class-p
-         (mapcar
-          (lambda (class-name)
-            (funcall (phpinspect--class-class-retriever class) class-name))
-          extensions)))
+  (phpinspect--class-edit class
+    (setf (phpinspect--class-extended-classes class)
+          (seq-filter
+           #'phpinspect--class-p
+           (mapcar
+            (lambda (class-name)
+              (funcall (phpinspect--class-class-retriever class) class-name))
+            extensions)))
 
-  (dolist (extended (phpinspect--class-extended-classes class))
-    (phpinspect--class-incorporate class extended)))
+    (dolist (extended (phpinspect--class-extended-classes class))
+      (phpinspect--class-incorporate class extended))))
 
 
 (cl-defmethod phpinspect--class-set-index ((class phpinspect--class)
                                            (index (head 
phpinspect--indexed-class)))
-  (setf (phpinspect--class-declaration class) (alist-get 'declaration index))
-  (setf (phpinspect--class-name class) (alist-get 'class-name index))
+  (phpinspect--class-edit class
+    (setf (phpinspect--class-declaration class) (alist-get 'declaration index))
+    (setf (phpinspect--class-name class) (alist-get 'class-name index))
 
-  ;; Override methods when class seems syntactically correct (has balanced 
braces)
-  (when (alist-get 'complete index)
-    (let ((methods (phpinspect--class-methods class))
-          (static-methods (phpinspect--class-static-methods class)))
+    ;; Override methods when class seems syntactically correct (has balanced 
braces)
+    (when (alist-get 'complete index)
+      (let ((methods (phpinspect--class-methods class))
+            (static-methods (phpinspect--class-static-methods class)))
 
-      (dolist (method (hash-table-values methods))
-        (unless (phpinspect--function--inherited method)
-          (remhash (phpinspect--function-name-symbol method) methods)))
-      (dolist (method (hash-table-values static-methods))
-        (unless (phpinspect--function--inherited method)
-          (remhash (phpinspect--function-name-symbol method) 
static-methods)))))
+        (dolist (method (hash-table-values methods))
+          (unless (phpinspect--function--inherited method)
+            (remhash (phpinspect--function-name-symbol method) methods)))
+        (dolist (method (hash-table-values static-methods))
+          (unless (phpinspect--function--inherited method)
+            (remhash (phpinspect--function-name-symbol method) 
static-methods)))))
 
-  (setf (phpinspect--class-initial-index class) t)
-  (setf (phpinspect--class-index class) index)
+    (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))
@@ -118,22 +88,23 @@
   (phpinspect--class-update-extensions
    class `(,@(alist-get 'implements index) ,@(alist-get 'extends index)))
 
-  (phpinspect--class-trigger-update class))
+  (phpinspect--class-trigger-update class)))
 
 (cl-defmethod phpinspect--class-update-declaration
   ((class phpinspect--class) declaration imports namespace-name)
-  (pcase-let ((`(,class-name ,extends ,implements ,_used-types)
-               (phpinspect--index-class-declaration
-                declaration (phpinspect--make-type-resolver
-                             (phpinspect--uses-to-types imports) nil 
namespace-name))))
-    (setf (phpinspect--class-name class) class-name)
-    (setf (phpinspect--class-declaration class) declaration)
-    (phpinspect--class-update-extensions class `(,@extends ,@implements))))
-
-(cl-defmethod phpinspect--class-get-method ((class phpinspect--class) 
(method-name symbol))
+  (phpinspect--class-edit class
+    (pcase-let ((`(,class-name ,extends ,implements ,_used-types)
+                 (phpinspect--index-class-declaration
+                  declaration (phpinspect--make-type-resolver
+                               (phpinspect--uses-to-types imports) nil 
namespace-name))))
+      (setf (phpinspect--class-name class) class-name)
+      (setf (phpinspect--class-declaration class) declaration)
+      (phpinspect--class-update-extensions class `(,@extends ,@implements)))))
+
+(cl-defmethod phpinspect--class-get-method ((class phpinspect--class) 
(method-name (head phpinspect-name)))
   (gethash method-name (phpinspect--class-methods class)))
 
-(cl-defmethod phpinspect--class-get-static-method ((class phpinspect--class) 
(method-name symbol))
+(cl-defmethod phpinspect--class-get-static-method ((class phpinspect--class) 
(method-name (head phpinspect-name)))
   (gethash method-name (phpinspect--class-static-methods class)))
 
 (cl-defmethod phpinspect--class-get-variable
@@ -145,13 +116,15 @@
 
 (cl-defmethod phpinspect--class-set-variable ((class phpinspect--class)
                                               (var phpinspect--variable))
-  (push var (phpinspect--class-variables class)))
+  (phpinspect--class-edit class
+    (push var (phpinspect--class-variables class))))
 
 (cl-defmethod phpinspect--class-delete-variable ((class phpinspect--class)
                                                  (var phpinspect--variable))
-  (setf (phpinspect--class-variables class)
-        (seq-filter (lambda (clvar) (not (eq var clvar)))
-                    (phpinspect--class-variables class))))
+  (phpinspect--class-edit class
+    (setf (phpinspect--class-variables class)
+          (seq-filter (lambda (clvar) (not (eq var clvar)))
+                      (phpinspect--class-variables class)))))
 
 (cl-defmethod phpinspect--class-get-variables ((class phpinspect--class))
   (seq-filter #'phpinspect--variable-vanilla-p (phpinspect--class-variables 
class)))
@@ -179,34 +152,35 @@
 
 (cl-defmethod phpinspect--class-set-method ((class phpinspect--class)
                                             (method phpinspect--function))
-  (phpinspect--log "Adding method by name %s to class"
-                   (phpinspect--function-name method))
-  (phpinspect--add-method-copy-to-map
-   (phpinspect--class-methods class)
-   (phpinspect--class-name class)
-   method))
-
+  (phpinspect--class-edit class
+    (phpinspect--log "Adding method by name %s to class"
+                     (phpinspect--function-name method))
+    (phpinspect--add-method-copy-to-map
+     (phpinspect--class-methods class)
+     (phpinspect--class-name class)
+     method)))
 
 (cl-defmethod phpinspect--class-set-static-method ((class phpinspect--class)
                                                    (method 
phpinspect--function))
-  (phpinspect--add-method-copy-to-map
-   (phpinspect--class-static-methods class)
-   (phpinspect--class-name class)
-   method))
-
+  (phpinspect--class-edit class
+    (phpinspect--add-method-copy-to-map
+     (phpinspect--class-static-methods class)
+     (phpinspect--class-name class)
+     method)))
 
 (cl-defmethod phpinspect--class-delete-method ((class phpinspect--class) 
(method phpinspect--function))
-  (remhash (phpinspect--function-name-symbol method) 
(phpinspect--class-static-methods class))
-  (remhash (phpinspect--function-name-symbol method) 
(phpinspect--class-methods class)))
+  (phpinspect--class-edit class
+    (remhash (phpinspect--function-name-symbol method) 
(phpinspect--class-static-methods class))
+    (remhash (phpinspect--function-name-symbol method) 
(phpinspect--class-methods class))))
 
 (cl-defmethod phpinspect--class-get-method-return-type
-  ((class phpinspect--class) (method-name symbol))
+  ((class phpinspect--class) (method-name (head phpinspect-name)))
   (let ((method (phpinspect--class-get-method class method-name)))
     (when method
       (phpinspect--function-return-type method))))
 
 (cl-defmethod phpinspect--class-get-static-method-return-type
-  ((class phpinspect--class) (method-name symbol))
+  ((class phpinspect--class) (method-name (head phpinspect-name)))
   (let ((method (phpinspect--class-get-static-method class method-name)))
     (when method
       (phpinspect--function-return-type method))))
@@ -240,49 +214,54 @@
 (cl-defmethod phpinspect--class-update-static-method ((class phpinspect--class)
                                                       (method 
phpinspect--function)
                                                       &optional extended)
-  (let ((existing (gethash (phpinspect--function-name-symbol method)
-                           (phpinspect--class-static-methods class))))
-    (if existing
-        (phpinspect--merge-method
-         (alist-get 'class-name (phpinspect--class-index class))
-         existing method extended)
-      (setf (phpinspect--function--inherited method) extended)
-      (phpinspect--class-set-static-method class method))))
+  (phpinspect--class-edit class
+    (let ((existing (gethash (phpinspect--function-name-symbol method)
+                             (phpinspect--class-static-methods class))))
+      (if existing
+          (phpinspect--merge-method
+           (alist-get 'class-name (phpinspect--class-index class))
+           existing method extended)
+        (setf (phpinspect--function--inherited method) extended)
+        (phpinspect--class-set-static-method class method)))))
 
 (cl-defmethod phpinspect--class-update-method ((class phpinspect--class)
                                                (method phpinspect--function)
                                                &optional extended)
-  (let* ((existing (gethash (phpinspect--function-name-symbol method)
-                            (phpinspect--class-methods class))))
+  (phpinspect--class-edit class
+    (let* ((existing (gethash (phpinspect--function-name-symbol method)
+                              (phpinspect--class-methods class))))
 
-    (if existing
-        (phpinspect--merge-method
-         (alist-get 'class-name (phpinspect--class-index class))
-         existing method extended)
-      (setf (phpinspect--function--inherited method) extended)
-      (phpinspect--class-set-method class method))))
+      (if existing
+          (phpinspect--merge-method
+           (alist-get 'class-name (phpinspect--class-index class))
+           existing method extended)
+        (setf (phpinspect--function--inherited method) extended)
+        (phpinspect--class-set-method class method)))))
 
 ;; FIXME: Remove inherited methods when they no longer exist in parent classes
 ;; (and/or the current class in the case of abstract methods).
 (cl-defmethod phpinspect--class-incorporate ((class phpinspect--class)
                                              (other-class phpinspect--class))
-  (dolist (method (phpinspect--class-get-method-list other-class))
-    (phpinspect--class-update-method class method 'extended))
+  (phpinspect--class-edit class
+    (dolist (method (phpinspect--class-get-method-list other-class))
+      (phpinspect--class-update-method class method 'extended))
 
-  (dolist (method (phpinspect--class-get-static-method-list other-class))
-    (phpinspect--class-update-static-method class method 'extended))
+    (dolist (method (phpinspect--class-get-static-method-list other-class))
+      (phpinspect--class-update-static-method class method 'extended))
 
-    (phpinspect--class-subscribe class other-class))
+    (phpinspect--class-subscribe class other-class)))
 
 (cl-defmethod phpinspect--class-subscribe ((class phpinspect--class)
                                            (subscription-class 
phpinspect--class))
-  (unless (gethash subscription-class (phpinspect--class-subscriptions class))
-    (let ((update-function
-           (lambda (new-class)
-             (phpinspect--class-incorporate class new-class)
-             (phpinspect--class-trigger-update class))))
-      (puthash subscription-class update-function
-               (phpinspect--class-subscriptions subscription-class)))))
+  (phpinspect--class-edit class
+    (unless (gethash subscription-class (phpinspect--class-subscriptions 
class))
+      (let ((update-function
+             (lambda (new-class)
+               (phpinspect--class-edit class
+                 (phpinspect--class-incorporate class new-class)
+                 (phpinspect--class-trigger-update class)))))
+        (puthash subscription-class update-function
+                 (phpinspect--class-subscriptions subscription-class))))))
 
 (provide 'phpinspect-class)
 ;;; phpinspect-class.el ends here
diff --git a/phpinspect-completion.el b/phpinspect-completion.el
index 5f4e5ae519..b32bfeaf44 100644
--- a/phpinspect-completion.el
+++ b/phpinspect-completion.el
@@ -23,6 +23,8 @@
 
 ;;; Code:
 
+(require 'obarray)
+
 (require 'phpinspect-bmap)
 (require 'phpinspect-buffer)
 (require 'phpinspect-resolvecontext)
diff --git a/phpinspect-eldoc.el b/phpinspect-eldoc.el
index 4c24d87407..d8a85ec2c6 100644
--- a/phpinspect-eldoc.el
+++ b/phpinspect-eldoc.el
@@ -28,6 +28,9 @@
 (require 'phpinspect-resolve)
 (require 'phpinspect-buffer)
 
+(eval-when-compile
+  (phpinspect--declare-log-group 'eldoc))
+
 (defvar phpinspect-eldoc-word-width 14
   "The maximum width of words in eldoc strings.")
 
@@ -65,7 +68,7 @@ be implemented for return values of 
`phpinspect-eld-strategy-execute'")
     (setq type-before (phpinspect-resolve-type-from-context rctx))
 
     (when type-before
-      (let ((class (phpinspect-project-get-class-create
+      (let ((class (phpinspect-project-get-class-extra-or-create
                     (phpinspect--resolvecontext-project rctx)
                     type-before))
             (attribute-name (cadadr attrib))
@@ -167,15 +170,18 @@ be implemented for return values of 
`phpinspect-eld-strategy-execute'")
         (setf (phpinspect--resolvecontext-subject rctx)
               (mapcar #'phpinspect-meta-token (butlast statement 2)))
 
+
+
         (when-let* ((type-of-previous-statement
                      (phpinspect-resolve-type-from-context rctx))
                     (method-name-sym (phpinspect-intern-name (cadadr 
(phpinspect-meta-token (car match-result)))))
-                    (class (phpinspect-project-get-class-create
+                    (class (phpinspect-project-get-class-extra-or-create
                             (phpinspect--resolvecontext-project rctx)
                             type-of-previous-statement))
                     (method (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))))
        ((setq match-result (phpinspect--match-sequence (last statement 2)
@@ -191,7 +197,7 @@ be implemented for return values of 
`phpinspect-eld-strategy-execute'")
                            count))
                        (phpinspect-meta-find-children-before arg-list 
(phpinspect-eldoc-query-point q)) 0))
 
-        (let ((func (phpinspect-project-get-function
+        (let ((func (phpinspect-project-get-function-or-extra
                      (phpinspect--resolvecontext-project rctx)
                      (phpinspect-intern-name (cadr (phpinspect-meta-token (car 
match-result)))))))
           (phpinspect--log "Got past that")
diff --git a/phpinspect-imports.el b/phpinspect-imports.el
index 77fb890e51..6375f9ed2f 100644
--- a/phpinspect-imports.el
+++ b/phpinspect-imports.el
@@ -100,7 +100,7 @@ buffer position to insert the use statement at."
 
     (let ((fqns (gethash typename fqn-bags)))
       (cond ((= 1 (length fqns))
-             (phpinspect-add-use (symbol-name (car fqns)) buffer 
namespace-token))
+             (phpinspect-add-use (phpinspect-name-string (car fqns)) buffer 
namespace-token))
             ((> (length fqns) 1)
              (phpinspect-add-use (completing-read "Class: " fqns)
                                  buffer namespace-token))
@@ -122,7 +122,7 @@ buffer position to insert the use statement at."
       ;; with a fully qualified name.
       (unless (or (or (alist-get type imports))
                   (gethash (phpinspect-intern-name
-                            (concat namespace-name "\\" (symbol-name type)))
+                            (concat namespace-name "\\" 
(phpinspect-name-string type)))
                            (phpinspect-autoloader-types
                             (phpinspect-project-autoload project))))
         (phpinspect-add-use-interactive type buffer project namespace)
diff --git a/phpinspect-project-struct.el b/phpinspect-project-struct.el
index 94c51627ac..f3ee9812dc 100644
--- a/phpinspect-project-struct.el
+++ b/phpinspect-project-struct.el
@@ -26,8 +26,31 @@
 (eval-when-compile
   (declare-function phpinspect-make-dynamic-worker "phpinspect-worker.el"))
 
-
 (cl-defstruct (phpinspect-project (:constructor phpinspect--make-project))
+  (read-only-p nil
+               :type boolean
+               :documentation
+               "Whether this project instance is read-only, meaning that its 
data
+should never be changed.
+
+When this slot has a non-nil value:
+
+- Methods and functions that are meant to manipulate class data
+should become no-ops.
+- All classes retrieved from it should be marked as read-only as well.")
+  (extra-class-retriever nil
+                         :type lambda
+                         :documentation
+                         "A function that should accept a `phpinspect--type' 
and return
+matching `phpinspect--class' instances or nil. Used to discover
+classes that are defined outside of project code.")
+  (extra-function-retriever nil
+                            :type lambda
+                            :documentation
+                            "A function that should accept a `phpinspect-name' 
(see
+`phpinspect-intern-name') and return matching `phpinspect--function'
+instances or nil. Used to discover functions that are defined
+outside of project code.")
   (class-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5)
                :type hash-table
                :documentation
diff --git a/phpinspect-project.el b/phpinspect-project.el
index 0d103ebb21..a5b3764927 100644
--- a/phpinspect-project.el
+++ b/phpinspect-project.el
@@ -43,13 +43,17 @@ serious performance hits. Enable at your own risk (:")
 (defvar-local phpinspect--buffer-project nil
   "The root directory of the PHP project that this buffer belongs to")
 
+(defmacro phpinspect-project-edit (project &rest body)
+  (declare (indent 1))
+  `(unless (phpinspect-project-read-only-p ,project)
+     ,@body))
+
 (defsubst phpinspect-current-project-root ()
   "Call `phpinspect-project-root-function' with ARGS as arguments."
   (unless (and (boundp 'phpinspect--buffer-project) phpinspect--buffer-project)
     (set (make-local-variable 'phpinspect--buffer-project) (funcall 
phpinspect-project-root-function)))
   phpinspect--buffer-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))
@@ -62,72 +66,87 @@ serious performance hits. Enable at your own risk (:")
 (cl-defmethod phpinspect-project-watch-file ((project phpinspect-project)
                                               filepath
                                               callback)
-  (let ((watcher (file-notify-add-watch filepath '(change) callback)))
-    (puthash filepath watcher (phpinspect-project-file-watchers project))))
+  (phpinspect-project-edit project
+    (let ((watcher (file-notify-add-watch filepath '(change) callback)))
+      (puthash filepath watcher (phpinspect-project-file-watchers project)))))
 
 (cl-defmethod phpinspect-project-add-return-types-to-index-queueue
   ((project phpinspect-project) methods)
-  (dolist (method methods)
-    (when (phpinspect--function-return-type method)
-      (phpinspect-project-enqueue-if-not-present
-       project
-       (phpinspect--function-return-type method)))))
+  (phpinspect-project-edit project
+    (dolist (method methods)
+      (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-project-enqueue-if-not-present project 
(phpinspect--variable-type var)))))
+  (phpinspect-project-edit project
+    (dolist (var variables)
+      (when (phpinspect--variable-type var)
+        (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))
-  (unless (phpinspect--type-is-native type)
-    (let ((class (phpinspect-project-get-class project type)))
-      (when (or (not class)
-                (not (or (phpinspect--class-initial-index class))))
-        (when (not class)
-          (setq class (phpinspect-project-create-class project type)))
-        (unless (or (phpinspect--type= phpinspect--null-type type)
-                    (phpinspect--type-is-native type))
-          (phpinspect--log "Adding unpresent class %s to index queue" type)
-          (phpinspect-worker-enqueue (phpinspect-project-worker project)
-                                     (phpinspect-make-index-task project 
type)))))))
+  (phpinspect-project-edit project
+    (unless (phpinspect--type-is-native type)
+      (let ((class (phpinspect-project-get-class project type)))
+        (when (or (not class)
+                  (not (or (phpinspect--class-initial-index class))))
+          (when (not class)
+            (setq class (phpinspect-project-create-class project type)))
+          (unless (or (phpinspect--type= phpinspect--null-type type)
+                      (phpinspect--type-is-native type))
+            (phpinspect--log "Adding unpresent class %s to index queue" type)
+            (phpinspect-worker-enqueue (phpinspect-project-worker project)
+                                       (phpinspect-make-index-task project 
type))))))))
 
 (cl-defmethod phpinspect-project-add-class-attribute-types-to-index-queue
   ((project phpinspect-project) (class phpinspect--class))
-  (phpinspect-project-add-return-types-to-index-queueue
-   project
-   (phpinspect--class-get-method-list class))
-  (phpinspect-project-add-return-types-to-index-queueue
-   project
-   (phpinspect--class-get-static-method-list class))
-  (phpinspect-project-add-variable-types-to-index-queue
-   project
-   (phpinspect--class-variables class)))
+  (phpinspect-project-edit project
+    (phpinspect-project-add-return-types-to-index-queueue
+     project
+     (phpinspect--class-get-method-list class))
+    (phpinspect-project-add-return-types-to-index-queueue
+     project
+     (phpinspect--class-get-static-method-list class))
+    (phpinspect-project-add-variable-types-to-index-queue
+     project
+     (phpinspect--class-variables class))))
 
 (cl-defmethod phpinspect-project-add-index
   ((project phpinspect-project) (index (head phpinspect--root-index)) 
&optional index-imports)
-  (when index-imports
-    (phpinspect-project-enqueue-imports project (alist-get 'imports (cdr 
index))))
+  (phpinspect-project-edit project
+    (when index-imports
+      (phpinspect-project-enqueue-imports project (alist-get 'imports (cdr 
index))))
 
-  (dolist (indexed-class (alist-get 'classes (cdr index)))
-    (phpinspect-project-add-class project (cdr indexed-class) index-imports))
+    (dolist (indexed-class (alist-get 'classes (cdr index)))
+      (phpinspect-project-add-class project (cdr indexed-class) index-imports))
 
-  (dolist (func (alist-get 'functions (cdr index)))
-    (phpinspect-project-set-function project func)))
+    (dolist (func (alist-get 'functions (cdr index)))
+      (phpinspect-project-set-function project func))))
 
 (cl-defmethod phpinspect-project-set-function
   ((project phpinspect-project) (func phpinspect--function))
-  (puthash (phpinspect--function-name-symbol func) func
-           (phpinspect-project-function-index project)))
+  (phpinspect-project-edit project
+    (puthash (phpinspect--function-name-symbol func) func
+             (phpinspect-project-function-index project))))
 
 (cl-defmethod phpinspect-project-get-function
-  ((project phpinspect-project) (name symbol))
+  ((project phpinspect-project) (name (head phpinspect-name)))
   (gethash name (phpinspect-project-function-index project)))
 
+(cl-defmethod phpinspect-project-get-function-or-extra
+  ((project phpinspect-project) (name (head phpinspect-name)))
+  (or (phpinspect-project-get-function project name)
+      (and (phpinspect-project-extra-function-retriever project)
+           (funcall (phpinspect-project-extra-function-retriever project)
+                    name))))
+
 (cl-defmethod phpinspect-project-delete-function
-  ((project phpinspect-project) (name symbol))
-  (remhash name (phpinspect-project-function-index project)))
+  ((project phpinspect-project) (name (head phpinspect-name)))
+  (phpinspect-project-edit project
+    (remhash name (phpinspect-project-function-index project))))
 
 (cl-defmethod phpinspect-project-get-functions ((project phpinspect-project))
   (let ((funcs))
@@ -137,69 +156,102 @@ serious performance hits. Enable at your own risk (:")
 
     funcs))
 
+(cl-defmethod phpinspect-project-get-functions-with-extra ((project 
phpinspect-project))
+  (let ((funcs))
+    (maphash
+     (lambda (_name func) (push func funcs))
+     (phpinspect-project-function-index project))
+
+    (if (phpinspect-project-extra-function-retriever project)
+        (nconc funcs (funcall (phpinspect-project-extra-function-retriever 
project) nil))
+      funcs)))
+
 (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)))))
+  (phpinspect-project-edit project
+    (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-delete-class ((project phpinspect-project) 
(class phpinspect--class))
   (phpinspect-project-delete-class project (phpinspect--class-name class)))
 
 (cl-defmethod phpinspect-project-delete-class ((project phpinspect-project) 
(class-name phpinspect--type))
-  (remhash (phpinspect--type-name-symbol class-name) 
(phpinspect-project-class-index project)))
+  (phpinspect-project-edit project
+    (remhash (phpinspect--type-name-symbol class-name) 
(phpinspect-project-class-index project))))
 
 (cl-defmethod phpinspect-project-add-class
   ((project phpinspect-project) (indexed-class (head 
phpinspect--indexed-class)) &optional index-imports)
-  (if (not (alist-get 'class-name (cdr indexed-class)))
-      (phpinspect--log "Error: Class with declaration %s does not have a name" 
(alist-get 'declaration indexed-class))
-    ;; Else
-    (let* ((class-name (phpinspect--type-name-symbol
-                        (alist-get 'class-name (cdr indexed-class))))
-           (class (gethash class-name
-                           (phpinspect-project-class-index project))))
-      (unless class
-        (setq class (phpinspect--make-class-generated
-                     :class-retriever (phpinspect-project-make-class-retriever 
project))))
-
-      (when index-imports
-        (phpinspect-project-enqueue-imports
-         project (alist-get 'imports (cdr indexed-class))))
-
-      (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))))
+  (phpinspect-project-edit project
+    (if (not (alist-get 'class-name (cdr indexed-class)))
+        (phpinspect--log "Error: Class with declaration %s does not have a 
name" (alist-get 'declaration indexed-class))
+      ;; Else
+      (let* ((class-name (phpinspect--type-name-symbol
+                          (alist-get 'class-name (cdr indexed-class))))
+             (class (gethash class-name
+                             (phpinspect-project-class-index project))))
+        (unless class
+          (setq class (phpinspect--make-class-generated
+                       :class-retriever 
(phpinspect-project-make-class-retriever project))))
+
+        (when index-imports
+          (phpinspect-project-enqueue-imports
+           project (alist-get 'imports (cdr indexed-class))))
+
+        (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-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)))
+  (phpinspect-project-edit project
+    (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
-                :class-retriever (phpinspect-project-make-class-retriever 
project))))
-    (phpinspect-project-set-class project class-fqn class)
-    class))
+  (phpinspect-project-edit project
+    (let ((class (phpinspect--make-class-generated
+                  :class-retriever (phpinspect-project-make-class-retriever 
project))))
+      (phpinspect-project-set-class project class-fqn class)
+      class)))
 
 (cl-defmethod phpinspect-project-get-class-create
   ((project phpinspect-project) (class-fqn phpinspect--type) &optional 
no-enqueue)
   (let ((class (phpinspect-project-get-class project class-fqn)))
     (unless class
-      (setq class (phpinspect-project-create-class project class-fqn))
-      (unless no-enqueue
-        (phpinspect-project-enqueue-if-not-present project class-fqn)))
+      (phpinspect-project-edit project
+        (setq class (phpinspect-project-create-class project class-fqn))
+        (unless no-enqueue
+          (phpinspect-project-enqueue-if-not-present project class-fqn))))
     class))
 
+(cl-defmethod phpinspect-project-get-class-extra-or-create
+  ((project phpinspect-project) (class-fqn phpinspect--type) &optional 
no-enqueue)
+  (or (phpinspect-project-get-class-or-extra project class-fqn)
+      (phpinspect-project-get-class-create project class-fqn no-enqueue)))
+
 (defalias 'phpinspect-project-add-class-if-missing 
#'phpinspect-project-get-class-create)
 
 (cl-defmethod phpinspect-project-get-class
   ((project phpinspect-project) (class-fqn phpinspect--type))
   "Get indexed class by name of CLASS-FQN stored in PROJECT."
-  (gethash (phpinspect--type-name-symbol class-fqn)
-           (phpinspect-project-class-index project)))
+  (let ((class (gethash (phpinspect--type-name-symbol class-fqn)
+                        (phpinspect-project-class-index project))))
+    (when (and class (phpinspect-project-read-only-p project)
+               (not (phpinspect--class-read-only-p class)))
+      (setf (phpinspect--class-read-only-p class) t))
+
+    class))
+
+(cl-defmethod phpinspect-project-get-class-or-extra
+  ((project phpinspect-project) (class-fqn phpinspect--type))
+  (or (phpinspect-project-get-class project class-fqn)
+      (and (phpinspect-project-extra-class-retriever project)
+           (funcall (phpinspect-project-extra-class-retriever project)
+                    class-fqn))))
 
 (cl-defmethod phpinspect-project-get-type-filepath
   ((project phpinspect-project) (type phpinspect--type) &optional index-new)
@@ -209,7 +261,8 @@ when INDEX-NEW is non-nil, new files are added to the index
 before the search is executed."
   (let* ((autoloader (phpinspect-project-autoload project)))
     (when (eq index-new 'index-new)
-      (phpinspect-autoloader-refresh autoloader))
+      (phpinspect-project-edit project
+        (phpinspect-autoloader-refresh autoloader)))
     (let* ((result (phpinspect-autoloader-resolve
                     autoloader (phpinspect--type-name-symbol type))))
       (if (not result)
@@ -263,7 +316,9 @@ before the search is executed."
   (lambda () (phpinspect-project-root project)))
 
 (defun phpinspect-project-make-class-retriever (project)
-  (lambda (type) (phpinspect-project-get-class-create project type)))
+  (lambda (type)
+    (or (phpinspect-project-get-class-or-extra project type)
+        (phpinspect-project-get-class-create project type))))
 
 ;;; INDEX TASK
 (cl-defstruct (phpinspect-index-task
diff --git a/phpinspect-resolve.el b/phpinspect-resolve.el
index 1aba206d5d..cae5fa8185 100644
--- a/phpinspect-resolve.el
+++ b/phpinspect-resolve.el
@@ -124,7 +124,7 @@
 ;; object through global variables.
 (defsubst phpinspect-get-cached-project-class (project-root class-fqn)
   (when project-root
-    (phpinspect-project-get-class
+    (phpinspect-project-get-class-or-extra
      (phpinspect--cache-get-project-create 
(phpinspect--get-or-create-global-cache)
                                            project-root)
      class-fqn)))
@@ -143,16 +143,6 @@
               (phpinspect--class-get-static-method-list class)
             (phpinspect--class-get-method-list class))))))
 
-(defmacro phpinspect-find-function-in-list (method-name list)
-  (let ((break-sym (gensym))
-        (method-name-sym (gensym)))
-    `(let ((,method-name-sym (phpinspect-intern-name ,method-name)))
-       (catch (quote ,break-sym)
-         (dolist (func ,list)
-           (when (eq (phpinspect--function-name-symbol func)
-                     ,method-name-sym)
-             (throw (quote ,break-sym) func)))))))
-
 (defsubst phpinspect-get-cached-project-class-method-type
   (project-root class-fqn method-name)
     (when project-root
diff --git a/phpinspect-serialize.el b/phpinspect-serialize.el
index 14bc58c0f5..4c11e840c8 100644
--- a/phpinspect-serialize.el
+++ b/phpinspect-serialize.el
@@ -26,6 +26,9 @@
 (require 'phpinspect-type)
 (require 'phpinspect-class)
 
+(cl-defgeneric phpinspect--serialize-type (_type)
+  nil)
+
 (cl-defmethod phpinspect--serialize-type ((type phpinspect--type))
   `(phpinspect--make-type
     :name ,(phpinspect--type-name type)
@@ -34,6 +37,9 @@
                  (phpinspect--serialize-type (phpinspect--type-contains type)))
     :fully-qualified ,(phpinspect--type-fully-qualified type)))
 
+;; (cl-defmethod phpinspect--serialize-function (_func)
+;;   nil)
+
 (cl-defmethod phpinspect--serialize-function ((func phpinspect--function))
   `(phpinspect--make-function
     :name ,(phpinspect--function-name func)
diff --git a/phpinspect-suggest.el b/phpinspect-suggest.el
index fa4e401353..30c83c87e3 100644
--- a/phpinspect-suggest.el
+++ b/phpinspect-suggest.el
@@ -32,7 +32,7 @@
 
 (defun phpinspect-suggest-functions (rctx)
   (let* ((project (phpinspect--resolvecontext-project rctx)))
-    (phpinspect-project-get-functions project)))
+    (phpinspect-project-get-functions-with-extra project)))
 
 (defun phpinspect-suggest-variables-at-point (resolvecontext)
   (phpinspect--log "Suggesting variables at point")
@@ -72,9 +72,12 @@
       (let ((class (phpinspect-get-or-create-cached-project-class
                     project-root
                     class-fqn)))
+        (phpinspect--log (if class
+                             "Retrieved class index, starting method 
collection %s (%s)"
+                           "No class index found in %s for %s")
+                         project-root class-fqn)
+
         (when class
-          (phpinspect--log "Retrieved class index, starting method collection 
%s (%s)"
-                           project-root class-fqn)
           (if static
               (phpinspect--class-get-static-method-list class)
             (phpinspect--class-get-method-list class))))))
diff --git a/phpinspect-type.el b/phpinspect-type.el
index 3d6ccbb4ec..5c2291ffd0 100644
--- a/phpinspect-type.el
+++ b/phpinspect-type.el
@@ -29,7 +29,6 @@
 (eval-when-compile
   (require 'phpinspect-parser))
 
-
 (cl-defstruct (phpinspect--type
                (:constructor phpinspect--make-type-generated)
                (:copier phpinspect--copy-type))
@@ -82,6 +81,18 @@ that the collection is expected to contain")
 (defconst phpinspect--this-type (phpinspect--make-type :name "\\this" 
:fully-qualified t))
 (defconst phpinspect--null-type (phpinspect--make-type :name "\\null" 
:fully-qualified t))
 
+(defun phpinspect-define-standard-types ()
+  (setq phpinspect-native-types
+        (phpinspect--make-types (mapcar (lambda (name) (concat "\\" name))
+                                        phpinspect-native-typenames))
+        phpinspect-collection-types (phpinspect--make-types
+                                     '("\\array" "\\iterable" 
"\\SplObjectCollection" "\\mixed"))
+        phpinspect--object-type (phpinspect--make-type :name "\\object" 
:fully-qualified t)
+        phpinspect--static-type (phpinspect--make-type :name "\\static" 
:fully-qualified t)
+        phpinspect--self-type (phpinspect--make-type :name "\\self" 
:fully-qualified t)
+        phpinspect--this-type (phpinspect--make-type :name "\\this" 
:fully-qualified t)
+        phpinspect--null-type (phpinspect--make-type :name "\\null" 
:fully-qualified t)))
+
 (cl-defmethod phpinspect--type-set-name ((type phpinspect--type) (name string))
   (setf (phpinspect--type-name-symbol type) (phpinspect-intern-name name)))
 
@@ -112,7 +123,7 @@ See https://wiki.php.net/rfc/static_return_type ."
 
 
 (cl-defmethod phpinspect--type-name ((type phpinspect--type))
-  (symbol-name (phpinspect--type-name-symbol type)))
+  (phpinspect-name-string (phpinspect--type-name-symbol type)))
 
 (defun phpinspect--get-bare-class-name-from-fqn (fqn)
   (car (last (split-string fqn "\\\\"))))
@@ -242,10 +253,10 @@ return type of the function."))
     ,@(phpinspect--wrap-plist-name-in-symbol property-list)))
 
 (cl-defmethod phpinspect--function-set-name ((func phpinspect--function) (name 
string))
-  (setf (phpinspect--function-name-symbol func) (intern name 
phpinspect-name-obarray)))
+  (setf (phpinspect--function-name-symbol func) (intern name 
phpinspect-names)))
 
 (define-inline phpinspect--function-name (func)
-  (inline-quote (symbol-name (phpinspect--function-name-symbol ,func))))
+  (inline-quote (phpinspect-name-string (phpinspect--function-name-symbol 
,func))))
 
 (cl-defstruct (phpinspect--variable (:constructor phpinspect--make-variable))
   "A PHP Variable."
diff --git a/phpinspect-util.el b/phpinspect-util.el
index 05c1f11dcc..baf930585d 100644
--- a/phpinspect-util.el
+++ b/phpinspect-util.el
@@ -23,9 +23,15 @@
 
 ;;; Code:
 
-(defvar phpinspect-name-obarray (obarray-make)
-  "An obarray containing symbols for all encountered names in
-PHP. Used to optimize string comparison.")
+(defvar phpinspect-names (make-hash-table :test #'equal :size 5000 
:rehash-size 1.2)
+  "An hash-table containing cons cells representing encountered names in
+PHP code. Used to optimize string comparison. See also 
`phpinspect-indern-name'")
+
+(defun phpinspect-make-name-hash ()
+  (make-hash-table :test #'equal :size 5000 :rehash-size 1.2))
+
+(define-inline phpinspect-name-string (name)
+  (inline-quote (cdr ,name)))
 
 (defvar phpinspect-project-root-file-list
   '("composer.json" "composer.lock" ".git" ".svn" ".hg")
@@ -34,6 +40,11 @@ PHP. Used to optimize string comparison.")
 (defvar phpinspect--debug nil
   "Enable debug logs for phpinspect by setting this variable to true")
 
+(defun phpinspect-message (&rest args)
+  (let ((format-string (car args))
+        (args (cdr args)))
+    (apply #'message `(,(concat "[phpinspect] " format-string) ,@args))))
+
 (defun phpinspect-toggle-logging ()
   (interactive)
   (if (setq phpinspect--debug (not phpinspect--debug))
@@ -112,8 +123,10 @@ level of START-FILE in stead of `default-directory`."
                            (string= parent-without-vendor "")))
               (phpinspect--find-project-root parent-without-vendor))))))))
 
-(defsubst phpinspect-intern-name (name)
-  (intern name phpinspect-name-obarray))
+(defun phpinspect-intern-name (name)
+  (setq name (cons 'phpinspect-name name))
+  (or (gethash name phpinspect-names)
+      (puthash name name phpinspect-names)))
 
 (defsubst phpinspect--wrap-plist-name-in-symbol (property-list)
   (let ((new-plist)
diff --git a/phpinspect-worker.el b/phpinspect-worker.el
index 4df35d6a8e..ad80ff9725 100644
--- a/phpinspect-worker.el
+++ b/phpinspect-worker.el
@@ -31,6 +31,9 @@
 (require 'phpinspect-queue)
 (require 'phpinspect-pipeline)
 
+(eval-when-compile
+  (phpinspect--declare-log-group 'worker))
+
 (defcustom phpinspect-worker-pause-time 1
   "Number of seconds that `phpinspect-worker' should pause when
 user input is detected. A higher value means better
@@ -93,6 +96,7 @@ on the worker independent of dynamic variables during 
testing.")
 
 (cl-defmethod phpinspect-worker-wakeup ((worker phpinspect-worker))
   (when (eq main-thread (thread--blocker (phpinspect-worker-thread worker)))
+    (phpinspect--log "Attempting to wakeup worker thread")
     (thread-signal (phpinspect-worker-thread worker)
                    'phpinspect-wakeup-thread nil)))
 
@@ -120,6 +124,7 @@ on the worker independent of dynamic variables during 
testing.")
   "Specialized enqueuement method for index tasks. Prevents
 indexation tasks from being added when there are identical tasks
 already present in the queue."
+  (phpinspect--log "Enqueuing task")
   (phpinspect-queue-enqueue-noduplicate (phpinspect-worker-queue worker) task 
#'phpinspect-task=))
 
 (cl-defmethod phpinspect-worker-enqueue ((worker phpinspect-dynamic-worker) 
task)
@@ -135,15 +140,19 @@ already present in the queue."
       ;; queue.
       (condition-case err
           (ignore-error phpinspect-wakeup-thread
+            (phpinspect--log "Dequeueing next task")
             (let* ((task (phpinspect-queue-dequeue (phpinspect-worker-queue 
worker)))
                    (mx (make-mutex))
                    (continue (make-condition-variable mx)))
               (if task
                   ;; Execute task if it belongs to a project that has not been
                   ;; purged (meaning that it is still actively used).
-                  (unless (phpinspect-project-purged (phpinspect-task-project 
task))
+                  (if (phpinspect-project-purged (phpinspect-task-project 
task))
+                      (phpinspect--log "Projecthas been purged. Skipping task")
+                    (phpinspect--log "Executing task")
                     (phpinspect-task-execute task worker))
                 ;; else: join with the main thread until wakeup is signaled
+                (phpinspect--log "No tasks, joining main thread")
                 (thread-join main-thread))
 
               ;; Pause for a second after indexing something, to allow user 
input to
@@ -225,5 +234,8 @@ already present in the queue."
 (cl-defgeneric phpinspect-task-project (task)
   "The project that this task belongs to.")
 
+(cl-defmethod phpinspect-worker-enqueue ((_worker (eql 'nil-worker)) &rest 
_ignored))
+(cl-defmethod phpinspect-worker-live-p ((_worker (eql 'nil-worker)) &rest 
_ignored) t)
+
 (provide 'phpinspect-worker)
 ;;; phpinspect-worker.el ends here
diff --git a/phpinspect.el b/phpinspect.el
index 8cb19b4904..ccab2148a0 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -28,7 +28,6 @@
 
 (require 'cl-lib)
 (require 'json)
-(require 'obarray)
 
 ;; internal dependencies
 (require 'phpinspect-cache)
@@ -47,10 +46,6 @@
 (require 'phpinspect-suggest)
 (require 'phpinspect-completion)
 
-(defvar-local phpinspect--buffer-index nil
-  "The result of the last successfull parse + index action
-  executed by phpinspect for the current buffer")
-
 (defvar phpinspect-insert-file-contents-function 
#'insert-file-contents-literally
   "Function that phpinspect uses to insert file contents into a buffer.")
 
@@ -82,12 +77,16 @@
 (defun phpinspect--init-mode ()
   "Initialize the phpinspect minor mode for the current buffer."
   (phpinspect-ensure-worker)
+  (when (and phpinspect-load-stubs (not phpinspect-stub-cache))
+    (phpinspect-load-stub-index))
+
   (setq phpinspect-current-buffer
-        (phpinspect-make-buffer
-         :buffer (current-buffer)
-         :project (phpinspect--cache-get-project-create
-                   (phpinspect--get-or-create-global-cache)
-                   (phpinspect-current-project-root))))
+        (phpinspect-make-buffer :buffer (current-buffer)))
+
+  (phpinspect-register-current-buffer
+   (lambda () (phpinspect-buffer-reset phpinspect-current-buffer)))
+  (add-hook 'kill-buffer-hook #'phpinspect-unregister-current-buffer)
+
   (add-hook 'after-change-functions #'phpinspect-after-change-function)
 
   (when (featurep 'company)
@@ -121,7 +120,8 @@ Reparses the entire buffer without token reuse."
   (kill-local-variable 'phpinspect--buffer-project)
   (kill-local-variable 'company-backends)
   (kill-local-variable 'eldoc-documentation-function)
-  (kill-local-variable 'eldoc-message-commands))
+  (kill-local-variable 'eldoc-message-commands)
+  (phpinspect-unregister-current-buffer))
 
 (defun phpinspect--mode-function ()
   (if (and (boundp 'phpinspect-mode) phpinspect-mode)
@@ -305,7 +305,7 @@ dependencies, are returned."
                    (phpinspect-current-project-root)))
          (autoloader (phpinspect-project-autoload project)))
     (let ((fqns))
-      (maphash (lambda (type _) (push (symbol-name type) fqns))
+      (maphash (lambda (type _) (push (phpinspect-name-string type) fqns))
                (if (eq 'own filter)
                    (phpinspect-autoloader-own-types autoloader)
                  (phpinspect-autoloader-types autoloader)))
diff --git a/scripts/install-deps.el b/scripts/install-deps.el
new file mode 100644
index 0000000000..5f00ea9329
--- /dev/null
+++ b/scripts/install-deps.el
@@ -0,0 +1,13 @@
+;;; install-deps.el --- Install dependencies -*- lexical-binding: t -*-
+
+(require 'lisp-mnt)
+
+(let* ((project-dir (file-name-parent-directory (file-name-directory 
(macroexp-file-name))))
+       (file (expand-file-name "phpinspect.el" project-dir))
+       dependencies)
+
+  (with-temp-buffer
+    (insert-file-contents file)
+    (setq dependencies (read (lm-header-multiline "package-requires")))
+    (dolist (dep dependencies)
+      (package-install (car dep)))))
diff --git a/test/phpinspect-test.el b/test/phpinspect-test.el
index 409fdcc5fb..21f4e383c2 100644
--- a/test/phpinspect-test.el
+++ b/test/phpinspect-test.el
@@ -303,64 +303,6 @@ class FlufferUpper
               (phpinspect--make-type-resolver-for-resolvecontext
                context))))))
 
-(ert-deftest phpinspect-eldoc-function-for-object-method ()
-  (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))
-    (phpinspect-purge-cache)
-    (phpinspect-cache-project-class
-     (phpinspect-current-project-root)
-     (cdar (alist-get 'classes (cdr index))))
-
-    (should (string= "getThis: ($moment DateTime, $thing Thing, $other): Thing"
-                   (with-temp-buffer
-                     (insert php-code)
-                     (backward-char)
-                     (setq-local phpinspect-current-buffer
-                                 (phpinspect-make-buffer :buffer 
(current-buffer)))
-                     (phpinspect-buffer-parse phpinspect-current-buffer)
-                     (phpinspect-eldoc-function))))))
-
-(ert-deftest phpinspect-eldoc-function-for-static-method ()
-  (let* ((php-code "
-class Thing
-{
-    static function doThing(\\DateTime $moment, Thing $thing, $other): static
-    {
-        return $this;
-    }
-
-    function doStuff()
-    {
-        self::doThing(")
-         (tokens (phpinspect-parse-string php-code))
-         (index (phpinspect--index-tokens tokens))
-         (phpinspect-project-root-function (lambda () "phpinspect-test"))
-         (phpinspect-eldoc-word-width 100))
-    (phpinspect-purge-cache)
-    (phpinspect-cache-project-class
-     (phpinspect-current-project-root)
-     (cdar (alist-get 'classes (cdr index))))
-
-    (should (string= "doThing: ($moment DateTime, $thing Thing, $other): Thing"
-                   (with-temp-buffer
-                     (insert php-code)
-                     (setq-local phpinspect-current-buffer
-                                 (phpinspect-make-buffer :buffer 
(current-buffer)))
-                     (phpinspect-eldoc-function))))))
-
 
 (ert-deftest phpinspect-resolve-type-from-context-static-method ()
   (with-temp-buffer
diff --git a/test/test-buffer.el b/test/test-buffer.el
index c8872870b8..e7b034006f 100644
--- a/test/test-buffer.el
+++ b/test/test-buffer.el
@@ -288,7 +288,7 @@ class YYY {
 
 
 (ert-deftest phpinspect-buffer-index-classes ()
-  (let* ((buffer (phpinspect-make-buffer :project (phpinspect--make-project 
:autoload (phpinspect-make-autoloader))))
+  (let* ((buffer (phpinspect-make-buffer :-project (phpinspect--make-project 
:autoload (phpinspect-make-autoloader))))
          (namespaces (phpinspect-make-splayt))
          (declarations (phpinspect-make-splayt))
          (classes (phpinspect-make-splayt))
@@ -356,7 +356,7 @@ class YYY {
       (should (= 1 (hash-table-count (phpinspect-project-class-index 
(phpinspect-buffer-project buffer))))))))
 
 (ert-deftest phpinspect-buffer-index-functions ()
-  (let ((buffer (phpinspect-make-buffer :project (phpinspect--make-project 
:autoload (phpinspect-make-autoloader))))
+  (let ((buffer (phpinspect-make-buffer :-project (phpinspect--make-project 
:autoload (phpinspect-make-autoloader))))
         (namespaces (phpinspect-make-splayt))
         (declarations  (phpinspect-make-splayt))
         (classes (phpinspect-make-splayt))
@@ -408,7 +408,7 @@ class YYY {
                                      (phpinspect--make-type :name 
"\\NS\\TestClass"))))))))
 
 (ert-deftest phpinspect-buffer-index-class-variables ()
-  (let ((buffer (phpinspect-make-buffer :project (phpinspect--make-project 
:autoload (phpinspect-make-autoloader))))
+  (let ((buffer (phpinspect-make-buffer :-project (phpinspect--make-project 
:autoload (phpinspect-make-autoloader))))
         (namespaces (phpinspect-make-splayt))
         (declarations  (phpinspect-make-splayt))
         (classes (phpinspect-make-splayt))
diff --git a/test/test-eldoc.el b/test/test-eldoc.el
index 86a52a105f..79696e6ca8 100644
--- a/test/test-eldoc.el
+++ b/test/test-eldoc.el
@@ -5,6 +5,9 @@
 
 (ert-deftest phpinspect-eld-method-call ()
   (with-temp-buffer
+    (phpinspect-ensure-worker)
+    (phpinspect-purge-cache)
+
     (let* ((php-code "
 class Thing
 {
@@ -23,8 +26,6 @@ class Thing
            (phpinspect-eldoc-word-width 100)
            (buffer (phpinspect-make-buffer :buffer (current-buffer)))
            second-arg-pos inside-nested-list-pos first-arg-pos)
-      (phpinspect-ensure-worker)
-      (phpinspect-purge-cache)
       (phpinspect-cache-project-class
        (phpinspect-current-project-root)
        (cdar (alist-get 'classes (cdr index))))
@@ -53,42 +54,60 @@ class Thing
         (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;
+(ert-deftest phpinspect-eldoc-function-for-object-method ()
+  (phpinspect-purge-cache)
+  (let* ((php-code "
+class Thing
+{
+    function getThis(\\DateTime $moment, Thing $thing, $other): static
+    {
+        return $this;
+    }
 
-;;     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))
+    (phpinspect-cache-project-class
+     (phpinspect-current-project-root)
+     (cdar (alist-get 'classes (cdr index))))
 
-;;     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)
+    (should (string= "getThis: ($moment DateTime, $thing Thing, $other): Thing"
+                   (with-temp-buffer
+                     (insert php-code)
+                     (backward-char)
+                     (setq-local phpinspect-current-buffer
+                                 (phpinspect-make-buffer :buffer 
(current-buffer)))
+                     (phpinspect-buffer-parse phpinspect-current-buffer)
+                     (phpinspect-eldoc-function))))))
 
-;;       (insert php-code)
-;;       (backward-char 28)
-;;       (setq getThis-pos (point))
-;;       (backward-char 22)
-;;       (setq banana-pos (point))
+(ert-deftest phpinspect-eldoc-function-for-static-method ()
+  (phpinspect-purge-cache)
+  (let* ((php-code "
+class Thing
+{
+    static function doThing(\\DateTime $moment, Thing $thing, $other): static
+    {
+        return $this;
+    }
 
-;;       (phpinspect-ensure-worker)
-;;       (phpinspect-purge-cache)
-;;       (phpinspect-cache-project-class
-;;        (phpinspect-current-project-root)
-;;        (cdar (alist-get 'classes (cdr index))))
+    function doStuff()
+    {
+        self::doThing(")
+         (tokens (phpinspect-parse-string php-code))
+         (index (phpinspect--index-tokens tokens))
+         (phpinspect-project-root-function (lambda () "phpinspect-test"))
+         (phpinspect-eldoc-word-width 100))
+    (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)))))
+    (should (string= "doThing: ($moment DateTime, $thing Thing, $other): Thing"
+                   (with-temp-buffer
+                     (insert php-code)
+                     (setq-local phpinspect-current-buffer
+                                 (phpinspect-make-buffer :buffer 
(current-buffer)))
+                     (phpinspect-eldoc-function))))))
diff --git a/test/test-index.el b/test/test-index.el
index f5c092f847..d1b5fda91b 100644
--- a/test/test-index.el
+++ b/test/test-index.el
@@ -51,7 +51,7 @@
           `(phpinspect--root-index
             (imports)
             (classes
-             (,(phpinspect--make-type :name"\\Potato" :fully-qualified t)
+             (,(phpinspect--make-type :name "\\Potato" :fully-qualified t)
               phpinspect--indexed-class
               (complete . t)
               (class-name . ,(phpinspect--make-type :name "\\Potato" 
:fully-qualified t))
@@ -103,7 +103,7 @@ return StaticThing::create(new 
ThingFactory())->makeThing((((new Potato())->anti
                        '("Cheese" "Bacon" "Ham" "Bagel" "Monkey" 
"ExtendedThing"
                          "StaticThing" "Thing" "ThingFactory" "Potato" 
"OtherThing"))
                       #'string<))
-             (sort used-types (lambda (s1 s2) (string< (symbol-name s1) 
(symbol-name s2))))))))
+             (sort used-types (lambda (s1 s2) (string< (phpinspect-name-string 
s1) (phpinspect-name-string s2))))))))
 
 (ert-deftest phpinspect--find-used-types-in-tokens ()
   (let ((blocks `(



reply via email to

[Prev in Thread] Current Thread [Next in Thread]