[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
- [elpa] externals/phpinspect 8d3bd21015 006/126: Add license information, (continued)
- [elpa] externals/phpinspect 8d3bd21015 006/126: Add license information, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 811a9a9141 010/126: Add more tests for the parser code, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect b338aa9b75 012/126: Fix most of the byte-compilation warnings, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect f5fe299c01 027/126: Make functions that access the filesystem configurable and add test, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect a6bb09b2b3 026/126: Test and fix static function indexation, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 3838e02820 067/126: Prevent worker thread from associating with the current buffer, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 91e24b97d4 074/126: Make bmap-token-meta error on unexpected input, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 7f76ba4c11 072/126: Fix some bugs introduced by the incremental parsing feature, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 1ec0e0cfa2 078/126: Limit token lookback range and start completion from the first non-blank character, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 6c767fc877 089/126: Implement eldoc for object attributes, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect d1d34a4249 084/126: Move more functionalities from main file to separate modules,
ELPA Syncer <=
- [elpa] externals/phpinspect 05ca0ace20 116/126: Fix all remaining byte compiler warnings, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 2d2f9912c1 102/126: Wrap queue items in a queue object, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect f5cc681105 113/126: Fix let parenthesis in test-buffer.el, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect e57edab86e 025/126: Index new files when no FQN can be found for a type, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect f8bf0b611a 035/126: WIP: List static methods when requested, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect faa936a4f0 024/126: Test type-resolver + make type resolving work for "blocked" namespaces, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 43ab1bd99b 047/126: Make sure that the worker is running during tests, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 7e7914befa 062/126: Convert CI definition to new (woodpecker) format, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect c2b06fe265 063/126: Another attempt at fixing CI, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 5fab07b426 082/126: Keep track of multi-call edits of the same region, ELPA Syncer, 2023/08/12