From e04ab0c11852fa095db1183c404376241482f657 Mon Sep 17 00:00:00 2001 From: Hugo Thunnissen Date: Fri, 16 Aug 2024 13:26:04 +0200 Subject: [PATCH] Resolve types of suggested variable completions --- phpinspect-resolve.el | 8 ++++++++ phpinspect-resolvecontext.el | 17 +++++++++++++++++ phpinspect-suggest.el | 34 +++++++++++++++++++++------------- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/phpinspect-resolve.el b/phpinspect-resolve.el index 04a9cb5..f50f208 100644 --- a/phpinspect-resolve.el +++ b/phpinspect-resolve.el @@ -73,6 +73,7 @@ (blocks-or-lists) (statements (phpinspect--split-statements token))) (dolist (statement statements) + (phpinspect--log "Finding assignment in statement '%s'" statement) (when (seq-find #'phpinspect-maybe-assignment-p statement) (phpinspect--log "Found assignment statement") (push (phpinspect--make-assignment-context @@ -500,9 +501,16 @@ EXPRESSION." (defun phpinspect-resolve-type-from-context (resolvecontext &optional type-resolver) + "Resolve the type that RESOLVECONTEXT's subject evaluates to." + ;; Subject should be a statement, not a single token. + (when (phpinspect-probably-token-p (phpinspect--resolvecontext-subject resolvecontext)) + (setf (phpinspect--resolvecontext-subject resolvecontext) + (list (phpinspect--resolvecontext-subject resolvecontext)))) + (unless type-resolver (setq type-resolver (phpinspect--make-type-resolver-for-resolvecontext resolvecontext))) + (phpinspect--log "Looking for type of statement: %s in nested token" (phpinspect--resolvecontext-subject resolvecontext)) ;; Find all enclosing tokens that aren't classes. Classes do not contain variable diff --git a/phpinspect-resolvecontext.el b/phpinspect-resolvecontext.el index 8d3b9f5..0d7b48b 100644 --- a/phpinspect-resolvecontext.el +++ b/phpinspect-resolvecontext.el @@ -68,6 +68,23 @@ :documentation "Tokens that enclose the subject.")) +(defun phpinspect--repurpose-resolvecontext (rctx &optional enclosing-tokens subject) + "Copy RCTX, optionally replacing the enclosing tokens and subject. + +Note: if ENCLOSING-TOKENS are provided, the repurposed +resolvecontext will have it's enclosing token metadata unset as +it would no longer be valid for the new enclosing tokens." + (let ((rctx (phpinspect--copy-resolvecontext rctx))) + (when subject + (setf (phpinspect--resolvecontext-subject rctx) subject)) + + (when enclosing-tokens + ;; Unset enclosing-metadata as it is no longer valid. + (setf (phpinspect--resolvecontext-enclosing-metadata rctx) nil) + (setf (phpinspect--resolvecontext-enclosing-tokens rctx) enclosing-tokens)) + + rctx)) + (cl-defmethod phpinspect--resolvecontext-push-enclosing-token ((resolvecontext phpinspect--resolvecontext) enclosing-token) "Add ENCLOSING-TOKEN to RESOLVECONTEXTs enclosing token stack." diff --git a/phpinspect-suggest.el b/phpinspect-suggest.el index 0a56fd3..d7be82c 100644 --- a/phpinspect-suggest.el +++ b/phpinspect-suggest.el @@ -38,7 +38,8 @@ (defun phpinspect-suggest-variables-at-point (resolvecontext) (phpinspect--log "Suggesting variables at point") - (let ((variables)) + + (let ((variables (make-hash-table :test 'equal))) (dolist (token (phpinspect--resolvecontext-enclosing-tokens resolvecontext)) (when (phpinspect-not-class-p token) (let ((token-list token) @@ -46,26 +47,33 @@ (while token-list (setq potential-variable (pop token-list)) (cond ((phpinspect-variable-p potential-variable) - (phpinspect--log "Pushing variable %s" potential-variable) - (push (phpinspect--make-variable - :name (cadr potential-variable) - :type phpinspect--null-type) - variables)) + (puthash (cadr potential-variable) + (phpinspect--make-variable :name (cadr potential-variable)) + variables)) ((phpinspect-function-p potential-variable) (push (phpinspect-function-block potential-variable) token-list) (dolist (argument (phpinspect-function-argument-list potential-variable)) (when (phpinspect-variable-p argument) - (push (phpinspect--make-variable - :name (cadr argument) - :type phpinspect--null-type) - variables)))) + (puthash (cadr argument) + (phpinspect--make-variable :name (cadr argument)) + variables)))) ((phpinspect-block-p potential-variable) (dolist (nested-token (cdr potential-variable)) (push nested-token token-list)))))))) - ;; Only return variables that have a name. Unnamed variables are just dollar - ;; signs (: - (seq-filter #'phpinspect--variable-name variables))) + (let (variable-list) + (dolist (var (hash-table-values variables)) + ;; Only return variables that have a name. Unnamed variables are just dollar + ;; signs (: + (when (phpinspect--variable-name var) + (setf (phpinspect--variable-type var) + (phpinspect-resolve-type-from-context + (phpinspect--repurpose-resolvecontext + resolvecontext nil `(:variable ,(phpinspect--variable-name var))))) + + (push var variable-list))) + + variable-list))) (defun phpinspect-get-cached-project-class-methods (project-root class-fqn &optional static) (phpinspect--log "Getting cached project class methods for %s (%s)"