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

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

[elpa] externals/phpinspect d1d34a4249 084/126: Move more functionalitie


From: ELPA Syncer
Subject: [elpa] externals/phpinspect d1d34a4249 084/126: Move more functionalities from main file to separate modules
Date: Sat, 12 Aug 2023 00:58:46 -0400 (EDT)

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

    Move more functionalities from main file to separate modules
---
 phpinspect-autoload.el       |   1 +
 phpinspect-bmap.el           |  15 +-
 phpinspect-completion.el     | 187 +++++++++++
 phpinspect-eldoc.el          |   3 +-
 phpinspect-index.el          |   7 +-
 phpinspect-project.el        |   5 +
 phpinspect-resolve.el        | 508 ++++++++++++++++++++++++++++
 phpinspect-resolvecontext.el |  18 +
 phpinspect-suggest.el        | 139 ++++++++
 phpinspect-type.el           |  32 +-
 phpinspect-util.el           |  15 +
 phpinspect.el                | 778 +------------------------------------------
 12 files changed, 927 insertions(+), 781 deletions(-)

diff --git a/phpinspect-autoload.el b/phpinspect-autoload.el
index d7b1fed9ca..e145755715 100644
--- a/phpinspect-autoload.el
+++ b/phpinspect-autoload.el
@@ -26,6 +26,7 @@
 (require 'cl-lib)
 (require 'phpinspect-project)
 (require 'phpinspect-fs)
+(require 'phpinspect-util)
 
 (cl-defstruct (phpinspect-psr0
                (:constructor phpinspect-make-psr0-generated))
diff --git a/phpinspect-bmap.el b/phpinspect-bmap.el
index a9907f20e7..cc8fe8c17a 100644
--- a/phpinspect-bmap.el
+++ b/phpinspect-bmap.el
@@ -325,15 +325,24 @@
 LIMIT is the maximum number of positions to check backward before
 giving up. If not provided, this is 100."
   (unless limit (setq limit 100))
-  (let* ((ends (phpinspect-bmap-ends bmap))
-         (ending)
+  (let* ((ending)
          (point-limit (- point limit)))
-    (unless (hash-table-empty-p ends)
+    (unless (hash-table-empty-p (phpinspect-bmap-ends bmap))
       (while (not (or (<= point 0) (<= point point-limit)
                       (setq ending (phpinspect-bmap-tokens-ending-at bmap 
point))))
         (setq point (- point 1)))
       (car (last ending)))))
 
+(cl-defmethod phpinspect-bmap-last-token-starting-before-point ((bmap 
phpinspect-bmap) point &optional limit)
+  (unless limit (setq limit 100))
+  (let* ((starting)
+         (point-limit (- point limit)))
+    (unless (hash-table-empty-p (phpinspect-bmap-starts bmap))
+      (while (not (or (<= point 0) (<= point point-limit)
+                      (setq starting (phpinspect-bmap-token-starting-at bmap 
point))))
+        (setq point (- point 1)))
+      starting)))
+
 (defsubst phpinspect-bmap-overlay (bmap bmap-overlay token-meta pos-delta 
&optional whitespace-before)
   (let* ((overlays (phpinspect-bmap-overlays bmap))
          (start (+ (phpinspect-meta-start token-meta) pos-delta))
diff --git a/phpinspect-completion.el b/phpinspect-completion.el
new file mode 100644
index 0000000000..c41894c451
--- /dev/null
+++ b/phpinspect-completion.el
@@ -0,0 +1,187 @@
+;;; phpinspect-type.el --- PHP parsing and completion package -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021  Free Software Foundation, Inc
+
+;; Author: Hugo Thunnissen <devel@hugot.nl>
+;; Keywords: php, languages, tools, convenience
+;; Version: 0
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'phpinspect-bmap)
+(require 'phpinspect-buffer)
+(require 'phpinspect-resolvecontext)
+(require 'phpinspect-suggest)
+
+(defvar phpinspect--last-completion-list nil
+  "Used internally to save metadata about completion options
+  between company backend calls")
+
+(cl-defstruct (phpinspect--completion
+               (:constructor phpinspect--construct-completion))
+  "Contains a possible completion value with all it's attributes."
+  (value nil :type string)
+  (meta nil :type string)
+  (annotation nil :type string)
+  (kind nil :type symbol))
+
+(cl-defgeneric phpinspect--make-completion (completion-candidate)
+  "Creates a `phpinspect--completion` for a possible completion
+candidate. Candidates can be indexed functions and variables.")
+
+(cl-defstruct (phpinspect--completion-list
+               (:constructor phpinspect--make-completion-list))
+  "Contains all data for a completion at point"
+  (completions (obarray-make)
+               :type obarray
+               :documentation
+               "A list of completion strings"))
+
+(cl-defgeneric phpinspect--completion-list-add
+    (comp-list completion)
+  "Add a completion to a completion-list.")
+
+(cl-defmethod phpinspect--completion-list-add
+  ((comp-list phpinspect--completion-list) (completion phpinspect--completion))
+  (unless (intern-soft (phpinspect--completion-value completion)
+                      (phpinspect--completion-list-completions comp-list))
+    (set (intern (phpinspect--completion-value completion)
+                 (phpinspect--completion-list-completions comp-list))
+         completion)))
+
+(cl-defmethod phpinspect--completion-list-get-metadata
+  ((comp-list phpinspect--completion-list) (completion-name string))
+  (let ((comp-sym (intern-soft completion-name
+                               (phpinspect--completion-list-completions 
comp-list))))
+    (when comp-sym
+      (symbol-value comp-sym))))
+
+
+(cl-defmethod phpinspect--completion-list-strings
+  ((comp-list phpinspect--completion-list))
+  (let ((strings))
+    (obarray-map (lambda (sym) (push (symbol-name sym) strings))
+                 (phpinspect--completion-list-completions comp-list))
+    strings))
+
+(cl-defstruct (phpinspect-completion-query (:constructor 
phpinspect-make-completion-query))
+  (completion-point 0
+                    :type integer
+                    :documentation
+                    "Position in the buffer from where the resolvecontext is 
determined.")
+  (point 0
+         :type integer
+         :documentation "Position in buffer for which to provide completions")
+  (buffer nil
+          :type phpinspect-buffer))
+
+(cl-defmethod phpinspect-completion-query-execute ((query 
phpinspect-completion-query))
+  "Execute QUERY.
+
+Returns list of `phpinspect--completion'."
+  (let* ((buffer (phpinspect-completion-query-buffer query))
+         (point (phpinspect-completion-query-point query))
+         (buffer-map (phpinspect-buffer-parse-map buffer))
+         (rctx (phpinspect-get-resolvecontext buffer-map point))
+         (candidates))
+    (dolist (strategy phpinspect-completion-strategies)
+      (when (phpinspect-comp-strategy-supports strategy query rctx)
+        (phpinspect--log "Found matching completion strategy. Executing...")
+        (nconc candidates (phpinspect-comp-strategy-execute strategy query 
rctx))))
+
+    (mapcar #'phpinspect--make-completion candidates)))
+
+(cl-defgeneric phpinspect-comp-strategy-supports (strategy (query 
phpinspect-completion-query) (context phpinspect--resolvecontext))
+  "Should return non-nil if STRATEGY should be deployed for QUERY
+and CONTEXT. All strategies must implement this method.")
+
+(cl-defgeneric phpinspect-comp-strategy-execute (strategy (query 
phpinspect-completion-query) (context phpinspect--resolvecontext))
+  "Should return a list of objects for which `phpinspect--make-completion' is 
implemented.")
+
+(cl-defstruct (phpinspect-comp-sigil (:constructor phpinspect-make-comp-sigil))
+  "Completion strategy for the sigil ($) character.")
+
+(cl-defmethod phpinspect-comp-strategy-supports
+  ((strat phpinspect-comp-sigil) (q phpinspect-completion-query)
+   (rctx phpinspect--resolvecontext))
+  (and (= (phpinspect-completion-query-completion-point q)
+          (phpinspect-completion-query-point q))
+       (phpinspect-variable-p
+        (phpinspect-meta-token
+         (phpinspect-bmap-last-token-starting-before-point
+          (phpinspect-buffer-parse-map (phpinspect-completion-query-buffer q))
+          (phpinspect-completion-query-point q))))))
+
+(cl-defmethod phpinspect-comp-strategy-execute
+  ((strat phpinspect-comp-sigil) (q phpinspect-completion-query)
+   (rctx phpinspect--resolvecontext))
+  (phpinspect-suggest-variables-at-point rctx))
+
+(cl-defstruct (phpinspect-comp-attribute (:constructor 
phpinspect-make-comp-attribute))
+  "Completion strategy for object attributes")
+
+(cl-defmethod phpinspect-comp-strategy-supports
+  ((strat phpinspect-comp-attribute) (q phpinspect-completion-query)
+   (context phpinspect--resolvecontext))
+  (phpinspect-object-attrib-p (car (last (phpinspect--resolvecontext-subject 
rctx)))))
+
+(cl-defmethod phpinspect-comp-strategy-execute
+  ((strat phpinspect-comp-sigil) (q phpinspect-completion-query)
+   (rctx phpinspect--resolvecontext))
+  (phpinspect-suggest-variables-at-point rctx))
+
+(cl-defstruct (phpinspect-comp-static-attribute (:constructor 
phpinspect-make-comp-static-attribute))
+  "Completion strategy for static attributes")
+
+(cl-defstruct (phpinspect-comp-bareword (:constructor 
phpinspect-make-comp-bareword))
+  "Completion strategy for bare words")
+
+
+(cl-defmethod phpinspect--make-completion
+  ((completion-candidate phpinspect--function))
+  "Create a `phpinspect--completion` for COMPLETION-CANDIDATE."
+  (phpinspect--construct-completion
+   :value (phpinspect--function-name completion-candidate)
+   :meta (concat "(" (mapconcat (lambda (arg)
+                                  (concat (phpinspect--format-type-name (cadr 
arg)) " "
+                                          "$" (if (> (length (car arg)) 8)
+                                                  (truncate-string-to-width 
(car arg) 8 nil)
+                                                (car arg))))
+                                (phpinspect--function-arguments 
completion-candidate)
+                                ", ")
+                 ") "
+                 (phpinspect--format-type-name 
(phpinspect--function-return-type completion-candidate)))
+   :annotation (concat " "
+                       (phpinspect--type-bare-name
+                        (phpinspect--function-return-type 
completion-candidate)))
+   :kind 'function))
+
+(cl-defmethod phpinspect--make-completion
+  ((completion-candidate phpinspect--variable))
+  (phpinspect--construct-completion
+   :value (phpinspect--variable-name completion-candidate)
+   :meta (phpinspect--format-type-name
+          (or (phpinspect--variable-type completion-candidate)
+              phpinspect--null-type))
+   :annotation (concat " "
+                       (phpinspect--type-bare-name
+                        (or (phpinspect--variable-type completion-candidate)
+                            phpinspect--null-type)))
+   :kind 'variable))
+
+(provide 'phpinspect-completion)
diff --git a/phpinspect-eldoc.el b/phpinspect-eldoc.el
index bc65c3586d..26d82b6ab5 100644
--- a/phpinspect-eldoc.el
+++ b/phpinspect-eldoc.el
@@ -23,7 +23,8 @@
 
 ;;; Code:
 
-
+(defvar phpinspect-eldoc-word-width 14
+  "The maximum width of words in eldoc strings.")
 
 (cl-defstruct (phpinspect-eldoc-query (:constructor 
phpinspect-make-eldoc-query))
   (point 0
diff --git a/phpinspect-index.el b/phpinspect-index.el
index 0e2e509944..b0a6b259be 100644
--- a/phpinspect-index.el
+++ b/phpinspect-index.el
@@ -113,12 +113,13 @@ function (think \"new\" statements, return types etc.)."
 (defun phpinspect--index-const-from-scope (scope)
   (phpinspect--make-variable
    :scope `(,(car scope))
+   :mutability `(,(caadr scope))
    :name (cadr (cadr (cadr scope)))))
 
 (defun phpinspect--var-annotations-from-token (token)
   (seq-filter #'phpinspect-var-annotation-p token))
 
-(defun phpinspect--index-variable-from-scope (type-resolver scope 
comment-before)
+(defun phpinspect--index-variable-from-scope (type-resolver scope 
comment-before &optional static)
   "Index the variable inside `scope`."
   (let* ((var-annotations (phpinspect--var-annotations-from-token 
comment-before))
          (variable-name (cadr (cadr scope)))
@@ -133,6 +134,7 @@ function (think \"new\" statements, return types etc.)."
     (phpinspect--make-variable
      :name variable-name
      :scope `(,(car scope))
+     :lifetime (when static '(:static))
      :type (if type (funcall type-resolver (phpinspect--make-type :name 
type))))))
 
 (defun phpinspect-doc-block-p (token)
@@ -248,7 +250,8 @@ function (think \"new\" statements, return types etc.)."
                            (push (phpinspect--index-variable-from-scope 
type-resolver
                                                                         (list 
(car token)
                                                                               
(cadadr token))
-                                                                        
comment-before)
+                                                                        
comment-before
+                                                                        
'static)
                                  static-variables))))
                    (t
                     (phpinspect--log "comment-before is: %s" comment-before)
diff --git a/phpinspect-project.el b/phpinspect-project.el
index a90ac7d0ed..723a218f64 100644
--- a/phpinspect-project.el
+++ b/phpinspect-project.el
@@ -28,6 +28,11 @@
 (require 'phpinspect-fs)
 (require 'filenotify)
 
+(defvar phpinspect-auto-reindex nil
+  "Whether or not phpinspect should automatically search for new
+files. The current implementation is clumsy and can result in
+serious performance hits. Enable at your own risk (:")
+
 (defvar phpinspect-project-root-function #'phpinspect--find-project-root
   "Function that phpinspect uses to find the root directory of a project.")
 
diff --git a/phpinspect-resolve.el b/phpinspect-resolve.el
new file mode 100644
index 0000000000..b3efb2467e
--- /dev/null
+++ b/phpinspect-resolve.el
@@ -0,0 +1,508 @@
+;;; phpinspect-resolve.el --- PHP parsing and completion package -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021  Free Software Foundation, Inc
+
+;; Author: Hugo Thunnissen <devel@hugot.nl>
+;; Keywords: php, languages, tools, convenience
+;; Version: 0
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'phpinspect-resolvecontext)
+(require 'phpinspect-type)
+(require 'phpinspect-parser)
+
+(cl-defstruct (phpinspect--assignment
+               (:constructor phpinspect--make-assignment))
+  (to nil
+      :type phpinspect-variable
+      :documentation "The variable that is assigned to")
+  (from nil
+        :type phpinspect-token
+        :documentation "The token that is assigned from"))
+
+(defsubst phpinspect-block-or-list-p (token)
+  (or (phpinspect-block-p token)
+      (phpinspect-list-p token)))
+
+(defsubst phpinspect-maybe-assignment-p (token)
+  "Like `phpinspect-assignment-p', but includes \"as\" barewords as possible 
tokens."
+  (or (phpinspect-assignment-p token)
+      (equal '(:word "as") token)))
+
+(cl-defgeneric phpinspect--find-assignments-in-token (token)
+  "Find any assignments that are in TOKEN, at top level or nested in blocks"
+  (when (keywordp (car token))
+    (setq token (cdr token)))
+
+  (let ((assignments)
+        (blocks-or-lists)
+        (statements (phpinspect--split-statements token)))
+    (dolist (statement statements)
+      (when (seq-find #'phpinspect-maybe-assignment-p statement)
+        (phpinspect--log "Found assignment statement")
+        (push statement assignments))
+
+      (when (setq blocks-or-lists (seq-filter #'phpinspect-block-or-list-p 
statement))
+        (dolist (block-or-list blocks-or-lists)
+          (phpinspect--log "Found block or list %s" block-or-list)
+          (let ((local-assignments (phpinspect--find-assignments-in-token 
block-or-list)))
+            (dolist (local-assignment (nreverse local-assignments))
+              (push local-assignment assignments))))))
+
+    ;; return
+    (phpinspect--log "Found assignments in token: %s" assignments)
+    (phpinspect--log "Found statements in token: %s" statements)
+    assignments))
+
+(defsubst phpinspect-not-assignment-p (token)
+  "Inverse of applying `phpinspect-assignment-p to TOKEN."
+  (not (phpinspect-maybe-assignment-p token)))
+
+(defsubst phpinspect-not-comment-p (token)
+  (not (phpinspect-comment-p token)))
+
+(defun phpinspect--find-assignments-by-predicate (token predicate)
+  (let ((variable-assignments)
+        (all-assignments (phpinspect--find-assignments-in-token token)))
+    (dolist (assignment all-assignments)
+      (let* ((is-loop-assignment nil)
+             (left-of-assignment
+              (seq-filter #'phpinspect-not-comment-p
+                          (seq-take-while #'phpinspect-not-assignment-p 
assignment)))
+             (right-of-assignment
+              (seq-filter
+               #'phpinspect-not-comment-p
+               (cdr (seq-drop-while
+                     (lambda (elt)
+                       (if (phpinspect-maybe-assignment-p elt)
+                           (progn
+                             (when (equal '(:word "as") elt)
+                               (phpinspect--log "It's a loop assignment %s" 
elt)
+                               (setq is-loop-assignment t))
+                             nil)
+                         t))
+                     assignment)))))
+
+        (if is-loop-assignment
+            (when (funcall predicate right-of-assignment)
+              ;; Masquerade as an array access assignment
+              (setq left-of-assignment (append left-of-assignment '((:array))))
+              (push (phpinspect--make-assignment :to right-of-assignment
+                                                 :from left-of-assignment)
+                    variable-assignments))
+          (when (funcall predicate left-of-assignment)
+            (push (phpinspect--make-assignment :from right-of-assignment
+                                               :to left-of-assignment)
+                  variable-assignments)))))
+    (phpinspect--log "Returning the thing %s" variable-assignments)
+    (nreverse variable-assignments)))
+
+(defsubst phpinspect-drop-preceding-barewords (statement)
+  (while (and statement (phpinspect-word-p (cadr statement)))
+    (pop statement))
+  statement)
+
+;; TODO: the use of this function and similar ones should be replaced with code
+;; that uses locally injected project objects in stead of retrieving the 
project
+;; object through global variables.
+(defsubst phpinspect-get-cached-project-class (project-root class-fqn)
+  (when project-root
+    (phpinspect-project-get-class
+     (phpinspect--cache-get-project-create 
(phpinspect--get-or-create-global-cache)
+                                           project-root)
+     class-fqn)))
+
+(defun phpinspect-get-cached-project-class-methods (project-root class-fqn 
&optional static)
+    (phpinspect--log "Getting cached project class methods for %s (%s)"
+                   project-root class-fqn)
+    (when project-root
+      (let ((class (phpinspect-get-or-create-cached-project-class
+                    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))))))
+
+(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
+    (let* ((class (phpinspect-get-or-create-cached-project-class project-root 
class-fqn))
+           (method))
+      (when class
+        (setq method
+              (phpinspect--class-get-method class (phpinspect-intern-name 
method-name)))
+        (when method
+          (phpinspect--function-return-type method))))))
+
+(defsubst phpinspect-get-cached-project-class-variable-type
+  (project-root class-fqn variable-name)
+  (phpinspect--log "Getting cached project class variable type for %s (%s::%s)"
+                   project-root class-fqn variable-name)
+  (when project-root
+    (let ((found-variable
+           (phpinspect--class-get-variable
+            (phpinspect-get-or-create-cached-project-class project-root 
class-fqn)
+            variable-name)))
+      (when found-variable
+        (phpinspect--variable-type found-variable)))))
+
+(defsubst phpinspect-get-cached-project-class-static-method-type
+  (project-root class-fqn method-name)
+  (when project-root
+    (let* ((class (phpinspect-get-or-create-cached-project-class project-root 
class-fqn))
+           (method))
+      (when class
+        (setq method
+              (phpinspect--class-get-static-method
+               class
+               (phpinspect-intern-name method-name)))
+        (when method
+          (phpinspect--function-return-type method))))))
+
+(defun phpinspect-get-derived-statement-type-in-block
+    (resolvecontext statement php-block type-resolver &optional 
function-arg-list)
+  "Get type of RESOLVECONTEXT subject in PHP-BLOCK.
+
+Use TYPE-RESOLVER and FUNCTION-ARG-LIST in the process.
+
+An example of a derived statement would be the following php code:
+$variable->attribute->method();
+$variable->attribute;
+$variable->method();
+self::method();
+ClassName::method();
+$variable = ClassName::method();
+$variable = $variable->method();"
+    ;; A derived statement can be an assignment itself.
+    (when (seq-find #'phpinspect-assignment-p statement)
+      (phpinspect--log "Derived statement is an assignment: %s" statement)
+      (setq statement (cdr (seq-drop-while #'phpinspect-not-assignment-p 
statement))))
+    (phpinspect--log "Get derived statement type in block: %s" statement)
+    (let* ((first-token (pop statement))
+           (current-token)
+           (previous-attribute-type))
+      ;; No first token means we were passed an empty list.
+      (when (and first-token
+                 (setq previous-attribute-type
+                       (or
+                           ;; Statements starting with a bare word can 
indicate a static
+                           ;; method call. These could be statements with 
"return" or
+                           ;; another bare-word at the start though, so we 
drop preceding
+                           ;; barewords when they are present.
+                           (when (phpinspect-word-p first-token)
+                             (when (phpinspect-word-p (car statement))
+                               (setq statement 
(phpinspect-drop-preceding-barewords
+                                                statement))
+                               (setq first-token (pop statement)))
+                             (funcall type-resolver (phpinspect--make-type
+                                                     :name (cadr 
first-token))))
+
+                           ;; No bare word, assume we're dealing with a 
variable.
+                           (phpinspect-get-variable-type-in-block
+                            resolvecontext
+                            (cadr first-token)
+                            php-block
+                            type-resolver
+                            function-arg-list))))
+
+        (phpinspect--log "Statement: %s" statement)
+        (phpinspect--log "Starting attribute type: %s" previous-attribute-type)
+        (while (setq current-token (pop statement))
+          (phpinspect--log "Current derived statement token: %s" current-token)
+          (cond ((phpinspect-object-attrib-p current-token)
+                 (let ((attribute-word (cadr current-token)))
+                   (when (phpinspect-word-p attribute-word)
+                     (if (phpinspect-list-p (car statement))
+                         (progn
+                           (pop statement)
+                           (setq previous-attribute-type
+                                 (or
+                                  
(phpinspect-get-cached-project-class-method-type
+                                   (phpinspect--resolvecontext-project-root
+                                    resolvecontext)
+                                   (funcall type-resolver 
previous-attribute-type)
+                                   (cadr attribute-word))
+                                  previous-attribute-type)))
+                       (setq previous-attribute-type
+                             (or
+                              
(phpinspect-get-cached-project-class-variable-type
+                               (phpinspect--resolvecontext-project-root
+                                resolvecontext)
+                               (funcall type-resolver previous-attribute-type)
+                               (cadr attribute-word))
+                              previous-attribute-type))))))
+                ((phpinspect-static-attrib-p current-token)
+                 (let ((attribute-word (cadr current-token)))
+                   (phpinspect--log "Found attribute word: %s" attribute-word)
+                   (phpinspect--log "checking if next token is a list. Token: 
%s"
+                                    (car statement))
+                   (when (phpinspect-word-p attribute-word)
+                     (if (phpinspect-list-p (car statement))
+                         (progn
+                           (pop statement)
+                           (setq previous-attribute-type
+                                 (or
+                                  
(phpinspect-get-cached-project-class-static-method-type
+                                   (phpinspect--resolvecontext-project-root
+                                    resolvecontext)
+                                   (funcall type-resolver 
previous-attribute-type)
+                                   (cadr attribute-word))
+                                  previous-attribute-type)))))))
+                ((and previous-attribute-type (phpinspect-array-p 
current-token))
+                 (setq previous-attribute-type
+                       (or (phpinspect--type-contains previous-attribute-type)
+                           previous-attribute-type)))))
+        (phpinspect--log "Found derived type: %s" previous-attribute-type)
+        ;; Make sure to always return a FQN
+        (funcall type-resolver previous-attribute-type))))
+
+;;;;
+;; TODO: since we're passing type-resolver to all of the get-variable-type 
functions now,
+;; we may as well always return FQNs in stead of relative type names.
+;;;;
+(defun phpinspect-get-variable-type-in-block
+    (resolvecontext variable-name php-block type-resolver &optional 
function-arg-list)
+  "Find the type of VARIABLE-NAME in PHP-BLOCK using TYPE-RESOLVER.
+
+Returns either a FQN or a relative type name, depending on
+whether or not the root variable of the assignment value (right
+side of assignment) can be found in FUNCTION-ARG-LIST.
+
+When PHP-BLOCK belongs to a function, supply FUNCTION-ARG-LIST to
+resolve types of function argument variables."
+  (phpinspect--log "Looking for assignments of variable %s in php block" 
variable-name)
+  (if (string= variable-name "this")
+      (funcall type-resolver (phpinspect--make-type :name "self"))
+    (phpinspect-get-pattern-type-in-block
+     resolvecontext (phpinspect--make-pattern :m `(:variable ,variable-name))
+     php-block type-resolver function-arg-list)))
+
+(defun phpinspect-get-pattern-type-in-block
+    (resolvecontext pattern php-block type-resolver &optional 
function-arg-list)
+  "Find the type of PATTERN in PHP-BLOCK using TYPE-RESOLVER.
+
+PATTERN must be an object of the type `phpinspect--pattern'.
+
+Returns either a FQN or a relative type name, depending on
+whether or not the root variable of the assignment value (right
+side of assignment) needs to be extracted from FUNCTION-ARG-LIST.
+
+When PHP-BLOCK belongs to a function, supply FUNCTION-ARG-LIST to
+resolve types of function argument variables."
+  (let* ((assignments
+          (phpinspect--find-assignments-by-predicate
+           php-block (phpinspect--pattern-matcher pattern)))
+         (last-assignment (when assignments (car (last assignments))))
+         (last-assignment-value (when last-assignment
+                                  (phpinspect--assignment-from 
last-assignment)))
+         (pattern-code (phpinspect--pattern-code pattern))
+         (result))
+    (phpinspect--log "Looking for assignments of pattern %s in php block" 
pattern-code)
+
+    (if (not assignments)
+        (when (and (= (length pattern-code) 2) (phpinspect-variable-p (cadr 
pattern-code)))
+          (let ((variable-name (cadadr pattern-code)))
+            (progn
+              (phpinspect--log "No assignments found for variable %s, checking 
function arguments: %s"
+                               variable-name function-arg-list)
+              (setq result (phpinspect-get-variable-type-in-function-arg-list
+                            variable-name type-resolver function-arg-list)))))
+      (setq result
+            (phpinspect--interpret-expression-type-in-context
+             resolvecontext php-block type-resolver
+             last-assignment-value function-arg-list)))
+
+    (phpinspect--log "Type interpreted from last assignment expression of 
pattern %s: %s"
+                     pattern-code result)
+
+    (when (and result (phpinspect--type-collection result) (not 
(phpinspect--type-contains result)))
+      (phpinspect--log (concat
+                        "Interpreted type %s is a collection type, but 
'contains'"
+                        "attribute is not set. Attempting to infer type from 
context")
+                       result)
+      (setq result (phpinspect--copy-type result))
+      (let ((concat-pattern
+             (phpinspect--pattern-concat
+              pattern (phpinspect--make-pattern :f #'phpinspect-array-p))))
+        (phpinspect--log "Inferring type of concatenated pattern %s"
+                         (phpinspect--pattern-code concat-pattern))
+        (setf (phpinspect--type-contains result)
+              (phpinspect-get-pattern-type-in-block
+               resolvecontext concat-pattern php-block
+               type-resolver function-arg-list))))
+
+    ; return
+    result))
+
+(defun phpinspect--split-statements (tokens &optional predicate)
+  "Split TOKENS into separate statements.
+
+If PREDICATE is provided, it is used as additional predicate to
+determine whether a token delimits a statement."
+  (let ((sublists)
+        (current-sublist))
+    (dolist (thing tokens)
+      (if (or (phpinspect-end-of-statement-p thing)
+              (when predicate (funcall predicate thing)))
+          (when current-sublist
+            (when (phpinspect-block-p thing)
+              (push thing current-sublist))
+            (push (nreverse current-sublist) sublists)
+            (setq current-sublist nil))
+        (push thing current-sublist)))
+    (when current-sublist
+      (push (nreverse current-sublist) sublists))
+    (nreverse sublists)))
+
+(defun phpinspect-get-variable-type-in-function-arg-list (variable-name 
type-resolver arg-list)
+  "Infer VARIABLE-NAME's type from typehints in
+ARG-LIST. ARG-LIST should be a list token as returned by
+`phpinspect--list-handler` (see also `phpinspect-list-p`)"
+  (let ((arg-no (seq-position arg-list
+                              variable-name
+                              (lambda (token variable-name)
+                                (and (phpinspect-variable-p token)
+                                     (string= (car (last token)) 
variable-name))))))
+    (if (and arg-no
+             (> arg-no 0))
+        (let ((arg (elt arg-list (- arg-no 1))))
+          (if (phpinspect-word-p arg)
+              (funcall type-resolver
+                       (phpinspect--make-type :name (car (last arg))))
+            nil)))))
+
+(defun phpinspect--interpret-expression-type-in-context
+    (resolvecontext php-block type-resolver expression &optional 
function-arg-list)
+  "Infer EXPRESSION's type from provided context.
+
+Use RESOLVECONTEXT, PHP-BLOCK, TYPE-RESOLVER and
+FUNCTION-ARG-LIST as contextual information to infer type of
+EXPRESSION."
+
+  ;; When the right of an assignment is more than $variable; or "string";(so
+  ;; (:variable "variable") (:terminator ";") or (:string "string") 
(:terminator ";")
+  ;; in tokens), we're likely working with a derived assignment like 
$object->method()
+  ;; or $object->attributen
+  (cond ((phpinspect-array-p (car expression))
+         (let ((collection-contains)
+               (collection-items (phpinspect--split-statements (cdr (car 
expression))))
+               (count 0))
+           (phpinspect--log "Checking collection items: %s" collection-items)
+           (while (and (< count (length collection-items))
+                       (not collection-contains))
+             (setq collection-contains
+                   (phpinspect--interpret-expression-type-in-context
+                    resolvecontext php-block type-resolver
+                    (elt collection-items count) function-arg-list)
+                   count (+ count 1)))
+
+           (phpinspect--log "Collection contained: %s" collection-contains)
+
+           (phpinspect--make-type :name "\\array"
+                                  :fully-qualified t
+                                  :collection t
+                                  :contains collection-contains)))
+        ((and (phpinspect-word-p (car expression))
+              (string= (cadar expression) "new"))
+         (funcall
+          type-resolver (phpinspect--make-type :name (cadadr expression))))
+        ((and (> (length expression) 1)
+              (seq-find (lambda (part) (or (phpinspect-attrib-p part)
+                                               (phpinspect-array-p part)))
+                        expression))
+         (phpinspect--log "Variable was assigned with a derived statement")
+         (phpinspect-get-derived-statement-type-in-block
+          resolvecontext expression php-block
+          type-resolver function-arg-list))
+
+        ;; If the right of an assignment is just $variable;, we can check if 
it is a
+        ;; function argument and otherwise recurse to find the type of that 
variable.
+        ((phpinspect-variable-p (car expression))
+         (phpinspect--log "Variable was assigned with the value of another 
variable: %s"
+                          expression)
+         (or (when function-arg-list
+               (phpinspect-get-variable-type-in-function-arg-list
+                (cadar expression)
+                type-resolver function-arg-list))
+             (phpinspect-get-variable-type-in-block resolvecontext
+                                                    (cadar expression)
+                                                    php-block
+                                                    type-resolver
+                                                    function-arg-list)))))
+
+
+(defun phpinspect-resolve-type-from-context (resolvecontext &optional 
type-resolver)
+  (unless type-resolver
+    (setq type-resolver
+          (phpinspect--make-type-resolver-for-resolvecontext resolvecontext)))
+  (phpinspect--log "Looking for type of statement: %s in nested token"
+                   (phpinspect--resolvecontext-subject resolvecontext))
+  ;; Find all enclosing tokens that aren't classes. Classes do not contain 
variable
+  ;; assignments which have effect in the current scope, which is what we're 
trying
+  ;; to find here to infer the statement type.
+  (let ((enclosing-tokens (seq-filter #'phpinspect-not-class-p
+                                       
(phpinspect--resolvecontext-enclosing-tokens
+                                        resolvecontext)))
+        (enclosing-token)
+        (type))
+    (while (and enclosing-tokens (not type))
+      ;;(phpinspect--log "Trying to find type in %s" enclosing-token)
+      (setq enclosing-token (pop enclosing-tokens))
+
+      (setq type
+            (cond ((phpinspect-namespace-p enclosing-token)
+                   (phpinspect-get-derived-statement-type-in-block
+                    resolvecontext
+                    (phpinspect--resolvecontext-subject
+                     resolvecontext)
+                    (or (phpinspect-namespace-block enclosing-token)
+                        enclosing-token)
+                    type-resolver))
+                  ((or (phpinspect-block-p enclosing-token)
+                       (phpinspect-root-p enclosing-token))
+                   (phpinspect-get-derived-statement-type-in-block
+                    resolvecontext
+                    (phpinspect--resolvecontext-subject
+                     resolvecontext)
+                    enclosing-token
+                    type-resolver))
+                  ((phpinspect-function-p enclosing-token)
+                   (phpinspect-get-derived-statement-type-in-block
+                    resolvecontext
+                    (phpinspect--resolvecontext-subject
+                     resolvecontext)
+                    (phpinspect-function-block enclosing-token)
+                    type-resolver
+                    (phpinspect-function-argument-list enclosing-token))))))
+    type))
+
+(provide 'phpinspect-resolve)
diff --git a/phpinspect-resolvecontext.el b/phpinspect-resolvecontext.el
index 526ad4087b..16dca768bc 100644
--- a/phpinspect-resolvecontext.el
+++ b/phpinspect-resolvecontext.el
@@ -76,6 +76,24 @@
                 (push (phpinspect-meta-token child) previous-siblings)))))
         previous-siblings))))
 
+(defun phpinspect--get-last-statement-in-token (token)
+  (setq token (cond ((phpinspect-function-p token)
+                     (phpinspect-function-block token))
+                    ((phpinspect-namespace-p token)
+                     (phpinspect-namespace-block token))
+                    (t token)))
+  (nreverse
+   (seq-take-while
+    (let ((keep-taking t) (last-test nil))
+      (lambda (elt)
+        (when last-test
+          (setq keep-taking nil))
+        (setq last-test (phpinspect-variable-p elt))
+        (and keep-taking
+             (not (phpinspect-end-of-statement-p elt))
+             (listp elt))))
+    (reverse token))))
+
 (cl-defmethod phpinspect-get-resolvecontext
   ((bmap phpinspect-bmap) (point integer))
   (let* ((enclosing-tokens)
diff --git a/phpinspect-suggest.el b/phpinspect-suggest.el
new file mode 100644
index 0000000000..79531424c0
--- /dev/null
+++ b/phpinspect-suggest.el
@@ -0,0 +1,139 @@
+;;; phpinspect-suggest.el --- PHP parsing and completion package -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021  Free Software Foundation, Inc
+
+;; Author: Hugo Thunnissen <devel@hugot.nl>
+;; Keywords: php, languages, tools, convenience
+;; Version: 0
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'phpinspect-resolvecontext)
+(require 'phpinspect-resolve)
+(require 'phpinspect-parser)
+(require 'phpinspect-type)
+(require 'phpinspect-project)
+(require 'phpinspect-class)
+
+(defun phpinspect-suggest-variables-at-point (resolvecontext)
+  (phpinspect--log "Suggesting variables at point")
+  (let ((variables))
+    (dolist (token (phpinspect--resolvecontext-enclosing-tokens 
resolvecontext))
+      (when (phpinspect-not-class-p token)
+        (let ((token-list token)
+              (potential-variable))
+        (while token-list
+          (setq potential-variable (pop token-list))
+          (cond ((phpinspect-variable-p potential-variable)
+                 (phpinspect--log "Pushing variable %s" potential-variable)
+                 (push (phpinspect--make-variable
+                        :name (cadr potential-variable)
+                        :type phpinspect--null-type)
+                       variables))
+                ((phpinspect-function-p potential-variable)
+                 (push (phpinspect-function-block potential-variable) 
token-list)
+                 (dolist (argument (phpinspect-function-argument-list 
potential-variable))
+                   (when (phpinspect-variable-p argument)
+                     (push (phpinspect--make-variable
+                            :name (cadr argument)
+                            :type phpinspect--null-type)
+                           variables))))
+                ((phpinspect-block-p potential-variable)
+                 (dolist (nested-token (cdr potential-variable))
+                   (push nested-token token-list))))))))
+
+    ;; Only return variables that have a name. Unnamed variables are just 
dollar
+    ;; signs (:
+    (seq-filter #'phpinspect--variable-name variables)))
+
+(defun phpinspect-get-cached-project-class-methods (project-root class-fqn 
&optional static)
+    (phpinspect--log "Getting cached project class methods for %s (%s)"
+                   project-root class-fqn)
+    (when project-root
+      (let ((class (phpinspect-get-or-create-cached-project-class
+                    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))))))
+
+(defun phpinspect--get-methods-for-class
+    (resolvecontext buffer-classes class &optional static)
+  "Extract all possible methods for a class from `buffer-classes` and the 
class index.
+`buffer-classes` will be preferred because their data should be
+more recent"
+  (let ((methods (phpinspect-get-cached-project-class-methods
+                  (phpinspect--resolvecontext-project-root
+                   resolvecontext)
+                  class
+                  static))
+        (buffer-index (alist-get class buffer-classes nil nil 
#'phpinspect--type=)))
+      (phpinspect--log "Getting methods for class (%s)" class)
+      (when buffer-index
+          (dolist (method (alist-get (if static 'static-methods 'methods)
+                                     buffer-index))
+            (push method methods)))
+      (unless methods
+        (phpinspect--log "Failed to find methods for class %s :(" class))
+      methods))
+
+(defun phpinspect--get-variables-for-class (buffer-classes class-name 
&optional static)
+  (let ((class (phpinspect-get-or-create-cached-project-class
+                (phpinspect-current-project-root)
+                class-name)))
+    ;; TODO return static variables/constants when static is set
+    (when class
+      (phpinspect--class-variables class))))
+
+(defun phpinspect--make-method-lister (resolvecontext buffer-classes &optional 
static)
+  (lambda (fqn)
+    (phpinspect--get-methods-for-class resolvecontext buffer-classes fqn 
static)))
+
+(defun phpinspect-suggest-attributes-at-point
+    (resolvecontext &optional static)
+  "Suggest object or class attributes at point.
+
+RESOLVECONTEXT must be a structure of the type
+`phpinspect--resolvecontext'.  The PHP type of its subject is
+resolved to provide completion candidates.
+
+If STATIC is non-nil, candidates are provided for constants,
+static variables and static methods."
+  (let* ((buffer-index phpinspect--buffer-index)
+         (buffer-classes (alist-get 'classes (cdr buffer-index)))
+         (type-resolver (phpinspect--make-type-resolver-for-resolvecontext
+                         resolvecontext))
+         (method-lister (phpinspect--make-method-lister
+                         resolvecontext
+                         buffer-classes
+                         static)))
+    (let ((statement-type (phpinspect-resolve-type-from-context
+                           resolvecontext
+                           type-resolver)))
+      (when statement-type
+        (let ((type (funcall type-resolver statement-type)))
+          (append (phpinspect--get-variables-for-class
+                   buffer-classes
+                   type
+                   static)
+                  (funcall method-lister type)))))))
+
+(provide 'phpinspect-suggest)
diff --git a/phpinspect-type.el b/phpinspect-type.el
index dce58057a2..37ee58762a 100644
--- a/phpinspect-type.el
+++ b/phpinspect-type.el
@@ -154,6 +154,20 @@ NAMESPACE may be nil, or a string with a namespace FQN."
     (setf (phpinspect--type-collection type) t))
   type)
 
+(defun phpinspect--find-innermost-incomplete-class (token)
+  (let ((last-token (car (last token))))
+    (cond ((phpinspect-incomplete-class-p token) token)
+          ((phpinspect-incomplete-token-p last-token)
+           (phpinspect--find-innermost-incomplete-class last-token)))))
+
+(defun phpinspect--find-class-token (token)
+  "Recurse into token tree until a class is found."
+  (when (and (listp token) (> (length token) 1))
+    (let ((last-token (car (last token))))
+      (cond ((phpinspect-class-p token) token)
+            (last-token
+             (phpinspect--find-class-token last-token))))))
+
 (defun phpinspect--make-type-resolver (types &optional token-tree namespace)
   "Little wrapper closure to pass around and resolve types with."
   (let* ((inside-class
@@ -215,7 +229,6 @@ return type of the function."))
 (cl-defmethod phpinspect--function-name ((func phpinspect--function))
   (symbol-name (phpinspect--function-name-symbol func)))
 
-
 (cl-defstruct (phpinspect--variable (:constructor phpinspect--make-variable))
   "A PHP Variable."
   (name nil
@@ -223,16 +236,29 @@ return type of the function."))
         :documentation
         "A string containing the name of the variable.")
   (scope nil
-         :type phpinspect-scope
          :documentation
          "When the variable is an object attribute, this should
 contain the scope of the variable as returned by
-`phpinspect-parse-scope`")
+`phpinspect-parse-scope'")
+  (lifetime nil
+            :documentation
+            "The lifetime of the variable (e.g. whether it is static or not). 
Will
+contain the parsed keyword token indicating the lifetime of the variable")
+  (mutability nil
+              :documentation
+              "The mutability of the variable (e.g. whether it is constant or
+not). Will contain the parsed keyword token indicating the
+mutability of the variable")
   (type nil
         :type string
         :documentation
         "A string containing the FQN of the variable's type"))
 
+(defun phpinspect--variable-static-p (variable)
+  (phpinspect-static-p (phpinspect--variable-lifetime variable)))
+
+(defun phpinspect--variable-const-p (variable)
+  (phpinspect-const-p (phpinspect--variable-mutability variable)))
 
 (provide 'phpinspect-type)
 ;;; phpinspect-type.el ends here
diff --git a/phpinspect-util.el b/phpinspect-util.el
index 7edab54174..d4ca48faaf 100644
--- a/phpinspect-util.el
+++ b/phpinspect-util.el
@@ -172,5 +172,20 @@ hierarchy as long as no matching files are found.  See also
               phpinspect-project-root-file-list)
     dominating-file))
 
+(defun phpinspect--determine-completion-point ()
+  "Find first point backwards that could contain any kind of
+context for completion."
+  (save-excursion
+    (re-search-backward "[^[:blank:]\n]")
+    (forward-char)
+    (point)))
+
+(defmacro phpinspect-json-preset (&rest body)
+  "Default options to wrap around `json-read' and similar BODY."
+  `(let ((json-object-type 'hash-table)
+            (json-array-type 'list)
+            (json-key-type 'string))
+     ,@body))
+
 (provide 'phpinspect-util)
 ;;; phpinspect-util.el ends here
diff --git a/phpinspect.el b/phpinspect.el
index e9e367c54d..33cc0044c8 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -43,11 +43,8 @@
 (require 'phpinspect-buffer)
 (require 'phpinspect-resolvecontext)
 (require 'phpinspect-eldoc)
-
-(defvar phpinspect-auto-reindex nil
-  "Whether or not phpinspect should automatically search for new
-files. The current implementation is clumsy and can result in
-serious performance hits. Enable at your own risk (:")
+(require 'phpinspect-suggest)
+(require 'phpinspect-completion)
 
 (defvar-local phpinspect--buffer-index nil
   "The result of the last successfull parse + index action
@@ -67,46 +64,6 @@ phpinspect")
   '("composer.json" "composer.lock" ".git" ".svn" ".hg")
   "List of files that could indicate a project root directory.")
 
-(defvar phpinspect--last-completion-list nil
-  "Used internally to save metadata about completion options
-  between company backend calls")
-
-(defvar phpinspect-eldoc-word-width 14
-  "The maximum width of words in eldoc strings.")
-
-(cl-defstruct (phpinspect--completion
-               (:constructor phpinspect--construct-completion))
-  "Contains a possible completion value with all it's attributes."
-  (value nil :type string)
-  (meta nil :type string)
-  (annotation nil :type string)
-  (kind nil :type symbol))
-
-
-(cl-defgeneric phpinspect--make-completion (completion-candidate)
-  "Creates a `phpinspect--completion` for a possible completion
-candidate. Candidates can be indexed functions and variables.")
-
-(cl-defmethod phpinspect--make-completion
-  ((completion-candidate phpinspect--function))
-  "Create a `phpinspect--completion` for COMPLETION-CANDIDATE."
-  (phpinspect--construct-completion
-   :value (phpinspect--function-name completion-candidate)
-   :meta (concat "(" (mapconcat (lambda (arg)
-                                  (concat (phpinspect--format-type-name (cadr 
arg)) " "
-                                          "$" (if (> (length (car arg)) 8)
-                                                  (truncate-string-to-width 
(car arg) 8 nil)
-                                                (car arg))))
-                                (phpinspect--function-arguments 
completion-candidate)
-                                ", ")
-                 ") "
-                 (phpinspect--format-type-name 
(phpinspect--function-return-type completion-candidate)))
-   :annotation (concat " "
-                       (phpinspect--type-bare-name
-                        (phpinspect--function-return-type 
completion-candidate)))
-   :kind 'function))
-
-
 (defsubst phpinspect-cache-project-class (project-root indexed-class)
   (when project-root
     (phpinspect-project-add-class
@@ -114,101 +71,6 @@ candidate. Candidates can be indexed functions and 
variables.")
                                            project-root)
      indexed-class)))
 
-(defsubst phpinspect-get-cached-project-class (project-root class-fqn)
-  (when project-root
-    (phpinspect-project-get-class
-     (phpinspect--cache-get-project-create 
(phpinspect--get-or-create-global-cache)
-                                           project-root)
-     class-fqn)))
-
-(defun phpinspect-get-project-class-inherit-classes (project-root class)
-  (let ((classnames `(,@(alist-get 'extends class)
-                      ,@(alist-get 'implements class)))
-        (classes))
-
-    (phpinspect--log "Found inherit classes: %s" classnames)
-    (while classnames
-      (let ((inherit-class (phpinspect-get-or-create-cached-project-class
-                            project-root
-                            (pop classnames))))
-        (push inherit-class classes)
-        (dolist (nested-class (phpinspect-get-project-class-inherit-classes
-                               project-root
-                               inherit-class))
-          (push nested-class classes))))
-
-    (seq-uniq classes #'eq)))
-
-(defun phpinspect-get-cached-project-class-methods (project-root class-fqn 
&optional static)
-    (phpinspect--log "Getting cached project class methods for %s (%s)"
-                   project-root class-fqn)
-    (when project-root
-      (let ((class (phpinspect-get-or-create-cached-project-class
-                    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))))))
-
-(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
-    (let* ((class (phpinspect-get-or-create-cached-project-class project-root 
class-fqn))
-           (method))
-      (when class
-        (setq method
-              (phpinspect--class-get-method class (phpinspect-intern-name 
method-name)))
-        (when method
-          (phpinspect--function-return-type method))))))
-
-(defsubst phpinspect-get-cached-project-class-variable-type
-  (project-root class-fqn variable-name)
-  (phpinspect--log "Getting cached project class variable type for %s (%s::%s)"
-                   project-root class-fqn variable-name)
-  (when project-root
-    (let ((found-variable
-           (phpinspect--class-get-variable
-            (phpinspect-get-or-create-cached-project-class project-root 
class-fqn)
-            variable-name)))
-      (when found-variable
-        (phpinspect--variable-type found-variable)))))
-
-;; (defsubst phpinspect-get-cached-project-class-static-method-type
-;;   (project-root class-fqn method-name)
-;;   (when project-root
-;;     (let* ((found-method
-;;             (phpinspect-find-function-in-list
-;;              method-name
-;;              (phpinspect-get-cached-project-class-methods project-root 
class-fqn 'static))))
-;;       (when found-method
-;;         (phpinspect--function-return-type found-method)))))
-
-(defsubst phpinspect-get-cached-project-class-static-method-type
-  (project-root class-fqn method-name)
-  (when project-root
-    (let* ((class (phpinspect-get-or-create-cached-project-class project-root 
class-fqn))
-           (method))
-      (when class
-        (setq method
-              (phpinspect--class-get-static-method
-               class
-               (phpinspect-intern-name method-name)))
-        (when method
-          (phpinspect--function-return-type method))))))
-
 (defun phpinspect-parse-file (file)
   (with-temp-buffer
     (phpinspect-insert-file-contents file)
@@ -234,452 +96,6 @@ candidate. Candidates can be indexed functions and 
variables.")
     (insert string)
     (phpinspect-parse-current-buffer)))
 
-(defun phpinspect--split-statements (tokens &optional predicate)
-  "Split TOKENS into separate statements.
-
-If PREDICATE is provided, it is used as additional predicate to
-determine whether a token delimits a statement."
-  (let ((sublists)
-        (current-sublist))
-    (dolist (thing tokens)
-      (if (or (phpinspect-end-of-statement-p thing)
-              (when predicate (funcall predicate thing)))
-          (when current-sublist
-            (when (phpinspect-block-p thing)
-              (push thing current-sublist))
-            (push (nreverse current-sublist) sublists)
-            (setq current-sublist nil))
-        (push thing current-sublist)))
-    (when current-sublist
-      (push (nreverse current-sublist) sublists))
-    (nreverse sublists)))
-
-(defun phpinspect-get-variable-type-in-function-arg-list (variable-name 
type-resolver arg-list)
-  "Infer VARIABLE-NAME's type from typehints in
-ARG-LIST. ARG-LIST should be a list token as returned by
-`phpinspect--list-handler` (see also `phpinspect-list-p`)"
-  (let ((arg-no (seq-position arg-list
-                              variable-name
-                              (lambda (token variable-name)
-                                (and (phpinspect-variable-p token)
-                                     (string= (car (last token)) 
variable-name))))))
-    (if (and arg-no
-             (> arg-no 0))
-        (let ((arg (elt arg-list (- arg-no 1))))
-          (if (phpinspect-word-p arg)
-              (funcall type-resolver
-                       (phpinspect--make-type :name (car (last arg))))
-            nil)))))
-
-(defun phpinspect--determine-completion-point ()
-  "Find first point backwards that could contain any kind of
-context for completion."
-  (save-excursion
-    (re-search-backward "[^[:blank:]\n]")
-    (forward-char)
-    (point)))
-
-(cl-defstruct (phpinspect--assignment
-               (:constructor phpinspect--make-assignment))
-  (to nil
-      :type phpinspect-variable
-      :documentation "The variable that is assigned to")
-  (from nil
-        :type phpinspect-token
-        :documentation "The token that is assigned from"))
-
-(defsubst phpinspect-block-or-list-p (token)
-  (or (phpinspect-block-p token)
-      (phpinspect-list-p token)))
-
-(defsubst phpinspect-maybe-assignment-p (token)
-  "Like `phpinspect-assignment-p', but includes \"as\" barewords as possible 
tokens."
-  (or (phpinspect-assignment-p token)
-      (equal '(:word "as") token)))
-
-(cl-defgeneric phpinspect--find-assignments-in-token (token)
-  "Find any assignments that are in TOKEN, at top level or nested in blocks"
-  (when (keywordp (car token))
-    (setq token (cdr token)))
-
-  (let ((assignments)
-        (blocks-or-lists)
-        (statements (phpinspect--split-statements token)))
-    (dolist (statement statements)
-      (when (seq-find #'phpinspect-maybe-assignment-p statement)
-        (phpinspect--log "Found assignment statement")
-        (push statement assignments))
-
-      (when (setq blocks-or-lists (seq-filter #'phpinspect-block-or-list-p 
statement))
-        (dolist (block-or-list blocks-or-lists)
-          (phpinspect--log "Found block or list %s" block-or-list)
-          (let ((local-assignments (phpinspect--find-assignments-in-token 
block-or-list)))
-            (dolist (local-assignment (nreverse local-assignments))
-              (push local-assignment assignments))))))
-
-    ;; return
-    (phpinspect--log "Found assignments in token: %s" assignments)
-    (phpinspect--log "Found statements in token: %s" statements)
-    assignments))
-
-(defsubst phpinspect-not-assignment-p (token)
-  "Inverse of applying `phpinspect-assignment-p to TOKEN."
-  (not (phpinspect-maybe-assignment-p token)))
-
-(defsubst phpinspect-not-comment-p (token)
-  (not (phpinspect-comment-p token)))
-
-(defun phpinspect--find-assignments-by-predicate (token predicate)
-  (let ((variable-assignments)
-        (all-assignments (phpinspect--find-assignments-in-token token)))
-    (dolist (assignment all-assignments)
-      (let* ((is-loop-assignment nil)
-             (left-of-assignment
-              (seq-filter #'phpinspect-not-comment-p
-                          (seq-take-while #'phpinspect-not-assignment-p 
assignment)))
-             (right-of-assignment
-              (seq-filter
-               #'phpinspect-not-comment-p
-               (cdr (seq-drop-while
-                     (lambda (elt)
-                       (if (phpinspect-maybe-assignment-p elt)
-                           (progn
-                             (when (equal '(:word "as") elt)
-                               (phpinspect--log "It's a loop assignment %s" 
elt)
-                               (setq is-loop-assignment t))
-                             nil)
-                         t))
-                     assignment)))))
-
-        (if is-loop-assignment
-            (when (funcall predicate right-of-assignment)
-              ;; Masquerade as an array access assignment
-              (setq left-of-assignment (append left-of-assignment '((:array))))
-              (push (phpinspect--make-assignment :to right-of-assignment
-                                                 :from left-of-assignment)
-                    variable-assignments))
-          (when (funcall predicate left-of-assignment)
-            (push (phpinspect--make-assignment :from right-of-assignment
-                                               :to left-of-assignment)
-                  variable-assignments)))))
-    (phpinspect--log "Returning the thing %s" variable-assignments)
-    (nreverse variable-assignments)))
-
-(defsubst phpinspect-drop-preceding-barewords (statement)
-  (while (and statement (phpinspect-word-p (cadr statement)))
-    (pop statement))
-  statement)
-
-(defun phpinspect-get-derived-statement-type-in-block
-    (resolvecontext statement php-block type-resolver &optional 
function-arg-list)
-  "Get type of RESOLVECONTEXT subject in PHP-BLOCK.
-
-Use TYPE-RESOLVER and FUNCTION-ARG-LIST in the process.
-
-An example of a derived statement would be the following php code:
-$variable->attribute->method();
-$variable->attribute;
-$variable->method();
-self::method();
-ClassName::method();
-$variable = ClassName::method();
-$variable = $variable->method();"
-    ;; A derived statement can be an assignment itself.
-    (when (seq-find #'phpinspect-assignment-p statement)
-      (phpinspect--log "Derived statement is an assignment: %s" statement)
-      (setq statement (cdr (seq-drop-while #'phpinspect-not-assignment-p 
statement))))
-    (phpinspect--log "Get derived statement type in block: %s" statement)
-    (let* ((first-token (pop statement))
-           (current-token)
-           (previous-attribute-type))
-      ;; No first token means we were passed an empty list.
-      (when (and first-token
-                 (setq previous-attribute-type
-                       (or
-                           ;; Statements starting with a bare word can 
indicate a static
-                           ;; method call. These could be statements with 
"return" or
-                           ;; another bare-word at the start though, so we 
drop preceding
-                           ;; barewords when they are present.
-                           (when (phpinspect-word-p first-token)
-                             (when (phpinspect-word-p (car statement))
-                               (setq statement 
(phpinspect-drop-preceding-barewords
-                                                statement))
-                               (setq first-token (pop statement)))
-                             (funcall type-resolver (phpinspect--make-type
-                                                     :name (cadr 
first-token))))
-
-                           ;; No bare word, assume we're dealing with a 
variable.
-                           (phpinspect-get-variable-type-in-block
-                            resolvecontext
-                            (cadr first-token)
-                            php-block
-                            type-resolver
-                            function-arg-list))))
-
-        (phpinspect--log "Statement: %s" statement)
-        (phpinspect--log "Starting attribute type: %s" previous-attribute-type)
-        (while (setq current-token (pop statement))
-          (phpinspect--log "Current derived statement token: %s" current-token)
-          (cond ((phpinspect-object-attrib-p current-token)
-                 (let ((attribute-word (cadr current-token)))
-                   (when (phpinspect-word-p attribute-word)
-                     (if (phpinspect-list-p (car statement))
-                         (progn
-                           (pop statement)
-                           (setq previous-attribute-type
-                                 (or
-                                  
(phpinspect-get-cached-project-class-method-type
-                                   (phpinspect--resolvecontext-project-root
-                                    resolvecontext)
-                                   (funcall type-resolver 
previous-attribute-type)
-                                   (cadr attribute-word))
-                                  previous-attribute-type)))
-                       (setq previous-attribute-type
-                             (or
-                              
(phpinspect-get-cached-project-class-variable-type
-                               (phpinspect--resolvecontext-project-root
-                                resolvecontext)
-                               (funcall type-resolver previous-attribute-type)
-                               (cadr attribute-word))
-                              previous-attribute-type))))))
-                ((phpinspect-static-attrib-p current-token)
-                 (let ((attribute-word (cadr current-token)))
-                   (phpinspect--log "Found attribute word: %s" attribute-word)
-                   (phpinspect--log "checking if next token is a list. Token: 
%s"
-                                    (car statement))
-                   (when (phpinspect-word-p attribute-word)
-                     (if (phpinspect-list-p (car statement))
-                         (progn
-                           (pop statement)
-                           (setq previous-attribute-type
-                                 (or
-                                  
(phpinspect-get-cached-project-class-static-method-type
-                                   (phpinspect--resolvecontext-project-root
-                                    resolvecontext)
-                                   (funcall type-resolver 
previous-attribute-type)
-                                   (cadr attribute-word))
-                                  previous-attribute-type)))))))
-                ((and previous-attribute-type (phpinspect-array-p 
current-token))
-                 (setq previous-attribute-type
-                       (or (phpinspect--type-contains previous-attribute-type)
-                           previous-attribute-type)))))
-        (phpinspect--log "Found derived type: %s" previous-attribute-type)
-        ;; Make sure to always return a FQN
-        (funcall type-resolver previous-attribute-type))))
-
-;;;;
-;; TODO: since we're passing type-resolver to all of the get-variable-type 
functions now,
-;; we may as well always return FQNs in stead of relative type names.
-;;;;
-(defun phpinspect-get-variable-type-in-block
-    (resolvecontext variable-name php-block type-resolver &optional 
function-arg-list)
-  "Find the type of VARIABLE-NAME in PHP-BLOCK using TYPE-RESOLVER.
-
-Returns either a FQN or a relative type name, depending on
-whether or not the root variable of the assignment value (right
-side of assignment) can be found in FUNCTION-ARG-LIST.
-
-When PHP-BLOCK belongs to a function, supply FUNCTION-ARG-LIST to
-resolve types of function argument variables."
-  (phpinspect--log "Looking for assignments of variable %s in php block" 
variable-name)
-  (if (string= variable-name "this")
-      (funcall type-resolver (phpinspect--make-type :name "self"))
-    (phpinspect-get-pattern-type-in-block
-     resolvecontext (phpinspect--make-pattern :m `(:variable ,variable-name))
-     php-block type-resolver function-arg-list)))
-
-(defun phpinspect-get-pattern-type-in-block
-    (resolvecontext pattern php-block type-resolver &optional 
function-arg-list)
-  "Find the type of PATTERN in PHP-BLOCK using TYPE-RESOLVER.
-
-PATTERN must be an object of the type `phpinspect--pattern'.
-
-Returns either a FQN or a relative type name, depending on
-whether or not the root variable of the assignment value (right
-side of assignment) needs to be extracted from FUNCTION-ARG-LIST.
-
-When PHP-BLOCK belongs to a function, supply FUNCTION-ARG-LIST to
-resolve types of function argument variables."
-  (let* ((assignments
-          (phpinspect--find-assignments-by-predicate
-           php-block (phpinspect--pattern-matcher pattern)))
-         (last-assignment (when assignments (car (last assignments))))
-         (last-assignment-value (when last-assignment
-                                  (phpinspect--assignment-from 
last-assignment)))
-         (pattern-code (phpinspect--pattern-code pattern))
-         (result))
-    (phpinspect--log "Looking for assignments of pattern %s in php block" 
pattern-code)
-
-    (if (not assignments)
-        (when (and (= (length pattern-code) 2) (phpinspect-variable-p (cadr 
pattern-code)))
-          (let ((variable-name (cadadr pattern-code)))
-            (progn
-              (phpinspect--log "No assignments found for variable %s, checking 
function arguments: %s"
-                               variable-name function-arg-list)
-              (setq result (phpinspect-get-variable-type-in-function-arg-list
-                            variable-name type-resolver function-arg-list)))))
-      (setq result
-            (phpinspect--interpret-expression-type-in-context
-             resolvecontext php-block type-resolver
-             last-assignment-value function-arg-list)))
-
-    (phpinspect--log "Type interpreted from last assignment expression of 
pattern %s: %s"
-                     pattern-code result)
-
-    (when (and result (phpinspect--type-collection result) (not 
(phpinspect--type-contains result)))
-      (phpinspect--log (concat
-                        "Interpreted type %s is a collection type, but 
'contains'"
-                        "attribute is not set. Attempting to infer type from 
context")
-                       result)
-      (setq result (phpinspect--copy-type result))
-      (let ((concat-pattern
-             (phpinspect--pattern-concat
-              pattern (phpinspect--make-pattern :f #'phpinspect-array-p))))
-        (phpinspect--log "Inferring type of concatenated pattern %s"
-                         (phpinspect--pattern-code concat-pattern))
-        (setf (phpinspect--type-contains result)
-              (phpinspect-get-pattern-type-in-block
-               resolvecontext concat-pattern php-block
-               type-resolver function-arg-list))))
-
-    ; return
-    result))
-
-
-(defun phpinspect--interpret-expression-type-in-context
-    (resolvecontext php-block type-resolver expression &optional 
function-arg-list)
-  "Infer EXPRESSION's type from provided context.
-
-Use RESOLVECONTEXT, PHP-BLOCK, TYPE-RESOLVER and
-FUNCTION-ARG-LIST as contextual information to infer type of
-EXPRESSION."
-
-  ;; When the right of an assignment is more than $variable; or "string";(so
-  ;; (:variable "variable") (:terminator ";") or (:string "string") 
(:terminator ";")
-  ;; in tokens), we're likely working with a derived assignment like 
$object->method()
-  ;; or $object->attributen
-  (cond ((phpinspect-array-p (car expression))
-         (let ((collection-contains)
-               (collection-items (phpinspect--split-statements (cdr (car 
expression))))
-               (count 0))
-           (phpinspect--log "Checking collection items: %s" collection-items)
-           (while (and (< count (length collection-items))
-                       (not collection-contains))
-             (setq collection-contains
-                   (phpinspect--interpret-expression-type-in-context
-                    resolvecontext php-block type-resolver
-                    (elt collection-items count) function-arg-list)
-                   count (+ count 1)))
-
-           (phpinspect--log "Collection contained: %s" collection-contains)
-
-           (phpinspect--make-type :name "\\array"
-                                  :fully-qualified t
-                                  :collection t
-                                  :contains collection-contains)))
-        ((and (phpinspect-word-p (car expression))
-              (string= (cadar expression) "new"))
-         (funcall
-          type-resolver (phpinspect--make-type :name (cadadr expression))))
-        ((and (> (length expression) 1)
-              (seq-find (lambda (part) (or (phpinspect-attrib-p part)
-                                               (phpinspect-array-p part)))
-                        expression))
-         (phpinspect--log "Variable was assigned with a derived statement")
-         (phpinspect-get-derived-statement-type-in-block
-          resolvecontext expression php-block
-          type-resolver function-arg-list))
-
-        ;; If the right of an assignment is just $variable;, we can check if 
it is a
-        ;; function argument and otherwise recurse to find the type of that 
variable.
-        ((phpinspect-variable-p (car expression))
-         (phpinspect--log "Variable was assigned with the value of another 
variable: %s"
-                          expression)
-         (or (when function-arg-list
-               (phpinspect-get-variable-type-in-function-arg-list
-                (cadar expression)
-                type-resolver function-arg-list))
-             (phpinspect-get-variable-type-in-block resolvecontext
-                                                    (cadar expression)
-                                                    php-block
-                                                    type-resolver
-                                                    function-arg-list)))))
-
-
-(defun phpinspect-resolve-type-from-context (resolvecontext &optional 
type-resolver)
-  (unless type-resolver
-    (setq type-resolver
-          (phpinspect--make-type-resolver-for-resolvecontext resolvecontext)))
-  (phpinspect--log "Looking for type of statement: %s in nested token"
-                   (phpinspect--resolvecontext-subject resolvecontext))
-  ;; Find all enclosing tokens that aren't classes. Classes do not contain 
variable
-  ;; assignments which have effect in the current scope, which is what we're 
trying
-  ;; to find here to infer the statement type.
-  (let ((enclosing-tokens (seq-filter #'phpinspect-not-class-p
-                                       
(phpinspect--resolvecontext-enclosing-tokens
-                                        resolvecontext)))
-        (enclosing-token)
-        (type))
-    (while (and enclosing-tokens (not type))
-      ;;(phpinspect--log "Trying to find type in %s" enclosing-token)
-      (setq enclosing-token (pop enclosing-tokens))
-
-      (setq type
-            (cond ((phpinspect-namespace-p enclosing-token)
-                   (phpinspect-get-derived-statement-type-in-block
-                    resolvecontext
-                    (phpinspect--resolvecontext-subject
-                     resolvecontext)
-                    (or (phpinspect-namespace-block enclosing-token)
-                        enclosing-token)
-                    type-resolver))
-                  ((or (phpinspect-block-p enclosing-token)
-                       (phpinspect-root-p enclosing-token))
-                   (phpinspect-get-derived-statement-type-in-block
-                    resolvecontext
-                    (phpinspect--resolvecontext-subject
-                     resolvecontext)
-                    enclosing-token
-                    type-resolver))
-                  ((phpinspect-function-p enclosing-token)
-                   (phpinspect-get-derived-statement-type-in-block
-                    resolvecontext
-                    (phpinspect--resolvecontext-subject
-                     resolvecontext)
-                    (phpinspect-function-block enclosing-token)
-                    type-resolver
-                    (phpinspect-function-argument-list enclosing-token))))))
-    type))
-
-
-(defun phpinspect--get-variables-for-class (buffer-classes class-name 
&optional static)
-  (let ((class (phpinspect-get-or-create-cached-project-class
-                (phpinspect-current-project-root)
-                class-name)))
-    ;; TODO return static variables/constants when static is set
-    (when class
-      (phpinspect--class-variables class))))
-
-(defun phpinspect--get-methods-for-class
-    (resolvecontext buffer-classes class &optional static)
-  "Extract all possible methods for a class from `buffer-classes` and the 
class index.
-`buffer-classes` will be preferred because their data should be
-more recent"
-  (let ((methods (phpinspect-get-cached-project-class-methods
-                  (phpinspect--resolvecontext-project-root
-                   resolvecontext)
-                  class
-                  static))
-        (buffer-index (alist-get class buffer-classes nil nil 
#'phpinspect--type=)))
-      (phpinspect--log "Getting methods for class (%s)" class)
-      (when buffer-index
-          (dolist (method (alist-get (if static 'static-methods 'methods)
-                                     buffer-index))
-            (push method methods)))
-      (unless methods
-        (phpinspect--log "Failed to find methods for class %s :(" class))
-      methods))
-
 (defun phpinspect-after-change-function (start end pre-change-length)
   (when phpinspect-current-buffer
     (phpinspect-buffer-register-edit phpinspect-current-buffer start end 
pre-change-length)))
@@ -805,167 +221,9 @@ Example configuration:
 ;; End example configuration."
     :after-hook (phpinspect--mode-function))
 
-(defun phpinspect--find-class-token (token)
-  "Recurse into token tree until a class is found."
-  (when (and (listp token) (> (length token) 1))
-    (let ((last-token (car (last token))))
-      (cond ((phpinspect-class-p token) token)
-            (last-token
-             (phpinspect--find-class-token last-token))))))
-
-(defun phpinspect--find-innermost-incomplete-class (token)
-  (let ((last-token (car (last token))))
-    (cond ((phpinspect-incomplete-class-p token) token)
-          ((phpinspect-incomplete-token-p last-token)
-           (phpinspect--find-innermost-incomplete-class last-token)))))
-
-(defun phpinspect--find-last-variable-position-in-token (token)
-  "Find the last variable that can be encountered in the top
-level of a token. Nested variables are ignored."
-  (let ((i (length token)))
-    (while (and (not (= 0 i))
-                (not (phpinspect-variable-p
-                      (car (last token i)))))
-      (setq i (- i 1)))
-
-    (if (not (= i 0))(- (length token)  i))))
-
-(defun phpinspect--make-method-lister (resolvecontext buffer-classes &optional 
static)
-  (lambda (fqn)
-    (phpinspect--get-methods-for-class resolvecontext buffer-classes fqn 
static)))
-
 (defun phpinspect--buffer-index (buffer)
   (with-current-buffer buffer phpinspect--buffer-index))
 
-(defsubst phpinspect-not-variable-p (token)
-  (not (phpinspect-variable-p token)))
-
-(cl-defmethod phpinspect--make-completion
-  ((completion-candidate phpinspect--variable))
-  (phpinspect--construct-completion
-   :value (phpinspect--variable-name completion-candidate)
-   :meta (phpinspect--format-type-name
-          (or (phpinspect--variable-type completion-candidate)
-              phpinspect--null-type))
-   :annotation (concat " "
-                       (phpinspect--type-bare-name
-                        (or (phpinspect--variable-type completion-candidate)
-                            phpinspect--null-type)))
-   :kind 'variable))
-
-(cl-defstruct (phpinspect--completion-list
-               (:constructor phpinspect--make-completion-list))
-  "Contains all data for a completion at point"
-  (completions (obarray-make)
-               :type obarray
-               :documentation
-               "A list of completion strings"))
-
-(cl-defgeneric phpinspect--completion-list-add
-    (comp-list completion)
-  "Add a completion to a completion-list.")
-
-(cl-defmethod phpinspect--completion-list-add
-  ((comp-list phpinspect--completion-list) (completion phpinspect--completion))
-  (unless (intern-soft (phpinspect--completion-value completion)
-                      (phpinspect--completion-list-completions comp-list))
-    (set (intern (phpinspect--completion-value completion)
-                 (phpinspect--completion-list-completions comp-list))
-         completion)))
-
-(cl-defmethod phpinspect--completion-list-get-metadata
-  ((comp-list phpinspect--completion-list) (completion-name string))
-  (let ((comp-sym (intern-soft completion-name
-                               (phpinspect--completion-list-completions 
comp-list))))
-    (when comp-sym
-      (symbol-value comp-sym))))
-
-
-(cl-defmethod phpinspect--completion-list-strings
-  ((comp-list phpinspect--completion-list))
-  (let ((strings))
-    (obarray-map (lambda (sym) (push (symbol-name sym) strings))
-                 (phpinspect--completion-list-completions comp-list))
-    strings))
-
-(defun phpinspect--suggest-attributes-at-point
-    (resolvecontext &optional static)
-  "Suggest object or class attributes at point.
-
-RESOLVECONTEXT must be a structure of the type
-`phpinspect--resolvecontext'.  The PHP type of its subject is
-resolved to provide completion candidates.
-
-If STATIC is non-nil, candidates are provided for constants,
-static variables and static methods."
-  (let* ((buffer-index phpinspect--buffer-index)
-         (buffer-classes (alist-get 'classes (cdr buffer-index)))
-         (type-resolver (phpinspect--make-type-resolver-for-resolvecontext
-                         resolvecontext))
-         (method-lister (phpinspect--make-method-lister
-                         resolvecontext
-                         buffer-classes
-                         static)))
-    (let ((statement-type (phpinspect-resolve-type-from-context
-                           resolvecontext
-                           type-resolver)))
-      (when statement-type
-        (let ((type (funcall type-resolver statement-type)))
-          (append (phpinspect--get-variables-for-class
-                   buffer-classes
-                   type
-                   static)
-                  (funcall method-lister type)))))))
-
-(defun phpinspect--get-last-statement-in-token (token)
-  (setq token (cond ((phpinspect-function-p token)
-                     (phpinspect-function-block token))
-                    ((phpinspect-namespace-p token)
-                     (phpinspect-namespace-block token))
-                    (t token)))
-  (nreverse
-   (seq-take-while
-    (let ((keep-taking t) (last-test nil))
-      (lambda (elt)
-        (when last-test
-          (setq keep-taking nil))
-        (setq last-test (phpinspect-variable-p elt))
-        (and keep-taking
-             (not (phpinspect-end-of-statement-p elt))
-             (listp elt))))
-    (reverse token))))
-
-(defun phpinspect--suggest-variables-at-point (resolvecontext)
-  (phpinspect--log "Suggesting variables at point")
-  (let ((variables))
-    (dolist (token (phpinspect--resolvecontext-enclosing-tokens 
resolvecontext))
-      (when (phpinspect-not-class-p token)
-        (let ((token-list token)
-              (potential-variable))
-        (while token-list
-          (setq potential-variable (pop token-list))
-          (cond ((phpinspect-variable-p potential-variable)
-                 (phpinspect--log "Pushing variable %s" potential-variable)
-                 (push (phpinspect--make-variable
-                        :name (cadr potential-variable)
-                        :type phpinspect--null-type)
-                       variables))
-                ((phpinspect-function-p potential-variable)
-                 (push (phpinspect-function-block potential-variable) 
token-list)
-                 (dolist (argument (phpinspect-function-argument-list 
potential-variable))
-                   (when (phpinspect-variable-p argument)
-                     (push (phpinspect--make-variable
-                            :name (cadr argument)
-                            :type phpinspect--null-type)
-                           variables))))
-                ((phpinspect-block-p potential-variable)
-                 (dolist (nested-token (cdr potential-variable))
-                   (push nested-token token-list))))))))
-
-    ;; Only return variables that have a name. Unnamed variables are just 
dollar
-    ;; signs (:
-    (seq-filter #'phpinspect--variable-name variables)))
-
 (defun phpinspect--suggest-at-point ()
   (phpinspect--log "Entering suggest at point. Point: %d" (point))
   (let* ((bmap (phpinspect-buffer-parse-map phpinspect-current-buffer))
@@ -977,16 +235,16 @@ static variables and static methods."
     (cond ((and (phpinspect-object-attrib-p (car last-tokens))
                 (phpinspect-word-p (cadr last-tokens)))
            (phpinspect--log "word-attributes")
-           (phpinspect--suggest-attributes-at-point resolvecontext))
+           (phpinspect-suggest-attributes-at-point resolvecontext))
           ((phpinspect-object-attrib-p (cadr last-tokens))
            (phpinspect--log "object-attributes")
-           (phpinspect--suggest-attributes-at-point resolvecontext))
+           (phpinspect-suggest-attributes-at-point resolvecontext))
           ((phpinspect-static-attrib-p (cadr last-tokens))
            (phpinspect--log "static-attributes")
-           (phpinspect--suggest-attributes-at-point token-tree resolvecontext 
t))
+           (phpinspect-suggest-attributes-at-point token-tree resolvecontext 
t))
           ((phpinspect-variable-p (car(phpinspect--resolvecontext-subject
                                        resolvecontext)))
-           (phpinspect--suggest-variables-at-point resolvecontext)))))
+           (phpinspect-suggest-variables-at-point resolvecontext)))))
 
 
 (defun phpinspect-company-backend (command &optional arg &rest _ignored)
@@ -1063,14 +321,6 @@ currently opened projects."
   ;; Assign a fresh cache object
   (setq phpinspect-cache (phpinspect--make-cache)))
 
-
-(defmacro phpinspect-json-preset (&rest body)
-  "Default options to wrap around `json-read' and similar BODY."
-  `(let ((json-object-type 'hash-table)
-            (json-array-type 'list)
-            (json-key-type 'string))
-     ,@body))
-
 (defsubst phpinspect-insert-file-contents (&rest args)
   "Call `phpinspect-insert-file-contents-function' with ARGS as arguments."
   (apply phpinspect-insert-file-contents-function args))
@@ -1129,17 +379,6 @@ before the search is executed."
                    (phpinspect-current-project-root))))
     (phpinspect-project-get-type-filepath project class index-new)))
 
-
-(defun phpinspect-unique-strings (strings)
-  (seq-filter
-   (let ((last-line nil))
-     (lambda (line)
-       (let ((return-line (unless (and last-line (string= last-line line))
-                            line)))
-         (setq last-line line)
-         return-line)))
-   strings))
-
 (defun phpinspect-index-current-project ()
   "Index all available FQNs in the current project."
   (interactive)
@@ -1153,10 +392,5 @@ before the search is executed."
              (hash-table-count (phpinspect-autoloader-own-types autoloader))
              (hash-table-count (phpinspect-autoloader-types autoloader)))))
 
-(defun phpinspect-unique-lines ()
-  (let ((unique-lines (phpinspect-unique-strings (split-string (buffer-string) 
"\n" nil nil))))
-    (erase-buffer)
-    (insert (string-join unique-lines "\n"))))
-
 (provide 'phpinspect)
 ;;; phpinspect.el ends here



reply via email to

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