Implement support for PHP8.1 property typehints

master
Hugo Thunnissen 2 months ago
parent 8569553981
commit dfdef3e382

@ -49,4 +49,4 @@ compile-native: ./.deps
.PHONY: test .PHONY: test
test: deps test: deps
$(RUN_EMACS) -L ./test -l ./test/phpinspect-test e -f ert-run-tests-batch $(RUN_EMACS) -L ./test -l ./test/phpinspect-test -f ert-run-tests-batch

@ -339,27 +339,38 @@ linked with."
(setf (phpinspect-buffer-class-variables buffer) (phpinspect-make-toc class-variables))) (setf (phpinspect-buffer-class-variables buffer) (phpinspect-make-toc class-variables)))
(dolist (var to-be-indexed) (dolist (var to-be-indexed)
;; We have left the class we were previously indexing properties
;; for.
(when (and class (> (phpinspect-meta-start var) (phpinspect-meta-end class))) (when (and class (> (phpinspect-meta-start var) (phpinspect-meta-end class)))
(setq class nil)) (setq class nil))
;; Retrieve the class that the property belongs to. In a lot of cases only
;; one class will be in the current buffer. But PHP allows the definition
;; of multiple classes in the same file so this should be supported.
(unless class (unless class
(setq class (phpinspect-toc-token-at-point classes (phpinspect-meta-start var)))) (setq class (phpinspect-toc-token-at-point classes (phpinspect-meta-start var))))
;; Fetch the index for the current class
(setq class-obj (phpinspect-buffer-get-index-for-token buffer (phpinspect-meta-token class))) (setq class-obj (phpinspect-buffer-get-index-for-token buffer (phpinspect-meta-token class)))
(let (scope static indexed index-env comment-before) (let (scope static indexed index-env comment-before)
(if (phpinspect-static-p (phpinspect-meta-token (phpinspect-meta-parent var))) (if (phpinspect-static-p (phpinspect-meta-token (phpinspect-meta-parent var)))
;; Variable is defined as [scope?] static [type?] $variable
(progn (progn
(setq static (phpinspect-meta-parent var)) (setq static (phpinspect-meta-parent var))
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent static))) (when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent static)))
;; Variable is defined as scope static [type?] $variable
(setq scope `(,(car (phpinspect-meta-token (phpinspect-meta-parent static))) (setq scope `(,(car (phpinspect-meta-token (phpinspect-meta-parent static)))
,(phpinspect-meta-token var)) ,@(phpinspect-meta-token-with-left-siblings var))
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent static))))) comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent static)))))
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent var))) (when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent var)))
;; Variable is defined as scope [type?] $variable
(setq scope (phpinspect-meta-token (phpinspect-meta-parent var)) (setq scope (phpinspect-meta-token (phpinspect-meta-parent var))
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent var))))) comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent var)))))
(unless scope (setq scope `(:public ,(phpinspect-meta-token var)))) (unless scope
(setq scope `(:public ,@(mapcar #'phpinspect-meta-token (phpinspect-meta-left-siblings var))
,(phpinspect-meta-token var))))
(unless (setq index-env (alist-get class class-environments nil nil #'eq)) (unless (setq index-env (alist-get class class-environments nil nil #'eq))
(setq index-env (phpinspect-get-token-index-context namespaces imports class)) (setq index-env (phpinspect-get-token-index-context namespaces imports class))
@ -419,6 +430,16 @@ linked with."
(phpinspect-buffer-parse buffer 'no-interrupt)) (phpinspect-buffer-parse buffer 'no-interrupt))
(cl-defmethod phpinspect-buffer-update-project-index ((buffer phpinspect-buffer)) (cl-defmethod phpinspect-buffer-update-project-index ((buffer phpinspect-buffer))
"Update project index using the last parsed token map of this
buffer. When `phpinspect-buffer-parse' has been executed before
and a map is available from the previous parse, this is used. If
none is available `phpinspect-buffer-parse' is called before
continuing execution."
;; Parse buffer if no map is available.
(unless (phpinspect-buffer-map buffer)
(phpinspect-buffer-parse buffer))
;; Use inhibit-quit to prevent index corruption though partial index ;; Use inhibit-quit to prevent index corruption though partial index
;; application. ;; application.
(let ((inhibit-quit t)) (let ((inhibit-quit t))

@ -174,10 +174,29 @@ function (think \"new\" statements, return types etc.)."
(when (stringp type) type))) (when (stringp type) type)))
(defun phpinspect--index-variable-from-scope (type-resolver scope comment-before &optional static) (defun phpinspect--index-variable-from-scope (type-resolver scope comment-before &optional static)
"Index the variable inside `scope`." "Index the variable inside SCOPE, use doc in COMMENT-BEFORE if missing typehint.
(let* ((variable-name (cadr (cadr scope)))
(type Provide STATIC if the variable was defined as static.
(phpinspect--variable-type-string-from-comment comment-before variable-name)))
SCOPE should be a scope token (`phpinspect-scope-p')."
(setq scope (take 5 (seq-filter #'phpinspect-not-comment-p scope)))
(let (variable-name type)
(cond
((phpinspect--match-sequence (take 3 scope)
;; Sequence: scope-type, typehint, variable [ = value ]
:m * :f #'phpinspect-word-p :f #'phpinspect-variable-p)
(setq variable-name (cadr (nth 2 scope)))
(setq type (cadr (nth 1 scope))))
((phpinspect--match-sequence (take 2 scope)
;; Sequence: variable [ = value ]
:m * :f #'phpinspect-variable-p)
(setq variable-name (cadr (nth 1 scope))
;; Since no typehint is available, attempt extracting one from a
;; docstring.
type (phpinspect--variable-type-string-from-comment
comment-before variable-name)))
(t (error (format "Failed to determine variable from scope %s" scope))))
(phpinspect--log "calling resolver from index-variable-from-scope") (phpinspect--log "calling resolver from index-variable-from-scope")
(phpinspect--make-variable (phpinspect--make-variable
;; Static class variables are always prefixed with dollar signs when ;; Static class variables are always prefixed with dollar signs when
@ -260,7 +279,7 @@ function (think \"new\" statements, return types etc.)."
(cond ((phpinspect-const-p (cadr token)) (cond ((phpinspect-const-p (cadr token))
(push (phpinspect--index-const-from-scope token) constants)) (push (phpinspect--index-const-from-scope token) constants))
((phpinspect-variable-p (cadr token)) ((seq-find #'phpinspect-variable-p token)
(push (phpinspect--index-variable-from-scope type-resolver (push (phpinspect--index-variable-from-scope type-resolver
token token
comment-before) comment-before)
@ -275,10 +294,9 @@ function (think \"new\" statements, return types etc.)."
add-used-types) add-used-types)
static-methods)) static-methods))
((phpinspect-variable-p (cadadr token)) ((seq-find #'phpinspect-variable-p (cdadr token))
(push (phpinspect--index-variable-from-scope type-resolver (push (phpinspect--index-variable-from-scope type-resolver
(list (car token) `(,(car token) ,@(cdadr token))
(cadadr token))
comment-before comment-before
'static) 'static)
static-variables)))) static-variables))))
@ -298,11 +316,11 @@ function (think \"new\" statements, return types etc.)."
add-used-types) add-used-types)
static-methods)) static-methods))
((phpinspect-variable-p (cadr token)) ((seq-find #'phpinspect-variable-p (cdr token))
(push (phpinspect--index-variable-from-scope type-resolver (push (phpinspect--index-variable-from-scope type-resolver
`(:public `(:public ,@(cdr token))
,(cadr token)) comment-before
comment-before) 'static)
static-variables)))) static-variables))))
((phpinspect-const-p token) ((phpinspect-const-p token)
;; Bare constants are always public ;; Bare constants are always public

@ -149,6 +149,22 @@
(phpinspect-meta-children (phpinspect-meta-parent meta)) (phpinspect-meta-parent-offset meta)) (phpinspect-meta-children (phpinspect-meta-parent meta)) (phpinspect-meta-parent-offset meta))
#'phpinspect-meta-sort-start)) #'phpinspect-meta-sort-start))
(defun phpinspect-meta-left-sibling-tokens (meta)
(let* ((tokens (cons nil nil))
(rear tokens))
(dolist (sibling (phpinspect-meta-left-siblings meta))
(setq rear (setcdr rear (cons (phpinspect-meta-token sibling) nil))))
(cdr tokens)))
(defun phpinspect-meta-token-with-left-siblings (meta)
(nconc (phpinspect-meta-left-sibling-tokens meta) (list (phpinspect-meta-token meta))))
(defun phpinspect-meta-left-siblings (meta)
(sort
(phpinspect-splayt-find-all-before
(phpinspect-meta-children (phpinspect-meta-parent meta)) (phpinspect-meta-parent-offset meta))
#'phpinspect-meta-sort-start))
(defun phpinspect-meta-wrap-token-pred (predicate) (defun phpinspect-meta-wrap-token-pred (predicate)
(lambda (meta) (funcall predicate (phpinspect-meta-token meta)))) (lambda (meta) (funcall predicate (phpinspect-meta-token meta))))

@ -760,19 +760,19 @@ Returns the consumed text string without face properties."
(phpinspect-defparser scope-public (phpinspect-defparser scope-public
:tree-keyword "public" :tree-keyword "public"
:handlers '(function-keyword static-keyword const-keyword class-variable here-doc :handlers '(function-keyword static-keyword const-keyword class-variable here-doc
string terminator tag comment) string terminator tag comment word)
:delimiter-predicate #'phpinspect--scope-terminator-p) :delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defparser scope-private (phpinspect-defparser scope-private
:tree-keyword "private" :tree-keyword "private"
:handlers '(function-keyword static-keyword const-keyword class-variable here-doc :handlers '(function-keyword static-keyword const-keyword class-variable here-doc
string terminator tag comment) string terminator tag comment word)
:delimiter-predicate #'phpinspect--scope-terminator-p) :delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defparser scope-protected (phpinspect-defparser scope-protected
:tree-keyword "protected" :tree-keyword "protected"
:handlers '(function-keyword static-keyword const-keyword class-variable here-doc :handlers '(function-keyword static-keyword const-keyword class-variable here-doc
string terminator tag comment) string terminator tag comment word)
:delimiter-predicate #'phpinspect--scope-terminator-p) :delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defhandler scope-keyword (start-token max-point) (phpinspect-defhandler scope-keyword (start-token max-point)

@ -46,6 +46,11 @@
(or (phpinspect-assignment-p token) (or (phpinspect-assignment-p token)
(equal '(:word "as") token))) (equal '(:word "as") token)))
(define-inline phpinspect-not-assignment-p (token)
"Inverse of applying `phpinspect-assignment-p to TOKEN."
(inline-quote
(not (phpinspect-maybe-assignment-p ,token))))
(cl-defgeneric 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" "Find any assignments that are in TOKEN, at top level or nested in blocks"
(when (keywordp (car token)) (when (keywordp (car token))
@ -71,13 +76,6 @@
(phpinspect--log "Found statements in token: %s" statements) (phpinspect--log "Found statements in token: %s" statements)
assignments)) 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) (defun phpinspect--find-assignments-by-predicate (token predicate)
(let ((variable-assignments) (let ((variable-assignments)
(all-assignments (phpinspect--find-assignments-in-token token))) (all-assignments (phpinspect--find-assignments-in-token token)))

@ -251,4 +251,9 @@ Type can be any of the token types returned by
(and (listp token) (and (listp token)
(keywordp (car token)))) (keywordp (car token))))
(define-inline phpinspect-not-comment-p (token)
(inline-quote
(not (phpinspect-comment-p ,token))))
(provide 'phpinspect-token-predicates) (provide 'phpinspect-token-predicates)

@ -1 +1 @@
(:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Entity") (:terminator ";") (:use (:word "Doctrine\\ORM\\Mapping") (:word "as") (:word "ORM") (:terminator ";")) (:doc-block (:annotation "ORM\\Entity")) (:class (:declaration (:word "class") (:word "AuthToken")) (:block (:private (:class-variable "token") (:terminator ";")) (:doc-block (:var-annotation (:word "App\\\\Entity\\\\User"))) (:private (:class-variable "user") (:terminator ";")) (:doc-block (:var-annotation (:word "bool"))) (:private (:class-variable "valid") (:terminator ";")) (:doc-block (:var-annotation (:word "\\DateTime"))) (:private (:class-variable "creation_time") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "string") (:variable "token") (:comma ",") (:word "User") (:variable "user") (:comma ",") (:word "bool") (:variable "valid") (:assignment "=") (:word "false") (:comma ",") (:word "\\DateTime") (:variable "creation_time") (:assignment "=") (:word "null"))) (:block (:variable "this") (:object-attrib (:word "token")) (:assignment "=") (:variable "token") (:terminator ";") (:variable "this") (:object-attrib (:word "user")) (:assignment "=") (:variable "user") (:terminator ";") (:variable "this") (:object-attrib (:word "valid")) (:assignment "=") (:variable "valid") (:terminator ";") (:variable "this") (:object-attrib (:word "creation_time")) (:assignment "=") (:variable "creation_time") (:word "new") (:word "\\DateTime") (:list) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getToken") (:list) (:word "string")) (:block (:word "return") (:variable "this") (:object-attrib (:word "token")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getUser") (:list) (:word "User")) (:block (:word "return") (:variable "this") (:object-attrib (:word "user")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "hasStudentRole") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "role_student")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "isValid") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "valid")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getCreationTime") (:list) (:word "\\DateTime")) (:block (:word "return") (:variable "this") (:object-attrib (:word "creation_time")) (:terminator ";")))) (:doc-block (:return-annotation (:word "DateTime[]"))) (:public (:function (:declaration (:word "function") (:word "arrayReturn") (:list) (:word "array")) (:block (:word "return") (:array (:word "new") (:word "\\DateTime") (:list)) (:terminator ";")))))))) (:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Entity") (:terminator ";") (:use (:word "Doctrine\\ORM\\Mapping") (:word "as") (:word "ORM") (:terminator ";")) (:doc-block (:annotation "ORM\\Entity")) (:class (:declaration (:word "class") (:word "AuthToken")) (:block (:private (:class-variable "token") (:terminator ";")) (:doc-block (:var-annotation (:word "App\\\\Entity\\\\User"))) (:private (:class-variable "user") (:terminator ";")) (:doc-block (:var-annotation (:word "bool"))) (:private (:class-variable "valid") (:word "false") (:terminator ";")) (:doc-block (:var-annotation (:word "\\DateTime"))) (:private (:class-variable "creation_time") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "string") (:variable "token") (:comma ",") (:word "User") (:variable "user") (:comma ",") (:word "bool") (:variable "valid") (:assignment "=") (:word "false") (:comma ",") (:word "\\DateTime") (:variable "creation_time") (:assignment "=") (:word "null"))) (:block (:variable "this") (:object-attrib (:word "token")) (:assignment "=") (:variable "token") (:terminator ";") (:variable "this") (:object-attrib (:word "user")) (:assignment "=") (:variable "user") (:terminator ";") (:variable "this") (:object-attrib (:word "valid")) (:assignment "=") (:variable "valid") (:terminator ";") (:variable "this") (:object-attrib (:word "creation_time")) (:assignment "=") (:variable "creation_time") (:word "new") (:word "\\DateTime") (:list) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getToken") (:list) (:word "string")) (:block (:word "return") (:variable "this") (:object-attrib (:word "token")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getUser") (:list) (:word "User")) (:block (:word "return") (:variable "this") (:object-attrib (:word "user")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "hasStudentRole") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "role_student")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "isValid") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "valid")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getCreationTime") (:list) (:word "\\DateTime")) (:block (:word "return") (:variable "this") (:object-attrib (:word "creation_time")) (:terminator ";")))) (:doc-block (:return-annotation (:word "DateTime[]"))) (:public (:function (:declaration (:word "function") (:word "arrayReturn") (:list) (:word "array")) (:block (:word "return") (:array (:word "new") (:word "\\DateTime") (:list)) (:terminator ";"))))))))

