diff --git a/phpinspect-index.el b/phpinspect-index.el index a806829..a026080 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 b846adc..087406e 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))))))))))