Add testcase for derived statement starting with function + fix bug

- Derived statements starting with functions were not resolved to a type. This
was caused by bugs in `phpinspect--get-derived-statement-type-in-block' and
`phpinspect--interpret-expression-type-in-block'. The division in each
function's functionalities was blurry and both duplicated some of each other's
logic. The situation has now been cleaned up a bit.
- An extra testcase was added for derived statements starting with a function
call
- a bunch of code that broke because of the changes was fixed
master
Hugo Thunnissen 4 weeks ago
parent 81194568e3
commit e020bb4e05

@ -81,7 +81,7 @@ be implemented for return values of `phpinspect-eld-strategy-execute'")
(let ((attrib (car (last (phpinspect--resolvecontext-subject rctx))))
type-before)
(setf (phpinspect--resolvecontext-subject rctx) (butlast (phpinspect--resolvecontext-subject rctx)))
(setq type-before (phpinspect-resolve-type-from-context rctx))
(setq type-before (phpinspect-resolve-type-from-context rctx nil t))
(when type-before
(let ((class (phpinspect-project-get-class-extra-or-create
@ -187,7 +187,7 @@ be implemented for return values of `phpinspect-eld-strategy-execute'")
(mapcar #'phpinspect-meta-token (butlast statement 2)))
(when-let* ((type-of-previous-statement
(phpinspect-resolve-type-from-context rctx))
(phpinspect-resolve-type-from-context rctx nil t))
(method-name (cadadr (phpinspect-meta-token (car match-result))))
(class (phpinspect-rctx-get-or-create-cached-project-class
rctx type-of-previous-statement 'no-enqueue))

@ -215,6 +215,10 @@ $variable = $variable->method();"
(or assignments (phpinspect--find-assignment-ctxs-in-token php-block))
type-resolver function-arg-list))
(defun phpinspect-no-derivation-p (token)
(not (or (phpinspect-attrib-p token)
(phpinspect-array-p token))))
(defun phpinspect--get-derived-statement-type-in-block
(resolvecontext statement php-block assignments type-resolver &optional function-arg-list)
"Determine the type that STATEMENT evaluates to in RESOLVECONTEXT.
@ -228,92 +232,67 @@ a derived statement. In the statement $foo->bar which is parsed
into ((:variable foo) (:object-attrib (:word bar))), the
value/type of ->bar must be derived from the type of $foo. So
->bar derives from the base token $foo."
;; 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: (truncated, real length: %d) %s"
(length statement)
(take 10 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))))
;; First token is a list, for example "(new DateTime())"
(when (phpinspect-list-p first-token)
(phpinspect--interpret-expression-type-in-context
resolvecontext php-block type-resolver (cdr first-token)
function-arg-list assignments))
;; No bare word, assume we're dealing with a variable.
(when (phpinspect-variable-p first-token)
(phpinspect--get-variable-type-in-block
resolvecontext (cadr first-token) php-block assignments
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
resolvecontext
(funcall type-resolver previous-attribute-type)
(cadr attribute-word))
previous-attribute-type)))
(setq previous-attribute-type
(phpinspect--log "Get derived statement type in block: (truncated, real length: %d) %s"
(length statement)
(take 10 statement))
(when-let ((start-expression (seq-take-while #'phpinspect-no-derivation-p statement))
(statement (nthcdr (length start-expression) statement))
(type-before
(if (phpinspect--match-sequence start-expression :f #'phpinspect-word-p)
(progn
(funcall type-resolver (phpinspect--make-type :name (cadar start-expression))))
(phpinspect--interpret-expression-type-in-context
resolvecontext php-block type-resolver start-expression
function-arg-list assignments))))
(phpinspect--log "Rest of statement: %s" statement)
(phpinspect--log "Starting attribute type: %s" type-before)
(while-let ((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 type-before
(or
(phpinspect-get-cached-project-class-method-type
resolvecontext
(funcall type-resolver type-before)
(cadr attribute-word))
type-before)))
(setq type-before
(or
(phpinspect-get-cached-project-class-variable-type
resolvecontext
(funcall type-resolver type-before)
(cadr attribute-word))
type-before))))))
((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 type-before
(or
(phpinspect-get-cached-project-class-variable-type
resolvecontext
(funcall type-resolver previous-attribute-type)
(phpinspect-get-cached-project-class-static-method-type
resolvecontext
(funcall type-resolver type-before)
(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
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))))
type-before)))))))
((and type-before (phpinspect-array-p current-token))
(setq type-before
(or (phpinspect--type-contains type-before)
type-before)))))
(phpinspect--log "Found derived type: %s" type-before)
;; Make sure to always return a FQN
(funcall type-resolver type-before)))
(defun phpinspect-get-variable-type-in-block
(resolvecontext variable-name php-block type-resolver &optional function-arg-list)
@ -335,7 +314,7 @@ 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"))
(funcall type-resolver (phpinspect--make-type :name "\\self" :fully-qualified t))
(phpinspect--get-pattern-type-in-block
resolvecontext (phpinspect--make-pattern :m `(:variable ,variable-name))
php-block assignments type-resolver function-arg-list)))
@ -461,6 +440,18 @@ ARG-LIST. ARG-LIST should be a list token as returned by
(phpinspect--make-type :name (car (last arg))))
nil)))))
(define-inline phpinspect-new-p (token)
(inline-letevals (token)
(inline-quote
(and (phpinspect-word-p ,token)
(string= "new" (cadr ,token))))))
(defun phpinspect-interpret-expression-type-in-context
(resolvecontext php-block type-resolver expression &optional function-arg-list assignments)
(phpinspect--interpret-expression-type-in-context
resolvecontext php-block type-resolver expression function-arg-list
(or assignments (phpinspect--find-assignment-ctxs-in-token php-block))))
(defun phpinspect--interpret-expression-type-in-context
(resolvecontext php-block type-resolver expression &optional function-arg-list assignments)
"Infer EXPRESSION's type from provided context.
@ -475,6 +466,9 @@ value/type."
(length expression)
(take 10 expression))
(unless (phpinspect-new-p (car expression))
(setq expression (phpinspect-drop-preceding-barewords expression)))
(cond ((phpinspect-array-p (car expression))
(let ((collection-contains)
(collection-items (phpinspect--split-statements (cdr (car expression))))
@ -496,7 +490,7 @@ value/type."
:collection t
:contains collection-contains)))
((phpinspect--match-sequence expression
:m '(:word "new")
:f #'phpinspect-new-p
:f #'phpinspect-word-p
:f #'phpinspect-list-p)
(funcall
@ -507,6 +501,14 @@ value/type."
:f #'phpinspect-list-p)
(phpinspect-rctx-get-function-return-type resolvecontext (cadar expression)))
;; Expression is a (chain of) assignments. The right-most subexpression
;; is the type it evaluates to.
((seq-find #'phpinspect-assignment-p expression)
(phpinspect--interpret-expression-type-in-context
resolvecontext php-block type-resolver
(car (last (phpinspect--split-statements expression #'phpinspect-maybe-assignment-p)))
function-arg-list assignments))
((and (phpinspect-list-p (car expression))
(= 1 (length (cdar expression)))
(phpinspect-word-p (cadar expression)))
@ -527,13 +529,6 @@ value/type."
(phpinspect--interpret-expression-type-in-context
resolvecontext php-block type-resolver (cdar expression)
function-arg-list assignments))
;; Expression is a (chain of) assignments. The right-most subexpression
;; is the type it evaluates to.
((seq-find #'phpinspect-assignment-p expression)
(phpinspect--interpret-expression-type-in-context
resolvecontext php-block type-resolver
(car (last (phpinspect--split-statements expression #'phpinspect-maybe-assignment-p)))
function-arg-list assignments))
;; 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.
@ -548,8 +543,14 @@ value/type."
resolvecontext (cadar expression) php-block assignments type-resolver function-arg-list)))))
(defun phpinspect-resolve-type-from-context (resolvecontext &optional type-resolver)
"Resolve the type that RESOLVECONTEXT's subject evaluates to."
(defun phpinspect-resolve-type-from-context (resolvecontext &optional type-resolver assume-derived)
"Resolve the type that RESOLVECONTEXT's subject evaluates to.
When ASSUME-DERIVED is non-nil, it will be assumed that
RESOLVECONTEXT's subject precedes a token that passes
`phpinspect-attrib-p'. In this case, when the subject is a single
bare word, it is assumed to be a type name at the start of a
static method call and resolved to a fully qualified type. (`phpinspect--type-p')"
;; Subject should be a statement, not a single token.
(when (phpinspect-probably-token-p (phpinspect--resolvecontext-subject resolvecontext))
(setf (phpinspect--resolvecontext-subject resolvecontext)
@ -573,31 +574,29 @@ value/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))))))
(let ((subject (phpinspect--resolvecontext-subject resolvecontext)))
(setq type
(cond ((and assume-derived
(phpinspect--match-sequence subject :f #'phpinspect-word-p))
(funcall type-resolver (phpinspect--make-type :name (cadar subject))))
((phpinspect-namespace-p enclosing-token)
(phpinspect-interpret-expression-type-in-context
resolvecontext
(or (phpinspect-namespace-block enclosing-token) enclosing-token)
type-resolver subject))
((or (phpinspect-block-p enclosing-token)
(phpinspect-root-p enclosing-token))
(phpinspect-interpret-expression-type-in-context
resolvecontext enclosing-token type-resolver subject))
((phpinspect-function-p enclosing-token)
(phpinspect-interpret-expression-type-in-context
resolvecontext
(phpinspect-function-block enclosing-token)
type-resolver subject
(phpinspect-function-argument-list enclosing-token)))))))
type))
(defun phpinspect--function-get-pattern-type (fn rctx pattern type-resolver)

@ -65,6 +65,7 @@
(complete . ,,(alist-get 'complete class))
(class-name . ,,(phpinspect--serialize-type (alist-get 'class-name class)))
(declaration . ,(quote ,(alist-get 'declaration class)))
(location . ,(quote ,(alist-get 'location class)))
(imports . ,,(append '(list)
(mapcar #'phpinspect--serialize-import
(alist-get 'imports class))))
@ -88,7 +89,9 @@
(alist-get 'extends class))))
(implements . ,,(append '(list)
(mapcar #'phpinspect--serialize-type
(alist-get 'implements class))))))
(alist-get 'implements class))))
(used-types . ,(list ,@(mapcar #'phpinspect--serialize-name
(alist-get 'used-types class))))))
(cl-defmethod phpinspect--serialize-root-index ((index (head phpinspect--root-index)))
``(phpinspect--root-index
@ -99,7 +102,9 @@
,@(mapcar (lambda (cons-class)
`(cons ,(phpinspect--serialize-type (car cons-class))
,(phpinspect--serialize-indexed-class (cdr cons-class))))
(alist-get 'classes index))))
(alist-get 'classes index))))
(used-types . ,(list ,@(mapcar #'phpinspect--serialize-name
(alist-get 'used-types index))))
(functions . ,,(append '(list)
(mapcar #'phpinspect--serialize-function
(alist-get 'functions index))))))
@ -110,5 +115,8 @@
(phpinspect-intern-name ,(phpinspect-name-string (car import)))
,(phpinspect--serialize-type (cdr import))))
(defun phpinspect--serialize-name (name)
`(phpinspect-intern-name ,(phpinspect-name-string name)))
(provide 'phpinspect-serialize)
;;; phpinspect-serialize.el ends here

@ -149,6 +149,9 @@ Type can be any of the token types returned by
"Get the argument list of a function"
(seq-find #'phpinspect-list-p (seq-find #'phpinspect-declaration-p php-func nil) nil))
(defun phpinspect-equals-p (token)
(phpinspect-token-type-p token :equals))
(defun phpinspect-annotation-p (token)
(phpinspect-token-type-p token :annotation))

@ -204,7 +204,13 @@ NAMESPACE may be nil, or a string with a namespace FQN."
(phpinspect--type-resolve
types
namespace
(if (and inside-class-name (phpinspect--type= type phpinspect--self-type))
(if (and inside-class-name
(or (phpinspect--type= type phpinspect--self-type)
;; Type has not yet been resolved, so we can compare bare
;; names to detect a "self" type.
(and (not (phpinspect--type-fully-qualified type))
(eq (phpinspect--type-bare-name-sym type)
(phpinspect--type-bare-name-sym phpinspect--self-type)))))
(progn
(phpinspect--log "Returning inside class name for %s : %s"
type inside-class-name)

@ -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") (: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 ";"))))))))
(: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") (:assignment "=") (: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") (: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 ";"))))))))
(: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") (:assignment "=") (: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 ";"))))))))

@ -237,68 +237,6 @@ class FlufferUpper
(phpinspect--make-type-resolver-for-resolvecontext
context))))))
(ert-deftest phpinspect-resolve-type-from-context-static-method ()
(with-temp-buffer
(insert "
class Thing
{
static function doThing(\\DateTime $moment, Thing $thing, $other): static
{
return $this;
}
function doStuff()
{
self::doThing()->")
(let* ((bmap (phpinspect-make-bmap))
(tokens (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t
:bmap bmap)
(phpinspect-parse-current-buffer)))
(index (phpinspect--index-tokens tokens))
(phpinspect-project-root-function (lambda () "phpinspect-test"))
(phpinspect-eldoc-word-width 100)
(project (phpinspect--make-dummy-project))
(context (phpinspect-get-resolvecontext project bmap (point))))
(phpinspect-purge-cache)
(phpinspect-project-add-index project index)
(should (phpinspect--type= (phpinspect--make-type :name "\\Thing")
(phpinspect-resolve-type-from-context
context
(phpinspect--make-type-resolver-for-resolvecontext
context)))))))
(ert-deftest phpinspect-resolve-type-from-context-static-method-with-preceding-words ()
(with-temp-buffer
(insert "
class Thing
{
static function doThing(\\DateTime $moment, Thing $thing, $other): static
{
return $this;
}
function doStuff()
{
if (true) {
return self::doThing()->")
(let* ((bmap (phpinspect-make-bmap))
(tokens (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t
:bmap bmap)
(phpinspect-parse-current-buffer)))
(index (phpinspect--index-tokens tokens))
(phpinspect-eldoc-word-width 100)
(project (phpinspect--make-dummy-project))
(context (phpinspect-get-resolvecontext project bmap (point))))
(phpinspect-purge-cache)
(phpinspect-project-add-index project index)
(should (phpinspect--type= (phpinspect--make-type :name "\\Thing")
(phpinspect-resolve-type-from-context
context
(phpinspect--make-type-resolver-for-resolvecontext
context)))))))
(ert-deftest phpinspect-get-last-statement-in-token-with-static-attribute-context ()
(let* ((php-code-function "

@ -46,11 +46,11 @@
(:word "array")
(:variable "things")))
(:block)))))))
(index (phpinspect--index-tokens class-tokens))
(index (eval (phpinspect--serialize-root-index
(phpinspect--index-tokens class-tokens))))
(expected-index
`(phpinspect--root-index
(imports)
(namespaces)
(classes
(,(phpinspect--make-type :name "\\Potato" :fully-qualified t)
phpinspect--indexed-class
@ -227,11 +227,14 @@ try {
(phpinspect--make-type :name "\\void" :fully-qualified t)
(phpinspect--function-return-type method))))))))
(require 'phpinspect-serialize)
(ert-deftest phpinspect-index-tokens-class ()
(let* ((index1
(phpinspect--index-tokens
(phpinspect-test-read-fixture-data "IndexClass1")))
(eval
(phpinspect--serialize-root-index
(phpinspect--index-tokens
(phpinspect-test-read-fixture-data "IndexClass1")))))
(index2
(phpinspect-test-read-fixture-serialization "IndexClass1-indexed"))
(index1-class (car (alist-get 'classes index1)))
@ -248,10 +251,13 @@ try {
(insert-file-contents (expand-file-name "IndexClass1.php" phpinspect-test-php-file-directory))
(setf (phpinspect-pctx-bmap pctx) (phpinspect-make-bmap))
(phpinspect-with-parse-context pctx (setq tree (phpinspect-parse-current-buffer))))
(let* ((index1 (phpinspect--index-tokens tree
nil
(phpinspect-bmap-make-location-resolver
(phpinspect-pctx-bmap pctx))))
(let* ((index1
(eval
(phpinspect--serialize-root-index
(phpinspect--index-tokens tree
nil
(phpinspect-bmap-make-location-resolver
(phpinspect-pctx-bmap pctx))))))
(index2
(phpinspect-test-read-fixture-serialization "IndexClass1-indexed"))
(index1-class (car (alist-get 'classes index1)))

@ -169,10 +169,10 @@
result))))))
(ert-deftest phpinspect-get-variable-type-in-block-function-return ()
(let ((base-code "$bar = foo();")
(paths (list (cons "$bar" "Foo")
(cons "$bar->baz" "string")))
(let ((base-code "$bar = foo()")
(paths (list (cons ";$bar" "Foo")
(cons ";$bar->baz" "string")
(cons "->baz" "string")))
(project (phpinspect--make-dummy-project)))
(phpinspect-project-add-index
@ -189,3 +189,66 @@
(should result)
(should (phpinspect--type= (phpinspect--make-type :name (concat "\\" (cdr path)))
result))))))
(ert-deftest phpinspect-resolve-type-from-context-static-method ()
(with-temp-buffer
(insert "
class Thing
{
static function doThing(\\DateTime $moment, Thing $thing, $other): static
{
return $this;
}
function doStuff()
{
self::doThing()->")
(let* ((bmap (phpinspect-make-bmap))
(tokens (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t
:bmap bmap)
(phpinspect-parse-current-buffer)))
(index (phpinspect--index-tokens tokens))
(phpinspect-project-root-function (lambda () "phpinspect-test"))
(phpinspect-eldoc-word-width 100)
(project (phpinspect--make-dummy-project))
(context (phpinspect-get-resolvecontext project bmap (point))))
(phpinspect-purge-cache)
(phpinspect-project-add-index project index)
(should (phpinspect--type= (phpinspect--make-type :name "\\Thing")
(phpinspect-resolve-type-from-context
context
(phpinspect--make-type-resolver-for-resolvecontext
context)))))))
(ert-deftest phpinspect-resolve-type-from-context-static-method-with-preceding-words ()
(with-temp-buffer
(insert "
class Thing
{
static function doThing(\\DateTime $moment, Thing $thing, $other): static
{
return $this;
}
function doStuff()
{
if (true) {
return self::doThing()->")
(let* ((bmap (phpinspect-make-bmap))
(tokens (phpinspect-with-parse-context (phpinspect-make-pctx :incremental t
:bmap bmap)
(phpinspect-parse-current-buffer)))
(index (phpinspect--index-tokens tokens))
(phpinspect-eldoc-word-width 100)
(project (phpinspect--make-dummy-project))
(context (phpinspect-get-resolvecontext project bmap (point))))
(phpinspect-purge-cache)
(phpinspect-project-add-index project index)
(should (phpinspect--type= (phpinspect--make-type :name "\\Thing")
(phpinspect-resolve-type-from-context
context
(phpinspect--make-type-resolver-for-resolvecontext
context)))))))

Loading…
Cancel
Save