@ -1 +1 @@
(:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Entity") (:terminator ";") (:use (:word "Doctrine\\ORM\\Mapping") (:word "as") (:word "ORM") (:terminator ";")) (:doc-block (:annotation "ORM\\Entity")) (:class (:declaration (:word "class") (:word "AuthToken")) (:block (:private (:class-variable "token") (:terminator ";")) (:private (:class-variable "extra") (:terminator ";")) (:doc-block (:var-annotation (:word "App\\\\Entity\\\\User"))) (:private (:class-variable "user") (:terminator ";")) (:doc-block (:var-annotation (:word "bool"))) (:private (:class-variable "valid") (:terminator ";")) (:doc-block (:var-annotation (:word "\\DateTime"))) (:private (:class-variable "creation_time") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "string") (:variable "token") (:comma ",") (:word "User") (:variable "user") (:comma ",") (:word "bool") (:variable "valid") (:assignment "=") (:word "false") (:comma ",") (:word "\\DateTime") (:variable "creation_time") (:assignment "=") (:word "null"))) (:block (:variable "this") (:object-attrib (:word "token")) (:assignment "=") (:variable "token") (:terminator ";") (:variable "this") (:object-attrib (:word "user")) (:assignment "=") (:variable "user") (:terminator ";") (:variable "this") (:object-attrib (:word "valid")) (:assignment "=") (:variable "valid") (:terminator ";") (:variable "this") (:object-attrib (:word "creation_time")) (:assignment "=") (:variable "creation_time") (:word "new") (:word "\\DateTime") (:list) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getToken") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "token")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getUser") (:list) (:word "User")) (:block (:word "return") (:variable "this") (:object-attrib (:word "user")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "hasStudentRole") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "role_student")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "isValid") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "valid")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "anAddedFunction") (:list)) (:block (:word "return") (:variable "this") (:object-attrib (:word "extra")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getCreationTime") (:list) (:word "\\DateTime")) (:block (:word "return") (:variable "this") (:object-attrib (:word "creation_time")) (:terminator ";")))))))) (:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Entity") (:terminator ";") (:use (:word "Doctrine\\ORM\\Mapping") (:word "as") (:word "ORM") (:terminator ";")) (:doc-block (:annotation "ORM\\Entity")) (:class (:declaration (:word "class") (:word "AuthToken")) (:block (:private (:class-variable "token") (:terminator ";")) (:private (:class-variable "extra") (:terminator ";")) (:doc-block (:var-annotation (:word "App\\\\Entity\\\\User"))) (:private (:class-variable "user") (:terminator ";")) (:doc-block (:var-annotation (:word "bool"))) (:private (:class-variable "valid") (:word "false") (:terminator ";")) (:doc-block (:var-annotation (:word "\\DateTime"))) (:private (:class-variable "creation_time") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "string") (:variable "token") (:comma ",") (:word "User") (:variable "user") (:comma ",") (:word "bool") (:variable "valid") (:assignment "=") (:word "false") (:comma ",") (:word "\\DateTime") (:variable "creation_time") (:assignment "=") (:word "null"))) (:block (:variable "this") (:object-attrib (:word "token")) (:assignment "=") (:variable "token") (:terminator ";") (:variable "this") (:object-attrib (:word "user")) (:assignment "=") (:variable "user") (:terminator ";") (:variable "this") (:object-attrib (:word "valid")) (:assignment "=") (:variable "valid") (:terminator ";") (:variable "this") (:object-attrib (:word "creation_time")) (:assignment "=") (:variable "creation_time") (:word "new") (:word "\\DateTime") (:list) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getToken") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "token")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getUser") (:list) (:word "User")) (:block (:word "return") (:variable "this") (:object-attrib (:word "user")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "hasStudentRole") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "role_student")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "isValid") (:list) (:word "bool")) (:block (:word "return") (:variable "this") (:object-attrib (:word "valid")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "anAddedFunction") (:list)) (:block (:word "return") (:variable "this") (:object-attrib (:word "extra")) (:terminator ";")))) (:public (:function (:declaration (:word "function") (:word "getCreationTime") (:list) (:word "\\DateTime")) (:block (:word "return") (:variable "this") (:object-attrib (:word "creation_time")) (:terminator ";"))))))))

