Keep index synchronized with buffer state

WIP-cache
Hugo Thunnissen 9 months ago
parent 3175d9a6ac
commit 68c826243c

@ -14,7 +14,19 @@
(garbage-collect) (garbage-collect)
(benchmark (benchmark
1 '(dotimes (i 10000) 1 '(dotimes (i 10000)
(phpinspect-splayt-find tree i)))) (phpinspect-splayt-find tree i)))
(message "Splay tree 10000 items traversal:")
(garbage-collect)
(benchmark
1 '(phpinspect-splayt-traverse (i tree)
nil))
(message "Splay tree 10000 items LR traversal:")
(garbage-collect)
(benchmark
1 '(phpinspect-splayt-traverse-lr (i tree)
nil)))
(let (map) (let (map)
@ -30,4 +42,9 @@
(garbage-collect) (garbage-collect)
(benchmark (benchmark
1 '(dotimes (i 10000) 1 '(dotimes (i 10000)
(gethash i map)))) (gethash i map)))
(message "Hashtable 10000 iterations:")
(garbage-collect)
(benchmark
1 '(maphash (lambda (k v) nil) map)))

@ -28,6 +28,7 @@
(require 'phpinspect-changeset) (require 'phpinspect-changeset)
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'compat) (require 'compat)
(require 'phpinspect-token-predicates)
(eval-when-compile (eval-when-compile
(defvar phpinspect-parse-context nil (defvar phpinspect-parse-context nil
@ -39,18 +40,36 @@
(cl-defstruct (phpinspect-bmap (:constructor phpinspect-make-bmap)) (cl-defstruct (phpinspect-bmap (:constructor phpinspect-make-bmap))
(starts (make-hash-table :test #'eql (starts (make-hash-table :test #'eql
:size (floor (/ (point-max) 4)) :size (floor (/ (point-max) 2))
:rehash-size 1.5)) :rehash-size 1.5))
(ends (make-hash-table :test #'eql (ends (make-hash-table :test #'eql
:size (floor (/ (point-max) 4)) :size (floor (/ (point-max) 2))
:rehash-size 1.5)) :rehash-size 1.5))
(meta (make-hash-table :test #'eq (meta (make-hash-table :test #'eq
:size (floor (/ (point-max) 4)) :size (floor (/ (point-max) 2))
:rehash-size 1.5)) :rehash-size 1.5))
(token-stack nil (token-stack nil
:type list) :type list)
(overlays (phpinspect-make-splayt) (overlays (phpinspect-make-splayt)
:type phpinspect-splayt) :type phpinspect-splayt)
(declarations (phpinspect-make-splayt)
:type phpinspect-splayt
:documentation "The declaration tokens encountered.")
(imports (phpinspect-make-splayt)
:type phpinspect-splayt
:documentation "The import statements encountered.")
(functions (phpinspect-make-splayt)
:type phpinspect-splayt
:documentation "The function definitions encountered.")
(classes (phpinspect-make-splayt)
:type phpinspect-splayt
:documentation "The classes encountered.")
(class-variables (phpinspect-make-splayt)
:type phpinspect-splayt
:documentation "The class attribute variables encountered")
(namespaces (phpinspect-make-splayt)
:type phpinspect-splayt
:documentation "The namespaces encountered")
(-root-meta nil (-root-meta nil
:type phpinspect-meta) :type phpinspect-meta)
(last-token-start nil (last-token-start nil
@ -158,7 +177,28 @@
(puthash start token-meta starts) (puthash start token-meta starts)
(if existing-end (cond
((phpinspect-use-p (phpinspect-meta-token token-meta))
(phpinspect-splayt-insert
(phpinspect-bmap-imports bmap) (phpinspect-meta-start token-meta) token-meta))
((phpinspect-class-p (phpinspect-meta-token token-meta))
(phpinspect-splayt-insert
(phpinspect-bmap-classes bmap) (phpinspect-meta-start token-meta) token-meta))
((phpinspect-declaration-p (phpinspect-meta-token token-meta))
(phpinspect-splayt-insert
(phpinspect-bmap-declarations bmap) (phpinspect-meta-start token-meta) token-meta))
((phpinspect-function-p (phpinspect-meta-token token-meta))
(phpinspect-splayt-insert
(phpinspect-bmap-functions bmap) (phpinspect-meta-start token-meta) token-meta))
((phpinspect-namespace-p (phpinspect-meta-token token-meta))
(phpinspect-splayt-insert
(phpinspect-bmap-namespaces bmap) (phpinspect-meta-start token-meta) token-meta))
((or (phpinspect-const-p (phpinspect-meta-token token-meta))
(phpinspect-class-variable-p (phpinspect-meta-token token-meta)))
(phpinspect-splayt-insert
(phpinspect-bmap-class-variables bmap) (phpinspect-meta-start token-meta) token-meta)))
(if existing-end
(push token existing-end) (push token existing-end)
(puthash end (list token-meta) ends)) (puthash end (list token-meta) ends))
@ -222,10 +262,6 @@
(cl-defmethod phpinspect-bmap-token-meta ((overlay (head overlay)) token) (cl-defmethod phpinspect-bmap-token-meta ((overlay (head overlay)) token)
(phpinspect-bmap-token-meta (phpinspect-overlay-bmap overlay) token)) (phpinspect-bmap-token-meta (phpinspect-overlay-bmap overlay) token))
(defsubst phpinspect-probably-token-p (token)
(and (listp token)
(keywordp (car token))))
(cl-defmethod phpinspect-bmap-token-meta ((bmap phpinspect-bmap) token) (cl-defmethod phpinspect-bmap-token-meta ((bmap phpinspect-bmap) token)
(unless (phpinspect-probably-token-p token) (unless (phpinspect-probably-token-p token)
(error "Unexpected argument, expected `phpinspect-token-p'. Got invalid token %s" token)) (error "Unexpected argument, expected `phpinspect-token-p'. Got invalid token %s" token))
@ -248,7 +284,7 @@
(let* ((overlays (phpinspect-bmap-overlays bmap)) (let* ((overlays (phpinspect-bmap-overlays bmap))
(start (+ (phpinspect-meta-start token-meta) pos-delta)) (start (+ (phpinspect-meta-start token-meta) pos-delta))
(end (+ (phpinspect-meta-end token-meta) pos-delta)) (end (+ (phpinspect-meta-end token-meta) pos-delta))
(overlay) overlay
(last-overlay (phpinspect-splayt-node-value (phpinspect-splayt-root-node overlays)))) (last-overlay (phpinspect-splayt-node-value (phpinspect-splayt-root-node overlays))))
(phpinspect-meta-with-changeset token-meta (phpinspect-meta-with-changeset token-meta

@ -27,6 +27,10 @@
(require 'phpinspect-bmap) (require 'phpinspect-bmap)
(require 'phpinspect-edtrack) (require 'phpinspect-edtrack)
(require 'phpinspect-index) (require 'phpinspect-index)
(require 'phpinspect-toc)
(require 'phpinspect-resolvecontext)
(require 'phpinspect-resolve)
(require 'phpinspect-util)
(defvar-local phpinspect-current-buffer nil (defvar-local phpinspect-current-buffer nil
"An instance of `phpinspect-buffer' local to the active "An instance of `phpinspect-buffer' local to the active
@ -44,12 +48,26 @@ emacs buffer."
"Parsed token tree that resulted from last parse") "Parsed token tree that resulted from last parse")
(map nil (map nil
:type phpinspect-bmap) :type phpinspect-bmap)
(-last-indexed-bmap nil)
(imports nil
:type phpinspect-toc)
(namespaces nil
:type phpinspect-toc)
(classes nil
:type phpinspect-toc)
(class-variables nil
:type phpinspect-toc)
(declarations nil
:type phpinspect-toc)
(functions nil
:type phpinspect-toc)
(token-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
(project nil (project nil
:type phpinspect-project) :type phpinspect-project)
(edit-tracker (phpinspect-make-edtrack) (edit-tracker (phpinspect-make-edtrack)
:type phpinspect-edtrack)) :type phpinspect-edtrack))
(cl-defmethod phpinspect-buffer-parse ((buffer phpinspect-buffer) &optional no-interrupt no-index) (cl-defmethod phpinspect-buffer-parse ((buffer phpinspect-buffer) &optional no-interrupt)
"Parse the PHP code in the the emacs buffer that this object is "Parse the PHP code in the the emacs buffer that this object is
linked with." linked with."
(let ((tree)) (let ((tree))
@ -72,27 +90,331 @@ linked with."
(phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer)) (phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer))
;; set return value ;; set return value
(setq tree parsed) (setq tree parsed)))))
(unless (or no-index
(not (phpinspect-buffer-project buffer)))
(phpinspect--log "Adding buffer index to project")
(phpinspect-project-add-index
(phpinspect-buffer-project buffer)
(phpinspect--index-tokens tree nil (phpinspect-buffer-location-resolver buffer))
'index-imports))))))
;; Else: Just return last parse result ;; Else: Just return last parse result
(setq tree (phpinspect-buffer-tree buffer))) (setq tree (phpinspect-buffer-tree buffer)))
tree)) tree))
(cl-defmethod phpinspect-buffer-get-index-for-token ((buffer phpinspect-buffer) token)
(gethash token (phpinspect-buffer-token-index buffer)))
(cl-defmethod phpinspect-buffer-set-index-reference-for-token ((buffer phpinspect-buffer) token index)
(unless (phpinspect-probably-token-p token)
(error "%s does not seem to be a token" token))
(puthash token index (phpinspect-buffer-token-index buffer)))
(cl-defmethod phpinspect-buffer-update-index-reference-for-token ((buffer phpinspect-buffer) old new)
(unless (and (phpinspect-probably-token-p old) (phpinspect-probably-token-p new))
(when (and old new)
(error "old and new parameters should be tokens")))
(when-let ((index (gethash old (phpinspect-buffer-token-index buffer))))
(remhash old (phpinspect-buffer-token-index buffer))
(puthash new index (phpinspect-buffer-token-index buffer))))
(cl-defmethod phpinspect-buffer-delete-index-for-token ((buffer phpinspect-buffer) token)
(unless (phpinspect-probably-token-p token)
(error "%s does not seem to be a token" token))
(cond ((phpinspect-class-p token)
(when-let ((class (gethash token (phpinspect-buffer-token-index buffer))))
(remhash token (phpinspect-buffer-token-index buffer))
(phpinspect-project-delete-class (phpinspect-buffer-project buffer) class)))
((or (phpinspect-const-p token) (phpinspect-variable-p token))
(when-let ((var (gethash token (phpinspect-buffer-token-index buffer))))
(remhash token (phpinspect-buffer-token-index buffer))
(when-let ((class (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(car var))))
(phpinspect--class-delete-variable class (cdr var)))))
((phpinspect-function-p token)
(when-let ((func (gethash token (phpinspect-buffer-token-index buffer))))
(remhash token (phpinspect-buffer-token-index buffer))
(cond ((phpinspect-project-p (car func))
(phpinspect-project-delete-function (phpinspect-buffer-project buffer) (phpinspect--function-name-symbol (cdr func))))
((phpinspect--type-p (car func))
(when-let ((class (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(car func))))
(phpinspect--class-delete-method class (cdr func))))
(t (error "Invalid index location")))))
(t (error "Cannot delete index for token %s" token))))
(cl-defmethod phpinspect-buffer-namespace-at-point ((buffer phpinspect-buffer) (point integer))
(let ((namespace (phpinspect-splayt-find-largest-before
(phpinspect-toc-tree (phpinspect-buffer-namespaces buffer))
point)))
(and namespace (phpinspect-meta-overlaps-point namespace point) namespace)))
(cl-defmethod phpinspect-buffer-index-imports ((buffer phpinspect-buffer) (imports (head phpinspect-splayt)))
(let (to-be-indexed)
(if (phpinspect-buffer-imports buffer)
(pcase-let* ((`(,new) (phpinspect-toc-update
(phpinspect-buffer-imports buffer) imports (phpinspect-buffer-root-meta buffer))))
(setq to-be-indexed new))
(setq to-be-indexed (phpinspect-splayt-to-list imports))
(setf (phpinspect-buffer-imports buffer) (phpinspect-make-toc imports)))
(phpinspect-project-enqueue-imports
(phpinspect-buffer-project buffer)
(phpinspect--uses-to-types (mapcar #'phpinspect-meta-token to-be-indexed)))))
(cl-defmethod phpinspect-buffer-index-namespaces ((buffer phpinspect-buffer) (namespaces (head phpinspect-splayt)))
(if (phpinspect-buffer-namespaces buffer)
(phpinspect-toc-update (phpinspect-buffer-namespaces buffer) namespaces (phpinspect-buffer-root-meta buffer))
(setf (phpinspect-buffer-namespaces buffer) (phpinspect-make-toc namespaces))))
(cl-defmethod phpinspect-buffer-index-declarations ((buffer phpinspect-buffer) (declarations (head phpinspect-splayt)))
(if (phpinspect-buffer-declarations buffer)
(phpinspect-toc-update (phpinspect-buffer-declarations buffer) declarations (phpinspect-buffer-root-meta buffer))
(setf (phpinspect-buffer-declarations buffer) (phpinspect-make-toc declarations))))
(defun phpinspect-get-token-index-context (namespaces all-imports meta)
(let ((namespace (phpinspect-toc-token-at-point namespaces (phpinspect-meta-start meta)))
namespace-name imports)
(if namespace
(progn
(setq namespace-name (phpinspect-namespace-name (phpinspect-meta-token namespace))
imports (mapcar #'phpinspect-meta-token
(phpinspect-toc-tokens-in-region
all-imports (phpinspect-meta-start namespace) (phpinspect-meta-start meta)))))
(setq namespace-name nil
imports (mapcar #'phpinspect-meta-token
(phpinspect-toc-tokens-in-region
all-imports 0 (phpinspect-meta-start meta)))))
(list imports namespace-name)))
(cl-defmethod phpinspect-buffer-index-classes ((buffer phpinspect-buffer) (classes (head phpinspect-splayt)))
(let ((declarations (phpinspect-buffer-declarations buffer))
(namespaces (phpinspect-buffer-namespaces buffer))
(buffer-imports (phpinspect-buffer-imports buffer))
(project (phpinspect-buffer-project buffer)))
(if (phpinspect-buffer-classes buffer)
(pcase-let* ((`(,new-classes ,deleted-classes) (phpinspect-toc-update
(phpinspect-buffer-classes buffer)
classes (phpinspect-buffer-root-meta buffer)))
(new-declarations) (declaration) (replaced) (indexed) (class))
(dolist (class new-classes)
(when (setq declaration (phpinspect-toc-token-at-or-after-point declarations (phpinspect-meta-start class)))
(push (cons (phpinspect-meta-token declaration) class) new-declarations)))
(dolist (deleted deleted-classes)
(if (and (setq class (phpinspect-buffer-get-index-for-token
buffer (phpinspect-meta-token deleted)))
(setq replaced (assoc (phpinspect--class-declaration class) new-declarations #'equal)))
(pcase-let ((`(,imports ,namespace-name) (phpinspect-get-token-index-context namespaces buffer-imports (cdr replaced))))
(phpinspect-buffer-update-index-reference-for-token
buffer (phpinspect-meta-token deleted) (phpinspect-meta-token (cdr replaced)))
(phpinspect--class-update-declaration class (car replaced) imports namespace-name)
(push (cdr replaced) indexed))
(phpinspect-buffer-delete-index-for-token buffer (phpinspect-meta-token deleted))))
(dolist (class new-declarations)
(unless (memq (cdr class) indexed)
(pcase-let* ((`(,imports ,namespace-name) (phpinspect-get-token-index-context namespaces buffer-imports (cdr class)))
(`(,class-name) (phpinspect--index-class-declaration
(car class)
(phpinspect--make-type-resolver
(phpinspect--uses-to-types imports)
(phpinspect-class-block (phpinspect-meta-token (cdr class)))
namespace-name)))
(class-obj (phpinspect-project-get-class-create project class-name 'no-enqueue)))
(phpinspect-buffer-set-index-reference-for-token buffer (phpinspect-meta-token (cdr class)) class-obj)
(phpinspect--class-update-declaration class-obj (car class) imports namespace-name)))))
;; Else: Index all classes
(setf (phpinspect-buffer-classes buffer) (phpinspect-make-toc classes))
(phpinspect-splayt-traverse (class classes)
(pcase-let* ((declaration (phpinspect-toc-token-at-or-after-point declarations (phpinspect-meta-start class)))
(`(,imports ,namespace-name) (phpinspect-get-token-index-context namespaces buffer-imports class))
(`(,class-name) (phpinspect--index-class-declaration
(phpinspect-meta-token declaration)
(phpinspect--make-type-resolver
(phpinspect--uses-to-types imports)
(phpinspect-class-block (phpinspect-meta-token class))
namespace-name)))
(class-obj (phpinspect-project-get-class-create project class-name 'no-enqueue)))
(phpinspect-buffer-set-index-reference-for-token buffer (phpinspect-meta-token class) class-obj)
(phpinspect--class-update-declaration class-obj (phpinspect-meta-token declaration) imports namespace-name))))))
(cl-defmethod phpinspect-buffer-index-functions ((buffer phpinspect-buffer) (functions (head phpinspect-splayt)))
(let ((classes (phpinspect-buffer-classes buffer))
(namespaces (phpinspect-buffer-namespaces buffer))
(imports (phpinspect-buffer-imports buffer))
to-be-indexed class-environments class indexed)
(if (phpinspect-buffer-functions buffer)
(pcase-let ((`(,new-funcs ,deleted-funcs)
(phpinspect-toc-update (phpinspect-buffer-functions buffer) functions (phpinspect-buffer-root-meta buffer))))
(setq to-be-indexed new-funcs)
(dolist (deleted deleted-funcs)
(phpinspect-buffer-delete-index-for-token buffer (phpinspect-meta-token deleted))))
(setq to-be-indexed (phpinspect-splayt-to-list functions))
(setf (phpinspect-buffer-functions buffer) (phpinspect-make-toc functions)))
(dolist (func to-be-indexed)
(if (setq class (phpinspect-toc-token-at-point classes (phpinspect-meta-start func)))
(let (scope static indexed index-env comment-before)
(if (phpinspect-static-p (phpinspect-meta-token (phpinspect-meta-parent func)))
(progn
(setq static (phpinspect-meta-parent func))
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent static)))
(setq scope `(,(car (phpinspect-meta-token (phpinspect-meta-parent static)))
,(phpinspect-meta-token func))
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent static)))))
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent func)))
(setq scope (phpinspect-meta-token (phpinspect-meta-parent func))
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent func)))))
(unless scope (setq scope `(:public ,(phpinspect-meta-token func))))
(unless (setq index-env (alist-get class class-environments nil nil #'eq))
(setq index-env (phpinspect-get-token-index-context namespaces imports class))
(setcar index-env (phpinspect--uses-to-types (car index-env)))
(push (phpinspect--make-type-resolver (car index-env) (phpinspect-meta-token class) (cadr index-env))
index-env)
(push (cons class index-env) class-environments))
(unless comment-before
(setq comment-before (phpinspect-meta-find-left-sibling func)))
(setq comment-before (phpinspect-meta-token comment-before))
(pcase-let ((`(,type-resolver) index-env)
(class-obj (phpinspect-buffer-get-index-for-token buffer (phpinspect-meta-token class))))
(unless class-obj (error "Unable to find class obj for class %s" (phpinspect-meta-token class)))
(setq indexed (phpinspect--index-function-from-scope
type-resolver
scope
(and (phpinspect-comment-p comment-before) comment-before)))
(if static
(phpinspect--class-set-static-method class-obj indexed)
(phpinspect--class-set-method class-obj indexed))
(phpinspect-buffer-set-index-reference-for-token
buffer (phpinspect-meta-token func)
(cons (phpinspect--class-name class-obj) indexed))))
;; Else: index function
(pcase-let ((`(,imports ,namespace-name) (phpinspect-get-token-index-context namespaces imports func))
(comment-before (phpinspect-meta-find-left-sibling func)))
(setq indexed (phpinspect--index-function-from-scope
(phpinspect--make-type-resolver
(phpinspect--uses-to-types imports) nil namespace-name)
`(:public ,(phpinspect-meta-token func))
(and (phpinspect-comment-p comment-before) comment-before)
nil namespace-name))
(phpinspect-project-set-function (phpinspect-buffer-project buffer) indexed)
(phpinspect-buffer-set-index-reference-for-token
buffer (phpinspect-meta-token func)
(cons (phpinspect-buffer-project buffer) indexed)))))))
(cl-defmethod phpinspect-buffer-index-class-variables ((buffer phpinspect-buffer) (class-variables (head phpinspect-splayt)))
(let ((classes (phpinspect-buffer-classes buffer))
(namespaces (phpinspect-buffer-namespaces buffer))
(imports (phpinspect-buffer-imports buffer))
to-be-indexed class-environments class class-obj)
(if (phpinspect-buffer-class-variables buffer)
(pcase-let ((`(,new-vars ,deleted-vars)
(phpinspect-toc-update
(phpinspect-buffer-class-variables buffer) class-variables (phpinspect-buffer-root-meta buffer))))
(setq to-be-indexed new-vars)
(dolist (deleted deleted-vars)
(phpinspect-buffer-delete-index-for-token buffer (phpinspect-meta-token deleted))))
(setq to-be-indexed (phpinspect-splayt-to-list class-variables))
(setf (phpinspect-buffer-class-variables buffer) (phpinspect-make-toc class-variables)))
(dolist (var to-be-indexed)
(when (and class (> (phpinspect-meta-start var) (phpinspect-meta-end class)))
(setq class nil))
(unless class
(setq class (phpinspect-toc-token-at-point classes (phpinspect-meta-start var))))
(setq class-obj (phpinspect-buffer-get-index-for-token buffer (phpinspect-meta-token class)))
(let (scope static indexed index-env comment-before)
(if (phpinspect-static-p (phpinspect-meta-token (phpinspect-meta-parent var)))
(progn
(setq static (phpinspect-meta-parent var))
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent static)))
(setq scope `(,(car (phpinspect-meta-token (phpinspect-meta-parent static)))
,(phpinspect-meta-token var))
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent static)))))
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent var)))
(setq scope (phpinspect-meta-token (phpinspect-meta-parent var))
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent var)))))
(unless scope (setq scope `(:public ,(phpinspect-meta-token var))))
(unless (setq index-env (alist-get class class-environments nil nil #'eq))
(setq index-env (phpinspect-get-token-index-context namespaces imports class))
(push (cons class index-env) class-environments))
(unless comment-before
(setq comment-before (phpinspect-meta-find-left-sibling var)))
(setq comment-before (phpinspect-meta-token comment-before))
(pcase-let* ((`(,imports ,namespace-name) index-env)
(type-resolver
(phpinspect--make-type-resolver
(phpinspect--uses-to-types imports)
(phpinspect-meta-token class)
namespace-name)))
(setq indexed
(if (phpinspect-const-p (phpinspect-meta-token var))
(phpinspect--index-const-from-scope scope)
(phpinspect--index-variable-from-scope
type-resolver
scope
(and (phpinspect-comment-p comment-before) comment-before)
static)))
(when (and (phpinspect-variable-p (phpinspect-meta-token var)) (not (phpinspect--variable-type indexed)))
(when-let* ((constructor (phpinspect--class-get-method class-obj (phpinspect-intern-name "__construct")))
(rctx (phpinspect--make-resolvecontext :enclosing-tokens (list (phpinspect-meta-token class))
:enclosing-metadata (list class))))
(setf (phpinspect--variable-type indexed)
(phpinspect-get-pattern-type-in-block
rctx (phpinspect--make-pattern :m `(:variable "this") :m `(:object-attrib (:word ,(cadr var))))
(phpinspect-function-block (phpinspect--function-token constructor))
type-resolver
(phpinspect-function-argument-list (phpinspect--function-token constructor))))))
(phpinspect--class-set-variable class-obj indexed)
(phpinspect-buffer-set-index-reference-for-token
buffer (phpinspect-meta-token var)
(cons (phpinspect--class-name class-obj) indexed)))))))
(cl-defmethod phpinspect-buffer-reparse ((buffer phpinspect-buffer)) (cl-defmethod phpinspect-buffer-reparse ((buffer phpinspect-buffer))
(setf (phpinspect-buffer-tree buffer) nil) (setf (phpinspect-buffer-tree buffer) nil)
(setf (phpinspect-buffer-map buffer) (phpinspect-make-bmap)) (setf (phpinspect-buffer-map buffer) (phpinspect-make-bmap))
(setf (phpinspect-buffer-declarations buffer) nil)
(setf (phpinspect-buffer-imports buffer) nil)
(phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer)) (phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer))
(phpinspect-buffer-parse buffer 'no-interrupt)) (phpinspect-buffer-parse buffer 'no-interrupt))
(cl-defmethod phpinspect-buffer-update-project-index ((buffer phpinspect-buffer))
(when (phpinspect-buffer-project buffer)
(let ((map (phpinspect-buffer-map buffer)))
(unless (eq map (phpinspect-buffer--last-indexed-bmap buffer))
(phpinspect-buffer-index-imports buffer (phpinspect-bmap-imports map))
(phpinspect-buffer-index-declarations buffer (phpinspect-bmap-declarations map))
(phpinspect-buffer-index-namespaces buffer (phpinspect-bmap-namespaces map))
(phpinspect-buffer-index-classes buffer (phpinspect-bmap-classes map))
(phpinspect-buffer-index-functions buffer (phpinspect-bmap-functions map))
(phpinspect-buffer-index-class-variables buffer (phpinspect-bmap-class-variables map))
(setf (phpinspect-buffer--last-indexed-bmap buffer) map)))))
(defsubst phpinspect-buffer-parse-map (buffer) (defsubst phpinspect-buffer-parse-map (buffer)
(phpinspect-buffer-parse buffer) (phpinspect-buffer-parse buffer)
(phpinspect-buffer-map buffer)) (phpinspect-buffer-map buffer))
@ -134,14 +456,6 @@ use."
(cl-defmethod phpinspect-buffer-root-meta ((buffer phpinspect-buffer)) (cl-defmethod phpinspect-buffer-root-meta ((buffer phpinspect-buffer))
(phpinspect-bmap-root-meta (phpinspect-buffer-map buffer))) (phpinspect-bmap-root-meta (phpinspect-buffer-map buffer)))
(defun phpinspect-display-buffer-tree ()
(interactive)
(when phpinspect-current-buffer
(let ((buffer phpinspect-current-buffer))
(pop-to-buffer (generate-new-buffer "phpinspect-buffer-tree"))
(insert (pp-to-string (phpinspect-buffer-parse buffer 'no-interrupt)))
(read-only-mode))))
(defun phpinspect-display-buffer-index () (defun phpinspect-display-buffer-index ()
(interactive) (interactive)
(when phpinspect-current-buffer (when phpinspect-current-buffer
@ -150,5 +464,8 @@ use."
(insert (pp-to-string (phpinspect--index-tokens (phpinspect-buffer-parse buffer 'no-interrupt)))) (insert (pp-to-string (phpinspect--index-tokens (phpinspect-buffer-parse buffer 'no-interrupt))))
(read-only-mode)))) (read-only-mode))))
(defun phpinspect-after-change-function (start end pre-change-length)
(when phpinspect-current-buffer
(phpinspect-buffer-register-edit phpinspect-current-buffer start end pre-change-length)))
(provide 'phpinspect-buffer) (provide 'phpinspect-buffer)

@ -30,14 +30,6 @@
(defvar phpinspect-cache nil (defvar phpinspect-cache nil
"An object used to store and access metadata of PHP projects.") "An object used to store and access metadata of PHP projects.")
(defun phpinspect--get-or-create-global-cache ()
"Get `phpinspect-cache'.
If its value is nil, it is created and then returned."
(or phpinspect-cache
(setq phpinspect-cache (phpinspect--make-cache))))
(cl-defstruct (phpinspect--cache (:constructor phpinspect--make-cache)) (cl-defstruct (phpinspect--cache (:constructor phpinspect--make-cache))
(projects (make-hash-table :test 'equal :size 10) (projects (make-hash-table :test 'equal :size 10)
:type hash-table :type hash-table
@ -45,6 +37,26 @@ If its value is nil, it is created and then returned."
"A `hash-table` with the root directories of projects "A `hash-table` with the root directories of projects
as keys and project caches as values.")) as keys and project caches as values."))
(defun phpinspect--get-or-create-global-cache ()
"Get `phpinspect-cache'.
If its value is nil, it is created and then returned."
(or phpinspect-cache
(setq phpinspect-cache (phpinspect--make-cache))))
(defun phpinspect-purge-cache ()
"Assign a fresh, empty cache object to `phpinspect-cache'.
This effectively purges any cached code information from all
currently opened projects."
(interactive)
(when phpinspect-cache
;; Allow currently known cached projects to cleanup after themselves
(maphash (lambda (_ project)
(phpinspect-project-purge project))
(phpinspect--cache-projects phpinspect-cache)))
;; Assign a fresh cache object
(setq phpinspect-cache (phpinspect--make-cache)))
(cl-defgeneric phpinspect--cache-getproject (cl-defgeneric phpinspect--cache-getproject
((cache phpinspect--cache) (project-name string)) ((cache phpinspect--cache) (project-name string))
"Get project by PROJECT-NAME that is located in CACHE.") "Get project by PROJECT-NAME that is located in CACHE.")

@ -43,20 +43,23 @@
:documentation :documentation
"All static methods this class provides, "All static methods this class provides,
including those from extended classes.") including those from extended classes.")
(name nil
:type phpinspect--type)
(variables nil (variables nil
:type list :type list
:documentation :documentation
"Variables that belong to this class.") "Variables that belong to this class.")
(extended-classes (make-hash-table :test 'eq) (extended-classes nil
:type hash-table :type list
:documentation :documentation
"All extended/implemented classes.") "All extended/implemented classes.")
(subscriptions nil (subscriptions (make-hash-table :test #'eq :size 10 :rehash-size 1.5)
:type list :type hash-table
:documentation :documentation
"A list of subscription functions that should be "A list of subscription functions that should be
called whenever anything about this class is called whenever anything about this class is
updated") updated")
(declaration nil)
(initial-index nil (initial-index nil
:type bool :type bool
:documentation :documentation
@ -64,13 +67,43 @@
has been indexed yet.")) has been indexed yet."))
(cl-defmethod phpinspect--class-trigger-update ((class phpinspect--class)) (cl-defmethod phpinspect--class-trigger-update ((class phpinspect--class))
(dolist (sub (phpinspect--class-subscriptions class)) (dolist (sub (hash-table-values (phpinspect--class-subscriptions class)))
(funcall sub class))) (funcall sub class)))
(cl-defmethod phpinspect--class-update-extensions ((class phpinspect--class) extensions)
(setf (phpinspect--class-extended-classes class)
(seq-filter
#'phpinspect--class-p
(mapcar
(lambda (class-name)
(phpinspect-project-get-class-create (phpinspect--class-project class)
class-name))
extensions)))
(dolist (extended (phpinspect--class-extended-classes class))
(phpinspect--class-incorporate class extended)))
(cl-defmethod phpinspect--class-set-index ((class phpinspect--class) (cl-defmethod phpinspect--class-set-index ((class phpinspect--class)
(index (head phpinspect--indexed-class))) (index (head phpinspect--indexed-class)))
(setf (phpinspect--class-declaration class) (alist-get 'declaration index))
(setf (phpinspect--class-name class) (alist-get 'class-name index))
;; Override methods when class seems syntactically correct (has balanced braces)
(when (alist-get 'complete index)
(let ((methods (phpinspect--class-methods class))
(static-methods (phpinspect--class-static-methods class)))
(dolist (method (hash-table-values methods))
(unless (phpinspect--function--inherited method)
(remhash (phpinspect--function-name-symbol method) methods)))
(dolist (method (hash-table-values static-methods))
(unless (phpinspect--function--inherited method)
(remhash (phpinspect--function-name-symbol method) static-methods)))))
(setf (phpinspect--class-initial-index class) t) (setf (phpinspect--class-initial-index class) t)
(setf (phpinspect--class-index class) index) (setf (phpinspect--class-index class) index)
(dolist (method (alist-get 'methods index)) (dolist (method (alist-get 'methods index))
(phpinspect--class-update-method class method)) (phpinspect--class-update-method class method))
@ -82,21 +115,21 @@
(alist-get 'constants index) (alist-get 'constants index)
(alist-get 'static-variables index))) (alist-get 'static-variables index)))
(setf (phpinspect--class-extended-classes class) (phpinspect--class-update-extensions
(seq-filter class `(,@(alist-get 'implements index) ,@(alist-get 'extends index)))
#'phpinspect--class-p
(mapcar
(lambda (class-name)
(phpinspect-project-get-class-create (phpinspect--class-project class)
class-name))
`(,@(alist-get 'implements index) ,@(alist-get 'extends index)))))
(dolist (extended (phpinspect--class-extended-classes class))
(phpinspect--class-incorporate class extended)
(phpinspect--class-subscribe class extended))
(phpinspect--class-trigger-update class)) (phpinspect--class-trigger-update class))
(cl-defmethod phpinspect--class-update-declaration
((class phpinspect--class) declaration imports namespace-name)
(pcase-let ((`(,class-name ,extends ,implements ,_used-types)
(phpinspect--index-class-declaration
declaration (phpinspect--make-type-resolver
(phpinspect--uses-to-types imports) nil namespace-name))))
(setf (phpinspect--class-name class) class-name)
(setf (phpinspect--class-declaration class) declaration)
(phpinspect--class-update-extensions class `(,@extends ,@implements))))
(cl-defmethod phpinspect--class-get-method ((class phpinspect--class) (method-name symbol)) (cl-defmethod phpinspect--class-get-method ((class phpinspect--class) (method-name symbol))
(gethash method-name (phpinspect--class-methods class))) (gethash method-name (phpinspect--class-methods class)))
@ -110,6 +143,16 @@
(when (string= variable-name (phpinspect--variable-name variable)) (when (string= variable-name (phpinspect--variable-name variable))
(throw 'found variable))))) (throw 'found variable)))))
(cl-defmethod phpinspect--class-set-variable ((class phpinspect--class)
(var phpinspect--variable))
(push var (phpinspect--class-variables class)))
(cl-defmethod phpinspect--class-delete-variable ((class phpinspect--class)
(var phpinspect--variable))
(setf (phpinspect--class-variables class)
(seq-filter (lambda (clvar) (not (eq var clvar)))
(phpinspect--class-variables class))))
(cl-defmethod phpinspect--class-get-variables ((class phpinspect--class)) (cl-defmethod phpinspect--class-get-variables ((class phpinspect--class))
(seq-filter #'phpinspect--variable-vanilla-p (phpinspect--class-variables class))) (seq-filter #'phpinspect--variable-vanilla-p (phpinspect--class-variables class)))
@ -140,16 +183,22 @@
(phpinspect--function-name method)) (phpinspect--function-name method))
(phpinspect--add-method-copy-to-map (phpinspect--add-method-copy-to-map
(phpinspect--class-methods class) (phpinspect--class-methods class)
(alist-get 'class-name (phpinspect--class-index class)) (phpinspect--class-name class)
method)) method))
(cl-defmethod phpinspect--class-set-static-method ((class phpinspect--class) (cl-defmethod phpinspect--class-set-static-method ((class phpinspect--class)
(method phpinspect--function)) (method phpinspect--function))
(phpinspect--add-method-copy-to-map (phpinspect--add-method-copy-to-map
(phpinspect--class-static-methods class) (phpinspect--class-static-methods class)
(alist-get 'class-name (phpinspect--class-index class)) (phpinspect--class-name class)
method)) method))
(cl-defmethod phpinspect--class-delete-method ((class phpinspect--class) (method phpinspect--function))
(remhash (phpinspect--function-name-symbol method) (phpinspect--class-static-methods class))
(remhash (phpinspect--function-name-symbol method) (phpinspect--class-methods class)))
(cl-defmethod phpinspect--class-get-method-return-type (cl-defmethod phpinspect--class-get-method-return-type
((class phpinspect--class) (method-name symbol)) ((class phpinspect--class) (method-name symbol))
(let ((method (phpinspect--class-get-method class method-name))) (let ((method (phpinspect--class-get-method class method-name)))
@ -171,7 +220,8 @@
(cl-defmethod phpinspect--merge-method ((class-name phpinspect--type) (cl-defmethod phpinspect--merge-method ((class-name phpinspect--type)
(existing phpinspect--function) (existing phpinspect--function)
(method phpinspect--function)) (method phpinspect--function)
&optional extended)
(let ((new-return-type (phpinspect--resolve-late-static-binding (let ((new-return-type (phpinspect--resolve-late-static-binding
(phpinspect--function-return-type method) (phpinspect--function-return-type method)
class-name))) class-name)))
@ -180,49 +230,59 @@
(setf (phpinspect--function-return-type existing) (setf (phpinspect--function-return-type existing)
new-return-type)) new-return-type))
(setf (phpinspect--function--inherited existing)
extended)
(setf (phpinspect--function-arguments existing) (setf (phpinspect--function-arguments existing)
(phpinspect--function-arguments method))) (phpinspect--function-arguments method)))
existing) existing)
(cl-defmethod phpinspect--class-update-static-method ((class phpinspect--class) (cl-defmethod phpinspect--class-update-static-method ((class phpinspect--class)
(method phpinspect--function)) (method phpinspect--function)
&optional extended)
(let ((existing (gethash (phpinspect--function-name-symbol method) (let ((existing (gethash (phpinspect--function-name-symbol method)
(phpinspect--class-static-methods class)))) (phpinspect--class-static-methods class))))
(if existing (if existing
(phpinspect--merge-method (phpinspect--merge-method
(alist-get 'class-name (phpinspect--class-index class)) (alist-get 'class-name (phpinspect--class-index class))
existing method) existing method extended)
(setf (phpinspect--function--inherited method) extended)
(phpinspect--class-set-static-method class method)))) (phpinspect--class-set-static-method class method))))
(cl-defmethod phpinspect--class-update-method ((class phpinspect--class) (cl-defmethod phpinspect--class-update-method ((class phpinspect--class)
(method phpinspect--function)) (method phpinspect--function)
&optional extended)
(let* ((existing (gethash (phpinspect--function-name-symbol method) (let* ((existing (gethash (phpinspect--function-name-symbol method)
(phpinspect--class-methods class)))) (phpinspect--class-methods class))))
(if existing (if existing
(phpinspect--merge-method (phpinspect--merge-method
(alist-get 'class-name (phpinspect--class-index class)) (alist-get 'class-name (phpinspect--class-index class))
existing method) existing method extended)
(setf (phpinspect--function--inherited method) extended)
(phpinspect--class-set-method class method)))) (phpinspect--class-set-method class method))))
;; FIXME: Remove inherited methods when they no longer exist in parent classes
;; (and/or the current class in the case of abstract methods).
(cl-defmethod phpinspect--class-incorporate ((class phpinspect--class) (cl-defmethod phpinspect--class-incorporate ((class phpinspect--class)
(other-class phpinspect--class)) (other-class phpinspect--class))
(dolist (method (phpinspect--class-get-method-list other-class)) (dolist (method (phpinspect--class-get-method-list other-class))
(phpinspect--class-update-method class method)) (phpinspect--class-update-method class method 'extended))
(dolist (method (phpinspect--class-get-static-method-list other-class))
(phpinspect--class-update-static-method class method)))
(dolist (method (phpinspect--class-get-static-method-list other-class))
(phpinspect--class-update-static-method class method 'extended))
(phpinspect--class-subscribe class other-class))
(cl-defmethod phpinspect--class-subscribe ((class phpinspect--class) (cl-defmethod phpinspect--class-subscribe ((class phpinspect--class)
(subscription-class phpinspect--class)) (subscription-class phpinspect--class))
(let ((update-function (unless (gethash subscription-class (phpinspect--class-subscriptions class))
(lambda (new-class) (let ((update-function
(phpinspect--class-incorporate class new-class) (lambda (new-class)
(phpinspect--class-trigger-update class)))) (phpinspect--class-incorporate class new-class)
(push update-function (phpinspect--class-subscriptions subscription-class)))) (phpinspect--class-trigger-update class))))
(puthash subscription-class update-function
(phpinspect--class-subscriptions subscription-class)))))
(provide 'phpinspect-class) (provide 'phpinspect-class)
;;; phpinspect-class.el ends here ;;; phpinspect-class.el ends here

@ -213,6 +213,8 @@ Returns list of `phpinspect--completion'."
(buffer-map (phpinspect-buffer-parse-map buffer)) (buffer-map (phpinspect-buffer-parse-map buffer))
(rctx (phpinspect-get-resolvecontext buffer-map point)) (rctx (phpinspect-get-resolvecontext buffer-map point))
(completion-list (phpinspect--make-completion-list))) (completion-list (phpinspect--make-completion-list)))
(phpinspect-buffer-update-project-index buffer)
(dolist (strategy phpinspect-completion-strategies) (dolist (strategy phpinspect-completion-strategies)
(when-let (region (phpinspect-comp-strategy-supports strategy query rctx)) (when-let (region (phpinspect-comp-strategy-supports strategy query rctx))
(setf (phpinspect--completion-list-completion-start completion-list) (setf (phpinspect--completion-list-completion-start completion-list)

@ -123,8 +123,7 @@ be implemented for return values of `phpinspect-eld-strategy-execute'")
enclosing-token) enclosing-token)
(setq left-sibling (phpinspect-meta-find-child-before-recursively (setq left-sibling (phpinspect-meta-find-child-before-recursively
enclosing-token (phpinspect-eldoc-query-point q))) enclosing-token (phpinspect-eldoc-query-point q))))
(phpinspect-meta-overlaps-point left-sibling (phpinspect-eldoc-query-point q)))
;; Subject is inside an argument list ;; Subject is inside an argument list
((and enclosing-token ((and enclosing-token
(phpinspect-list-p (phpinspect-meta-token enclosing-token))) (phpinspect-list-p (phpinspect-meta-token enclosing-token)))
@ -250,6 +249,7 @@ also `phpinspect-eldoc-query-execute'.")
(point (phpinspect-eldoc-query-point query)) (point (phpinspect-eldoc-query-point query))
(buffer-map (phpinspect-buffer-parse-map buffer)) (buffer-map (phpinspect-buffer-parse-map buffer))
(rctx (phpinspect-get-resolvecontext buffer-map point))) (rctx (phpinspect-get-resolvecontext buffer-map point)))
(phpinspect-buffer-update-project-index buffer)
(catch 'matched (catch 'matched
(dolist (strategy phpinspect-eldoc-strategies) (dolist (strategy phpinspect-eldoc-strategies)
(when (phpinspect-eld-strategy-supports strategy query rctx) (when (phpinspect-eld-strategy-supports strategy query rctx)

@ -30,6 +30,7 @@
(require 'phpinspect-autoload) (require 'phpinspect-autoload)
(require 'phpinspect-buffer) (require 'phpinspect-buffer)
(require 'phpinspect-cache) (require 'phpinspect-cache)
(require 'phpinspect-util)
(defun phpinspect-insert-at-point (point data) (defun phpinspect-insert-at-point (point data)
(save-excursion (save-excursion
@ -113,12 +114,6 @@ buffer position to insert the use statement at."
(defalias 'phpinspect-fix-uses-interactive #'phpinspect-fix-imports (defalias 'phpinspect-fix-uses-interactive #'phpinspect-fix-imports
"Alias for backwards compatibility") "Alias for backwards compatibility")
(defun phpinspect-namespace-name (namespace)
(or (and (phpinspect-namespace-p namespace)
(phpinspect-word-p (cadr namespace))
(cadadr namespace))
""))
(defun phpinspect-add-use-statements-for-missing-types (types buffer imports project parent-token) (defun phpinspect-add-use-statements-for-missing-types (types buffer imports project parent-token)
(let (namespace namespace-name) (let (namespace namespace-name)
(dolist (type types) (dolist (type types)

@ -27,6 +27,7 @@
(require 'phpinspect-util) (require 'phpinspect-util)
(require 'phpinspect-project) (require 'phpinspect-project)
(require 'phpinspect-type) (require 'phpinspect-type)
(require 'phpinspect-parser)
(defun phpinspect--function-from-scope (scope) (defun phpinspect--function-from-scope (scope)
(cond ((and (phpinspect-static-p (cadr scope)) (cond ((and (phpinspect-static-p (cadr scope))
@ -108,6 +109,7 @@ function (think \"new\" statements, return types etc.)."
(phpinspect--make-function (phpinspect--make-function
:scope `(,(car scope)) :scope `(,(car scope))
:token php-func
:name (concat (if namespace (concat namespace "\\") "") (cadadr (cdr declaration))) :name (concat (if namespace (concat namespace "\\") "") (cadadr (cdr declaration)))
:return-type (or type phpinspect--null-type) :return-type (or type phpinspect--null-type)
:arguments (phpinspect--index-function-arg-list :arguments (phpinspect--index-function-arg-list
@ -115,11 +117,16 @@ function (think \"new\" statements, return types etc.)."
(phpinspect-function-argument-list php-func) (phpinspect-function-argument-list php-func)
add-used-types)))) add-used-types))))
(define-inline phpinspect--safe-cadr (list)
(inline-letevals (list)
(inline-quote
(when (listp ,list) (cadr ,list)))))
(defun phpinspect--index-const-from-scope (scope) (defun phpinspect--index-const-from-scope (scope)
(phpinspect--make-variable (phpinspect--make-variable
:scope `(,(car scope)) :scope `(,(car scope))
:mutability `(,(caadr scope)) :mutability `(,(caadr scope))
:name (cadr (cadr (cadr scope))))) :name (phpinspect--safe-cadr (phpinspect--safe-cadr (phpinspect--safe-cadr scope)))))
(defun phpinspect--var-annotations-from-token (token) (defun phpinspect--var-annotations-from-token (token)
(seq-filter #'phpinspect-var-annotation-p token)) (seq-filter #'phpinspect-var-annotation-p token))
@ -184,6 +191,39 @@ function (think \"new\" statements, return types etc.)."
methods))))) methods)))))
methods)) methods))
(defun phpinspect--index-class-declaration (decl type-resolver)
;; Find out what the class extends or implements
(let (encountered-extends encountered-implements encountered-class
class-name extends implements used-types)
(dolist (word decl)
(if (phpinspect-word-p word)
(cond ((string= (cadr word) "extends")
(phpinspect--log "Class %s extends other classes" class-name)
(setq encountered-extends t))
((string= (cadr word) "implements")
(setq encountered-extends nil)
(phpinspect--log "Class %s implements in interface" class-name)
(setq encountered-implements t))
((string= (cadr word) "class")
(setq encountered-class t))
(t
(phpinspect--log "Calling Resolver from index-class on %s" (cadr word))
(cond (encountered-extends
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
extends)
(push (cadr word) used-types))
(encountered-implements
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
implements)
(push (cadr word) used-types))
(encountered-class
(setq class-name (funcall type-resolver (phpinspect--make-type :name (cadr word)))
encountered-class nil)))))))
(list class-name extends implements used-types)))
(defun phpinspect--index-class (imports type-resolver location-resolver class &optional doc-block) (defun phpinspect--index-class (imports type-resolver location-resolver class &optional doc-block)
"Create an alist with relevant attributes of a parsed class." "Create an alist with relevant attributes of a parsed class."
@ -195,7 +235,7 @@ function (think \"new\" statements, return types etc.)."
(constants) (constants)
(extends) (extends)
(implements) (implements)
(class-name (phpinspect--get-class-name-from-token class)) (class-name)
;; Keep track of encountered comments to be able to use type ;; Keep track of encountered comments to be able to use type
;; annotations. ;; annotations.
(comment-before) (comment-before)
@ -208,30 +248,9 @@ function (think \"new\" statements, return types etc.)."
(nconc used-types additional-used-types) (nconc used-types additional-used-types)
(setq used-types additional-used-types)))) (setq used-types additional-used-types))))
;; Find out what the class extends or implements (pcase-setq `(,class-name ,extends ,implements ,used-types)
(let ((enc-extends nil) (phpinspect--index-class-declaration (cadr class) type-resolver))
(enc-implements nil))
(dolist (word (cadr class))
(if (phpinspect-word-p word)
(cond ((string= (cadr word) "extends")
(phpinspect--log "Class %s extends other classes" class-name)
(setq enc-extends t))
((string= (cadr word) "implements")
(setq enc-extends nil)
(phpinspect--log "Class %s implements in interface" class-name)
(setq enc-implements t))
(t
(phpinspect--log "Calling Resolver from index-class on %s" (cadr word))
(cond (enc-extends
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
extends)
(push (cadr word) used-types))
(enc-implements
(push (funcall type-resolver (phpinspect--make-type
:name (cadr word)))
implements)
(push (cadr word) used-types))))))))
(dolist (token (caddr class)) (dolist (token (caddr class))
(cond ((phpinspect-scope-p token) (cond ((phpinspect-scope-p token)
@ -330,21 +349,22 @@ function (think \"new\" statements, return types etc.)."
(setq methods (setq methods
(nconc methods (phpinspect--index-method-annotations type-resolver doc-block)))) (nconc methods (phpinspect--index-method-annotations type-resolver doc-block))))
(let ((class-name (funcall type-resolver (phpinspect--make-type :name class-name)))) `(,class-name .
`(,class-name . (phpinspect--indexed-class
(phpinspect--indexed-class (complete . ,(not (phpinspect-incomplete-class-p class)))
(class-name . ,class-name) (class-name . ,class-name)
(location . ,(funcall location-resolver class)) (declaration . ,(seq-find #'phpinspect-declaration-p class))
(imports . ,imports) (location . ,(funcall location-resolver class))
(methods . ,methods) (imports . ,imports)
(static-methods . ,static-methods) (methods . ,methods)
(static-variables . ,static-variables) (static-methods . ,static-methods)
(variables . ,variables) (static-variables . ,static-variables)
(constants . ,constants) (variables . ,variables)
(extends . ,extends) (constants . ,constants)
(implements . ,implements) (extends . ,extends)
(used-types . ,(mapcar #'phpinspect-intern-name (implements . ,implements)
(seq-uniq used-types #'string=)))))))) (used-types . ,(mapcar #'phpinspect-intern-name
(seq-uniq used-types #'string=)))))))
(defsubst phpinspect-namespace-body (namespace) (defsubst phpinspect-namespace-body (namespace)
"Return the nested tokens in NAMESPACE tokens' body. "Return the nested tokens in NAMESPACE tokens' body.
@ -503,7 +523,7 @@ Return value is a list of the types that are \"newed\"."
tokens type-resolver-factory imports)))))) tokens type-resolver-factory imports))))))
(t (t
(phpinspect--log "phpinspect--index-tokens failed: %s. Enable debug-on-error for backtrace." err) (phpinspect--log "phpinspect--index-tokens failed: %s. Enable debug-on-error for backtrace." err)
(when debug-on-error (when (or debug-on-error phpinspect--debug)
(require 'backtrace) (require 'backtrace)
(backtrace)) (backtrace))
nil)) nil))

@ -52,17 +52,40 @@
(define-inline phpinspect-meta-whitespace-before (meta) (define-inline phpinspect-meta-whitespace-before (meta)
(inline-quote (car (cddddr ,meta)))) (inline-quote (car (cddddr ,meta))))
(defun phpinspect-meta-start (meta) (define-inline phpinspect-meta-parent-start (meta)
(if (phpinspect-meta-parent meta) "Calculate parent start position iteratively based on parent offsets."
(+ (phpinspect-meta-start (phpinspect-meta-parent meta)) (inline-letevals (meta)
(phpinspect-meta-parent-offset meta)) (inline-quote
(phpinspect-meta-absolute-start meta))) (let ((start (or (phpinspect-meta-parent-offset ,meta) 0))
(current ,meta))
(while (phpinspect-meta-parent current)
(setq current (phpinspect-meta-parent current)
start (+ start (or (phpinspect-meta-parent-offset current) 0))))
(defun phpinspect-meta-end (meta) (+ (phpinspect-meta-absolute-start current) start)))))
(+ (phpinspect-meta-start meta) (phpinspect-meta-width meta)))
(defsubst phpinspect-meta-width (meta) (define-inline phpinspect-meta-start (meta)
(- (phpinspect-meta-absolute-end meta) (phpinspect-meta-absolute-start meta))) "Calculate the start position of META."
(inline-quote
(if (phpinspect-meta-parent ,meta)
(+ (phpinspect-meta-parent-start (phpinspect-meta-parent ,meta))
(phpinspect-meta-parent-offset ,meta))
(phpinspect-meta-absolute-start ,meta))))
(define-inline phpinspect-meta-width (meta)
(inline-letevals (meta)
(inline-quote
(- (phpinspect-meta-absolute-end ,meta) (phpinspect-meta-absolute-start ,meta)))))
(define-inline phpinspect-meta-end (meta)
(inline-letevals (meta)
(inline-quote
(+ (phpinspect-meta-start ,meta) (phpinspect-meta-width ,meta)))))
(defsubst phpinspect-meta-find-root (meta)
(while (phpinspect-meta-parent meta)
(setq meta (phpinspect-meta-parent meta)))
meta)
(defun phpinspect-meta-sort-width (meta1 meta2) (defun phpinspect-meta-sort-width (meta1 meta2)
(< (phpinspect-meta-width meta1) (phpinspect-meta-width meta2))) (< (phpinspect-meta-width meta1) (phpinspect-meta-width meta2)))
@ -73,9 +96,12 @@
(define-inline phpinspect-meta-absolute-start (meta) (define-inline phpinspect-meta-absolute-start (meta)
(inline-quote (caddr ,meta))) (inline-quote (caddr ,meta)))
(defsubst phpinspect-meta-overlaps-point (meta point) (define-inline phpinspect-meta-overlaps-point (meta point)
(and (> (phpinspect-meta-end meta) point) "Check if META's region overlaps POINT."
(<= (phpinspect-meta-start meta) point))) (inline-letevals (point meta)
(inline-quote
(and (> (phpinspect-meta-end ,meta) ,point)
(<= (phpinspect-meta-start ,meta) ,point)))))
(defun phpinspect-meta-find-parent-matching-token (meta predicate) (defun phpinspect-meta-find-parent-matching-token (meta predicate)
(if (funcall predicate (phpinspect-meta-token meta)) (if (funcall predicate (phpinspect-meta-token meta))
@ -94,7 +120,9 @@
(setf (phpinspect-meta-parent-offset ,meta) (setf (phpinspect-meta-parent-offset ,meta)
(- (phpinspect-meta-start ,meta) (phpinspect-meta-start ,parent))) (- (phpinspect-meta-start ,meta) (phpinspect-meta-start ,parent)))
(phpinspect-meta-add-child ,parent ,meta)) (phpinspect-meta-add-child ,parent ,meta))
(setcar (cdr ,meta) ,parent))))) (setcar (cdr ,meta) ,parent)
,meta))))
;; Note: using defsubst here causes a byte code overflow ;; Note: using defsubst here causes a byte code overflow
(defun phpinspect-meta-add-child (meta child) (defun phpinspect-meta-add-child (meta child)
@ -138,7 +166,6 @@
(phpinspect-splayt-find-smallest-after (phpinspect-meta-children (phpinspect-meta-parent meta)) (phpinspect-splayt-find-smallest-after (phpinspect-meta-children (phpinspect-meta-parent meta))
(phpinspect-meta-parent-offset meta)))) (phpinspect-meta-parent-offset meta))))
(cl-defmethod phpinspect-meta-find-overlapping-child ((meta (head meta)) (point integer)) (cl-defmethod phpinspect-meta-find-overlapping-child ((meta (head meta)) (point integer))
(let ((child (phpinspect-splayt-find-largest-before (let ((child (phpinspect-splayt-find-largest-before
(phpinspect-meta-children meta) (phpinspect-meta--point-offset meta point)))) (phpinspect-meta-children meta) (phpinspect-meta--point-offset meta point))))
@ -209,6 +236,5 @@
(phpinspect-meta-start meta) (phpinspect-meta-end meta) (phpinspect-meta-token meta)) (phpinspect-meta-start meta) (phpinspect-meta-end meta) (phpinspect-meta-token meta))
"[nil]")) "[nil]"))
(provide 'phpinspect-meta) (provide 'phpinspect-meta)
;;; phpinspect-meta.el ends here ;;; phpinspect-meta.el ends here

