branch: externals/phpinspect commit 55413ea9fb99196ddf8cc22df601f4ffda51540a Author: Hugo Thunnissen <de...@hugot.nl> Commit: Hugo Thunnissen <de...@hugot.nl>
Implement basic support for function indexation and include dirs Does not yet include support for imported namespaced functions --- phpinspect-cache.el | 3 +- phpinspect-completion.el | 15 +++++++ phpinspect-eldoc.el | 21 ++++++++- phpinspect-index.el | 113 +++++++++++++++++++++++++++++++---------------- phpinspect-pipeline.el | 1 + phpinspect-project.el | 78 +++++++++++++++++++++++++++++--- phpinspect-suggest.el | 5 +++ phpinspect-type.el | 8 ++-- phpinspect-util.el | 11 ++--- phpinspect-worker.el | 68 ++++++++++++++++++++-------- phpinspect.el | 12 +++-- test/test-index.el | 50 +++++++++++++++++++++ 12 files changed, 306 insertions(+), 79 deletions(-) diff --git a/phpinspect-cache.el b/phpinspect-cache.el index d3920e3e60..cdf89ee124 100644 --- a/phpinspect-cache.el +++ b/phpinspect-cache.el @@ -68,7 +68,8 @@ then returned." (phpinspect--cache-projects cache))) (let ((autoloader (phpinspect-make-autoloader :project project))) (setf (phpinspect-project-autoload project) autoloader) - (phpinspect-autoloader-refresh autoloader))) + (phpinspect-autoloader-refresh autoloader) + (phpinspect-project-enqueue-include-dirs project))) project)) (provide 'phpinspect-cache) diff --git a/phpinspect-completion.el b/phpinspect-completion.el index 3048d3c7a2..2ffdd49299 100644 --- a/phpinspect-completion.el +++ b/phpinspect-completion.el @@ -144,8 +144,22 @@ and CONTEXT. All strategies must implement this method.") (rctx phpinspect--resolvecontext)) (phpinspect-suggest-attributes-at-point rctx 'static)) +(cl-defstruct (phpinspect-comp-word (:constructor phpinspect-make-comp-word)) + "Comletion strategy for bare words") + +(cl-defmethod phpinspect-comp-strategy-supports + ((_strat phpinspect-comp-word) (_q phpinspect-completion-query) + (rctx phpinspect--resolvecontext)) + (phpinspect-word-p (car (last (phpinspect--resolvecontext-subject rctx))))) + +(cl-defmethod phpinspect-comp-strategy-execute + ((_strat phpinspect-comp-word) (_q phpinspect-completion-query) + (rctx phpinspect--resolvecontext)) + (phpinspect-suggest-functions rctx)) + (defvar phpinspect-completion-strategies (list (phpinspect-make-comp-attribute) (phpinspect-make-comp-sigil) + (phpinspect-make-comp-word) (phpinspect-make-comp-static-attribute)) "List of completion strategies that phpinspect can use.") @@ -198,4 +212,5 @@ Returns list of `phpinspect--completion'." phpinspect--null-type))) :kind 'variable)) + (provide 'phpinspect-completion) diff --git a/phpinspect-eldoc.el b/phpinspect-eldoc.el index 515ac985a9..225746c285 100644 --- a/phpinspect-eldoc.el +++ b/phpinspect-eldoc.el @@ -178,7 +178,26 @@ be implemented for return values of `phpinspect-eld-strategy-execute'") (phpinspect--class-get-static-method class method-name-sym) (phpinspect--class-get-method class method-name-sym))))) (when method - (phpinspect-make-function-doc :fn method :arg-pos arg-pos)))))))) + (phpinspect-make-function-doc :fn method :arg-pos arg-pos)))) + ((setq match-result (phpinspect--match-sequence (last statement 2) + :f (phpinspect-meta-wrap-token-pred #'phpinspect-word-p) + :f (phpinspect-meta-wrap-token-pred #'phpinspect-list-p))) + (phpinspect--log "Eldoc context is a function call") + + (setq arg-list (car (last match-result)) + arg-pos (seq-reduce + (lambda (count meta) + (if (phpinspect-comma-p (phpinspect-meta-token meta)) + (+ count 1) + count)) + (phpinspect-meta-find-children-before arg-list (phpinspect-eldoc-query-point q)) 0)) + + (let ((func (phpinspect-project-get-function + (phpinspect--resolvecontext-project rctx) + (phpinspect-intern-name (cadr (phpinspect-meta-token (car match-result))))))) + (phpinspect--log "Got past that") + (when func + (phpinspect-make-function-doc :fn func :arg-pos arg-pos)))))))) (cl-defmethod phpinspect-eldoc-string ((var phpinspect--variable)) (concat (truncate-string-to-width diff --git a/phpinspect-index.el b/phpinspect-index.el index 5c61be5f75..d76b2d5899 100644 --- a/phpinspect-index.el +++ b/phpinspect-index.el @@ -59,7 +59,7 @@ of TYPE, if available." (or (not type) (phpinspect--type= type phpinspect--object-type))) -(defun phpinspect--index-function-from-scope (type-resolver scope comment-before &optional add-used-types) +(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. If ADD-USED-TYPES is set, it must be a function and will be @@ -104,7 +104,7 @@ function (think \"new\" statements, return types etc.)." (phpinspect--make-function :scope `(,(car scope)) - :name (cadadr (cdr declaration)) + :name (concat (if namespace (concat namespace "\\") "") (cadadr (cdr declaration))) :return-type (or type phpinspect--null-type) :arguments (phpinspect--index-function-arg-list type-resolver @@ -384,25 +384,54 @@ NAMESPACE will be assumed the root namespace if not provided" (mapcar #'phpinspect--use-to-type uses)) (defun phpinspect--index-namespace (namespace type-resolver-factory location-resolver) - (phpinspect--index-classes-in-tokens - (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p namespace)) - namespace - type-resolver-factory location-resolver (cadadr namespace))) + (let* (used-types + (index + `((classes . ,(phpinspect--index-classes-in-tokens + (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p namespace)) + namespace + type-resolver-factory location-resolver (cadadr namespace))) + (functions . ,(phpinspect--index-functions-in-tokens + namespace + type-resolver-factory + (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p namespace)) + (cadadr namespace) + (lambda (types) (setq used-types (nconc used-types types)))))))) + + (push `(used-types . ,used-types) index))) (defun phpinspect--index-namespaces (namespaces type-resolver-factory location-resolver &optional indexed) (if namespaces - (progn - (push (phpinspect--index-namespace (pop namespaces) - type-resolver-factory - location-resolver) - indexed) - (phpinspect--index-namespaces namespaces type-resolver-factory - location-resolver indexed)) - (apply #'append (nreverse indexed)))) - -(defun phpinspect--index-functions (&rest _args) - "TODO: implement function indexation. This is a stub function.") + (let ((namespace-index + (phpinspect--index-namespace + (pop namespaces) type-resolver-factory location-resolver))) + + (if indexed + (progn + (nconc (alist-get 'used-types indexed) + (alist-get 'used-types namespace-index)) + (nconc (alist-get 'classes indexed) + (alist-get 'classes namespace-index)) + (nconc (alist-get 'functions indexed) + (alist-get 'functions namespace-index))) + (setq indexed namespace-index)) + (phpinspect--index-namespaces + namespaces type-resolver-factory location-resolver indexed)) + indexed)) + +(defun phpinspect--index-functions-in-tokens (tokens type-resolver-factory &optional imports namespace add-used-types) + "TODO: implement function indexation. This is a stub function." + (let ((type-resolver (funcall type-resolver-factory imports nil namespace)) + comment-before functions) + (dolist (token tokens) + (cond ((phpinspect-comment-p token) + (setq comment-before token)) + ((phpinspect-function-p token) + (push (phpinspect--index-function-from-scope + type-resolver `(:public ,token) comment-before add-used-types + namespace) + functions)))) + functions)) (defun phpinspect--find-used-types-in-tokens (tokens) "Find usage of the \"new\" keyword in TOKENS. @@ -438,27 +467,35 @@ Return value is a list of the types that are \"newed\"." (defun phpinspect--index-tokens (tokens &optional type-resolver-factory location-resolver) "Index TOKENS as returned by `phpinspect--parse-current-buffer`." - (unless type-resolver-factory - (setq type-resolver-factory #'phpinspect--make-type-resolver)) - - (unless location-resolver - (setq location-resolver (lambda (_) (list 0 0)))) - - (let ((imports (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p tokens)))) - `(phpinspect--root-index - (imports . ,imports) - ,(append - (append '(classes) - (phpinspect--index-namespaces (seq-filter #'phpinspect-namespace-p tokens) - type-resolver-factory - location-resolver) - (phpinspect--index-classes-in-tokens - imports tokens type-resolver-factory location-resolver))) - ,(append '(used-types) - (phpinspect--find-used-types-in-tokens tokens)) - (functions)) - ;; TODO: Implement function indexation - )) + (or + (condition-case err + (progn + (unless type-resolver-factory + (setq type-resolver-factory #'phpinspect--make-type-resolver)) + + (unless location-resolver + (setq location-resolver (lambda (_) (list 0 0)))) + + (let* ((imports (phpinspect--uses-to-types (seq-filter #'phpinspect-use-p tokens))) + (namespace-index + (phpinspect--index-namespaces (seq-filter #'phpinspect-namespace-p tokens) + type-resolver-factory + location-resolver))) + `(phpinspect--root-index + (imports . ,imports) + (classes ,@(append + (alist-get 'classes namespace-index) + (phpinspect--index-classes-in-tokens + imports tokens type-resolver-factory location-resolver))) + (used-types ,@(append + (alist-get 'used-types namespace-index) + (phpinspect--find-used-types-in-tokens tokens))) + (functions . ,(append + (alist-get 'functions namespace-index) + (phpinspect--index-functions-in-tokens + tokens type-resolver-factory imports)))))) + (t (phpinspect--log "phpinspect--index-tokens failed: %s" err) nil)) + '(phpinspect--root-index))) (defun phpinspect-get-or-create-cached-project-class (project-root class-fqn) (when project-root diff --git a/phpinspect-pipeline.el b/phpinspect-pipeline.el index a55b944e0a..021a730feb 100644 --- a/phpinspect-pipeline.el +++ b/phpinspect-pipeline.el @@ -191,6 +191,7 @@ user input.") (setq ,continue-running nil)) (phpinspect-pipeline--enqueue ,out-queue ,outgoing))) (phpinspect-pipeline-incoming) + (quit) (t (phpinspect--log "Pipeline thread errored: %s" err) (setq ,end (phpinspect-make-pipeline-end :thread (current-thread) :error err)) (setq ,continue-running nil) diff --git a/phpinspect-project.el b/phpinspect-project.el index f45f2c9268..ef7e328db8 100644 --- a/phpinspect-project.el +++ b/phpinspect-project.el @@ -46,11 +46,16 @@ serious performance hits. Enable at your own risk (:") phpinspect--buffer-project) (cl-defstruct (phpinspect-project (:constructor phpinspect--make-project)) - (class-index (make-hash-table :test 'eq :size 100 :rehash-size 40) + (class-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5) :type hash-table :documentation "A `hash-table` that contains all of the currently indexed classes in the project") + (function-index (make-hash-table :test 'eq :size 100 :rehash-size 2.0) + :type hash-table + :documentation + "A hash able that contains all of the currently indexed functions +in the project") (fs nil :type phpinspect-fs :documentation @@ -115,9 +120,11 @@ indexed by the absolute paths of the files they're watching.")) (not (or (phpinspect--class-initial-index class)))) (when (not class) (setq class (phpinspect-project-create-class project type))) - (phpinspect--log "Adding unpresent class %s to index queue" type) - (phpinspect-worker-enqueue (phpinspect-project-worker project) - (phpinspect-make-index-task project type)))))) + (unless (or (phpinspect--type= phpinspect--null-type type) + (phpinspect--type-is-native type)) + (phpinspect--log "Adding unpresent class %s to index queue" type) + (phpinspect-worker-enqueue (phpinspect-project-worker project) + (phpinspect-make-index-task project type))))))) (cl-defmethod phpinspect-project-add-class-attribute-types-to-index-queue ((project phpinspect-project) (class phpinspect--class)) @@ -135,8 +142,29 @@ indexed by the absolute paths of the files they're watching.")) ((project phpinspect-project) (index (head phpinspect--root-index)) &optional index-imports) (when index-imports (phpinspect-project-enqueue-imports project (alist-get 'imports (cdr index)))) + (dolist (indexed-class (alist-get 'classes (cdr index))) - (phpinspect-project-add-class project (cdr indexed-class) index-imports))) + (phpinspect-project-add-class project (cdr indexed-class) index-imports)) + + (dolist (func (alist-get 'functions (cdr index))) + (phpinspect-project-set-function project func))) + +(cl-defmethod phpinspect-project-set-function + ((project phpinspect-project) (func phpinspect--function)) + (puthash (phpinspect--function-name-symbol func) func + (phpinspect-project-function-index project))) + +(cl-defmethod phpinspect-project-get-function + ((project phpinspect-project) (name symbol)) + (gethash name (phpinspect-project-function-index project))) + +(cl-defmethod phpinspect-project-get-functions ((project phpinspect-project)) + (let ((funcs)) + (maphash + (lambda (_name func) (push func funcs)) + (phpinspect-project-function-index project)) + + funcs)) (cl-defmethod phpinspect-project-enqueue-imports ((project phpinspect-project) imports) @@ -237,5 +265,45 @@ before the search is executed." (cl-defmethod phpinspect-project-add-file-index ((project phpinspect-project) (filename string)) (phpinspect-project-add-index project (phpinspect-project-index-file project filename))) +(defun phpinspect-project-enqueue-include-dirs (project) + (interactive (list (phpinspect--cache-get-project-create + (phpinspect--get-or-create-global-cache) + (phpinspect-current-project-root)))) + (let ((dirs (alist-get 'include-dirs + (alist-get (phpinspect-project-root project) + phpinspect-projects + nil nil #'string=)))) + (dolist (dir dirs) + (message "enqueueing dir %s" dir) + (phpinspect-worker-enqueue + (phpinspect-project-worker project) + (phpinspect-make-index-dir-task :dir dir :project project))))) + +(defgroup phpinspect '((phpinspect-projects custom-variable)) + "PHPInspect Configuration") + +(defcustom phpinspect-projects nil + "PHPInspect Projects." + :type '(alist :key-type string + :value-type (alist :key-type symbol + :options ((include-dirs (repeat string)))))) + +(defun phpinspect-project-add-include-dir (dir) + "Configure DIR as an include dir for the current project." + (interactive (list (read-directory-name "Include Directory: "))) + (custom-set-variables '(phpinspect-projects)) + (let ((existing + (alist-get (phpinspect-current-project-root) phpinspect-projects nil #'string=))) + (if existing + (push dir (alist-get 'include-dirs existing)) + (push `(,(phpinspect-current-project-root) . ((include-dirs . (,dir)))) phpinspect-projects))) + + (customize-save-variable 'phpinspect-projects phpinspect-projects) + + (phpinspect-project-enqueue-include-dirs (phpinspect--cache-get-project-create + (phpinspect--get-or-create-global-cache) + (phpinspect-current-project-root)))) + + (provide 'phpinspect-project) ;;; phpinspect-project.el ends here diff --git a/phpinspect-suggest.el b/phpinspect-suggest.el index 6851de075c..98c8fd6463 100644 --- a/phpinspect-suggest.el +++ b/phpinspect-suggest.el @@ -30,6 +30,11 @@ (require 'phpinspect-project) (require 'phpinspect-class) +(defun phpinspect-suggest-functions (rctx) + (let* ((project (phpinspect--resolvecontext-project rctx)) + (word (cadr (car (last (phpinspect--resolvecontext-subject rctx)))))) + (phpinspect-project-get-functions project))) + (defun phpinspect-suggest-variables-at-point (resolvecontext) (phpinspect--log "Suggesting variables at point") (let ((variables)) diff --git a/phpinspect-type.el b/phpinspect-type.el index 32409b31e3..8fc60064fa 100644 --- a/phpinspect-type.el +++ b/phpinspect-type.el @@ -172,10 +172,10 @@ NAMESPACE may be nil, or a string with a namespace FQN." (defun phpinspect--make-type-resolver (types &optional token-tree namespace) "Little wrapper closure to pass around and resolve types with." (let* ((inside-class - (if token-tree (or (phpinspect--find-innermost-incomplete-class token-tree) - (phpinspect--find-class-token token-tree)))) - (inside-class-name (if inside-class (phpinspect--get-class-name-from-token - inside-class)))) + (and token-tree (or (phpinspect--find-innermost-incomplete-class token-tree) + (phpinspect--find-class-token token-tree)))) + (inside-class-name + (and inside-class (phpinspect--get-class-name-from-token inside-class)))) (lambda (type) (phpinspect--type-resolve types diff --git a/phpinspect-util.el b/phpinspect-util.el index 76a484026a..190bfec77f 100644 --- a/phpinspect-util.el +++ b/phpinspect-util.el @@ -85,22 +85,19 @@ level of START-FILE in stead of `default-directory`." (phpinspect--declare-log-group 'bam) -(define-inline phpinspect--log (&rest args) +(defmacro phpinspect--log (&rest args) (let ((log-group (alist-get (or load-file-name buffer-file-name) phpinspect-log-groups nil nil #'string=))) - (push 'list args) - (inline-quote - (when (and phpinspect--debug + `(when (and phpinspect--debug (or (not phpinspect-enabled-log-groups) ,(when log-group - (inline-quote - (member (quote ,log-group) phpinspect-enabled-log-groups))))) + `(member (quote ,log-group) phpinspect-enabled-log-groups)))) (with-current-buffer (get-buffer-create "**phpinspect-logs**") (unless window-point-insertion-type (set (make-local-variable 'window-point-insertion-type) t)) (goto-char (buffer-end 1)) (insert (concat "[" (format-time-string "%H:%M:%S") "]: " ,(if log-group (concat "(" (symbol-name log-group) ") ") "") - (apply #'format ,args) "\n"))))))) + (format ,@args) "\n")))))) (defun phpinspect-filter-logs (group-name) (interactive (list (completing-read "Log group: " diff --git a/phpinspect-worker.el b/phpinspect-worker.el index c9bc372dc8..70ec5c2fbe 100644 --- a/phpinspect-worker.el +++ b/phpinspect-worker.el @@ -29,6 +29,7 @@ (require 'phpinspect-index) (require 'phpinspect-class) (require 'phpinspect-queue) +(require 'phpinspect-pipeline) (defvar phpinspect-worker nil "Contains the phpinspect worker that is used by all projects.") @@ -124,24 +125,26 @@ already present in the queue." (while (phpinspect-worker-continue-running worker) ;; This error is used to wake up the thread when new tasks are added to the ;; queue. - (ignore-error 'phpinspect-wakeup-thread - (let* ((task (phpinspect-queue-dequeue (phpinspect-worker-queue worker))) - (mx (make-mutex)) - (continue (make-condition-variable mx))) - (if task - ;; Execute task if it belongs to a project that has not been - ;; purged (meaning that it is still actively used). - (unless (phpinspect-project-purged (phpinspect-task-project task)) - (phpinspect-task-execute task worker)) - ;; else: join with the main thread until wakeup is signaled - (thread-join main-thread)) - - ;; Pause for a second after indexing something, to allow user input to - ;; interrupt the thread. - (unless (or (not (input-pending-p)) - (phpinspect-worker-skip-next-pause worker)) - (phpinspect-thread-pause 1 mx continue)) - (setf (phpinspect-worker-skip-next-pause worker) nil)))) + (condition-case err + (ignore-error 'phpinspect-wakeup-thread + (let* ((task (phpinspect-queue-dequeue (phpinspect-worker-queue worker))) + (mx (make-mutex)) + (continue (make-condition-variable mx))) + (if task + ;; Execute task if it belongs to a project that has not been + ;; purged (meaning that it is still actively used). + (unless (phpinspect-project-purged (phpinspect-task-project task)) + (phpinspect-task-execute task worker)) + ;; else: join with the main thread until wakeup is signaled + (thread-join main-thread)) + + ;; Pause for a second after indexing something, to allow user input to + ;; interrupt the thread. + (unless (or (not (input-pending-p)) + (phpinspect-worker-skip-next-pause worker)) + (phpinspect-thread-pause 1 mx continue)) + (setf (phpinspect-worker-skip-next-pause worker) nil))) + (t (message "Phpinspect worker thread errored :%s" err)))) (phpinspect--log "Worker thread exiting") (message "phpinspect worker thread exited"))) @@ -236,6 +239,7 @@ already present in the queue." (cl-defmethod phpinspect-task-project ((task phpinspect-index-task)) (phpinspect-index-task-project task)) + (cl-defmethod phpinspect-task= ((task1 phpinspect-index-task) (task2 phpinspect-index-task)) (and (eq (phpinspect-index-task-project task1) (phpinspect-index-task-project task2)) @@ -265,7 +269,33 @@ already present in the queue." (when root-index (phpinspect-project-add-index project root-index))))))) -;;; PARSE BUFFER TASK +;;; INDEX FILE TASK +(cl-defstruct (phpinspect-index-dir-task (:constructor phpinspect-make-index-dir-task)) + "A task for the indexation of files" + (project nil + :type phpinspect-project) + (dir nil + :type string)) + +(cl-defmethod phpinspect-task= + ((task1 phpinspect-index-dir-task) (task2 phpinspect-index-dir-task)) + (and (eq (phpinspect-index-dir-task-project task1) + (phpinspect-index-dir-task-project task2)) + (string= (phpinspect-index-dir-task-dir task1) + (phpinspect-index-dir-task-dir task2)))) + +(cl-defmethod phpinspect-task-project ((task phpinspect-index-dir-task)) + (phpinspect-index-dir-task-project task)) + +(cl-defmethod phpinspect-task-execute ((task phpinspect-index-dir-task) + (_worker phpinspect-worker)) + (phpinspect--log "Entering..") + (let* ((project (phpinspect-index-dir-task-project task)) + (fs (phpinspect-project-fs project)) + (dir (phpinspect-index-dir-task-dir task))) + (phpinspect--log "Indexing directory %s" dir) + (phpinspect-pipeline (phpinspect-fs-directory-files-recursively fs dir "\\.php$") + :into (phpinspect-project-add-file-index :with-context project)))) (provide 'phpinspect-worker) ;;; phpinspect-worker.el ends here diff --git a/phpinspect.el b/phpinspect.el index c8b66b7399..bfd7346301 100644 --- a/phpinspect.el +++ b/phpinspect.el @@ -85,6 +85,7 @@ (defun phpinspect--init-mode () "Initialize the phpinspect minor mode for the current buffer." + (phpinspect-ensure-worker) (setq phpinspect-current-buffer (phpinspect-make-buffer :buffer (current-buffer) @@ -103,7 +104,6 @@ (eldoc-add-command 'c-electric-paren) (eldoc-add-command 'c-electric-backspace) - (phpinspect-ensure-worker) (phpinspect--after-save-action) (add-hook 'after-save-hook #'phpinspect--after-save-action nil 'local)) @@ -219,9 +219,12 @@ Example configuration: ((looking-back "::[A-Za-z_0-9-]*" nil) (let ((match (match-string 0))) (substring match 2 (length match)))) - ((looking-back "\\$[A-Za-z_0-9-]*" nil) + ((looking-back "\\$[A-Za-z_0-9-]" nil) (let ((match (match-string 0))) - (substring match 1 (length match)))))) + (substring match 1 (length match)))) + ((looking-back "[A-Za-z_0-9-]+" nil t) + (message "Matched string %s" (match-string 0)) + (match-string 0)))) ((eq command 'post-completion) (when (eq 'function (phpinspect--completion-kind (phpinspect--completion-list-get-metadata @@ -338,7 +341,8 @@ before the search is executed." ;; appear frozen while the thread is executing. (redisplay) - (phpinspect-autoloader-refresh autoloader))) + (phpinspect-autoloader-refresh autoloader) + (phpinspect-project-enqueue-include-dirs project))) (provide 'phpinspect) diff --git a/test/test-index.el b/test/test-index.el index 0c49199f8a..cfd3981870 100644 --- a/test/test-index.el +++ b/test/test-index.el @@ -181,3 +181,53 @@ return StaticThing::create(new ThingFactory())->makeThing((((new Potato())->anti (should (alist-get 'location index1-class)) (should (alist-get 'location index1-class))))) + +(ert-deftest phpinspect-index-functions () + (let* ((code "<?php +use Example\\Thing; + +function test_func(): array {} + +function example(): Thing {}") + (tokens (phpinspect-parse-string code)) + (index (phpinspect--index-tokens tokens)) + functions) + + (should (setq functions (alist-get 'functions index))) + (should (= 2 (length functions))) + (should (string= "test_func" (phpinspect--function-name (cadr functions)))) + (should (string= "example" (phpinspect--function-name (car functions)))) + + (should (phpinspect--type= (phpinspect--make-type :name "\\array") + (phpinspect--function-return-type (cadr functions)))) + (should (phpinspect--type= (phpinspect--make-type :name "\\Example\\Thing") + (phpinspect--function-return-type (car functions)))))) + +(ert-deftest phpinspect-index-functions-in-namespace () + (let* ((code "<?php +namespace Local; + +use Example\\Thing; + +function test_func(): array {} + +function example(Firewall $wall): Thing {}") + (tokens (phpinspect-parse-string code)) + (index (phpinspect--index-tokens tokens)) + functions) + + (should (setq functions (alist-get 'functions index))) + (should (= 2 (length functions))) + (should (string= "Local\\test_func" (phpinspect--function-name (cadr functions)))) + (should (string= "Local\\example" (phpinspect--function-name (car functions)))) + + (should (phpinspect--type= (phpinspect--make-type :name "\\array") + (phpinspect--function-return-type (cadr functions)))) + (should (phpinspect--type= (phpinspect--make-type :name "\\Example\\Thing") + (phpinspect--function-return-type (car functions)))) + (should (= 3 (length (alist-get 'used-types index)))) + (should (member "Firewall" (alist-get 'used-types index))) + (should (member "array" (alist-get 'used-types index))) + (should (member "Thing" (alist-get 'used-types index))) + + (should (alist-get 'used-types index))))