@ -491,3 +491,61 @@ class AccountStatisticsController {
(:use (:word "Illuminate\\Support\\Facades\\Auth") (:terminator ";"))) (:use (:word "Illuminate\\Support\\Facades\\Auth") (:terminator ";")))
(mapcar #'phpinspect-meta-token (mapcar #'phpinspect-meta-token
(phpinspect-splayt-to-list (phpinspect-bmap-imports bmap))))))))) (phpinspect-splayt-to-list (phpinspect-bmap-imports bmap)))))))))
(ert-deftest phpinspect-buffer-index-typehinted-class-variables ()
(with-temp-buffer
(let ((buffer (phpinspect-make-buffer
:buffer (current-buffer)
:-project (phpinspect--make-project :autoload (phpinspect-make-autoloader)))))
(insert "<?php
declare(strict_types=1);
namespace App\\Controller\\Api\\V1;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Relations\\Relation;
use Illuminate\\Support\\Facades\\Auth;
class AccountStatisticsController {
public Model $model;
private Model $privModel;
static Relation $relation;
public static Relation $staticRelation;
}")
(phpinspect-buffer-update-project-index buffer)
(let ((class (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type
:name "\\App\\Controller\\Api\\V1\\AccountStatisticsController"
:fully-qualified t))))
(should class)
(let ((model (phpinspect--class-get-variable class "model"))
(priv-model (phpinspect--class-get-variable class "privModel"))
;; Static variables are stored with "$" prefix
(relation (phpinspect--class-get-variable class "$relation"))
(static-relation (phpinspect--class-get-variable class "$staticRelation")))
(should model)
(should priv-model)
(should relation)
(should static-relation)
(let ((model-type (phpinspect--make-type
:name "\\Illuminate\\Database\\Eloquent\\Model"
:fully-qualified t))
(relation-type (phpinspect--make-type
:name "\\Illuminate\\Database\\Eloquent\\Relations\\Relation"
:fully-qualified t)))
(should (phpinspect--variable-type model))
(should (phpinspect--type= model-type (phpinspect--variable-type model)))
(should (phpinspect--variable-type priv-model))
(should (phpinspect--type= model-type (phpinspect--variable-type priv-model)))
(should (phpinspect--variable-type relation))
(should (phpinspect--type= relation-type (phpinspect--variable-type relation)))
(should (phpinspect--variable-type static-relation))
(should (phpinspect--type= relation-type (phpinspect--variable-type static-relation)))))))))