@ -36,6 +36,7 @@ parsing. Usually used in combination with
(cl-defstruct (phpinspect-pctx (:constructor phpinspect-make-pctx)) (cl-defstruct (phpinspect-pctx (:constructor phpinspect-make-pctx))
"Parser Context" "Parser Context"
(incremental nil) (incremental nil)
(meta-iterator nil)
(interrupt-threshold (time-convert '(2 . 1000)) (interrupt-threshold (time-convert '(2 . 1000))
:documentation :documentation
"After how much time `interrupt-predicate' "After how much time `interrupt-predicate'

@ -28,17 +28,21 @@
(require 'phpinspect-bmap) (require 'phpinspect-bmap)
(require 'phpinspect-meta) (require 'phpinspect-meta)
(require 'phpinspect-parse-context) (require 'phpinspect-parse-context)
(require 'phpinspect-token-predicates)
(eval-when-compile (eval-when-compile
(define-inline phpinspect--word-end-regex () (define-inline phpinspect--word-end-regex ()
(inline-quote "\\([[:blank:]]\\|[^0-9a-zA-Z_]\\)"))) (inline-quote "\\([[:blank:]]\\|[^0-9a-zA-Z_]\\)")))
(defsubst phpinspect--strip-word-end-space (string) (define-inline phpinspect--strip-word-end-space (string)
(when phpinspect-parse-context (inline-letevals (string)
(phpinspect-pctx-register-whitespace (inline-quote
phpinspect-parse-context (progn
(substring string (- (length string) 1) (length string)))) (when phpinspect-parse-context
(substring string 0 (- (length string) 1))) (phpinspect-pctx-register-whitespace
phpinspect-parse-context
(substring ,string (- (length ,string) 1) (length ,string))))
(substring ,string 0 (- (length ,string) 1))))))
(defsubst phpinspect-munch-token-without-attribs (string token-keyword) (defsubst phpinspect-munch-token-without-attribs (string token-keyword)
"Return a token of type TOKEN-KEYWORD with STRING as value. "Return a token of type TOKEN-KEYWORD with STRING as value.
@ -49,218 +53,6 @@ If STRING has text properties, they are stripped."
(set-text-properties 0 length nil value) (set-text-properties 0 length nil value)
(list token-keyword value))) (list token-keyword value)))
(defsubst phpinspect-token-type-p (object type)
"Returns t if OBJECT is a token of type TYPE.
Type can be any of the token types returned by
`phpinspect-parse-buffer-until-point`"
(and (listp object) (eq (car object) type)))
(defsubst phpinspect-object-attrib-p (token)
(phpinspect-token-type-p token :object-attrib))
(defsubst phpinspect-static-attrib-p (token)
(phpinspect-token-type-p token :static-attrib))
(defsubst phpinspect-attrib-p (token)
(or (phpinspect-object-attrib-p token)
(phpinspect-static-attrib-p token)))
(defun phpinspect-html-p (token)
(phpinspect-token-type-p token :html))
(defun phpinspect-comma-p (token)
(phpinspect-token-type-p token :comma))
(defsubst phpinspect-terminator-p (token)
(phpinspect-token-type-p token :terminator))
(defsubst phpinspect-end-of-token-p (token)
(or (phpinspect-terminator-p token)
(phpinspect-comma-p token)
(phpinspect-html-p token)))
(defsubst phpinspect-end-of-statement-p (token)
(or (phpinspect-end-of-token-p token)
(phpinspect-block-p token)))
(defsubst phpinspect-incomplete-block-p (token)
(phpinspect-token-type-p token :incomplete-block))
(defsubst phpinspect-block-p (token)
(or (phpinspect-token-type-p token :block)
(phpinspect-incomplete-block-p token)))
(defun phpinspect-end-of-use-p (token)
(or (phpinspect-block-p token)
(phpinspect-end-of-token-p token)))
(defun phpinspect-static-p (token)
(phpinspect-token-type-p token :static))
(defsubst phpinspect-incomplete-const-p (token)
(phpinspect-token-type-p token :incomplete-const))
(defsubst phpinspect-const-p (token)
(or (phpinspect-token-type-p token :const)
(phpinspect-incomplete-const-p token)))
(defsubst phpinspect-scope-p (token)
(or (phpinspect-token-type-p token :public)
(phpinspect-token-type-p token :private)
(phpinspect-token-type-p token :protected)))
(defsubst phpinspect-namespace-p (object)
(phpinspect-token-type-p object :namespace))
(defun phpinspect-incomplete-class-p (token)
(and (phpinspect-class-p token)
(phpinspect-incomplete-block-p (car (last token)))))
(defun phpinspect-incomplete-namespace-p (token)
(and (phpinspect-namespace-p token)
(or (phpinspect-incomplete-block-p (car (last token)))
(phpinspect-incomplete-class-p (car (last token))))))
(defun phpinspect-function-p (token)
(phpinspect-token-type-p token :function))
(defun phpinspect-class-p (token)
(phpinspect-token-type-p token :class))
(defun phpinspect-incomplete-method-p (token)
(or (phpinspect-incomplete-function-p token)
(and (phpinspect-scope-p token)
(phpinspect-incomplete-function-p (car (last token))))
(and (phpinspect-scope-p token)
(phpinspect-static-p (car (last token)))
(phpinspect-incomplete-function-p (car (last (car (last token))))))
(and (phpinspect-scope-p token)
(phpinspect-function-p (car (last token))))))
(defun phpinspect-incomplete-function-p (token)
(and (phpinspect-function-p token)
(phpinspect-incomplete-block-p (car (last token)))))
(defsubst phpinspect-incomplete-list-p (token)
(phpinspect-token-type-p token :incomplete-list))
(defsubst phpinspect-list-p (token)
(or (phpinspect-token-type-p token :list)
(phpinspect-incomplete-list-p token)))
(defun phpinspect-declaration-p (token)
(phpinspect-token-type-p token :declaration))
(defsubst phpinspect-assignment-p (token)
(phpinspect-token-type-p token :assignment))
(defun phpinspect-function-argument-list (php-func)
"Get the argument list of a function"
(seq-find #'phpinspect-list-p (seq-find #'phpinspect-declaration-p php-func nil) nil))
(defun phpinspect-annotation-p (token)
(phpinspect-token-type-p token :annotation))
(defun phpinspect-method-annotation-p (token)
(phpinspect-token-type-p token :method-annotation))
(defun phpinspect-var-annotation-p (token)
(phpinspect-token-type-p token :var-annotation))
(defun phpinspect-return-annotation-p (token)
(phpinspect-token-type-p token :return-annotation))
(defsubst phpinspect-variable-p (token)
(phpinspect-token-type-p token :variable))
(defsubst phpinspect-word-p (token)
(phpinspect-token-type-p token :word))
(defsubst phpinspect-incomplete-array-p (token)
(phpinspect-token-type-p token :incomplete-array))
(defsubst phpinspect-array-p (token)
(or (phpinspect-token-type-p token :array)
(phpinspect-incomplete-array-p token)))
(defsubst phpinspect-incomplete-root-p (token)
(and (phpinspect-root-p token)
(seq-find #'phpinspect-incomplete-token-p (cdr token))))
(defsubst phpinspect-incomplete-token-p (token)
(or (phpinspect-incomplete-root-p token)
(phpinspect-incomplete-class-p token)
(phpinspect-incomplete-block-p token)
(phpinspect-incomplete-list-p token)
(phpinspect-incomplete-array-p token)
(phpinspect-incomplete-const-p token)
(phpinspect-incomplete-function-p token)
(phpinspect-incomplete-method-p token)
(phpinspect-incomplete-namespace-p token)))
(defun phpinspect--static-terminator-p (token)
(or (phpinspect-function-p token)
(phpinspect-end-of-token-p token)))
(defun phpinspect--scope-terminator-p (token)
(or (phpinspect-function-p token)
(phpinspect-end-of-token-p token)
(phpinspect-const-p token)
(phpinspect-static-p token)))
(defsubst phpinspect-enclosing-token-p (token)
"Returns t when a token can enclose other tokens"
(or
(phpinspect-list-p token)
(phpinspect-block-p token)
(phpinspect-class-p token)
(phpinspect-function-p token)
(phpinspect-array-p token)
(phpinspect-scope-p token)
(phpinspect-static-p token)
(phpinspect-const-p token)))
(defun phpinspect-namespace-keyword-p (token)
(and (phpinspect-word-p token) (string= (car (last token)) "namespace")))
(defun phpinspect-use-keyword-p (token)
(and (phpinspect-word-p token) (string= (car (last token)) "use")))
(defsubst phpinspect-root-p (object)
(phpinspect-token-type-p object :root))
(defsubst phpinspect-namespace-or-root-p (object)
(or (phpinspect-namespace-p object)
(phpinspect-root-p object)))
(defun phpinspect-use-p (object)
(phpinspect-token-type-p object :use))
(defun phpinspect-comment-p (token)
(or (phpinspect-token-type-p token :comment)
(phpinspect-token-type-p token :doc-block)))
(defsubst phpinspect-class-block (class)
(caddr class))
(define-inline phpinspect-namespace-is-blocked-p (namespace)
(inline-letevals (namespace)
(inline-quote
(and (= (length ,namespace) 3) (phpinspect-block-p (caddr ,namespace))))))
(defsubst phpinspect-namespace-block (namespace)
(when (phpinspect-namespace-is-blocked-p namespace)
(caddr namespace)))
(defsubst phpinspect-function-block (php-func)
(caddr php-func))
(defsubst phpinspect-not-class-p (token)
"Apply inverse of `phpinspect-class-p' to TOKEN."
(not (phpinspect-class-p token)))
(defun phpinspect-handler-func-name (handler-name) (defun phpinspect-handler-func-name (handler-name)
(intern (concat "phpinspect--" (symbol-name handler-name) "-handler"))) (intern (concat "phpinspect--" (symbol-name handler-name) "-handler")))
@ -715,6 +507,15 @@ parsing incrementally."
(phpinspect-munch-token-without-attribs (match-string 0) :variable) (phpinspect-munch-token-without-attribs (match-string 0) :variable)
(list :variable nil))) (list :variable nil)))
(phpinspect-defhandler class-variable (start-token &rest _ignored)
"Handler for tokens indicating reference to a variable"
((regexp . "\\$"))
(forward-char (length start-token))
(if (looking-at (phpinspect-handler-regexp word))
(phpinspect-munch-token-without-attribs (match-string 0) :class-variable)
(list :class-variable nil)))
(phpinspect-defhandler whitespace (whitespace &rest _ignored) (phpinspect-defhandler whitespace (whitespace &rest _ignored)
"Handler that discards whitespace" "Handler that discards whitespace"
((regexp . "[[:blank:]\n]+")) ((regexp . "[[:blank:]\n]+"))
@ -827,7 +628,7 @@ static keywords with the same meaning as in a class block."
(phpinspect-defparser class-block (phpinspect-defparser class-block
:tree-keyword "block" :tree-keyword "block"
:handlers '(array tag equals list comma attribute-reference variable :handlers '(array tag equals list comma attribute-reference class-variable
assignment-operator whitespace scope-keyword static-keyword assignment-operator whitespace scope-keyword static-keyword
const-keyword use-keyword function-keyword word terminator const-keyword use-keyword function-keyword word terminator
here-doc string comment block)) here-doc string comment block))
@ -961,19 +762,19 @@ nature like argument lists"
(phpinspect-defparser scope-public (phpinspect-defparser scope-public
:tree-keyword "public" :tree-keyword "public"
:handlers '(function-keyword static-keyword const-keyword variable here-doc :handlers '(function-keyword static-keyword const-keyword class-variable here-doc
string terminator tag comment) string terminator tag comment)
:delimiter-predicate #'phpinspect--scope-terminator-p) :delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defparser scope-private (phpinspect-defparser scope-private
:tree-keyword "private" :tree-keyword "private"
:handlers '(function-keyword static-keyword const-keyword variable here-doc :handlers '(function-keyword static-keyword const-keyword class-variable here-doc
string terminator tag comment) string terminator tag comment)
:delimiter-predicate #'phpinspect--scope-terminator-p) :delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defparser scope-protected (phpinspect-defparser scope-protected
:tree-keyword "protected" :tree-keyword "protected"
:handlers '(function-keyword static-keyword const-keyword variable here-doc :handlers '(function-keyword static-keyword const-keyword class-variable here-doc
string terminator tag comment) string terminator tag comment)
:delimiter-predicate #'phpinspect--scope-terminator-p) :delimiter-predicate #'phpinspect--scope-terminator-p)
@ -991,7 +792,7 @@ nature like argument lists"
(phpinspect-defparser static (phpinspect-defparser static
:tree-keyword "static" :tree-keyword "static"
:handlers '(comment function-keyword variable array word terminator tag) :handlers '(comment function-keyword class-variable array word terminator tag)
:delimiter-predicate #'phpinspect--static-terminator-p) :delimiter-predicate #'phpinspect--static-terminator-p)
(phpinspect-defhandler static-keyword (start-token max-point) (phpinspect-defhandler static-keyword (start-token max-point)

@ -56,6 +56,7 @@ indexed classes in the project")
:documentation :documentation
"A hash able that contains all of the currently indexed functions "A hash able that contains all of the currently indexed functions
in the project") in the project")
(function-token-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
(fs nil (fs nil
:type phpinspect-fs :type phpinspect-fs
:documentation :documentation
@ -66,7 +67,10 @@ can be accessed.")
:documentation :documentation
"The autoload object through which this project's type "The autoload object through which this project's type
definitions can be retrieved") definitions can be retrieved")
(worker (phpinspect-make-dynamic-worker) (worker (progn
(unless (featurep 'phpinspect-worker)
(require 'phpinspect-worker))
(phpinspect-make-dynamic-worker))
:type phpinspect-worker :type phpinspect-worker
:documentation :documentation
"The worker that this project may queue tasks for") "The worker that this project may queue tasks for")
@ -158,6 +162,10 @@ indexed by the absolute paths of the files they're watching."))
((project phpinspect-project) (name symbol)) ((project phpinspect-project) (name symbol))
(gethash name (phpinspect-project-function-index project))) (gethash name (phpinspect-project-function-index project)))
(cl-defmethod phpinspect-project-delete-function
((project phpinspect-project) (name symbol))
(remhash name (phpinspect-project-function-index project)))
(cl-defmethod phpinspect-project-get-functions ((project phpinspect-project)) (cl-defmethod phpinspect-project-get-functions ((project phpinspect-project))
(let ((funcs)) (let ((funcs))
(maphash (maphash
@ -173,6 +181,12 @@ indexed by the absolute paths of the files they're watching."))
(phpinspect--log "Adding import to index queue: %s" import) (phpinspect--log "Adding import to index queue: %s" import)
(phpinspect-project-enqueue-if-not-present project (cdr import))))) (phpinspect-project-enqueue-if-not-present project (cdr import)))))
(cl-defmethod phpinspect-project-delete-class ((project phpinspect-project) (class phpinspect--class))
(phpinspect-project-delete-class project (phpinspect--class-name class)))
(cl-defmethod phpinspect-project-delete-class ((project phpinspect-project) (class-name phpinspect--type))
(remhash (phpinspect--type-name-symbol class-name) (phpinspect-project-class-index project)))
(cl-defmethod phpinspect-project-add-class (cl-defmethod phpinspect-project-add-class
((project phpinspect-project) (indexed-class (head phpinspect--indexed-class)) &optional index-imports) ((project phpinspect-project) (indexed-class (head phpinspect--indexed-class)) &optional index-imports)
(let* ((class-name (phpinspect--type-name-symbol (let* ((class-name (phpinspect--type-name-symbol
@ -203,11 +217,12 @@ indexed by the absolute paths of the files they're watching."))
class)) class))
(cl-defmethod phpinspect-project-get-class-create (cl-defmethod phpinspect-project-get-class-create
((project phpinspect-project) (class-fqn phpinspect--type)) ((project phpinspect-project) (class-fqn phpinspect--type) &optional no-enqueue)
(let ((class (phpinspect-project-get-class project class-fqn))) (let ((class (phpinspect-project-get-class project class-fqn)))
(unless class (unless class
(setq class (phpinspect-project-create-class project class-fqn)) (setq class (phpinspect-project-create-class project class-fqn))
(phpinspect-project-enqueue-if-not-present project class-fqn)) (unless no-enqueue
(phpinspect-project-enqueue-if-not-present project class-fqn)))
class)) class))
(defalias 'phpinspect-project-add-class-if-missing #'phpinspect-project-get-class-create) (defalias 'phpinspect-project-add-class-if-missing #'phpinspect-project-get-class-create)

@ -37,6 +37,7 @@
(cl-defmethod phpinspect--serialize-function ((func phpinspect--function)) (cl-defmethod phpinspect--serialize-function ((func phpinspect--function))
`(phpinspect--make-function `(phpinspect--make-function
:name ,(phpinspect--function-name func) :name ,(phpinspect--function-name func)
:token (quote ,(phpinspect--function-token func))
:scope (quote ,(phpinspect--function-scope func)) :scope (quote ,(phpinspect--function-scope func))
:arguments ,(append '(list) :arguments ,(append '(list)
(mapcar (lambda (arg) (mapcar (lambda (arg)
@ -53,10 +54,11 @@
(phpinspect--variable-type var))) (phpinspect--variable-type var)))
:scope (quote ,(phpinspect--variable-scope var)))) :scope (quote ,(phpinspect--variable-scope var))))
(cl-defmethod phpinspect--serialize-indexed-class ((class (head phpinspect--indexed-class))) (cl-defmethod phpinspect--serialize-indexed-class ((class (head phpinspect--indexed-class)))
``(phpinspect--indexed-class ``(phpinspect--indexed-class
(complete . ,,(alist-get 'complete class))
(class-name . ,,(phpinspect--serialize-type (alist-get 'class-name class))) (class-name . ,,(phpinspect--serialize-type (alist-get 'class-name class)))
(declaration . ,(quote ,(alist-get 'declaration class)))
(imports . ,,(append '(list) (imports . ,,(append '(list)
(mapcar #'phpinspect--serialize-import (mapcar #'phpinspect--serialize-import
(alist-get 'imports class)))) (alist-get 'imports class))))

@ -88,10 +88,10 @@ apeared to be a little more performant than using `let'."
(define-inline phpinspect-make-splayt (&optional root-node) (define-inline phpinspect-make-splayt (&optional root-node)
(inline-quote (inline-quote
(cons ,root-node nil))) (cons 'phpinspect-splayt ,root-node)))
(define-inline phpinspect-splayt-root-node (splayt) (define-inline phpinspect-splayt-root-node (splayt)
(inline-quote (car ,splayt))) (inline-quote (cdr ,splayt)))
(define-inline phpinspect-splayt-empty-p (splayt) (define-inline phpinspect-splayt-empty-p (splayt)
(inline-quote (not (phpinspect-splayt-root-node ,splayt)))) (inline-quote (not (phpinspect-splayt-root-node ,splayt))))
@ -166,10 +166,6 @@ apeared to be a little more performant than using `let'."
(when (and ,splayt (eq ,node (phpinspect-splayt-root-node ,splayt))) (when (and ,splayt (eq ,node (phpinspect-splayt-root-node ,splayt)))
(setf (phpinspect-splayt-root-node ,splayt) (phpinspect-splayt-node-parent ,node))))))) (setf (phpinspect-splayt-root-node ,splayt) (phpinspect-splayt-node-parent ,node)))))))
(define-inline phpinspect-splayt-insert (splayt key value)
(inline-quote
(phpinspect-splayt-insert-node ,splayt (phpinspect-make-splayt-node ,key ,value))))
(define-inline phpinspect-splayt-node-grandparent (node) (define-inline phpinspect-splayt-node-grandparent (node)
(inline-quote (phpinspect-splayt-node-parent (phpinspect-splayt-node-parent ,node)))) (inline-quote (phpinspect-splayt-node-parent (phpinspect-splayt-node-parent ,node))))
@ -261,7 +257,7 @@ apeared to be a little more performant than using `let'."
(if ,reverse-sym (if ,reverse-sym
(push ,current-sym ,stack-sym) (push ,current-sym ,stack-sym)
(setf ,place (phpinspect-splayt-node-value ,current-sym)) (setf ,place ,current-sym)
,@body) ,@body)
(when (phpinspect-splayt-node-right ,current-sym) (when (phpinspect-splayt-node-right ,current-sym)
@ -275,7 +271,7 @@ apeared to be a little more performant than using `let'."
(when ,reverse-sym (when ,reverse-sym
(while ,stack-sym (while ,stack-sym
(setq ,current-sym (pop ,stack-sym)) (setq ,current-sym (pop ,stack-sym))
(setf ,place (phpinspect-splayt-node-value ,current-sym)) (setf ,place ,current-sym)
,@body)) ,@body))
(setq ,reverse-sym (not ,reverse-sym))) (setq ,reverse-sym (not ,reverse-sym)))
@ -291,9 +287,15 @@ Traversal is breadth-first to take advantage of the splay trees
main benefit: the most accessed interval of keys is likely to be main benefit: the most accessed interval of keys is likely to be
near the top of the tee." near the top of the tee."
(declare (indent 1)) (declare (indent 1))
`(phpinspect-splayt-node-traverse (let* ((current (gensym))
(,(car place-and-splayt) (phpinspect-splayt-root-node ,(cadr place-and-splayt))) (code `(phpinspect-splayt-node-traverse
,@body)) (,current (phpinspect-splayt-root-node ,(cadr place-and-splayt)))
(setf ,(car place-and-splayt) (phpinspect-splayt-node-value ,current))
,@body)))
(if (symbolp (car place-and-splayt))
`(let (,(car place-and-splayt))
,code)
code)))
(defmacro phpinspect-splayt-node-traverse-lr (place-and-node &rest body) (defmacro phpinspect-splayt-node-traverse-lr (place-and-node &rest body)
(declare (indent 1)) (declare (indent 1))
@ -309,7 +311,7 @@ near the top of the tee."
(push ,current ,stack) (push ,current ,stack)
(setq ,current (phpinspect-splayt-node-left ,current))) (setq ,current (phpinspect-splayt-node-left ,current)))
(setq ,current (pop ,stack)) (setq ,current (pop ,stack))
(setf ,place (phpinspect-splayt-node-value ,current)) (setf ,place ,current)
,@body ,@body
(setq ,current (phpinspect-splayt-node-right ,current))))))) (setq ,current (phpinspect-splayt-node-right ,current)))))))
@ -319,9 +321,16 @@ near the top of the tee."
The car of PLACE-AND-SPLAYT is assigned the value of each node. The car of PLACE-AND-SPLAYT is assigned the value of each node.
The cadr of PLACE-AND-SPLAYT is expected to be a splay tree." The cadr of PLACE-AND-SPLAYT is expected to be a splay tree."
(declare (indent 1)) (declare (indent 1))
`(phpinspect-splayt-node-traverse-lr (let* ((current (gensym))
(,(car place-and-splayt) (phpinspect-splayt-root-node ,(cadr place-and-splayt))) (code `(phpinspect-splayt-node-traverse-lr
,@body)) (,current (phpinspect-splayt-root-node ,(cadr place-and-splayt)))
(setf ,(car place-and-splayt) (phpinspect-splayt-node-value ,current))
,@body)))
(if (symbolp (car place-and-splayt))
`(let (,(car place-and-splayt))
,code)
code)))
(define-inline phpinspect-splayt-node-key-less-p (node key) (define-inline phpinspect-splayt-node-key-less-p (node key)
(inline-quote (> ,key (phpinspect-splayt-node-key ,node)))) (inline-quote (> ,key (phpinspect-splayt-node-key ,node))))
@ -412,54 +421,89 @@ The cadr of PLACE-AND-SPLAYT is expected to be a splay tree."
largest)))) largest))))
(defsubst phpinspect-splayt-find-all-after (splayt key) (defun phpinspect-splayt-find-all-after (splayt key)
"Find all values in SPLAYT with a key higher than KEY." "Find all values in SPLAYT with a key higher than KEY."
(let ((first (phpinspect-splayt-find-smallest-node-after splayt key)) (let* ((first (phpinspect-splayt-find-smallest-node-after splayt key))
all) (all (cons nil nil))
(all-rear all))
(while first (while first
(push (phpinspect-splayt-node-value first) all) (setq all-rear (setcdr all-rear (cons (phpinspect-splayt-node-value first) nil)))
(phpinspect-splayt-node-traverse (sibling (phpinspect-splayt-node-right first)) (phpinspect-splayt-node-traverse (sibling (phpinspect-splayt-node-right first))
(setq all (nconc all (list sibling)))) (setq all-rear (setcdr all-rear (cons (phpinspect-splayt-node-value sibling) nil))))
(if (and (phpinspect-splayt-node-parent first) (if (and (phpinspect-splayt-node-parent first)
(eq first (phpinspect-splayt-node-left (phpinspect-splayt-node-parent first)))) (eq first (phpinspect-splayt-node-left (phpinspect-splayt-node-parent first))))
(setq first (phpinspect-splayt-node-parent first)) (setq first (phpinspect-splayt-node-parent first))
(setq first nil))) (setq first nil)))
all)) (cdr all)))
(defsubst phpinspect-splayt-find-all-before (splayt key) (defun phpinspect-splayt-find-all-between (splayt key-min key-max)
(let* ((first (phpinspect-splayt-find-smallest-node-after splayt key-min))
(all (cons nil nil))
(all-rear all))
(catch 'return
(while first
(setq all-rear (setcdr all-rear (cons (phpinspect-splayt-node-value first) nil)))
(phpinspect-splayt-node-traverse-lr (sibling (phpinspect-splayt-node-right first))
(when (>= (phpinspect-splayt-node-key sibling) key-max)
(throw 'return all))
(setq all-rear (setcdr all-rear (cons (phpinspect-splayt-node-value sibling) nil))))
(if (and (phpinspect-splayt-node-parent first)
(eq first (phpinspect-splayt-node-left (phpinspect-splayt-node-parent first))))
(setq first (phpinspect-splayt-node-parent first))
(setq first nil)))
(cdr all))))
(defun phpinspect-splayt-find-all-before (splayt key)
"Find all values in SPLAYT with a key higher than KEY." "Find all values in SPLAYT with a key higher than KEY."
(let ((first (phpinspect-splayt-find-largest-node-before splayt key)) (let* ((first (phpinspect-splayt-find-largest-node-before splayt key))
all) (all (cons nil nil))
(all-rear all))
(while first (while first
(push (phpinspect-splayt-node-value first) all) (setq all-rear (setcdr all-rear (cons (phpinspect-splayt-node-value first) nil)))
(phpinspect-splayt-node-traverse (sibling (phpinspect-splayt-node-left first)) (phpinspect-splayt-node-traverse (sibling (phpinspect-splayt-node-left first))
(setq all (nconc all (list sibling)))) (setq all-rear (setcdr all-rear (cons (phpinspect-splayt-node-value sibling) nil))))
(if (and (phpinspect-splayt-node-parent first) (if (and (phpinspect-splayt-node-parent first)
(eq first (phpinspect-splayt-node-right (phpinspect-splayt-node-parent first)))) (eq first (phpinspect-splayt-node-right (phpinspect-splayt-node-parent first))))
(setq first (phpinspect-splayt-node-parent first)) (setq first (phpinspect-splayt-node-parent first))
(setq first nil))) (setq first nil)))
all)) (cdr all)))
(defun phpinspect-splayt-to-list (tree)
"Convert TREE to an ordered list."
(let* ((list (cons nil nil))
(rear list))
(phpinspect-splayt-traverse-lr (val tree)
(setq rear (setcdr rear (cons val nil))))
(cdr list)))
(cl-defmethod seq-do (func (tree (head phpinspect-splayt)))
(phpinspect-splayt-traverse-lr (val tree)
(funcall func val)))
(define-inline phpinspect-splayt-find-smallest-after (splayt key) (defun phpinspect-splayt-find-smallest-after (splayt key)
"Find value of node with smallest key that is higher than KEY in SPLAYT." "Find value of node with smallest key that is higher than KEY in SPLAYT."
(inline-quote (phpinspect-splayt-node-value
(phpinspect-splayt-node-value (phpinspect-splay
(phpinspect-splay splayt (phpinspect-splayt-find-smallest-node-after splayt key))))
,splayt (phpinspect-splayt-find-smallest-node-after ,splayt ,key)))))
(define-inline phpinspect-splayt-find-largest-before (splayt key) (defun phpinspect-splayt-find-largest-before (splayt key)
"Find value of node with smallest key that is higher than KEY in SPLAYT." "Find value of node with smallest key that is higher than KEY in SPLAYT."
(inline-quote
(phpinspect-splayt-node-value (phpinspect-splayt-node-value
(phpinspect-splay (phpinspect-splay
,splayt (phpinspect-splayt-find-largest-node-before ,splayt ,key))))) splayt (phpinspect-splayt-find-largest-node-before splayt key))))
(defsubst phpinspect-splayt-find (splayt key) (defun phpinspect-splayt-find (splayt key)
(phpinspect-splayt-node-value (phpinspect-splayt-find-node splayt key))) (phpinspect-splayt-node-value (phpinspect-splayt-find-node splayt key)))
(defun phpinspect-splayt-insert (tree key value)
"Insert KEY as VALUE into TREE."
(phpinspect-splayt-insert-node tree (phpinspect-make-splayt-node key value)))
(provide 'phpinspect-splayt) (provide 'phpinspect-splayt)

@ -0,0 +1,82 @@
;;; phpinspect-toc.el --- PHP parsing and completion package -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Free Software Foundation, Inc
;; Author: Hugo Thunnissen <devel@hugot.nl>
;; Keywords: php, languages, tools, convenience
;; Version: 0
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'phpinspect-splayt)
(require 'phpinspect-parser)
(defun phpinspect-make-toc (&optional tree)
(let ((table (make-hash-table :test #'eq :size 20 :rehash-size 2.0)))
(if tree
(phpinspect-splayt-traverse-lr (meta tree)
(puthash (phpinspect-meta-token meta) meta table))
(setq tree (phpinspect-make-splayt)))
(list tree table)))
(define-inline phpinspect-toc-register (toc meta)
(inline-letevals (toc meta)
(inline-quote
(progn
(phpinspect-splayt-insert (phpinspect-toc-tree ,toc) (phpinspect-meta-start ,meta) ,meta)
(puthash (phpinspect-meta-token ,meta) ,meta (phpinspect-toc-table ,toc))))))
(define-inline phpinspect-toc-tree (toc)
(inline-quote (car ,toc)))
(define-inline phpinspect-toc-table (toc)
(inline-quote (cadr ,toc)))
(defun phpinspect-toc-update (toc new-tree current-root)
(let ((current-tree (phpinspect-toc-tree toc))
(new-table (make-hash-table :test #'eq :size 20 :rehash-size 2.0))
new deleted)
(phpinspect-splayt-traverse-lr (meta new-tree)
(puthash (phpinspect-meta-token meta) meta new-table)
(push meta new))
(phpinspect-splayt-traverse-lr (meta current-tree)
(if (eq (phpinspect-meta-find-root meta) current-root)
(progn
(phpinspect-splayt-insert new-tree (phpinspect-meta-start meta) meta)
(puthash (phpinspect-meta-token meta) meta new-table))
(push meta deleted)))
(setf (phpinspect-toc-tree toc) new-tree)
(setf (phpinspect-toc-table toc) new-table)
(list new deleted)))
(defun phpinspect-toc-token-at-point (toc point)
(let ((result (phpinspect-splayt-find-largest-before (phpinspect-toc-tree toc) (+ point 1))))
(and result (phpinspect-meta-overlaps-point result point) result)))
(defun phpinspect-toc-token-at-or-after-point (toc point)
(phpinspect-splayt-find-smallest-after (phpinspect-toc-tree toc) (- point 1)))
(defun phpinspect-toc-tokens-in-region (toc start end)
(phpinspect-splayt-find-all-between (phpinspect-toc-tree toc) start end))
(provide 'phpinspect-toc)

@ -0,0 +1,250 @@
;;; phpinspect-token-predicates.el --- Predicates for phpinspect-parser tokens types -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Free Software Foundation, Inc
;; Author: Hugo Thunnissen <devel@hugot.nl>
;; Keywords: php, languages, tools, convenience
;; Version: 0
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(define-inline phpinspect-token-type-p (object type)
"Returns t if OBJECT is a token of type TYPE.
Type can be any of the token types returned by
`phpinspect-parse-buffer-until-point`"
(inline-letevals (object)
(inline-quote
(and (listp ,object) (eq (car ,object) ,type)))))
(defsubst phpinspect-object-attrib-p (token)
(phpinspect-token-type-p token :object-attrib))
(defsubst phpinspect-static-attrib-p (token)
(phpinspect-token-type-p token :static-attrib))
(defsubst phpinspect-attrib-p (token)
(or (phpinspect-object-attrib-p token)
(phpinspect-static-attrib-p token)))
(defun phpinspect-html-p (token)
(phpinspect-token-type-p token :html))
(defun phpinspect-comma-p (token)
(phpinspect-token-type-p token :comma))
(defsubst phpinspect-terminator-p (token)
(phpinspect-token-type-p token :terminator))
(defsubst phpinspect-end-of-token-p (token)
(or (phpinspect-terminator-p token)
(phpinspect-comma-p token)
(phpinspect-html-p token)))
(defsubst phpinspect-end-of-statement-p (token)
(or (phpinspect-end-of-token-p token)
(phpinspect-block-p token)))
(defsubst phpinspect-incomplete-block-p (token)
(phpinspect-token-type-p token :incomplete-block))
(defsubst phpinspect-block-p (token)
(or (phpinspect-token-type-p token :block)
(phpinspect-incomplete-block-p token)))
(defun phpinspect-end-of-use-p (token)
(or (phpinspect-block-p token)
(phpinspect-end-of-token-p token)))
(defun phpinspect-static-p (token)
(phpinspect-token-type-p token :static))
(defsubst phpinspect-incomplete-const-p (token)
(phpinspect-token-type-p token :incomplete-const))
(defsubst phpinspect-const-p (token)
(or (phpinspect-token-type-p token :const)
(phpinspect-incomplete-const-p token)))
(define-inline phpinspect-scope-p (token)
(inline-letevals (token)
(inline-quote
(or (phpinspect-token-type-p ,token :public)
(phpinspect-token-type-p ,token :private)
(phpinspect-token-type-p ,token :protected)))))
(define-inline phpinspect-namespace-p (object)
(inline-quote
(phpinspect-token-type-p ,object :namespace)))
(defun phpinspect-incomplete-class-p (token)
(and (phpinspect-class-p token)
(phpinspect-incomplete-block-p (car (last token)))))
(defun phpinspect-incomplete-namespace-p (token)
(and (phpinspect-namespace-p token)
(or (phpinspect-incomplete-block-p (car (last token)))
(phpinspect-incomplete-class-p (car (last token))))))
(define-inline phpinspect-function-p (token)
(inline-quote (phpinspect-token-type-p ,token :function)))
(define-inline phpinspect-class-p (token)
(inline-quote (phpinspect-token-type-p ,token :class)))
(defun phpinspect-incomplete-method-p (token)
(or (phpinspect-incomplete-function-p token)
(and (phpinspect-scope-p token)
(phpinspect-incomplete-function-p (car (last token))))
(and (phpinspect-scope-p token)
(phpinspect-static-p (car (last token)))
(phpinspect-incomplete-function-p (car (last (car (last token))))))
(and (phpinspect-scope-p token)
(phpinspect-function-p (car (last token))))))
(defun phpinspect-incomplete-function-p (token)
(and (phpinspect-function-p token)
(phpinspect-incomplete-block-p (car (last token)))))
(defsubst phpinspect-incomplete-list-p (token)
(phpinspect-token-type-p token :incomplete-list))
(defsubst phpinspect-list-p (token)
(or (phpinspect-token-type-p token :list)
(phpinspect-incomplete-list-p token)))
(define-inline phpinspect-declaration-p (token)
(inline-quote
(phpinspect-token-type-p ,token :declaration)))
(defsubst phpinspect-assignment-p (token)
(phpinspect-token-type-p token :assignment))
(defun phpinspect-function-argument-list (php-func)
"Get the argument list of a function"
(seq-find #'phpinspect-list-p (seq-find #'phpinspect-declaration-p php-func nil) nil))
(defun phpinspect-annotation-p (token)
(phpinspect-token-type-p token :annotation))
(defun phpinspect-method-annotation-p (token)
(phpinspect-token-type-p token :method-annotation))
(defun phpinspect-var-annotation-p (token)
(phpinspect-token-type-p token :var-annotation))
(defun phpinspect-return-annotation-p (token)
(phpinspect-token-type-p token :return-annotation))
(define-inline phpinspect-class-variable-p (token)
(inline-quote (phpinspect-token-type-p ,token :class-variable)))
(define-inline phpinspect-variable-p (token)
(inline-letevals (token)
(inline-quote
(or (phpinspect-token-type-p ,token :variable)
(phpinspect-token-type-p ,token :class-variable)))))
(defsubst phpinspect-word-p (token)
(phpinspect-token-type-p token :word))
(defsubst phpinspect-incomplete-array-p (token)
(phpinspect-token-type-p token :incomplete-array))
(defsubst phpinspect-array-p (token)
(or (phpinspect-token-type-p token :array)
(phpinspect-incomplete-array-p token)))
(defsubst phpinspect-incomplete-root-p (token)
(and (phpinspect-root-p token)
(seq-find #'phpinspect-incomplete-token-p (cdr token))))
(defsubst phpinspect-incomplete-token-p (token)
(or (phpinspect-incomplete-root-p token)
(phpinspect-incomplete-class-p token)
(phpinspect-incomplete-block-p token)
(phpinspect-incomplete-list-p token)
(phpinspect-incomplete-array-p token)
(phpinspect-incomplete-const-p token)
(phpinspect-incomplete-function-p token)
(phpinspect-incomplete-method-p token)
(phpinspect-incomplete-namespace-p token)))
(defun phpinspect--static-terminator-p (token)
(or (phpinspect-function-p token)
(phpinspect-end-of-token-p token)))
(defun phpinspect--scope-terminator-p (token)
(or (phpinspect-function-p token)
(phpinspect-end-of-token-p token)
(phpinspect-const-p token)
(phpinspect-static-p token)))
(defsubst phpinspect-enclosing-token-p (token)
"Returns t when a token can enclose other tokens"
(or
(phpinspect-list-p token)
(phpinspect-block-p token)
(phpinspect-class-p token)
(phpinspect-function-p token)
(phpinspect-array-p token)
(phpinspect-scope-p token)
(phpinspect-static-p token)
(phpinspect-const-p token)))
(defun phpinspect-namespace-keyword-p (token)
(and (phpinspect-word-p token) (string= (car (last token)) "namespace")))
(defun phpinspect-use-keyword-p (token)
(and (phpinspect-word-p token) (string= (car (last token)) "use")))
(defsubst phpinspect-root-p (object)
(phpinspect-token-type-p object :root))
(defsubst phpinspect-namespace-or-root-p (object)
(or (phpinspect-namespace-p object)
(phpinspect-root-p object)))
(define-inline phpinspect-use-p (object)
(inline-quote (phpinspect-token-type-p ,object :use)))
(defun phpinspect-comment-p (token)
(or (phpinspect-token-type-p token :comment)
(phpinspect-token-type-p token :doc-block)))
(defsubst phpinspect-class-block (class)
(caddr class))
(define-inline phpinspect-namespace-is-blocked-p (namespace)
(inline-letevals (namespace)
(inline-quote
(and (= (length ,namespace) 3) (phpinspect-block-p (caddr ,namespace))))))
(defsubst phpinspect-namespace-block (namespace)
(when (phpinspect-namespace-is-blocked-p namespace)
(caddr namespace)))
(defsubst phpinspect-function-block (php-func)
(caddr php-func))
(defsubst phpinspect-not-class-p (token)
"Apply inverse of `phpinspect-class-p' to TOKEN."
(not (phpinspect-class-p token)))
(provide 'phpinspect-token-predicates)

@ -206,6 +206,15 @@ NAMESPACE may be nil, or a string with a namespace FQN."
:type symbol :type symbol
:documentation :documentation
"A symbol associated with the name of the function") "A symbol associated with the name of the function")
(token nil
:type phpinspect-function-p
:documentation
"The tokens with which this function was declared.")
(-inherited nil
:type boolean
:documentation
"Whether this function has been incorporated into a class as
method of an extended class.")
(scope nil (scope nil
:type phpinspect-scope :type phpinspect-scope
:documentation :documentation

@ -265,5 +265,16 @@ CONTINUE must be a condition-variable"
(with-mutex mx (condition-wait continue)) (with-mutex mx (condition-wait continue))
(phpinspect--log "Thread '%s' continuing execution" (thread-name (current-thread)))) (phpinspect--log "Thread '%s' continuing execution" (thread-name (current-thread))))
(defun phpinspect-namespace-name (namespace)
(or (and (phpinspect-namespace-p namespace)
(phpinspect-word-p (cadr namespace))
(cadadr namespace))
""))
(defsubst phpinspect-probably-token-p (token)
(and (listp token)
(keywordp (car token))))
(provide 'phpinspect-util) (provide 'phpinspect-util)
;;; phpinspect-util.el ends here ;;; phpinspect-util.el ends here

@ -152,7 +152,7 @@ already present in the queue."
(phpinspect-worker-skip-next-pause worker)) (phpinspect-worker-skip-next-pause worker))
(phpinspect-thread-pause phpinspect-worker-pause-time mx continue)) (phpinspect-thread-pause phpinspect-worker-pause-time mx continue))
(setf (phpinspect-worker-skip-next-pause worker) nil))) (setf (phpinspect-worker-skip-next-pause worker) nil)))
(t (message "Phpinspect worker thread errored :%s" err)))) (t (phpinspect--log "Phpinspect worker thread errored :%s" err))))
(phpinspect--log "Worker thread exiting") (phpinspect--log "Worker thread exiting")
(message "phpinspect worker thread exited"))) (message "phpinspect worker thread exited")))

