[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/phpinspect a60dba5f11 031/126: WIP: new struct to repre
From: |
ELPA Syncer |
Subject: |
[elpa] externals/phpinspect a60dba5f11 031/126: WIP: new struct to represent types, and string comparison optimization with obarray |
Date: |
Sat, 12 Aug 2023 00:58:38 -0400 (EDT) |
branch: externals/phpinspect
commit a60dba5f11f4bf23c61648f83c0718e4946960b9
Author: Hugo Thunnissen <devel@hugot.nl>
Commit: Hugo Thunnissen <devel@hugot.nl>
WIP: new struct to represent types, and string comparison optimization with
obarray
---
phpinspect.el | 558 ++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 369 insertions(+), 189 deletions(-)
diff --git a/phpinspect.el b/phpinspect.el
index 589c79dd96..475c065818 100644
--- a/phpinspect.el
+++ b/phpinspect.el
@@ -35,6 +35,10 @@
(defvar phpinspect-handler-obarray (obarray-make)
"An obarray containing symbols for all phpinspect parser handlers.")
+(defvar phpinspect-name-obarray (obarray-make)
+ "An obarray containing symbols for all encountered names in
+PHP. Used to optimize string comparison.")
+
(defvar-local phpinspect--buffer-index nil
"The result of the last successfull parse + index action
executed by phpinspect for the current buffer")
@@ -80,6 +84,13 @@ Should normally be set to \"phpinspect-index.bash\" in the
source
;; see https://www.php.net/manual/ja/language.types.declarations.php
'("array" "bool" "callable" "float" "int" "iterable" "mixed" "object"
"string" "void"))
+(defvar phpinspect-collection-types
+ '("\\array" "\\iterable" "\\SplObjectCollection" "\\mixed")
+ "FQNs of types that should be treated as collecitons when inferring types.")
+
+(defsubst phpinspect-intern-name (name)
+ (intern name phpinspect-name-obarray))
+
(eval-when-compile
(define-inline phpinspect--word-end-regex ()
(inline-quote "\\([[:blank:]]\\|[^0-9a-zA-Z_]\\)")))
@@ -114,30 +125,30 @@ If STRING has text properties, they are stripped."
(list token-keyword value)))
-(defsubst phpinspect-type-p (object type)
+(defsubst phpinspect-token-type-p (object type)
"Returns t if OBJECT is a token of type TYPE.
Type can be any of the token types returned by
`phpinspect-parse-buffer-until-point`"
(and (listp object) (eq (car object) type)))
(defsubst phpinspect-object-attrib-p (token)
- (phpinspect-type-p token :object-attrib))
+ (phpinspect-token-type-p token :object-attrib))
(defsubst phpinspect-static-attrib-p (token)
- (phpinspect-type-p token :static-attrib))
+ (phpinspect-token-type-p token :static-attrib))
(defsubst phpinspect-attrib-p (token)
(or (phpinspect-object-attrib-p token)
(phpinspect-static-attrib-p token)))
(defun phpinspect-html-p (token)
- (phpinspect-type-p token :html))
+ (phpinspect-token-type-p token :html))
(defun phpinspect-comma-p (token)
- (phpinspect-type-p token :comma))
+ (phpinspect-token-type-p token :comma))
(defsubst phpinspect-terminator-p (token)
- (phpinspect-type-p token :terminator))
+ (phpinspect-token-type-p token :terminator))
(defsubst phpinspect-end-of-token-p (token)
(or (phpinspect-terminator-p token)
@@ -149,10 +160,10 @@ Type can be any of the token types returned by
(phpinspect-block-p token)))
(defsubst phpinspect-incomplete-block-p (token)
- (phpinspect-type-p token :incomplete-block))
+ (phpinspect-token-type-p token :incomplete-block))
(defsubst phpinspect-block-p (token)
- (or (phpinspect-type-p token :block)
+ (or (phpinspect-token-type-p token :block)
(phpinspect-incomplete-block-p token)))
(defun phpinspect-end-of-use-p (token)
@@ -160,22 +171,22 @@ Type can be any of the token types returned by
(phpinspect-end-of-token-p token)))
(defun phpinspect-static-p (token)
- (phpinspect-type-p token :static))
+ (phpinspect-token-type-p token :static))
(defsubst phpinspect-incomplete-const-p (token)
- (phpinspect-type-p token :incomplete-const))
+ (phpinspect-token-type-p token :incomplete-const))
(defsubst phpinspect-const-p (token)
- (or (phpinspect-type-p token :const)
+ (or (phpinspect-token-type-p token :const)
(phpinspect-incomplete-const-p token)))
(defsubst phpinspect-scope-p (token)
- (or (phpinspect-type-p token :public)
- (phpinspect-type-p token :private)
- (phpinspect-type-p token :protected)))
+ (or (phpinspect-token-type-p token :public)
+ (phpinspect-token-type-p token :private)
+ (phpinspect-token-type-p token :protected)))
(defsubst phpinspect-namespace-p (object)
- (phpinspect-type-p object :namespace))
+ (phpinspect-token-type-p object :namespace))
(defun phpinspect-incomplete-class-p (token)
(and (phpinspect-class-p token)
@@ -187,11 +198,11 @@ Type can be any of the token types returned by
(phpinspect-incomplete-class-p (car (last token))))))
(defun phpinspect-function-p (token)
- (phpinspect-type-p token :function))
+ (phpinspect-token-type-p token :function))
(defun phpinspect-class-p (token)
- (phpinspect-type-p token :class))
+ (phpinspect-token-type-p token :class))
(defun phpinspect-incomplete-method-p (token)
(or (phpinspect-incomplete-function-p token)
@@ -208,33 +219,33 @@ Type can be any of the token types returned by
(phpinspect-incomplete-block-p (car (last token)))))
(defsubst phpinspect-incomplete-list-p (token)
- (phpinspect-type-p token :incomplete-list))
+ (phpinspect-token-type-p token :incomplete-list))
(defsubst phpinspect-list-p (token)
- (or (phpinspect-type-p token :list)
+ (or (phpinspect-token-type-p token :list)
(phpinspect-incomplete-list-p token)))
(defun phpinspect-declaration-p (token)
- (phpinspect-type-p token :declaration))
+ (phpinspect-token-type-p token :declaration))
(defsubst phpinspect-assignment-p (token)
- (phpinspect-type-p token :assignment))
+ (phpinspect-token-type-p token :assignment))
(defun phpinspect-function-argument-list (php-func)
"Get the argument list of a function"
(seq-find #'phpinspect-list-p (seq-find #'phpinspect-declaration-p php-func
nil) nil))
(defsubst phpinspect-variable-p (token)
- (phpinspect-type-p token :variable))
+ (phpinspect-token-type-p token :variable))
(defsubst phpinspect-word-p (token)
- (phpinspect-type-p token :word))
+ (phpinspect-token-type-p token :word))
(defsubst phpinspect-incomplete-array-p (token)
- (phpinspect-type-p token :incomplete-array))
+ (phpinspect-token-type-p token :incomplete-array))
(defsubst phpinspect-array-p (token)
- (or (phpinspect-type-p token :array)
+ (or (phpinspect-token-type-p token :array)
(phpinspect-incomplete-array-p token)))
(defsubst phpinspect-incomplete-token-p (token)
@@ -265,17 +276,17 @@ Type can be any of the token types returned by
(defsubst phpinspect-root-p (object)
- (phpinspect-type-p object :root))
+ (phpinspect-token-type-p object :root))
(defsubst phpinspect-namespace-or-root-p (object)
(or (phpinspect-namespace-p object)
(phpinspect-root-p object)))
(defun phpinspect-use-p (object)
- (phpinspect-type-p object :use))
+ (phpinspect-token-type-p object :use))
(defun phpinspect-comment-p (token)
- (phpinspect-type-p token :comment))
+ (phpinspect-token-type-p token :comment))
(defsubst phpinspect-class-block (class)
(caddr class))
@@ -875,12 +886,59 @@ that contains all handlers necessary to parse code."
(current-buffer)
point))))
-(cl-defstruct (phpinspect--function (:constructor phpinspect--make-function))
+(cl-defstruct (phpinspect--type
+ (:constructor phpinspect--make-type-generated))
+ "Represents an instance of a PHP type in the phpinspect syntax tree."
+ (name-symbol nil
+ :type symbol
+ :documentation
+ "Symbol representation of the type name.")
+ (collection nil
+ :type bool
+ :documentation
+ "Whether or not the type is a collection")
+ (contains nil
+ :type phpinspect--type
+ :documentation
+ "When the type is a collection, this attribute is set to the type
that the collection is expected to contain")
+ (fully-qualified nil
+ :type bool
+ :documentation
+ "Whether or not the type name is fully qualified"))
+
+(defsubst phpinspect--wrap-plist-name-in-symbol (property-list)
+ (let ((new-plist)
+ (wrap-value))
+ (dolist (item property-list)
+ (when wrap-value
+ (setq item `(phpinspect-intern-name ,item))
+ (setq wrap-value nil))
+ (when (eq item :name)
+ (setq item :name-symbol)
+ (setq wrap-value t))
+ (push item new-plist))
+ (nreverse new-plist)))
+
+
+(defmacro phpinspect--make-type (&rest property-list)
+ `(phpinspect--make-type-generated
+ ,@(phpinspect--wrap-plist-name-in-symbol property-list)))
+
+(cl-defmethod phpinspect--type-set-name ((type phpinspect--type) (name string))
+ (setf (phpinspect--type-name-symbol type) (phpinspect-intern-name name)))
+
+(cl-defmethod phpinspect--type-name ((type phpinspect--type))
+ (symbol-name (phpinspect--type-name-symbol type)))
+
+(cl-defmethod phpinspect--type= ((type1 phpinspect--type) (type2
phpinspect--type))
+ (eq (phpinspect--type-name-symbol type1) (phpinspect--type-name-symbol
type2)))
+
+(cl-defstruct (phpinspect--function (:constructor
phpinspect--make-function-generated))
"A PHP function."
- (name nil
- :type string
- :documentation
- "A string containing the name of the function")
+ (name-symbol nil
+ :type symbol
+ :documentation
+ "A symbol associated with the name of the function")
(scope nil
:type phpinspect-scope
:documentation
@@ -893,10 +951,23 @@ scope of the function as returned by
`phpinspect-parse-scope`.")
types in tuples. Each list should have the name of the variable
as first element and the type as second element.")
(return-type nil
- :type string
+ :type phpinspect--type
:documentation
- "A string containing the FQN of the return value
-of the function."))
+ "A phpinspect--type object representing the the
+return type of the function."))
+
+(defmacro phpinspect--make-function (&rest property-list)
+ `(phpinspect--make-function-generated
+ ,@(phpinspect--wrap-plist-name-in-symbol property-list)))
+
+(cl-defmethod phpinspect--function-set-name ((func phpinspect--function) (name
string))
+ (setf (phpinspect--function-name-symbol func) (intern name
phpinspect-name-obarray)))
+
+(cl-defgeneric phpinspect--function-name ((func phpinspect--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."
@@ -923,9 +994,12 @@ contain the scope of the variable as returned by
(annotation nil :type string)
(kind nil :type symbol))
-(defun phpinspect--format-type-name (name)
+(cl-defgeneric phpinspect--format-type-name (name)
(string-remove-prefix "\\" name))
+(cl-defmethod phpinspect--format-type-name ((type phpinspect--type))
+ (phpinspect--format-type-name (phpinspect--type-name type)))
+
(cl-defgeneric phpinspect--make-completion (completion-candidate)
"Creates a `phpinspect--completion` for a possible completion
candidate. Candidates can be indexed functions and variables.")
@@ -945,9 +1019,9 @@ candidate. Candidates can be indexed functions and
variables.")
") "
(phpinspect--format-type-name
(phpinspect--function-return-type completion-candidate)))
:annotation (concat " "
- (phpinspect--get-bare-class-name-from-fqn
+ (phpinspect--type-bare-name
(or (phpinspect--function-return-type
completion-candidate)
- "")))
+ (phpinspect--make-type :name "\\"))))
:kind 'function))
(cl-defstruct (phpinspect--resolvecontext
@@ -1017,7 +1091,7 @@ accompanied by all of its enclosing tokens."
(unless window-point-insertion-type
(set (make-local-variable 'window-point-insertion-type) t))
(goto-char (buffer-end 1))
- (insert (concat "[" (format-time-string "%H:%M:%S.%N") "]: "
+ (insert (concat "[" (format-time-string "%H:%M:%S") "]: "
(apply #'format args) "\n")))))
(defsubst phpinspect-cache-project-class (project-root indexed-class)
@@ -1035,7 +1109,6 @@ accompanied by all of its enclosing tokens."
class-fqn)))
(defun phpinspect-get-project-class-inherit-classes (project-root class)
- (phpinspect--log "Getting inherit classes for %s" class)
(let ((classnames `(,@(alist-get 'extends class)
,@(alist-get 'implements class)))
(classes))
@@ -1069,16 +1142,26 @@ accompanied by all of its enclosing tokens."
(let ((methods-key (if static 'static-methods 'methods))
(methods))
- (dolist (method (alist-get methods-key index))
- (push method methods))
-
(dolist (class (phpinspect-get-project-class-inherit-classes
project-root
index))
(dolist (method (alist-get methods-key class))
(push method methods)))
- methods)))))
+ (dolist (method (alist-get methods-key index))
+ (push method methods))
+
+ (nreverse methods))))))
+
+(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)
@@ -1086,18 +1169,17 @@ accompanied by all of its enclosing tokens."
(phpinspect--log "Getting cached project class method type for %s (%s::%s)"
project-root class-fqn method-name)
(let ((found-method
- (seq-find (lambda (method)
- (and (string= (phpinspect--function-name method)
method-name)
- (phpinspect--function-return-type method)))
- (phpinspect-get-cached-project-class-methods
- project-root
- class-fqn))))
+ (phpinspect-find-function-in-list
+ method-name
+ (phpinspect-get-cached-project-class-methods project-root
class-fqn))))
(when found-method
(phpinspect--log "Found method: %s" found-method)
(phpinspect--function-return-type found-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
(seq-find (lambda (variable)
@@ -1113,13 +1195,9 @@ accompanied by all of its enclosing tokens."
(project-root class-fqn method-name)
(when project-root
(let* ((found-method
- (seq-find (lambda (method)
- (and (string= (phpinspect--function-name method)
method-name)
- (phpinspect--function-return-type method)))
- (phpinspect-get-cached-project-class-methods
- project-root
- class-fqn
- 'static))))
+ (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)))))
@@ -1139,18 +1217,17 @@ accompanied by all of its enclosing tokens."
(phpinspect-parse-current-buffer)))
(defun phpinspect--split-list (predicate list)
- (seq-reduce (let ((current-sublist))
- (lambda (result elt)
- (if (funcall predicate elt)
- (progn
- (push elt current-sublist)
- (push (nreverse current-sublist) result)
- (setq current-sublist nil))
- (push elt current-sublist))
- result))
- list
- nil))
-
+ (let ((sublists)
+ (current-sublist))
+ (dolist (thing list)
+ (if (funcall predicate thing)
+ (when 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
arg-list)
"Infer VARIABLE-NAME's type from typehints in
@@ -1206,19 +1283,14 @@ TODO:
(let* ((type-of-previous-statement
(phpinspect-resolve-type-from-context resolvecontext
type-resolver))
- (method-name (cadr (cadar (last statement 2))))
+ (method-name-sym (phpinspect-intern-name (cadr (cadar (last
statement 2)))))
(class-methods (phpinspect-get-cached-project-class-methods
(phpinspect--resolvecontext-project-root
resolvecontext)
type-of-previous-statement
static))
(method (and class-methods
- (seq-find
- (lambda (func)
- (when func
- (string= method-name
- (phpinspect--function-name func))))
- class-methods))))
- (phpinspect--log "Eldoc method name: %s" method-name)
+ (phpinspect-find-function-in-list method-name
class-methods))))
+ (phpinspect--log "Eldoc method name: %s" method-name-sym)
(phpinspect--log "Eldoc type of previous statement: %s"
type-of-previous-statement)
(phpinspect--log "Eldoc method: %s" method)
@@ -1251,46 +1323,88 @@ TODO:
(phpinspect--format-type-name
(phpinspect--function-return-type method)))))))))
+(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)))
-(defun phpinspect--find-assignments-in-token (token)
+(cl-defgeneric phpinspect--find-assignments-in-token (token)
"Find any assignments that are in TOKEN, at top level or nested in blocks"
(let ((assignments)
- (code-block)
- (statements (phpinspect--split-list
- (lambda (elt)
- (or (phpinspect-terminator-p elt)
- (phpinspect-block-p elt)))
- token)))
+ (block-or-list)
+ (statements (phpinspect--split-list #'phpinspect-end-of-statement-p
token)))
(dolist (statement statements)
(cond ((seq-find #'phpinspect-assignment-p statement)
(phpinspect--log "Found assignment statement")
(push statement assignments))
- ((setq code-block (seq-find #'phpinspect-block-p statement))
+ ((setq block-or-list (seq-find #'phpinspect-block-or-list-p
statement))
+ (phpinspect--log "Found block or list %s" block-or-list)
(setq assignments
(append
- (phpinspect--find-assignments-in-token code-block)
+ (phpinspect--find-assignments-in-token block-or-list)
assignments)))))
;; return
+ (phpinspect--log "Yayo Returning %s" assignments)
+ (phpinspect--log "Yayo had statements %s" statements)
assignments))
-(defun phpinspect-not-assignment-p (token)
+(cl-defmethod phpinspect--find-assignments-in-token ((token (head :list)))
+ "Find assignments that are in a list token."
+ (phpinspect--log "looking for assignments in list %s" token)
+ (let ((ajaja (seq-filter
+ (lambda (statement)
+ (phpinspect--log "checking statement %s" statement)
+ (seq-find #'phpinspect-maybe-assignment-p statement))
+ (phpinspect--split-list #'phpinspect-end-of-statement-p (cdr
token)))))
+ (phpinspect--log "Found ajaja %s" ajaja)
+ ajaja))
+
+(defsubst phpinspect-not-assignment-p (token)
"Inverse of applying `phpinspect-assignment-p to TOKEN."
- (not (phpinspect-assignment-p token)))
+ (not (phpinspect-maybe-assignment-p token)))
-(defun phpinspect--find-assignments-of-variable-in-token (variable-name token)
+(defun phpinspect--find-assignment-values-for-variable-in-token (variable-name
token)
"Find all assignments of variable VARIABLE-NAME in TOKEN."
(let ((variable-assignments)
(all-assignments (phpinspect--find-assignments-in-token token)))
(dolist (assignment all-assignments)
- (if (or (member `(:variable ,variable-name)
- (seq-take-while #'phpinspect-not-assignment-p
- assignment))
- (and (phpinspect-list-p (car assignment))
- (member `(:variable ,variable-name) (car assignment))))
- (push assignment variable-assignments)))
+ (let* ((is-loop-assignment nil)
+ (left-of-assignment
+ (seq-take-while #'phpinspect-not-assignment-p assignment))
+ (right-of-assignment
+ (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 (member `(:variable ,variable-name) right-of-assignment)
+ (push left-of-assignment variable-assignments))
+ (when (member `(:variable ,variable-name) left-of-assignment)
+ (push right-of-assignment variable-assignments)))))
(nreverse variable-assignments)))
-(defun phpinspect-drop-preceding-barewords (statement)
+ ;; (if (or (member `(:variable ,variable-name)
+ ;; (seq-take-while #'phpinspect-not-assignment-p
+ ;; assignment))5
+ ;; (and (phpinspect-list-p (car assignment))
+ ;; (member `(:variable ,variable-name) (car assignment)))
+ ;; (and (member '(:word "as") assignment)
+ ;; (member `(:variable ,variable-name)
+ ;; (seq-drop-while (lambda (elt)
+ ;; (not (equal '(:word "as")
elt)))))))
+ ;; (push assignment variable-assignments)))
+ ;; (nreverse variable-assignments)))
+
+(defsubst phpinspect-drop-preceding-barewords (statement)
(while (and statement (phpinspect-word-p (cadr statement)))
(pop statement))
statement)
@@ -1330,7 +1444,8 @@ $variable = $variable->method();"
(setq statement
(phpinspect-drop-preceding-barewords
statement))
(setq first-token (pop statement)))
- (funcall type-resolver (cadr first-token)))
+ (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
@@ -1403,38 +1518,37 @@ 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 "self")
+ (funcall type-resolver (phpinspect--make-type :name "self"))
;; else
(let* ((assignments
- (phpinspect--find-assignments-of-variable-in-token variable-name
php-block))
- (last-assignment (when assignments (car (last assignments))))
- (right-of-assignment (when assignments (cdr (seq-drop-while
#'phpinspect-not-assignment-p
-
last-assignment)))))
- (phpinspect--log "Last assignment: %s" right-of-assignment)
+ (phpinspect--find-assignment-values-for-variable-in-token
variable-name php-block))
+ (last-assignment-value (when assignments (car (last assignments)))))
+
+ (phpinspect--log "Last assignment: %s" last-assignment-value)
;; 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->attribute
- (cond ((and (phpinspect-word-p (car right-of-assignment))
- (string= (cadar right-of-assignment) "new"))
- (funcall type-resolver (cadadr right-of-assignment)))
- ((and (> (length right-of-assignment) 2)
- (seq-find #'phpinspect-attrib-p right-of-assignment))
+ (cond ((and (phpinspect-word-p (car last-assignment-value))
+ (string= (cadar last-assignment-value) "new"))
+ (funcall type-resolver (phpinspect--make-type :name (cadadr
last-assignment-value))))
+ ((and (> (length last-assignment-value) 2)
+ (seq-find #'phpinspect-attrib-p last-assignment-value))
(phpinspect--log "Variable was assigned with a derived statement")
(phpinspect-get-derived-statement-type-in-block resolvecontext
-
right-of-assignment
+
last-assignment-value
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 right-of-assignment))
+ ((phpinspect-variable-p (car last-assignment-value))
(phpinspect--log "Variable was assigned with the value of another
variable")
(or (when function-arg-list
- (phpinspect-get-variable-type-in-function-arg-list (cadar
right-of-assignment)
+ (phpinspect-get-variable-type-in-function-arg-list (cadar
last-assignment-value)
function-arg-list))
(phpinspect-get-variable-type-in-block resolvecontext
- (cadar
right-of-assignment)
+ (cadar
last-assignment-value)
php-block
type-resolver
function-arg-list)))
@@ -1500,21 +1614,24 @@ resolve types of function argument variables."
(if token-tree (or (phpinspect--find-innermost-incomplete-class
token-tree)
(phpinspect--find-class-token token-tree))))
(inside-class-name (if inside-class
(phpinspect--get-class-name-from-token
- inside-class))))
+ inside-class)))
+ (self-type (phpinspect--make-type :name "self"))
+ (static-type (phpinspect--make-type :name "static")))
(lambda (type)
- (phpinspect--real-type
+ (phpinspect--type-resolve
types
namespace
- (if (and inside-class-name (or (string= type "self")
- (string= type "static")))
+ (if (and inside-class-name (or (phpinspect--type= type self-type)
+ (phpinspect--type= type static-type)))
(progn
(phpinspect--log "Returning inside class name for %s : %s"
type inside-class-name)
- inside-class-name)
+ (phpinspect--make-type :name inside-class-name))
;; else
type)))))
-(defun phpinspect--real-type (types namespace type)
+
+(defun phpinspect--resolve-type-name (types namespace type)
"Get the FQN for TYPE, using TYPES and NAMESPACE as context.
TYPES must be an alist with class names as cars and FQNs as cdrs.
@@ -1533,16 +1650,26 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(concat "\\" namespace "\\" type))
;; Clas|interface|trait name
- (t (concat "\\" (or (assoc-default type types #'string=)
- (if namespace
- (concat namespace "\\" type)
- type))))))
+ (t (let ((from-types (assoc-default (phpinspect-intern-name type)
types #'eq)))
+ (concat "\\" (cond (from-types
+ (phpinspect--type-name from-types))
+ (namespace
+ (concat namespace "\\" type))
+ (t type)))))))
+
+(cl-defmethod phpinspect--type-resolve (types namespace (type
phpinspect--type))
+ (unless (phpinspect--type-fully-qualified type)
+ (phpinspect--type-set-name
+ type
+ (phpinspect--resolve-type-name types namespace (phpinspect--type-name
type)))
+ (setf (phpinspect--type-fully-qualified type) t))
+ type)
(defun phpinspect-var-annotation-p (token)
- (phpinspect-type-p token :var-annotation))
+ (phpinspect-token-type-p token :var-annotation))
(defun phpinspect-return-annotation-p (token)
- (phpinspect-type-p token :return-annotation))
+ (phpinspect-token-type-p token :return-annotation))
(defun phpinspect--index-function-arg-list (type-resolver arg-list)
(let ((arg-index)
@@ -1552,7 +1679,7 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(cond ((and (phpinspect-word-p current-token)
(phpinspect-variable-p (car arg-list)))
(push `(,(cadr (pop arg-list))
- ,(funcall type-resolver (cadr current-token)))
+ ,(funcall type-resolver (phpinspect--make-type :name (cadr
current-token))))
arg-index))
((phpinspect-variable-p (car arg-list))
(push `(,(cadr (pop arg-list))
@@ -1564,15 +1691,36 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(let* ((php-func (cadr scope))
(declaration (cadr php-func))
(type (if (phpinspect-word-p (car (last declaration)))
- (cadar (last declaration))
- ;; @return annotation
- (cadadr
- (seq-find #'phpinspect-return-annotation-p
- comment-before)))))
+ (phpinspect--make-type :name (cadar (last declaration))))))
+
+ ;; @return annotation. Has precedence over typehint when dealing with a
collection.
+ (let* ((is-collection
+ (when type
+ (member (phpinspect--type-name
+ (funcall type-resolver type))
phpinspect-collection-types)))
+ (return-annotation-type
+ (when (or (not type) is-collection)
+ (cadadr
+ (seq-find #'phpinspect-return-annotation-p
+ comment-before)))))
+ (phpinspect--log "found return annotation %s" return-annotation-type)
+
+ (when return-annotation-type
+ (cond ((not type)
+ (setq type (funcall type-resolver
+ (phpinspect--make-type :name
return-annotation-type))))
+ (is-collection
+ (phpinspect--log "Detected collection type in: %s" scope)
+ (setf (phpinspect--type-contains type)
+ (funcall type-resolver
+ (phpinspect--make-type :name
return-annotation-type)))
+ (setf (phpinspect--type-collection type) t)))))
+
(phpinspect--make-function
:scope `(,(car scope))
:name (cadadr (cdr declaration))
- :return-type (when type (funcall type-resolver type))
+ :return-type (if type (funcall type-resolver type)
+ (phpinspect--make-type :name "\\void"))
:arguments (phpinspect--index-function-arg-list
type-resolver
(phpinspect-function-argument-list php-func)))))
@@ -1600,10 +1748,10 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(phpinspect--make-variable
:name variable-name
:scope `(,(car scope))
- :type (if type (funcall type-resolver type)))))
+ :type (if type (funcall type-resolver (phpinspect--make-type :name
type))))))
(defun phpinspect-doc-block-p (token)
- (phpinspect-type-p token :doc-block))
+ (phpinspect-token-type-p token :doc-block))
(defun phpinspect--get-class-name-from-token (class-token)
(let ((subtoken (seq-find (lambda (word)
@@ -1644,9 +1792,13 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(t
(phpinspect--log "Calling Resolver from index-class on %s"
(cadr word))
(cond (enc-extends
- (push (funcall type-resolver (cadr word)) extends))
+ (push (funcall type-resolver (phpinspect--make-type
+ :name (cadr word)))
+ extends))
(enc-implements
- (push (funcall type-resolver (cadr word))
implements))))))))
+ (push (funcall type-resolver (phpinspect--make-type
+ :name (cadr word)))
+ implements))))))))
(dolist (token (caddr class))
(cond ((phpinspect-scope-p token)
@@ -1674,6 +1826,7 @@ NAMESPACE may be nil, or a string with a namespace FQN."
comment-before)
static-variables))))
(t
+ (phpinspect--log "comment-before is: %s" comment-before)
(push (phpinspect--index-function-from-scope type-resolver
token
comment-before)
@@ -1698,21 +1851,27 @@ NAMESPACE may be nil, or a string with a namespace FQN."
constants))
((phpinspect-function-p token)
;; Bare functions are always public
- (push (phpinspect--index-function-from-scope type-resolver (list
:public token) comment-before)
+ (push (phpinspect--index-function-from-scope type-resolver
+ (list :public token)
+ comment-before)
methods))
((phpinspect-doc-block-p token)
+ (phpinspect--log "setting comment-before %s" token)
(setq comment-before token))
;; Prevent comments from sticking around too long
- (t (setq comment-before nil))))
+ (t
+ (phpinspect--log "Unsetting comment-before")
+ (setq comment-before nil))))
;; Dirty hack that assumes the constructor argument names to be the same
as the object
;; attributes' names.
;;;
;; TODO: actually check the types of the variables assigned to object
attributes
- (let ((constructor (seq-find (lambda (method)
- (string= (phpinspect--function-name method)
- "__construct"))
+ (let* ((constructor-sym (phpinspect-intern-name "__construct"))
+ (constructor (seq-find (lambda (method)
+ (eq (phpinspect--function-name-symbol
method)
+ constructor-sym))
methods)))
(when constructor
(phpinspect--log "Constructor was found")
@@ -1728,7 +1887,7 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(setf (phpinspect--variable-type variable)
(funcall type-resolver
constructor-parameter-type))))))))
- (let ((class-name (funcall type-resolver class-name)))
+ (let ((class-name (funcall type-resolver (phpinspect--make-type :name
class-name))))
`(,class-name .
(phpinspect--class
(methods . ,methods)
@@ -1762,12 +1921,13 @@ namespace if not provided"
(defun phpinspect--use-to-type (use)
(let* ((fqn (cadr (cadr use)))
+ (type (phpinspect--make-type :name fqn :fully-qualified t))
(type-name (if (and (phpinspect-word-p (caddr use))
(string= "as" (cadr (caddr use))))
(cadr (cadddr use))
(progn (string-match "[^\\]+$" fqn)
(match-string 0 fqn)))))
- (cons type-name fqn)))
+ (cons (phpinspect-intern-name type-name) type)))
(defun phpinspect--uses-to-types (uses)
(mapcar #'phpinspect--use-to-type uses))
@@ -1822,7 +1982,7 @@ namespace if not provided"
(visited-buffer (when class-file (find-buffer-visiting
class-file)))
(new-index))
- (phpinspect--log "FQN: %s" class-fqn)
+ (phpinspect--log "No existing index for FQN: %s" class-fqn)
(phpinspect--log "filepath: %s" class-file)
(when class-file
(if visited-buffer
@@ -1837,7 +1997,7 @@ namespace if not provided"
(alist-get class-fqn (alist-get 'classes new-index)
nil
nil
- #'string=))))))))
+ #'phpinspect--type=))))))))
(defun phpinspect--index-current-buffer ()
@@ -1848,7 +2008,7 @@ namespace if not provided"
(phpinspect--index-tokens (phpinspect-parse-current-buffer)))
(defun phpinspect--get-variables-for-class (buffer-classes class &optional
static)
- (let ((class-index (or (assoc-default class buffer-classes #'string=)
+ (let ((class-index (or (assoc-default class buffer-classes
#'phpinspect--type=)
(phpinspect--get-or-create-index-for-class-file
class))))
(when class-index
(if static
@@ -1867,7 +2027,7 @@ more recent"
resolvecontext)
class
static))
- (buffer-index (alist-get class buffer-classes nil nil #'string=)))
+ (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)
@@ -1913,6 +2073,7 @@ users will have to use \\[phpinspect-purge-cache]."
(defun phpinspect--disable-mode ()
"Clean up the buffer environment for the mode to be disabled."
+ (kill-local-variable 'phpinspect--buffer-project)
(kill-local-variable 'phpinspect--buffer-index)
(kill-local-variable 'company-backends)
(kill-local-variable 'eldoc-documentation-function)
@@ -2038,7 +2199,7 @@ level of a token. Nested variables are ignored."
(dolist (class index2-classes)
(when class
(let* ((class-name (alist-get 'class-name (cdr class)))
- (existing-class (alist-get class-name index1-classes nil nil
'string=)))
+ (existing-class (alist-get class-name index1-classes nil nil
'phpinspect--type=)))
(if existing-class
(progn
(phpinspect--log "Found existing class in root index: %s"
class-name)
@@ -2056,28 +2217,28 @@ level of a token. Nested variables are ignored."
(defun phpinspect--get-bare-class-name-from-fqn (fqn)
(car (last (split-string fqn "\\\\"))))
+(cl-defmethod phpinspect--type-bare-name ((type phpinspect--type))
+ (phpinspect--get-bare-class-name-from-fqn (phpinspect--type-name type)))
+
(cl-defmethod phpinspect--make-completion
((completion-candidate phpinspect--variable))
(phpinspect--construct-completion
:value (phpinspect--variable-name completion-candidate)
- :meta (phpinspect--variable-type completion-candidate)
+ :meta (phpinspect--format-type-name
+ (phpinspect--variable-type completion-candidate))
:annotation (concat " "
- (phpinspect--get-bare-class-name-from-fqn
+ (phpinspect--type-bare-name
(or (phpinspect--variable-type completion-candidate)
- "")))
+ (phpinspect--make-type :name "\\"))))
:kind 'variable))
(cl-defstruct (phpinspect--completion-list
(:constructor phpinspect--make-completion-list))
"Contains all data for a completion at point"
- (completions nil
- :type list
+ (completions (obarray-make)
+ :type obarray
:documentation
- "A list of completion strings")
- (metadata (make-hash-table :size 20 :test 'equal)
- :type hash-table
- :documentation
- "A hash-table with `phpinspect--completion` structures."))
+ "A list of completion strings"))
(cl-defgeneric phpinspect--completion-list-add
(comp-list completion)
@@ -2085,13 +2246,26 @@ level of a token. Nested variables are ignored."
(cl-defmethod phpinspect--completion-list-add
((comp-list phpinspect--completion-list) (completion phpinspect--completion))
- (when (not (gethash (phpinspect--completion-value completion)
- (phpinspect--completion-list-metadata comp-list)))
- (push (phpinspect--completion-value completion)
- (phpinspect--completion-list-completions comp-list))
- (puthash (phpinspect--completion-value completion)
- completion
- (phpinspect--completion-list-metadata comp-list))))
+ (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
(token-tree resolvecontext &optional static)
@@ -2106,9 +2280,10 @@ resolved to provide completion candidates.
If STATIC is non-nil, candidates are provided for constants,
static variables and static methods."
- (let* ((buffer-classes (phpinspect--merge-indexes
+ (let* ((buffer-index (phpinspect--merge-indexes
phpinspect--buffer-index
(phpinspect--index-tokens token-tree)))
+ (buffer-classes (alist-get 'classes (cdr buffer-index)))
(type-resolver (phpinspect--make-type-resolver-for-resolvecontext
resolvecontext))
(method-lister (phpinspect--make-method-lister
@@ -2176,7 +2351,7 @@ static variables and static methods."
(phpinspect--log "Pushing variable %s" potential-variable)
(push (phpinspect--make-variable
:name (cadr potential-variable)
- :type "")
+ :type (phpinspect--make-type :name "\\void"))
variables))
((phpinspect-function-p potential-variable)
(push (phpinspect-function-block potential-variable)
token-list)
@@ -2184,7 +2359,7 @@ static variables and static methods."
(when (phpinspect-variable-p argument)
(push (phpinspect--make-variable
:name (cadr argument)
- :type "")
+ :type (phpinspect--make-type :name "\\void"))
variables))))
((phpinspect-block-p potential-variable)
(dolist (nested-token (cdr potential-variable))
@@ -2233,8 +2408,9 @@ static variables and static methods."
(substring match 1 (length match))))))
((eq command 'post-completion)
(when (eq 'function (phpinspect--completion-kind
- (gethash arg (phpinspect--completion-list-metadata
- phpinspect--last-completion-list))))
+ (phpinspect--completion-list-get-metadata
+ phpinspect--last-completion-list
+ arg)))
(insert "(")))
((eq command 'candidates)
(let ((completion-list (phpinspect--make-completion-list))
@@ -2249,24 +2425,23 @@ static variables and static methods."
(when completion
(string-match (concat "^" (regexp-quote arg))
completion)))
- (seq-uniq (phpinspect--completion-list-completions
- completion-list)
- #'string=)))
+ (phpinspect--completion-list-strings
+ completion-list)))
(setq phpinspect--last-completion-list completion-list)
candidates))
((eq command 'annotation)
(concat " " (phpinspect--completion-annotation
- (gethash arg
- (phpinspect--completion-list-metadata
- phpinspect--last-completion-list)))))
+ (phpinspect--completion-list-get-metadata
+ phpinspect--last-completion-list
+ arg))))
((eq command 'kind)
(phpinspect--completion-kind
- (gethash arg (phpinspect--completion-list-metadata
- phpinspect--last-completion-list))))
+ (phpinspect--completion-list-get-metadata
+ phpinspect--last-completion-list
+ arg)))
((eq command 'meta)
(phpinspect--completion-meta
- (gethash arg
- (phpinspect--completion-list-metadata
phpinspect--last-completion-list))))))
+ (phpinspect--completion-list-get-metadata
phpinspect--last-completion-list arg)))))
(cl-defstruct (phpinspect--cache (:constructor phpinspect--make-cache))
@@ -2316,7 +2491,7 @@ then returned.")
(cl-defmethod phpinspect--project-add-class
((project phpinspect--project) (class (head phpinspect--class)))
- (let* ((class-name (alist-get 'class-name (cdr class)))
+ (let* ((class-name (phpinspect--type-name (alist-get 'class-name (cdr
class))))
(existing-class (gethash class-name
(phpinspect--project-class-index project))))
(puthash class-name
@@ -2326,12 +2501,12 @@ then returned.")
(phpinspect--project-class-index project))))
(cl-defgeneric phpinspect--project-get-class
- ((project phpinspect--project) (class-fqn string))
+ ((project phpinspect--project) (class-fqn phpinspect--type))
"Get indexed class by name of CLASS-FQN stored in PROJECT.")
(cl-defmethod phpinspect--project-get-class
- ((project phpinspect--project) (class-fqn string))
- (gethash class-fqn
+ ((project phpinspect--project) (class-fqn phpinspect--type))
+ (gethash (phpinspect--type-name class-fqn)
(phpinspect--project-class-index project)))
(defun phpinspect--get-or-create-global-cache ()
@@ -2340,7 +2515,6 @@ If its value is nil, it is created and then returned."
(or phpinspect-cache
(setq phpinspect-cache (phpinspect--make-cache))))
-
(defun phpinspect-purge-cache ()
"Assign a fresh, empty cache object to `phpinspect-cache'.
This effectively purges any cached code information from all
@@ -2384,9 +2558,11 @@ level of START-FILE in stead of `default-directory`."
(string= parent-without-vendor "")))
(phpinspect--find-project-root parent-without-vendor))))))))
-(defsubst phpinspect-project-root (&rest args)
+(defsubst phpinspect-project-root ()
"Call `phpinspect-project-root-function' with ARGS as arguments."
- (apply phpinspect-project-root-function args))
+ (unless (and (boundp 'phpinspect--buffer-project) phpinspect--buffer-project)
+ (set (make-local-variable 'phpinspect--buffer-project) (funcall
phpinspect-project-root-function)))
+ phpinspect--buffer-project)
;; Use statements
;;;###autoload
@@ -2487,12 +2663,16 @@ before the search is executed."
(let* ((default-directory (phpinspect-project-root))
(result (with-temp-buffer
(phpinspect--log "dir: %s" default-directory)
- (phpinspect--log "class: %s" (string-remove-prefix "\\"
class))
+ (phpinspect--log "class: %s" (string-remove-prefix
+ "\\"
+ (phpinspect--type-name
class)))
(list (call-process phpinspect-index-executable
nil
(current-buffer)
nil
- "fp" (string-remove-prefix "\\" class))
+ "fp" (string-remove-prefix
+ "\\"
+ (phpinspect--type-name class)))
(buffer-string)))))
(if (not (= (car result) 0))
;; Index new files and try again if not done already.
- [elpa] externals/phpinspect f003b6a279 105/126: Make project indexation asynchronous using `phpinspect-pipeline', (continued)
- [elpa] externals/phpinspect f003b6a279 105/126: Make project indexation asynchronous using `phpinspect-pipeline', ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect ce995f2bc4 101/126: Remove unused variables, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect f2ece03f2a 109/126: Add factilities to filter logs from different modules, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 59a098a4cd 015/126: Add note about parser cache to defhandler + add config example, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 4430aaccb9 011/126: Rework parser code, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 0350069e34 005/126: Fix native (built-in) type names, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect f8689ac9df 018/126: Return parser function in stead of just the symbol, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 825a3de2c4 017/126: Add indexation command to mode docstring + add install to readme, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 1e4e865c9b 021/126: Add variables nested in (function or other) blocks to candidates, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 2b85271b2b 030/126: Test + fix get-last-statement-in-token for static attribute references, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect a60dba5f11 031/126: WIP: new struct to represent types, and string comparison optimization with obarray,
ELPA Syncer <=
- [elpa] externals/phpinspect 8caf967b57 029/126: Add test for resolve-type-from-context with preceding bareword, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 341afd42da 037/126: WIP: Index types in the background using collaborative threading., ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 98e88d45ac 034/126: WIP: Fix find-class-file, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 350850c07a 052/126: Fix phpinspect-index-static-methods test, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 224bbd7916 057/126: Implement array member type inference, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 9882ed2c60 061/126: Test/fix type inference of objects in nested arrays, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 47335f3450 064/126: Refactor phpinspect--project to phpinspect-project, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 1b1cf45638 054/126: Fix bug in extended classes' method merging + add some tests, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect 153ff71fcf 048/126: WIP: Implement psr0 and psr4 autoload strategies, ELPA Syncer, 2023/08/12
- [elpa] externals/phpinspect e65b268cea 053/126: Implement @method annotation indexation, ELPA Syncer, 2023/08/12