branch: externals/phpinspect
commit 2e064d52e120d4cd5dab714d8ae2883ffa8de23c
Author: Hugo Thunnissen <[email protected]>
Commit: Hugo Thunnissen <[email protected]>
Implement containing type inference for collection-like class properties
---
phpinspect-index.el | 65 ++++++++++++++++++++++++++++++++---------------------
test/test-buffer.el | 16 ++++++++++---
2 files changed, 52 insertions(+), 29 deletions(-)
diff --git a/phpinspect-index.el b/phpinspect-index.el
index a806829b82..a026080522 100644
--- a/phpinspect-index.el
+++ b/phpinspect-index.el
@@ -81,6 +81,39 @@ of TYPE, if available."
(list name function-args return-type)))
+(defun phpinspect--apply-annotation-type (annotation-type-string type
type-resolver)
+ "Add/modify information of a resolved TYPE based on ANNOTATION-TYPE-STRING.
+
+Annotation type is resolved using TYPE-RESOLVER.
+"
+ (if (stringp annotation-type-string)
+ (let ((is-collection (phpinspect--type-is-collection type)))
+ (phpinspect--log "found annotation type string %s when type is %s"
+ annotation-type-string type)
+
+ (when (string-suffix-p "[]" annotation-type-string)
+ (setq is-collection t)
+ (setq annotation-type-string (string-trim-right
annotation-type-string "\\[\\]")))
+
+
+ (cond ((phpinspect--should-prefer-return-annotation type)
+ ;; Sometimes it's better to override the typehint with a more
narrow annotation
+ (setq type (funcall type-resolver
+ (phpinspect--make-type :name
annotation-type-string))))
+
+ (is-collection
+ ;; Collections need to have their "contains" slot set
+ (phpinspect--log "Detected collection type, setting contains
from annotation type '%s'"
+ annotation-type-string)
+ (setf (phpinspect--type-contains type)
+ (funcall type-resolver
+ (phpinspect--make-type :name
annotation-type-string)))
+ (setf (phpinspect--type-collection type) t))))
+ ;; else
+ (phpinspect--log "Discarding invalid annotation type %s"
annotation-type-string))
+ type)
+
+
(defun phpinspect--index-function-from-scope (type-resolver scope
comment-before &optional add-used-types namespace)
"Index a function inside SCOPE token using phpdoc metadata in COMMENT-BEFORE.
@@ -106,31 +139,8 @@ function (think \"new\" statements, return types etc.)."
;; @return annotation. When dealing with a collection, we want to store the
;; type of its members.
(let* ((return-annotation-type
- (cadadr (seq-find #'phpinspect-return-annotation-p
comment-before)))
- (is-collection
- (and type
- (phpinspect--type-is-collection type))))
- (phpinspect--log "found return annotation %s in %s when type is %s"
- return-annotation-type comment-before type)
-
- (unless (stringp return-annotation-type)
- (phpinspect--log "Discarding invalid return annotation type %s"
return-annotation-type)
- (setq return-annotation-type nil))
-
- (when return-annotation-type
- (when (string-suffix-p "[]" return-annotation-type)
- (setq is-collection t)
- (setq return-annotation-type (string-trim-right
return-annotation-type "\\[\\]")))
-
- (cond ((phpinspect--should-prefer-return-annotation 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)))))
+ (cadadr (seq-find #'phpinspect-return-annotation-p
comment-before))))
+ (phpinspect--apply-annotation-type return-annotation-type type
type-resolver))
(when add-used-types
(let ((used-types (phpinspect--find-used-types-in-tokens
@@ -214,7 +224,10 @@ SCOPE should be a scope token (`phpinspect-scope-p')."
:lifetime (when static '(:static))
:type (when type
(when add-used-types (funcall add-used-types (list type)))
- (funcall type-resolver (phpinspect--make-type :name type)))))))
+ (phpinspect--apply-annotation-type
+ (phpinspect--variable-type-string-from-comment comment-before
variable-name)
+ (funcall type-resolver (phpinspect--make-type :name type))
+ type-resolver))))))
(defun phpinspect-doc-block-p (token)
(phpinspect-token-type-p token :doc-block))
diff --git a/test/test-buffer.el b/test/test-buffer.el
index b846adcdac..087406e8ad 100644
--- a/test/test-buffer.el
+++ b/test/test-buffer.el
@@ -494,6 +494,8 @@ class AccountStatisticsController {
private Model $privModel;
static Relation $relation;
public static Relation $staticRelation;
+ /* @var Relation[] */
+ private array $relations;
}")
(phpinspect-buffer-update-project-index buffer)
@@ -509,18 +511,21 @@ class AccountStatisticsController {
(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")))
+ (static-relation (phpinspect--class-get-variable class
"$staticRelation"))
+ (relations (phpinspect--class-get-variable class "relations")))
(should model)
(should priv-model)
(should relation)
(should static-relation)
+ (should relations)
(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)))
+ :fully-qualified t))
+ (array-type (phpinspect--make-type :name "\\array"
:fully-qualified t)))
(should (phpinspect--variable-type model))
(should (phpinspect--type= model-type (phpinspect--variable-type
model)))
@@ -529,4 +534,9 @@ class AccountStatisticsController {
(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)))))))))
+ (should (phpinspect--type= relation-type
(phpinspect--variable-type static-relation)))
+
+ (should (phpinspect--type= array-type (phpinspect--variable-type
relations)))
+ (should (phpinspect--type=
+ relation-type
+ (phpinspect--type-contains (phpinspect--variable-type
relations))))))))))