@ -79,10 +79,6 @@
(phpinspect-pctx-bmap context)))) (phpinspect-pctx-bmap context))))
(defun phpinspect-after-change-function (start end pre-change-length)
(when phpinspect-current-buffer
(phpinspect-buffer-register-edit phpinspect-current-buffer start end pre-change-length)))
(defun phpinspect--init-mode () (defun phpinspect--init-mode ()
"Initialize the phpinspect minor mode for the current buffer." "Initialize the phpinspect minor mode for the current buffer."
(phpinspect-ensure-worker) (phpinspect-ensure-worker)
@ -295,20 +291,6 @@ Example configuration for `company-mode':
(phpinspect--completion-meta (phpinspect--completion-meta
(phpinspect--completion-list-get-metadata phpinspect--last-completion-list arg))))) (phpinspect--completion-list-get-metadata phpinspect--last-completion-list arg)))))
(defun phpinspect-purge-cache ()
"Assign a fresh, empty cache object to `phpinspect-cache'.
This effectively purges any cached code information from all
currently opened projects."
(interactive)
(when phpinspect-cache
;; Allow currently known cached projects to cleanup after themselves
(maphash (lambda (_ project)
(phpinspect-project-purge project))
(phpinspect--cache-projects phpinspect-cache)))
;; Assign a fresh cache object
(setq phpinspect-cache (phpinspect--make-cache)))
(defsubst phpinspect-insert-file-contents (&rest args) (defsubst phpinspect-insert-file-contents (&rest args)
"Call `phpinspect-insert-file-contents-function' with ARGS as arguments." "Call `phpinspect-insert-file-contents-function' with ARGS as arguments."
(apply phpinspect-insert-file-contents-function args)) (apply phpinspect-insert-file-contents-function args))

@ -1 +1 @@
(:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Controller") (:terminator ";") (:use (:word "Symfony\\Component\\HttpFoundation\\Response") (:terminator ";")) (:use (:word "App\\Entity\\Address") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\RedirectResponse") (:terminator ";")) (:use (:word "App\\Repository\\AddressRepository") (:terminator ";")) (:use (:word "App\\Repository\\UserRepository") (:terminator ";")) (:use (:word "Doctrine\\ORM\\EntityManagerInterface") (:terminator ";")) (:use (:word "Twig\\Environment") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\Request") (:terminator ";")) (:use (:word "Symfony\\Component\\Routing\\Annotation\\Route") (:terminator ";")) (:class (:declaration (:word "class") (:word "AddressController")) (:incomplete-block (:const (:word "A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE") (:assignment "=") (:string "a value") (:terminator ";")) (:public (:const (:word "ARRAY_CONSTANT") (:assignment "=") (:array (:string "key") (:fat-arrow "=>") (:string "value") (:comma ",") (:string "key") (:fat-arrow "=>")) (:terminator ";"))) (:private (:variable "repo") (:terminator ";")) (:private (:variable "user_repo") (:terminator ";")) (:private (:variable "twig") (:terminator ";")) (:private (:variable "em") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "AddressRepository") (:variable "repo") (:comma ",") (:word "UserRepository") (:variable "user_repo") (:comma ",") (:word "Environment") (:variable "twig") (:comma ",") (:word "EntityManagerInterface") (:variable "em"))) (:block (:variable "this") (:object-attrib (:word "repo")) (:assignment "=") (:variable "repo") (:terminator ";") (:variable "this") (:object-attrib (:word "user_repo")) (:assignment "=") (:variable "user_repo") (:terminator ";") (:variable "this") (:object-attrib (:word "twig")) (:assignment "=") (:variable "twig") (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:assignment "=") (:variable "em") (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressPage") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:word "return") (:word "new") (:word "Response") (:list (:variable "this") (:object-attrib (:word "twig")) (:object-attrib (:word "render")) (:list (:string "address/create.html.twig") (:comma ",") (:array (:string "user") (:fat-arrow "=>") (:variable "user") (:comma ",")))) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:variable "address_string") (:assignment "=") (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address")) (:terminator ";") (:variable "address") (:assignment "=") (:word "new") (:word "Address") (:list (:variable "user") (:comma ",") (:variable "address_string")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "persist")) (:list (:variable "address")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "flush")) (:list) (:terminator ";") (:word "return") (:word "new") (:word "RedirectResponse") (:list (:string "/user/") (:variable "user") (:object-attrib (:word "getLoginName")) (:list) (:string "/manage")) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "deleteAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:incomplete-block (:variable "address") (:assignment "=") (:variable "this") (:object-attrib (:word "repo")) (:object-attrib (:word "find")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address"))) (:terminator ";") (:comment) (:comment) (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "remove")) (:incomplete-list (:variable "this") (:object-attrib (:word "em")) (:object-attrib nil))))))))) (:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Controller") (:terminator ";") (:use (:word "Symfony\\Component\\HttpFoundation\\Response") (:terminator ";")) (:use (:word "App\\Entity\\Address") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\RedirectResponse") (:terminator ";")) (:use (:word "App\\Repository\\AddressRepository") (:terminator ";")) (:use (:word "App\\Repository\\UserRepository") (:terminator ";")) (:use (:word "Doctrine\\ORM\\EntityManagerInterface") (:terminator ";")) (:use (:word "Twig\\Environment") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\Request") (:terminator ";")) (:use (:word "Symfony\\Component\\Routing\\Annotation\\Route") (:terminator ";")) (:class (:declaration (:word "class") (:word "AddressController")) (:incomplete-block (:const (:word "A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE") (:assignment "=") (:string "a value") (:terminator ";")) (:public (:const (:word "ARRAY_CONSTANT") (:assignment "=") (:array (:string "key") (:fat-arrow "=>") (:string "value") (:comma ",") (:string "key") (:fat-arrow "=>")) (:terminator ";"))) (:private (:class-variable "repo") (:terminator ";")) (:private (:class-variable "user_repo") (:terminator ";")) (:private (:class-variable "twig") (:terminator ";")) (:private (:class-variable "em") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "AddressRepository") (:variable "repo") (:comma ",") (:word "UserRepository") (:variable "user_repo") (:comma ",") (:word "Environment") (:variable "twig") (:comma ",") (:word "EntityManagerInterface") (:variable "em"))) (:block (:variable "this") (:object-attrib (:word "repo")) (:assignment "=") (:variable "repo") (:terminator ";") (:variable "this") (:object-attrib (:word "user_repo")) (:assignment "=") (:variable "user_repo") (:terminator ";") (:variable "this") (:object-attrib (:word "twig")) (:assignment "=") (:variable "twig") (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:assignment "=") (:variable "em") (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressPage") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:word "return") (:word "new") (:word "Response") (:list (:variable "this") (:object-attrib (:word "twig")) (:object-attrib (:word "render")) (:list (:string "address/create.html.twig") (:comma ",") (:array (:string "user") (:fat-arrow "=>") (:variable "user") (:comma ",")))) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:variable "address_string") (:assignment "=") (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address")) (:terminator ";") (:variable "address") (:assignment "=") (:word "new") (:word "Address") (:list (:variable "user") (:comma ",") (:variable "address_string")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "persist")) (:list (:variable "address")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "flush")) (:list) (:terminator ";") (:word "return") (:word "new") (:word "RedirectResponse") (:list (:string "/user/") (:variable "user") (:object-attrib (:word "getLoginName")) (:list) (:string "/manage")) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "deleteAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:incomplete-block (:variable "address") (:assignment "=") (:variable "this") (:object-attrib (:word "repo")) (:object-attrib (:word "find")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address"))) (:terminator ";") (:comment) (:comment) (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "remove")) (:incomplete-list (:variable "this") (:object-attrib (:word "em")) (:object-attrib nil)))))))))