@ -291,3 +291,57 @@ function example(Firewall $wall): Thing {}")
(should (member (phpinspect-intern-name "Thing") (alist-get 'used-types index))) (should (member (phpinspect-intern-name "Thing") (alist-get 'used-types index)))
(should (alist-get 'used-types index)))) (should (alist-get 'used-types index))))
(ert-deftest phpinspect-index-typehinted-variables ()
(with-temp-buffer
(let ((project (phpinspect--make-project :autoload (phpinspect-make-autoloader))))
(insert "<?php
declare(strict_types=1);
namespace App\\Controller\\Api\\V1;
use Illuminate\\Database\\Eloquent\\Model;
use Illuminate\\Database\\Eloquent\\Relations\\Relation;
use Illuminate\\Support\\Facades\\Auth;
class AccountStatisticsController {
public Model $model;
private Model $privModel;
static Relation $relation;
public static Relation $staticRelation;
}")
(phpinspect-project-add-index project (phpinspect-index-current-buffer))
(let ((class (phpinspect-project-get-class
project
(phpinspect--make-type
:name "\\App\\Controller\\Api\\V1\\AccountStatisticsController"
:fully-qualified t))))
(should class)
(let ((model (phpinspect--class-get-variable class "model"))
(priv-model (phpinspect--class-get-variable class "privModel"))
;; Static variables are stored with "$" prefix
(relation (phpinspect--class-get-variable class "$relation"))
(static-relation (phpinspect--class-get-variable class "$staticRelation")))
(should model)
(should priv-model)
(should relation)
(should static-relation)
(let ((model-type (phpinspect--make-type
:name "\\Illuminate\\Database\\Eloquent\\Model"
:fully-qualified t))
(relation-type (phpinspect--make-type
:name "\\Illuminate\\Database\\Eloquent\\Relations\\Relation"
:fully-qualified t)))
(should (phpinspect--variable-type model))
(should (phpinspect--type= model-type (phpinspect--variable-type model)))
(should (phpinspect--variable-type priv-model))
(should (phpinspect--type= model-type (phpinspect--variable-type priv-model)))
(should (phpinspect--variable-type relation))
(should (phpinspect--type= relation-type (phpinspect--variable-type relation)))
(should (phpinspect--variable-type static-relation))
(should (phpinspect--type= relation-type (phpinspect--variable-type static-relation)))))))))

Loading…
Cancel
Save