Keep index synchronized with buffer state

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

@ -14,7 +14,19 @@
(garbage-collect)
(benchmark
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)
@ -30,4 +42,9 @@
(garbage-collect)
(benchmark
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-util)
(require 'compat)
(require 'phpinspect-token-predicates)
(eval-when-compile
(defvar phpinspect-parse-context nil
@ -39,18 +40,36 @@
(cl-defstruct (phpinspect-bmap (:constructor phpinspect-make-bmap))
(starts (make-hash-table :test #'eql
:size (floor (/ (point-max) 4))
:size (floor (/ (point-max) 2))
:rehash-size 1.5))
(ends (make-hash-table :test #'eql
:size (floor (/ (point-max) 4))
:size (floor (/ (point-max) 2))
:rehash-size 1.5))
(meta (make-hash-table :test #'eq
:size (floor (/ (point-max) 4))
:size (floor (/ (point-max) 2))
:rehash-size 1.5))
(token-stack nil
:type list)
(overlays (phpinspect-make-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
:type phpinspect-meta)
(last-token-start nil
@ -158,7 +177,28 @@
(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)
(puthash end (list token-meta) ends))
@ -222,10 +262,6 @@
(cl-defmethod phpinspect-bmap-token-meta ((overlay (head 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)
(unless (phpinspect-probably-token-p token)
(error "Unexpected argument, expected `phpinspect-token-p'. Got invalid token %s" token))
@ -248,7 +284,7 @@
(let* ((overlays (phpinspect-bmap-overlays bmap))
(start (+ (phpinspect-meta-start 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))))
(phpinspect-meta-with-changeset token-meta

@ -27,6 +27,10 @@
(require 'phpinspect-bmap)
(require 'phpinspect-edtrack)
(require 'phpinspect-index)
(require 'phpinspect-toc)
(require 'phpinspect-resolvecontext)
(require 'phpinspect-resolve)
(require 'phpinspect-util)
(defvar-local phpinspect-current-buffer nil
"An instance of `phpinspect-buffer' local to the active
@ -44,12 +48,26 @@ emacs buffer."
"Parsed token tree that resulted from last parse")
(map nil
: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
:type phpinspect-project)
(edit-tracker (phpinspect-make-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
linked with."
(let ((tree))
@ -72,27 +90,331 @@ linked with."
(phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer))
;; set return value
(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))))))
(setq tree parsed)))))
;; Else: Just return last parse result
(setq tree (phpinspect-buffer-tree buffer)))
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))
(setf (phpinspect-buffer-tree buffer) nil)
(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-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)
(phpinspect-buffer-parse buffer)
(phpinspect-buffer-map buffer))
@ -134,14 +456,6 @@ use."
(cl-defmethod phpinspect-buffer-root-meta ((buffer phpinspect-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 ()
(interactive)
(when phpinspect-current-buffer
@ -150,5 +464,8 @@ use."
(insert (pp-to-string (phpinspect--index-tokens (phpinspect-buffer-parse buffer 'no-interrupt))))
(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)

@ -30,14 +30,6 @@
(defvar phpinspect-cache nil
"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))
(projects (make-hash-table :test 'equal :size 10)
: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
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
((cache phpinspect--cache) (project-name string))
"Get project by PROJECT-NAME that is located in CACHE.")

@ -43,20 +43,23 @@
:documentation
"All static methods this class provides,
including those from extended classes.")
(name nil
:type phpinspect--type)
(variables nil
:type list
:documentation
"Variables that belong to this class.")
(extended-classes (make-hash-table :test 'eq)
:type hash-table
(extended-classes nil
:type list
:documentation
"All extended/implemented classes.")
(subscriptions nil
:type list
(subscriptions (make-hash-table :test #'eq :size 10 :rehash-size 1.5)
:type hash-table
:documentation
"A list of subscription functions that should be
called whenever anything about this class is
updated")
(declaration nil)
(initial-index nil
:type bool
:documentation
@ -64,13 +67,43 @@
has been indexed yet."))
(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)))
(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)
(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-index class) index)
(dolist (method (alist-get 'methods index))
(phpinspect--class-update-method class method))
@ -82,21 +115,21 @@
(alist-get 'constants index)
(alist-get 'static-variables index)))
(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))
`(,@(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-update-extensions
class `(,@(alist-get 'implements index) ,@(alist-get 'extends index)))
(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))
(gethash method-name (phpinspect--class-methods class)))
@ -110,6 +143,16 @@
(when (string= variable-name (phpinspect--variable-name 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))
(seq-filter #'phpinspect--variable-vanilla-p (phpinspect--class-variables class)))
@ -140,16 +183,22 @@
(phpinspect--function-name method))
(phpinspect--add-method-copy-to-map
(phpinspect--class-methods class)
(alist-get 'class-name (phpinspect--class-index class))
(phpinspect--class-name class)
method))
(cl-defmethod phpinspect--class-set-static-method ((class phpinspect--class)
(method phpinspect--function))
(phpinspect--add-method-copy-to-map
(phpinspect--add-method-copy-to-map
(phpinspect--class-static-methods class)
(alist-get 'class-name (phpinspect--class-index class))
(phpinspect--class-name class)
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
((class phpinspect--class) (method-name symbol))
(let ((method (phpinspect--class-get-method class method-name)))
@ -171,7 +220,8 @@
(cl-defmethod phpinspect--merge-method ((class-name phpinspect--type)
(existing phpinspect--function)
(method phpinspect--function))
(method phpinspect--function)
&optional extended)
(let ((new-return-type (phpinspect--resolve-late-static-binding
(phpinspect--function-return-type method)
class-name)))
@ -180,49 +230,59 @@
(setf (phpinspect--function-return-type existing)
new-return-type))
(setf (phpinspect--function--inherited existing)
extended)
(setf (phpinspect--function-arguments existing)
(phpinspect--function-arguments method)))
existing)
(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)
(phpinspect--class-static-methods class))))
(if existing
(phpinspect--merge-method
(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))))
(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)
(phpinspect--class-methods class))))
(if existing
(phpinspect--merge-method
(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))))
;; 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)
(other-class phpinspect--class))
(dolist (method (phpinspect--class-get-method-list other-class))
(phpinspect--class-update-method class method))
(dolist (method (phpinspect--class-get-static-method-list other-class))
(phpinspect--class-update-static-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 'extended))
(phpinspect--class-subscribe class other-class))
(cl-defmethod phpinspect--class-subscribe ((class phpinspect--class)
(subscription-class phpinspect--class))
(let ((update-function
(lambda (new-class)
(phpinspect--class-incorporate class new-class)
(phpinspect--class-trigger-update class))))
(push update-function (phpinspect--class-subscriptions subscription-class))))
(unless (gethash subscription-class (phpinspect--class-subscriptions class))
(let ((update-function
(lambda (new-class)
(phpinspect--class-incorporate class new-class)
(phpinspect--class-trigger-update class))))
(puthash subscription-class update-function
(phpinspect--class-subscriptions subscription-class)))))
(provide 'phpinspect-class)
;;; phpinspect-class.el ends here

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

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

@ -30,6 +30,7 @@
(require 'phpinspect-autoload)
(require 'phpinspect-buffer)
(require 'phpinspect-cache)
(require 'phpinspect-util)
(defun phpinspect-insert-at-point (point data)
(save-excursion
@ -113,12 +114,6 @@ buffer position to insert the use statement at."
(defalias 'phpinspect-fix-uses-interactive #'phpinspect-fix-imports
"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)
(let (namespace namespace-name)
(dolist (type types)

@ -27,6 +27,7 @@
(require 'phpinspect-util)
(require 'phpinspect-project)
(require 'phpinspect-type)
(require 'phpinspect-parser)
(defun phpinspect--function-from-scope (scope)
(cond ((and (phpinspect-static-p (cadr scope))
@ -108,6 +109,7 @@ function (think \"new\" statements, return types etc.)."
(phpinspect--make-function
:scope `(,(car scope))
:token php-func
:name (concat (if namespace (concat namespace "\\") "") (cadadr (cdr declaration)))
:return-type (or type phpinspect--null-type)
:arguments (phpinspect--index-function-arg-list
@ -115,11 +117,16 @@ function (think \"new\" statements, return types etc.)."
(phpinspect-function-argument-list php-func)
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)
(phpinspect--make-variable
:scope `(,(car 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)
(seq-filter #'phpinspect-var-annotation-p token))
@ -184,6 +191,39 @@ function (think \"new\" statements, return types etc.)."
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)
"Create an alist with relevant attributes of a parsed class."
@ -195,7 +235,7 @@ function (think \"new\" statements, return types etc.)."
(constants)
(extends)
(implements)
(class-name (phpinspect--get-class-name-from-token class))
(class-name)
;; Keep track of encountered comments to be able to use type
;; annotations.
(comment-before)
@ -208,30 +248,9 @@ function (think \"new\" statements, return types etc.)."
(nconc used-types additional-used-types)
(setq used-types additional-used-types))))
;; Find out what the class extends or implements
(let ((enc-extends nil)
(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))))))))
(pcase-setq `(,class-name ,extends ,implements ,used-types)
(phpinspect--index-class-declaration (cadr class) type-resolver))
(dolist (token (caddr class))
(cond ((phpinspect-scope-p token)
@ -330,21 +349,22 @@ function (think \"new\" statements, return types etc.)."
(setq methods
(nconc methods (phpinspect--index-method-annotations type-resolver doc-block))))
(let ((class-name (funcall type-resolver (phpinspect--make-type :name class-name))))
`(,class-name .
(phpinspect--indexed-class
(class-name . ,class-name)
(location . ,(funcall location-resolver class))
(imports . ,imports)
(methods . ,methods)
(static-methods . ,static-methods)
(static-variables . ,static-variables)
(variables . ,variables)
(constants . ,constants)
(extends . ,extends)
(implements . ,implements)
(used-types . ,(mapcar #'phpinspect-intern-name
(seq-uniq used-types #'string=))))))))
`(,class-name .
(phpinspect--indexed-class
(complete . ,(not (phpinspect-incomplete-class-p class)))
(class-name . ,class-name)
(declaration . ,(seq-find #'phpinspect-declaration-p class))
(location . ,(funcall location-resolver class))
(imports . ,imports)
(methods . ,methods)
(static-methods . ,static-methods)
(static-variables . ,static-variables)
(variables . ,variables)
(constants . ,constants)
(extends . ,extends)
(implements . ,implements)
(used-types . ,(mapcar #'phpinspect-intern-name
(seq-uniq used-types #'string=)))))))
(defsubst phpinspect-namespace-body (namespace)
"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))))))
(t
(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)
(backtrace))
nil))

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

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

@ -28,17 +28,21 @@
(require 'phpinspect-bmap)
(require 'phpinspect-meta)
(require 'phpinspect-parse-context)
(require 'phpinspect-token-predicates)
(eval-when-compile
(define-inline phpinspect--word-end-regex ()
(inline-quote "\\([[:blank:]]\\|[^0-9a-zA-Z_]\\)")))
(defsubst phpinspect--strip-word-end-space (string)
(when phpinspect-parse-context
(phpinspect-pctx-register-whitespace
phpinspect-parse-context
(substring string (- (length string) 1) (length string))))
(substring string 0 (- (length string) 1)))
(define-inline phpinspect--strip-word-end-space (string)
(inline-letevals (string)
(inline-quote
(progn
(when phpinspect-parse-context
(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)
"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)
(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)
(intern (concat "phpinspect--" (symbol-name handler-name) "-handler")))
@ -715,6 +507,15 @@ parsing incrementally."
(phpinspect-munch-token-without-attribs (match-string 0) :variable)
(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)
"Handler that discards whitespace"
((regexp . "[[:blank:]\n]+"))
@ -827,7 +628,7 @@ static keywords with the same meaning as in a class block."
(phpinspect-defparser class-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
const-keyword use-keyword function-keyword word terminator
here-doc string comment block))
@ -961,19 +762,19 @@ nature like argument lists"
(phpinspect-defparser scope-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)
:delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defparser scope-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)
:delimiter-predicate #'phpinspect--scope-terminator-p)
(phpinspect-defparser scope-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)
:delimiter-predicate #'phpinspect--scope-terminator-p)
@ -991,7 +792,7 @@ nature like argument lists"
(phpinspect-defparser 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)
(phpinspect-defhandler static-keyword (start-token max-point)

@ -56,6 +56,7 @@ indexed classes in the project")
:documentation
"A hash able that contains all of the currently indexed functions
in the project")
(function-token-index (make-hash-table :test 'eq :size 100 :rehash-size 1.5))
(fs nil
:type phpinspect-fs
:documentation
@ -66,7 +67,10 @@ can be accessed.")
:documentation
"The autoload object through which this project's type
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
:documentation
"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))
(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))
(let ((funcs))
(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-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
((project phpinspect-project) (indexed-class (head phpinspect--indexed-class)) &optional index-imports)
(let* ((class-name (phpinspect--type-name-symbol
@ -203,11 +217,12 @@ indexed by the absolute paths of the files they're watching."))
class))
(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)))
(unless class
(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))
(defalias 'phpinspect-project-add-class-if-missing #'phpinspect-project-get-class-create)

@ -37,6 +37,7 @@
(cl-defmethod phpinspect--serialize-function ((func phpinspect--function))
`(phpinspect--make-function
:name ,(phpinspect--function-name func)
:token (quote ,(phpinspect--function-token func))
:scope (quote ,(phpinspect--function-scope func))
:arguments ,(append '(list)
(mapcar (lambda (arg)
@ -53,10 +54,11 @@
(phpinspect--variable-type var)))
:scope (quote ,(phpinspect--variable-scope var))))
(cl-defmethod phpinspect--serialize-indexed-class ((class (head phpinspect--indexed-class)))
``(phpinspect--indexed-class
(complete . ,,(alist-get 'complete class))
(class-name . ,,(phpinspect--serialize-type (alist-get 'class-name class)))
(declaration . ,(quote ,(alist-get 'declaration class)))
(imports . ,,(append '(list)
(mapcar #'phpinspect--serialize-import
(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)
(inline-quote
(cons ,root-node nil)))
(cons 'phpinspect-splayt ,root-node)))
(define-inline phpinspect-splayt-root-node (splayt)
(inline-quote (car ,splayt)))
(inline-quote (cdr ,splayt)))
(define-inline phpinspect-splayt-empty-p (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)))
(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)
(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
(push ,current-sym ,stack-sym)
(setf ,place (phpinspect-splayt-node-value ,current-sym))
(setf ,place ,current-sym)
,@body)
(when (phpinspect-splayt-node-right ,current-sym)
@ -275,7 +271,7 @@ apeared to be a little more performant than using `let'."
(when ,reverse-sym
(while ,stack-sym
(setq ,current-sym (pop ,stack-sym))
(setf ,place (phpinspect-splayt-node-value ,current-sym))
(setf ,place ,current-sym)
,@body))
(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
near the top of the tee."
(declare (indent 1))
`(phpinspect-splayt-node-traverse
(,(car place-and-splayt) (phpinspect-splayt-root-node ,(cadr place-and-splayt)))
,@body))
(let* ((current (gensym))
(code `(phpinspect-splayt-node-traverse
(,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)
(declare (indent 1))
@ -309,7 +311,7 @@ near the top of the tee."
(push ,current ,stack)
(setq ,current (phpinspect-splayt-node-left ,current)))
(setq ,current (pop ,stack))
(setf ,place (phpinspect-splayt-node-value ,current))
(setf ,place ,current)
,@body
(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 cadr of PLACE-AND-SPLAYT is expected to be a splay tree."
(declare (indent 1))
`(phpinspect-splayt-node-traverse-lr
(,(car place-and-splayt) (phpinspect-splayt-root-node ,(cadr place-and-splayt)))
,@body))
(let* ((current (gensym))
(code `(phpinspect-splayt-node-traverse-lr
(,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)
(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))))
(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."
(let ((first (phpinspect-splayt-find-smallest-node-after splayt key))
all)
(let* ((first (phpinspect-splayt-find-smallest-node-after splayt key))
(all (cons nil nil))
(all-rear all))
(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))
(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)
(eq first (phpinspect-splayt-node-left (phpinspect-splayt-node-parent first))))
(setq first (phpinspect-splayt-node-parent first))
(setq first nil)))
all))
(defsubst phpinspect-splayt-find-all-before (splayt key)
(cdr all)))
(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."
(let ((first (phpinspect-splayt-find-largest-node-before splayt key))
all)
(let* ((first (phpinspect-splayt-find-largest-node-before splayt key))
(all (cons nil nil))
(all-rear all))
(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))
(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)
(eq first (phpinspect-splayt-node-right (phpinspect-splayt-node-parent first))))
(setq first (phpinspect-splayt-node-parent first))
(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."
(inline-quote
(phpinspect-splayt-node-value
(phpinspect-splay
,splayt (phpinspect-splayt-find-smallest-node-after ,splayt ,key)))))
(phpinspect-splayt-node-value
(phpinspect-splay
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."
(inline-quote
(phpinspect-splayt-node-value
(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)))
(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)

@ -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
:documentation
"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
:type phpinspect-scope
:documentation

@ -265,5 +265,16 @@ CONTINUE must be a condition-variable"
(with-mutex mx (condition-wait continue))
(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)
;;; phpinspect-util.el ends here

@ -152,7 +152,7 @@ already present in the queue."
(phpinspect-worker-skip-next-pause worker))
(phpinspect-thread-pause phpinspect-worker-pause-time mx continue))
(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")
(message "phpinspect worker thread exited")))

@ -79,10 +79,6 @@
(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 ()
"Initialize the phpinspect minor mode for the current buffer."
(phpinspect-ensure-worker)
@ -295,20 +291,6 @@ Example configuration for `company-mode':
(phpinspect--completion-meta
(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)
"Call `phpinspect-insert-file-contents-function' with ARGS as arguments."
(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 'phpinspect)
;; 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")))
(require 'phpinspect-test-env
(concat (file-name-directory (or load-file-name buffer-file-name))
"phpinspect-test-env.el"))
(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.")
@ -544,6 +513,7 @@ class Thing
(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-pipeline.el"))
(load-file (concat phpinspect-test-directory "/test-toc.el"))
(provide 'phpinspect-test)

@ -26,7 +26,9 @@
(require 'ert)
(require 'phpinspect-parser)
(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 ()
(let* ((parsed)
@ -285,3 +287,185 @@ class YYY {
(setq parsed-after (phpinspect-buffer-parse buffer 'no-interrupt))
(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 'phpinspect-class)
(require 'phpinspect-project)
(require 'subr-x)
(require 'phpinspect-worker)
(phpinspect-ensure-worker)
(ert-deftest phpinspect--merge-method-return-type ()
(let* ((class-name (phpinspect--make-type :name "\\Something"))
@ -40,3 +45,67 @@
(phpinspect--function-return-type result)))
(should (phpinspect--type= (phpinspect--make-type :name "\\bool")
(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 'phpinspect-edtrack)
(require 'phpinspect-meta)

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