@ -1 +1 @@
(:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Controller") (:incomplete-block (:use (:word "Symfony\\Component\\HttpFoundation\\Response") (:terminator ";")) (:use (:word "App\\Entity\\Address") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\RedirectResponse") (:terminator ";")) (:use (:word "App\\Repository\\AddressRepository") (:terminator ";")) (:use (:word "App\\Repository\\UserRepository") (:terminator ";")) (:use (:word "Doctrine\\ORM\\EntityManagerInterface") (:terminator ";")) (:use (:word "Twig\\Environment") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\Request") (:terminator ";")) (:use (:word "Symfony\\Component\\Routing\\Annotation\\Route") (:terminator ";")) (:class (:declaration (:word "class") (:word "AddressController")) (:incomplete-block (:const (:word "A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE") (:assignment "=") (:string "a value") (:terminator ";")) (:public (:const (:word "ARRAY_CONSTANT") (:assignment "=") (:array (:string "key") (:fat-arrow "=>") (:string "value") (:comma ",") (:string "key") (:fat-arrow "=>")) (:terminator ";"))) (:private (:variable "repo") (:terminator ";")) (:private (:variable "user_repo") (:terminator ";")) (:private (:variable "twig") (:terminator ";")) (:private (:variable "em") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "AddressRepository") (:variable "repo") (:comma ",") (:word "UserRepository") (:variable "user_repo") (:comma ",") (:word "Environment") (:variable "twig") (:comma ",") (:word "EntityManagerInterface") (:variable "em"))) (:block (:variable "this") (:object-attrib (:word "repo")) (:assignment "=") (:variable "repo") (:terminator ";") (:variable "this") (:object-attrib (:word "user_repo")) (:assignment "=") (:variable "user_repo") (:terminator ";") (:variable "this") (:object-attrib (:word "twig")) (:assignment "=") (:variable "twig") (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:assignment "=") (:variable "em") (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressPage") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:word "return") (:word "new") (:word "Response") (:list (:variable "this") (:object-attrib (:word "twig")) (:object-attrib (:word "render")) (:list (:string "address/create.html.twig") (:comma ",") (:array (:string "user") (:fat-arrow "=>") (:variable "user") (:comma ",")))) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:variable "address_string") (:assignment "=") (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address")) (:terminator ";") (:variable "address") (:assignment "=") (:word "new") (:word "Address") (:list (:variable "user") (:comma ",") (:variable "address_string")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "persist")) (:list (:variable "address")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "flush")) (:list) (:terminator ";") (:word "return") (:word "new") (:word "RedirectResponse") (:list (:string "/user/") (:variable "user") (:object-attrib (:word "getLoginName")) (:list) (:string "/manage")) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "deleteAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:incomplete-block (:variable "address") (:assignment "=") (:variable "this") (:object-attrib (:word "repo")) (:object-attrib (:word "find")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address"))) (:terminator ";") (:comment) (:comment) (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "remove")) (:incomplete-list (:variable "this") (:object-attrib (:word "em")) (:object-attrib nil)))))))))) (:root (:word "declare") (:list (:word "strict_types") (:assignment "=")) (:terminator ";") (:namespace (:word "App\\Controller") (:incomplete-block (:use (:word "Symfony\\Component\\HttpFoundation\\Response") (:terminator ";")) (:use (:word "App\\Entity\\Address") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\RedirectResponse") (:terminator ";")) (:use (:word "App\\Repository\\AddressRepository") (:terminator ";")) (:use (:word "App\\Repository\\UserRepository") (:terminator ";")) (:use (:word "Doctrine\\ORM\\EntityManagerInterface") (:terminator ";")) (:use (:word "Twig\\Environment") (:terminator ";")) (:use (:word "Symfony\\Component\\HttpFoundation\\Request") (:terminator ";")) (:use (:word "Symfony\\Component\\Routing\\Annotation\\Route") (:terminator ";")) (:class (:declaration (:word "class") (:word "AddressController")) (:incomplete-block (:const (:word "A_CONSTANT_FOR_THE_SAKE_OF_HAVING_ONE") (:assignment "=") (:string "a value") (:terminator ";")) (:public (:const (:word "ARRAY_CONSTANT") (:assignment "=") (:array (:string "key") (:fat-arrow "=>") (:string "value") (:comma ",") (:string "key") (:fat-arrow "=>")) (:terminator ";"))) (:private (:class-variable "repo") (:terminator ";")) (:private (:class-variable "user_repo") (:terminator ";")) (:private (:class-variable "twig") (:terminator ";")) (:private (:class-variable "em") (:terminator ";")) (:public (:function (:declaration (:word "function") (:word "__construct") (:list (:word "AddressRepository") (:variable "repo") (:comma ",") (:word "UserRepository") (:variable "user_repo") (:comma ",") (:word "Environment") (:variable "twig") (:comma ",") (:word "EntityManagerInterface") (:variable "em"))) (:block (:variable "this") (:object-attrib (:word "repo")) (:assignment "=") (:variable "repo") (:terminator ";") (:variable "this") (:object-attrib (:word "user_repo")) (:assignment "=") (:variable "user_repo") (:terminator ";") (:variable "this") (:object-attrib (:word "twig")) (:assignment "=") (:variable "twig") (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:assignment "=") (:variable "em") (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressPage") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:word "return") (:word "new") (:word "Response") (:list (:variable "this") (:object-attrib (:word "twig")) (:object-attrib (:word "render")) (:list (:string "address/create.html.twig") (:comma ",") (:array (:string "user") (:fat-arrow "=>") (:variable "user") (:comma ",")))) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "addAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:block (:variable "user") (:assignment "=") (:variable "this") (:object-attrib (:word "user_repo")) (:object-attrib (:word "findOne")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "user"))) (:terminator ";") (:variable "address_string") (:assignment "=") (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address")) (:terminator ";") (:variable "address") (:assignment "=") (:word "new") (:word "Address") (:list (:variable "user") (:comma ",") (:variable "address_string")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "persist")) (:list (:variable "address")) (:terminator ";") (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "flush")) (:list) (:terminator ";") (:word "return") (:word "new") (:word "RedirectResponse") (:list (:string "/user/") (:variable "user") (:object-attrib (:word "getLoginName")) (:list) (:string "/manage")) (:terminator ";")))) (:doc-block (:annotation "Route")) (:public (:function (:declaration (:word "function") (:word "deleteAddressAction") (:list (:word "Request") (:variable "req")) (:word "Response")) (:incomplete-block (:variable "address") (:assignment "=") (:variable "this") (:object-attrib (:word "repo")) (:object-attrib (:word "find")) (:list (:variable "req") (:object-attrib (:word "request")) (:object-attrib (:word "get")) (:list (:string "address"))) (:terminator ";") (:comment) (:comment) (:variable "this") (:object-attrib (:word "em")) (:object-attrib (:word "remove")) (:incomplete-list (:variable "this") (:object-attrib (:word "em")) (:object-attrib nil))))))))))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -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 (:variable "token") (:terminator ";")) (:doc-block (:var-annotation (:word "App\\\\Entity\\\\User"))) (:private (:variable "user") (:terminator ";")) (:doc-block (:var-annotation (:word "bool"))) (:private (:variable "valid") (:terminator ";")) (:doc-block (:var-annotation (:word "\\DateTime"))) (:private (: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") (: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 ";"))))))))

File diff suppressed because one or more lines are too long

@ -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 (:variable "token") (:terminator ";")) (:private (:variable "extra") (:terminator ";")) (:doc-block (:var-annotation (:word "App\\\\Entity\\\\User"))) (:private (:variable "user") (:terminator ";")) (:doc-block (:var-annotation (:word "bool"))) (:private (:variable "valid") (:terminator ";")) (:doc-block (:var-annotation (:word "\\DateTime"))) (:private (: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") (: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 ";"))))))))

File diff suppressed because one or more lines are too long

@ -0,0 +1,41 @@
;;; phpinspect-test-env.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
(require 'phpinspect-worker)
(require 'phpinspect-cache)
;; Make sure that the worker is running. TODO: fully encapsulate the worker the
;; data types that are used in tests so that we don't depend on some global
;; worker object for tests.
(phpinspect-ensure-worker)
(phpinspect-purge-cache)
(defvar phpinspect-test-directory
(file-name-directory
(or load-file-name
buffer-file-name))
"Directory that phpinspect tests reside in.")
(defvar phpinspect-test-php-file-directory
(concat
(file-name-directory
(or load-file-name
buffer-file-name))
"/fixtures")
"Directory with syntax trees of example PHP files.")
(defun phpinspect-test-read-fixture-data (name)
(with-temp-buffer
(insert-file-contents-literally (concat phpinspect-test-php-file-directory "/" name ".eld"))
(read (current-buffer))))
(defun phpinspect-test-read-fixture-serialization (name)
(with-temp-buffer
(insert-file-contents-literally (concat phpinspect-test-php-file-directory "/" name ".eld"))
(eval (read (current-buffer)))))
(defun phpinspect-test-parse-fixture-code (name)
(phpinspect-parse-file
(concat phpinspect-test-php-file-directory "/" name ".php")))
(provide 'phpinspect-test-env)

@ -26,40 +26,9 @@
(require 'ert) (require 'ert)
(require 'phpinspect) (require 'phpinspect)
;; Make sure that the worker is running. TODO: fully encapsulate the worker the (require 'phpinspect-test-env
;; data types that are used in tests so that we don't depend on some global (concat (file-name-directory (or load-file-name buffer-file-name))
;; worker object for tests. "phpinspect-test-env.el"))
(phpinspect-ensure-worker)
(phpinspect-purge-cache)
(defvar phpinspect-test-directory
(file-name-directory
(or load-file-name
buffer-file-name))
"Directory that phpinspect tests reside in.")
(defvar phpinspect-test-php-file-directory
(concat
(file-name-directory
(or load-file-name
buffer-file-name))
"/fixtures")
"Directory with syntax trees of example PHP files.")
(defun phpinspect-test-read-fixture-data (name)
(with-temp-buffer
(insert-file-contents-literally (concat phpinspect-test-php-file-directory "/" name ".eld"))
(read (current-buffer))))
(defun phpinspect-test-read-fixture-serialization (name)
(with-temp-buffer
(insert-file-contents-literally (concat phpinspect-test-php-file-directory "/" name ".eld"))
(eval (read (current-buffer)))))
(defun phpinspect-test-parse-fixture-code (name)
(phpinspect-parse-file
(concat phpinspect-test-php-file-directory "/" name ".php")))
(ert-deftest phpinspect-get-variable-type-in-block () (ert-deftest phpinspect-get-variable-type-in-block ()
(let* ((code "class Foo { function a(\\Thing $baz) { $foo = new \\DateTime(); $bar = $foo; Whatever comes after don't matter.") (let* ((code "class Foo { function a(\\Thing $baz) { $foo = new \\DateTime(); $bar = $foo; Whatever comes after don't matter.")
@ -544,6 +513,7 @@ class Thing
(load-file (concat phpinspect-test-directory "/test-parse-context.el")) (load-file (concat phpinspect-test-directory "/test-parse-context.el"))
(load-file (concat phpinspect-test-directory "/test-splayt.el")) (load-file (concat phpinspect-test-directory "/test-splayt.el"))
(load-file (concat phpinspect-test-directory "/test-pipeline.el")) (load-file (concat phpinspect-test-directory "/test-pipeline.el"))
(load-file (concat phpinspect-test-directory "/test-toc.el"))
(provide 'phpinspect-test) (provide 'phpinspect-test)

@ -26,7 +26,9 @@
(require 'ert) (require 'ert)
(require 'phpinspect-parser) (require 'phpinspect-parser)
(require 'phpinspect-buffer) (require 'phpinspect-buffer)
(require 'phpinspect-test-env
(concat (file-name-directory (or load-file-name buffer-file-name))
"phpinspect-test-env.el"))
(ert-deftest phpinspect-buffer-region-lookups () (ert-deftest phpinspect-buffer-region-lookups ()
(let* ((parsed) (let* ((parsed)
@ -285,3 +287,185 @@ class YYY {
(setq parsed-after (phpinspect-buffer-parse buffer 'no-interrupt)) (setq parsed-after (phpinspect-buffer-parse buffer 'no-interrupt))
(should (equal parsed parsed-after)))) (should (equal parsed parsed-after))))
(ert-deftest phpinspect-buffer-index-classes ()
(let* ((buffer (phpinspect-make-buffer :project (phpinspect--make-project :autoload (phpinspect-make-autoloader))))
(namespaces (phpinspect-make-splayt))
(declarations (phpinspect-make-splayt))
(classes (phpinspect-make-splayt))
(root (phpinspect-make-meta nil 1 200 "" 'root)))
(phpinspect-splayt-insert
namespaces 1 (phpinspect-meta-set-parent
(phpinspect-make-meta nil 1 100 "" '(:namespace (:word "TestNamespace") (:terminator ";")))
root))
(phpinspect-splayt-insert
declarations 20
(phpinspect-make-meta nil 20 40 "" '(:declaration (:word "class") (:word "TestClass") (:word "extends") (:word "OtherTestClass"))))
(phpinspect-splayt-insert classes 20 (phpinspect-make-meta nil 20 80 "" '(:class (:comment "bla") '(:declaration (:word "class") (:word "TestClass") (:word "extends") (:word "OtherTestClass")))))
(phpinspect-buffer-index-declarations buffer declarations)
(phpinspect-buffer-index-namespaces buffer namespaces)
(phpinspect-buffer-index-classes buffer classes)
(should (phpinspect-project-get-class (phpinspect-buffer-project buffer) (phpinspect--make-type :name "\\TestNamespace\\TestClass")))
(should (= 2 (hash-table-count (phpinspect-project-class-index (phpinspect-buffer-project buffer)))))
(should (= 1 (length (phpinspect--class-extended-classes
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestNamespace\\TestClass"))))))
(let ((new-declarations (phpinspect-make-splayt))
(new-classes (phpinspect-make-splayt)))
(phpinspect-splayt-insert
new-declarations
20
(phpinspect-meta-set-parent
(phpinspect-make-meta nil 20 40 "" '(:declaration (:word "class") (:word "TestClass")))
root))
(phpinspect-splayt-insert
new-classes 20
(phpinspect-meta-set-parent
(phpinspect-make-meta nil 20 80 "" '(:class (:comment "bla") '(:declaration (:word "class") (:word "TestClass"))))
root))
(setf (phpinspect-buffer-map buffer) (phpinspect-make-bmap :-root-meta root))
(phpinspect-buffer-index-declarations buffer new-declarations)
(phpinspect-buffer-index-classes buffer new-classes)
(should (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestNamespace\\TestClass")))
(should (= 0 (length (phpinspect--class-extended-classes
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestNamespace\\TestClass")))))))
(let ((new-classes (phpinspect-make-splayt))
(new-root (phpinspect-make-meta nil 1 400 "" 'new-root)))
(setf (phpinspect-bmap--root-meta (phpinspect-buffer-map buffer)) new-root)
(phpinspect-buffer-index-classes buffer new-classes)
(should-not (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestNamespace\\TestClass")))
(should (= 1 (hash-table-count (phpinspect-project-class-index (phpinspect-buffer-project buffer))))))))
(ert-deftest phpinspect-buffer-index-functions ()
(let ((buffer (phpinspect-make-buffer :project (phpinspect--make-project :autoload (phpinspect-make-autoloader))))
(namespaces (phpinspect-make-splayt))
(declarations (phpinspect-make-splayt))
(classes (phpinspect-make-splayt))
(functions (phpinspect-make-splayt)))
(phpinspect-splayt-insert
namespaces 10
(phpinspect-make-meta nil 10 200 "" '(:namespace (:word "NS") (:terminator ";"))))
(phpinspect-splayt-insert
declarations 20
(phpinspect-make-meta nil 20 30 "" '(:declaration (:word "class") (:word "TestClass"))))
(phpinspect-splayt-insert
classes 20
(phpinspect-make-meta nil 20 70 "" '(:class (:declaration (:word "class") (:word "TestClass")))))
(phpinspect-splayt-insert
declarations 40
(phpinspect-make-meta nil 40 45 "" '(:declaration (:word "testMethod") (:list) (:word "RelativeType"))))
(phpinspect-splayt-insert
functions 40
(phpinspect-make-meta nil 40 50 "" '(:function (:declaration (:word "testMethod") (:list) (:word "RelativeType")))))
(phpinspect-buffer-index-declarations buffer declarations)
(phpinspect-buffer-index-namespaces buffer namespaces)
(phpinspect-buffer-index-classes buffer classes)
(phpinspect-buffer-index-functions buffer functions)
(should (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\NS\\TestClass")))
(should (= 1 (hash-table-count (phpinspect--class-methods
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\NS\\TestClass"))))))
(setf (phpinspect-buffer-map buffer) (phpinspect-make-bmap :-root-meta (phpinspect-make-meta nil 1 400 "" 'root)))
(phpinspect-buffer-index-functions buffer (phpinspect-make-splayt))
(should (= 0 (hash-table-count (phpinspect--class-methods
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\NS\\TestClass"))))))))
(ert-deftest phpinspect-buffer-index-class-variables ()
(let ((buffer (phpinspect-make-buffer :project (phpinspect--make-project :autoload (phpinspect-make-autoloader))))
(namespaces (phpinspect-make-splayt))
(declarations (phpinspect-make-splayt))
(classes (phpinspect-make-splayt))
(functions (phpinspect-make-splayt))
(variables (phpinspect-make-splayt)))
(phpinspect-splayt-insert
functions 60
(phpinspect-make-meta
nil 60 65 ""
(cadr (phpinspect-parse-string
"<?php function __construct(array $thing) { $this->banana = $thing; }"))))
(phpinspect-splayt-insert
declarations 20
(phpinspect-make-meta nil 20 30 "" '(:declaration (:word "class") (:word "TestClass"))))
(phpinspect-splayt-insert
classes 20
(phpinspect-make-meta nil 20 70 "" '(:class (:declaration (:word "class") (:word "TestClass")))))
(phpinspect-splayt-insert
variables 33
(phpinspect-make-meta nil 33 50 "" '(:class-variable "banana")))
(phpinspect-splayt-insert
variables 54
(phpinspect-make-meta nil 54 60 "" '(:const (:word "CONSTANT"))))
(phpinspect-buffer-index-declarations buffer declarations)
(phpinspect-buffer-index-namespaces buffer namespaces)
(phpinspect-buffer-index-classes buffer classes)
(phpinspect-buffer-index-functions buffer functions)
(phpinspect-buffer-index-class-variables buffer variables)
(should (phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestClass")))
(should (= 2 (length (phpinspect--class-variables
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestClass"))))))
(should (= 1 (length (phpinspect--class-get-constants
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestClass"))))))
(should (phpinspect--type= (phpinspect--make-type :name "\\array")
(phpinspect--variable-type
(phpinspect--class-get-variable
(phpinspect-project-get-class
(phpinspect-buffer-project buffer)
(phpinspect--make-type :name "\\TestClass"))
"banana"))))))

@ -25,6 +25,11 @@
(require 'ert) (require 'ert)
(require 'phpinspect-class) (require 'phpinspect-class)
(require 'phpinspect-project)
(require 'subr-x)
(require 'phpinspect-worker)
(phpinspect-ensure-worker)
(ert-deftest phpinspect--merge-method-return-type () (ert-deftest phpinspect--merge-method-return-type ()
(let* ((class-name (phpinspect--make-type :name "\\Something")) (let* ((class-name (phpinspect--make-type :name "\\Something"))
@ -40,3 +45,67 @@
(phpinspect--function-return-type result))) (phpinspect--function-return-type result)))
(should (phpinspect--type= (phpinspect--make-type :name "\\bool") (should (phpinspect--type= (phpinspect--make-type :name "\\bool")
(phpinspect--function-return-type method1))))) (phpinspect--function-return-type method1)))))
(ert-deftest phpinspect-class-incorporate ()
(let ((class (phpinspect--make-class-generated))
(other-class (phpinspect--make-class-generated)))
(phpinspect--class-set-index class `(phpinspect--indexed-class (class-name . ,(phpinspect--make-type :name "Class"))))
(phpinspect--class-set-index other-class `(phpinspect--indexed-class (class-name . ,(phpinspect--make-type :name "OtherClass"))))
(phpinspect--class-update-method
class (phpinspect--make-function :name "test" :return-type phpinspect--null-type))
(phpinspect--class-update-method
other-class (phpinspect--make-function :name "other-test" :return-type phpinspect--null-type))
(phpinspect--class-incorporate class other-class)
(should (= 2 (length (hash-table-values (phpinspect--class-methods class)))))
(should (= 1 (length (hash-table-values (phpinspect--class-subscriptions other-class)))))
(phpinspect--class-set-index
class
`(phpinspect--indexed-class
(complete . t)
(class-name . ,(phpinspect--make-type :name "Class"))
(methods . ,(list (phpinspect--make-function :name "test" :return-type phpinspect--null-type)
(phpinspect--make-function :name "foobar" :return-type phpinspect--null-type)))))
(should (= 3 (length (hash-table-values (phpinspect--class-methods class)))))
(phpinspect--class-incorporate class other-class)
(should (= 3 (length (hash-table-values (phpinspect--class-methods class)))))
(phpinspect--class-set-index
class
`(phpinspect--indexed-class
(complete . t)
(class-name . ,(phpinspect--make-type :name "Class"))
(methods . ,(list (phpinspect--make-function :name "foobar" :return-type phpinspect--null-type)))))
(should (= 2 (length (hash-table-values (phpinspect--class-methods class)))))
(should (phpinspect--class-get-method class (phpinspect-intern-name "other-test")))
(should (phpinspect--class-get-method class (phpinspect-intern-name "foobar")))
(phpinspect--class-set-index
class
`(phpinspect--indexed-class
(complete . t)
(class-name . ,(phpinspect--make-type :name "Class"))
(methods)))
(should (= 1 (length (hash-table-values (phpinspect--class-methods class)))))
(should (phpinspect--class-get-method class (phpinspect-intern-name "other-test")))
(phpinspect--class-incorporate class other-class)
(should (= 1 (length (hash-table-values (phpinspect--class-methods class)))))
(should (= 1 (length (hash-table-values (phpinspect--class-subscriptions other-class)))))))
(ert-deftest phpinspect--class-update-declaration ()
(let ((class (phpinspect--make-class-generated :project (phpinspect--make-project))))
(phpinspect--class-update-declaration class '(:declaration (:word "class") (:word "TestClass")
(:word "extends") (:word "OtherClass")
(:word "implements") (:word "ImplClass"))
nil "NS")
(should (= 2 (length (phpinspect--class-extended-classes class))))
(should (phpinspect--type= (phpinspect--make-type :name "\\NS\\TestClass" :fully-qualified t)
(phpinspect--class-name class)))))

@ -1,3 +1,5 @@
;;; test-edtrack.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
(require 'ert) (require 'ert)
(require 'phpinspect-edtrack) (require 'phpinspect-edtrack)
(require 'phpinspect-meta) (require 'phpinspect-meta)

@ -46,13 +46,22 @@
(classes (classes
(,(phpinspect--make-type :name"\\Potato" :fully-qualified t) (,(phpinspect--make-type :name"\\Potato" :fully-qualified t)
phpinspect--indexed-class phpinspect--indexed-class
(complete . t)
(class-name . ,(phpinspect--make-type :name "\\Potato" :fully-qualified t)) (class-name . ,(phpinspect--make-type :name "\\Potato" :fully-qualified t))
(declaration . (:declaration (:word "class") (:word "Potato")))
(location . (0 0)) (location . (0 0))
(imports) (imports)
(methods) (methods)
(static-methods . (,(phpinspect--make-function (static-methods . (,(phpinspect--make-function
:name "staticMethod" :name "staticMethod"
:scope '(:public) :scope '(:public)
:token '(:function (:declaration (:word "function")
(:word "staticMethod")
(:list (:variable "untyped")
(:comma)
(:word "array")
(:variable "things")))
(:block))
:arguments `(("untyped" nil) :arguments `(("untyped" nil)
("things" ,(phpinspect--make-type :name "\\array" ("things" ,(phpinspect--make-type :name "\\array"
:collection t :collection t

@ -0,0 +1,67 @@
;; test-meta.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
;; Copyright (C) 2021 Free Software Foundation, Inc.
;; Author: Hugo Thunnissen <devel@hugot.nl>
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(require 'ert)
(require 'phpinspect-meta)
(ert-deftest phpinspect-meta-start-relative-to-parent ()
(let ((meta (phpinspect-make-meta nil 10 20 "" 'token))
(parent1 (phpinspect-make-meta nil 9 22 "" 'token))
(parent2 (phpinspect-make-meta nil 0 100 "" 'token)))
(phpinspect-meta-set-parent meta parent1)
(phpinspect-meta-set-parent parent1 parent2)
(should (= 10 (phpinspect-meta-start meta)))
(phpinspect-meta-shift parent2 20)
(should (= 30 (phpinspect-meta-start meta)))
(should (phpinspect-meta-overlaps-point meta 30))))
(ert-deftest phpinspect-meta-iterator ()
(let* ((meta (phpinspect-make-meta nil 10 20 "" 'token))
(firstchild (phpinspect-make-meta nil 10 12 "" 'token))
(secondchild (phpinspect-make-meta nil 13 15 "" 'token))
(parent1 (phpinspect-make-meta nil 9 22 "" 'token))
(sibling (phpinspect-make-meta nil 30 55 "" 'token))
(parent2 (phpinspect-make-meta nil 0 100 "" 'token))
iterator)
(phpinspect-meta-set-parent meta parent1)
(phpinspect-meta-set-parent parent1 parent2)
(phpinspect-meta-set-parent sibling parent2)
(phpinspect-meta-set-parent firstchild meta)
(phpinspect-meta-set-parent secondchild meta)
(setq iterator (phpinspect-make-meta-iterator parent2))
(should (eq meta (phpinspect-meta-iterator-token-at-point iterator 10)))
(should (eq sibling (phpinspect-meta-iterator-token-at-point iterator 30)))
(should (eq meta (phpinspect-meta-iterator-token-at-point iterator 10)))
(should (eq firstchild (phpinspect-meta-iterator-token-at-point iterator 10)))
(should (eq secondchild (phpinspect-meta-iterator-token-at-point iterator 13)))
(should (eq meta (phpinspect-meta-iterator-token-at-point iterator 10)))
(should (eq firstchild (phpinspect-meta-iterator-token-at-point iterator 10)))
(should (eq sibling (phpinspect-meta-iterator-token-at-point iterator 30)))))

@ -163,3 +163,12 @@
(should (equal (sort '("eight" "nine" "eleven" "twelve") #'string-lessp) (should (equal (sort '("eight" "nine" "eleven" "twelve") #'string-lessp)
(sort (phpinspect-splayt-find-all-after tree 7) #'string-lessp))))) (sort (phpinspect-splayt-find-all-after tree 7) #'string-lessp)))))
(ert-deftest phpinspect-splayt-to-list ()
(let ((tree (phpinspect-make-splayt)))
(phpinspect-splayt-insert tree 3 "three")
(phpinspect-splayt-insert tree 1 "one")
(phpinspect-splayt-insert tree 2 "two")
(should (equal '("one" "two" "three") (phpinspect-splayt-to-list tree)))))

@ -0,0 +1,50 @@
;;; test-edtrack.el --- Unit tests for phpinspect.el -*- lexical-binding: t; -*-
(require 'phpinspect-toc)
(require 'phpinspect-splayt)
(ert-deftest phpinspect-make-toc ()
(let ((tokens (phpinspect-make-splayt))
toc)
(phpinspect-splayt-insert tokens 1 (phpinspect-make-meta nil 1 20 "" 'token1))
(phpinspect-splayt-insert tokens 40 (phpinspect-make-meta nil 40 45 "" 'token2))
(phpinspect-splayt-insert tokens 55 (phpinspect-make-meta nil 55 70 "" 'token3))
(setq toc (phpinspect-make-toc tokens))
(should (= 3 (hash-table-count (phpinspect-toc-table toc))))
(should (= 3 (length (phpinspect-splayt-to-list (phpinspect-toc-tree toc)))))))
(ert-deftest phpinspect-update-toc ()
(let ((tokens (phpinspect-make-splayt))
(root (phpinspect-make-meta nil 1 200 "" 'root))
(new-root (phpinspect-make-meta nil 1 400 "" 'root))
(tok1 (phpinspect-make-meta nil 1 20 "" 'token1))
(tok2 (phpinspect-make-meta nil 40 45 "" 'token2))
(tok3 (phpinspect-make-meta nil 55 70 "" 'token3))
(tok4 (phpinspect-make-meta nil 71 91 "" 'token4))
new-tokens toc)
(phpinspect-meta-set-parent tok1 root)
(phpinspect-meta-set-parent tok2 root)
(phpinspect-meta-set-parent tok3 root)
(phpinspect-splayt-insert tokens 1 tok1)
(phpinspect-splayt-insert tokens 40 tok2)
(phpinspect-splayt-insert tokens 55 tok3)
(setq toc (phpinspect-make-toc tokens))
(phpinspect-meta-set-parent tok2 new-root)
(phpinspect-meta-set-parent tok3 new-root)
(phpinspect-meta-set-parent tok4 new-root)
(setq new-tokens (phpinspect-make-splayt))
(phpinspect-splayt-insert new-tokens 71 tok4)
(pcase-let ((`(,result-new ,result-deleted) (phpinspect-toc-update toc new-tokens new-root)))
(should (= 1 (length result-new)))
(should (= 1 (length result-deleted)))
(should (eq tok1 (car result-deleted)))
(should (eq tok4 (car result-new))))))
Loading…
Cancel
Save