From ec8d4efdb64f18f9ee43f2831546d4e7cf1d0f5d Mon Sep 17 00:00:00 2001 From: Hugo Thunnissen Date: Sat, 26 Aug 2023 08:08:17 +0200 Subject: [PATCH] Implement storage of methods and variables --- phpinspect-cache.el | 676 ++++++++++++++++++++++++++++---------------- phpinspect-type.el | 3 + test/test-cache.el | 290 +++++++++++++++---- 3 files changed, 674 insertions(+), 295 deletions(-) diff --git a/phpinspect-cache.el b/phpinspect-cache.el index 088f2fd..620ee4f 100644 --- a/phpinspect-cache.el +++ b/phpinspect-cache.el @@ -21,6 +21,8 @@ ;;; Commentary: +;; FIXME: Storage mechanism for abstract methods is missing (@abstract-method) + ;;; Code: (require 'phpinspect-project) @@ -308,14 +310,14 @@ then returned." (defun phpinspect-bidi-graph-unlink-between (graph obj1 obj2) (when-let ((rel (gethash obj1 (phpinspect-bidi-graph-rel graph))) (back-rel (gethash obj2 (phpinspect-bidi-graph-rel-back graph)))) - (delq obj2 rel) - (delq obj1 back-rel))) + (puthash obj1 (delq obj2 rel) (phpinspect-bidi-graph-rel graph)) + (puthash obj2 (delq obj1 back-rel) (phpinspect-bidi-graph-rel-back graph)))) (defun phpinspect-bidi-graph-unlink (graph obj) (when-let ((obj-link (gethash obj (phpinspect-bidi-graph-rel graph)))) (dolist (back-rel obj-link) (when-let ((back-link (gethash back-rel (phpinspect-bidi-graph-rel-back graph)))) - (delq obj back-link) (phpinspect-bidi-graph-rel-back graph))) + (puthash back-rel (delq obj back-link) (phpinspect-bidi-graph-rel-back graph)))) (remhash obj (phpinspect-bidi-graph-rel graph)))) (defun phpinspect-bidi-graph-get-linking-from (graph obj) @@ -339,19 +341,20 @@ then returned." (functions nil)) (cl-defstruct (phpinspect-cache-group (:constructor phpinspect-make-cache-group)) + (spec nil) (namespaces (make-hash-table :test #'eq :size 2000 :rehash-size 2.0)) (extends (phpinspect-make-bidi-graph)) (implements (phpinspect-make-bidi-graph))) (eval-and-compile - (defconst phpinspect-cache-types '(interface trait class method type - abstract-method function variable namespace) + (defconst phpinspect-cache-types '(@interface @trait @class @method @type + @abstract-method @function @variable @namespace) "Types of entities that the cache can store.") - (defconst phpinspect-cache-containing-types '(class trait interface) + (defconst phpinspect-cache-containing-types '(@class @trait @interface) "Types of entities that the cache can store members for.") - (defconst phpinspect-cache-member-types '(method abstract-method function variable) + (defconst phpinspect-cache-member-types '(@method @abstract-method @function @variable) "Types of entities that the cache can store as members.")) (defun phpinspect-cache-type-get-extends (type) @@ -364,6 +367,11 @@ then returned." (phpinspect-cache-type-group type) (phpinspect-cache-type-name type))) +(defun phpinspect-cache-type-add-method (type method) + (push (cons (phpinspect--function-short-name-symbol method) + method) + (phpinspect-cache-type-methods type))) + (defun phpinspect-cache-group-get-extends (group type-name) (phpinspect-bidi-graph-get-linking-from (phpinspect-cache-group-extends group) @@ -406,7 +414,7 @@ then returned." (when-let ((entity (cdr (assq (phpinspect--type-short-name type) (phpinspect-cache-namespace-types namespace))))) - (and (or (eq 'type category) + (and (or (eq '@type category) (eq category (phpinspect-cache-type-category entity))) entity))) @@ -418,7 +426,7 @@ then returned." (while types (let ((type-cell (car types))) (when (eq (car type-cell) name) - (when (or (eq 'type category) + (when (or (eq '@type category) (eq category (phpinspect-cache-type-category (cdr type-cell)))) (if cell-before @@ -456,11 +464,16 @@ then returned." (phpinspect-bidi-graph-unlink (phpinspect-cache-group-implements group) name)) +(defmacro phpinspect--inline-wildcard-param-p (param) + `(let ((param ,param)) + (and (inline-const-p param) (eq '* (inline-const-val param))))) (define-inline phpinspect-cache-query--do-delete-type - (group param type member namespace implements extends) - (inline-letevals (group param member namespace implements extends) - (if (and (inline-const-p param) (eq '* (inline-const-val param))) + (group param type _member namespace _implements _extends) + (setq type (inline-const-val type)) + + (inline-letevals (group param namespace) + (if (phpinspect--inline-wildcard-param-p param) (if namespace (inline-quote (when-let ((namespace (phpinspect-cache-group-get-namespace @@ -469,7 +482,7 @@ then returned." (setf (phpinspect-cache-namespace-types namespace) (seq-filter (lambda (type-cell) - (if ,(if (eq type 'type) + (if ,(if (eq type '@type) t `(eq (phpinspect-cache-type-category (cdr type-cell)) (quote ,type))) @@ -487,7 +500,7 @@ then returned." (phpinspect-cache-group-namespaces ,group))) (let (new-types) (dolist (type-cell (phpinspect-cache-namespace-types namespace)) - (if ,(if (eq type 'type) + (if ,(if (eq type '@type) t `(eq (phpinspect-cache-type-category (cdr type-cell)) @@ -512,9 +525,10 @@ then returned." result))))) (define-inline phpinspect-cache-query--do-delete-function - (group param type member namespace implements extends) - (inline-letevals (group param member namespace implements extends) - (if (and (inline-const-p param) (eq '* (inline-const-val param))) + (group param _type _member namespace _implements _extends) + + (inline-letevals (group param namespace) + (if (phpinspect--inline-wildcard-param-p param) (if namespace (inline-quote (when-let ((namespace (phpinspect-cache-group-get-namespace @@ -538,36 +552,126 @@ then returned." resultset))) (cons 'phpinspect-cache-multiresult resultset)))) (inline-quote - (progn - (when-let ((namespace - (phpinspect-cache-group-get-namespace - ,group (or ,namespace - (phpinspect-intern-name - (phpinspect-type-name-namespace - (phpinspect-name-string ,param))))))) - (phpinspect-cache-namespace-delete-function - namespace ,param))))))) - -(define-inline phpinspect-cache-query--do-delete + (when-let ((namespace + (phpinspect-cache-group-get-namespace + ,group (or ,namespace + (phpinspect-intern-name + (phpinspect-type-name-namespace + (phpinspect-name-string ,param))))))) + (phpinspect-cache-namespace-delete-function + namespace ,param)))))) + +(defun phpinspect--assq-delete (key alist) + (let* ((result (cons nil nil)) + (result-rear result) + deleted) + (catch 'break + (while alist + (if (eq key (caar alist)) + (progn + (setcdr result-rear (cdr alist)) + (setq deleted (car alist)) + (throw 'break nil)) + (setq result-rear (setcdr result-rear (cons (car alist) nil))) + (setq alist (cdr alist))))) + + (list deleted (cdr result)))) + +;; OPTIMIZE: this is probably not optimal for large numbers of keys +(defun phpinspect--assq-delete-multi (keys alist) + (let (all-deleted) + (dolist (key keys) + (pcase-let ((`(,deleted ,filtered) (phpinspect--assq-delete key alist))) + (push deleted all-deleted) + (setq alist filtered))) + + (list all-deleted alist))) + +(defun phpinspect--alist-values (alist) + (let* ((vals (cons nil nil)) + (vals-rear vals)) + (dolist (cell alist) + (setq vals-rear (setcdr vals-rear (cons (cdr cell) nil)))) + + (cdr vals))) + +(defun phpinspect-cache-query--do-delete-method (cache group param type member) + (when-let ((member-type + (car + (phpinspect-cache-transact cache (list (phpinspect-cache-group-spec group)) + :get member :as @type)))) + (cond ((eq '* param) + (let ((deleted (phpinspect--alist-values + (phpinspect-cache-type-methods member-type)))) + (setf (phpinspect-cache-type-methods member-type) nil) + (cons 'phpinspect-cache-multiresult deleted))) + ((and (listp param) (not (phpinspect-name-p param))) + (pcase-let ((`(,deleted ,filtered) + (phpinspect--assq-delete-multi + param (phpinspect-cache-type-methods member-type)))) + (setf (phpinspect-cache-type-methods member-type) filtered) + (cons 'phpinspect-cache-multiresult deleted))) + (t + (pcase-let ((`(,deleted ,filtered) + (phpinspect--assq-delete + param (phpinspect-cache-type-methods member-type)))) + + (setf (phpinspect-cache-type-methods member-type) filtered) + deleted))))) + +(defun phpinspect-cache-query--do-delete-variable (cache group param type member) + (when-let ((member-type + (car + (phpinspect-cache-transact cache (list (phpinspect-cache-group-spec group)) + :get member :as @type)))) + (cond ((eq '* param) + (let ((deleted (phpinspect--alist-values + (phpinspect-cache-type-variables member-type)))) + (setf (phpinspect-cache-type-variables member-type) nil) + (cons 'phpinspect-cache-multiresult deleted))) + ((and (listp param) (not (phpinspect-name-p param))) + (pcase-let ((`(,deleted ,filtered) + (phpinspect--assq-delete-multi + param (phpinspect-cache-type-variables member-type)))) + (setf (phpinspect-cache-type-variables member-type) filtered) + (cons 'phpinspect-cache-multiresult deleted))) + (t + (pcase-let ((`(,deleted ,filtered) + (phpinspect--assq-delete + param (phpinspect-cache-type-variables member-type)))) + + (setf (phpinspect-cache-type-variables member-type) filtered) + deleted))))) + +(define-inline phpinspect-cache-query--do-delete-member (cache group param type member namespace implements extends) - (cl-assert (and (inline-const-p type) (symbolp (inline-const-val type)))) - - (let ((type (inline-const-val type)) - delete-form) - (inline-letevals (group param member namespace implements extends) - (cond - ((memq type (cons 'type phpinspect-cache-containing-types)) - (setq delete-form - (inline-quote - (phpinspect-cache-query--do-delete-type - ,group ,param ,type ,member ,namespace ,implements ,extends)))) - ((and (eq 'function type) (not member)) - (setq delete-form - (inline-quote - (phpinspect-cache-query--do-delete-function - ,group ,param ,type ,member ,namespace ,implements ,extends)))) - (t (inline-error "Delete not supported for entity type %s" type)))) - delete-form)) + (inline-letevals (cache group param member) + (setq type (inline-const-val type)) + + (pcase type + ((or '@function '@method) + (inline-quote + (phpinspect-cache-query--do-delete-method ,cache ,group ,param (quote ,type) ,member))) + ('@variable + (inline-quote + (phpinspect-cache-query--do-delete-variable ,cache ,group ,param (quote ,type) ,member))) + (_ (error "Delete not supported for member type %s" type))))) + +(defmacro phpinspect-cache-query--do-delete + (cache group param type member namespace implements extends) + (cl-assert (symbolp type)) + + (cond + ((memq type (cons '@type phpinspect-cache-containing-types)) + `(phpinspect-cache-query--do-delete-type + ,group ,param (quote ,type) ,member ,namespace ,implements ,extends)) + ((and (eq '@function type) (not member)) + `(phpinspect-cache-query--do-delete-function + ,group ,param (quote ,type) ,member ,namespace ,implements ,extends)) + ((and (memq type phpinspect-cache-member-types) member) + `(phpinspect-cache-query--do-delete-member + ,cache ,group ,param (quote ,type) ,member ,namespace ,implements ,extends)) + (t (error "Delete not supported for entity type %s" type)))) (defun phpinspect-cache-namespace-get-function (namespace func-name) (cdr (assq func-name (phpinspect-cache-namespace-functions namespace)))) @@ -590,111 +694,148 @@ then returned." (phpinspect--type-name-symbol type) (phpinspect--type-name-symbol implements)))) -(define-inline phpinspect-cache-query--do-insert - (cache group param type member namespace implements extends) - (cl-assert (and (inline-const-p type) (symbolp (inline-const-val type)))) - - (let ((type (inline-const-val type)) - register-form) - (inline-letevals (group param member namespace implements extends) - (cond - ((memq type (cons 'type phpinspect-cache-containing-types)) - - (setq register-form - (inline-quote - (let* ((namespace (phpinspect-cache-group-get-namespace-create - ,group - (or ,namespace (phpinspect--type-namespace ,param))))) - ,(when extends - `(phpinspect-cache-group-register-extends ,group ,param ,extends)) - - ,(when implements - `(phpinspect-cache-group-register-implements ,group ,param ,implements)) - - (phpinspect-cache-namespace-get-type-create - namespace ,param (quote ,type) ,group))))) - ((and (eq 'function type) (not member)) - (setq register-form - (inline-quote - (let ((namespace (phpinspect-cache-group-get-namespace-create - ,group (or ,namespace (phpinspect--function-namespace ,param))))) - (or (when-let ((existing (assq (phpinspect--function-name-symbol ,param) - (phpinspect-cache-namespace-functions namespace)))) - (setcdr existing ,param)) - (cdar (push (cons (phpinspect--function-short-name-symbol ,param) ,param) - (phpinspect-cache-namespace-functions namespace)))))))) - (t (inline-error "Insert not supported for entity type %s" type)))) - register-form)) - -(define-inline phpinspect-cache-query--do-get-type - (group param type member namespace implements extends) - (inline-letevals (group param member namespace implements extends) - (let ((form - (if (and (inline-const-p param) (eq '* (inline-const-val param))) - (if namespace - (inline-quote - (when-let ((namespace (phpinspect-cache-group-get-namespace - ,group ,namespace))) - (cons 'phpinspect-cache-multiresult - (mapcar #'cdr (phpinspect-cache-namespace-types namespace))))) - (inline-quote - (cons - 'phpinspect-cache-multiresult - (mapcan - (lambda (namespace) - (mapcar #'cdr (phpinspect-cache-namespace-types namespace))) - (hash-table-values (phpinspect-cache-group-namespaces ,group)))))) - (inline-quote - (when-let* ((namespace (phpinspect-cache-group-get-namespace - ,group - (or ,namespace - (phpinspect--type-namespace ,param))))) - (phpinspect-cache-namespace-get-type namespace ,param (quote ,type))))))) - - (setq form - (inline-quote - (if ,implements - (let ((implementing (phpinspect-cache-group-get-implementing ,group ,implements)) - (result ,form) - filtered) - (when result - (if (and (consp result) - (eq 'phpinspect-cache-multiresult (car result))) - (progn - (dolist (res (cdr result)) - (when (memq (phpinspect-cache-type-name res) implementing) - (push res filtered))) - (setq filtered (cons 'phpinspect-cache-multiresult filtered))) - (when (memq (phpinspect-cache-type-name result) implementing) - (setq filtered result))))) - ,form))) - - (setq form - (inline-quote - (if ,extends - (let ((extending (phpinspect-cache-group-get-extending ,group ,extends)) - (result ,form) - filtered) - (when result - (if (and (consp result) - (eq 'phpinspect-cache-multiresult (car result))) - (progn - (dolist (res (cdr result)) - (when (memq (phpinspect-cache-type-name res) extending) - (push res filtered))) - (setq filtered (cons 'phpinspect-cache-multiresult filtered))) - (when (memq (phpinspect-cache-type-name result) extending) - (setq filtered result))))) - ,form))) - form))) - +(defun phpinspect-cache-type-add-variable (type variable) + (push (cons (phpinspect--variable-name-symbol variable) + variable) + (phpinspect-cache-type-variables type))) + +(define-inline phpinspect-cache-query--do-insert-method + (cache group param type member namespace) + (setq type (inline-const-val type)) + (inline-letevals (cache group param member namespace) + (inline-quote + (let ((member-type + (car + (phpinspect-cache-transact ,cache (list (phpinspect-cache-group-spec ,group)) + :get ,member + :in ,namespace + :as @type))) + resultset) + ,(pcase type + ((or '@function '@method) + `(if (listp ,param) + (progn + (dolist (method ,param) + (push method resultset) + (phpinspect-cache-type-add-method member-type method)) + (cons 'phpinspect-cache-multiresult resultset)) + (cdar (phpinspect-cache-type-add-method member-type ,param)))) + ('@variable + `(if (listp ,param) + (progn + (dolist (variable ,param) + (push variable resultset) + (phpinspect-cache-type-add-variable member-type variable)) + (cons 'phpinspect-cache-multiresult resultset)) + (cdar (phpinspect-cache-type-add-variable member-type ,param)))) + (_ (error "Insert not supported for member type %s" type))))))) + +(defun phpinspect-cache-query--do-insert-function (cache group param namespace) + (let ((namespace + (phpinspect-cache-group-get-namespace-create + group (or namespace + (phpinspect--function-namespace param))))) + (or (when-let ((existing (assq (phpinspect--function-name-symbol param) + (phpinspect-cache-namespace-functions namespace)))) + (cdar (setcdr existing (cons param (cdr existing))))) + (cdar (push (cons (phpinspect--function-short-name-symbol param) param) + (phpinspect-cache-namespace-functions namespace)))))) + +(define-inline phpinspect-cache-query--do-insert-member + (cache group param type member namespace implements extends) + (if member + (inline-quote + (phpinspect-cache-query--do-insert-method + ,cache ,group ,param ,type ,member ,namespace)) + ;; Else: insert function in namespace + (inline-quote + (phpinspect-cache-query--do-insert-function ,cache ,group ,param ,namespace)))) +(defmacro phpinspect-cache-query--do-insert + (cache group param type member namespace implements extends) + (cl-assert (symbolp type)) + + (cond + ((memq type (cons '@type phpinspect-cache-containing-types)) + `(let* ((namespace (phpinspect-cache-group-get-namespace-create + ,group + (or ,namespace (phpinspect--type-namespace ,param))))) + ,(when extends + `(phpinspect-cache-group-register-extends ,group ,param ,extends)) + + ,(when implements + `(phpinspect-cache-group-register-implements ,group ,param ,implements)) + + (phpinspect-cache-namespace-get-type-create + namespace ,param (quote ,type) ,group))) + ((memq type phpinspect-cache-member-types) + `(phpinspect-cache-query--do-insert-member + ,cache ,group ,param (quote ,type) ,member ,namespace ,implements ,extends)) + (t (error "Insert not supported for entity type %s" type)))) + +(defun phpinspect-cache-query--do-get-type-wildcard (group param type namespace) + (if namespace + (when-let ((namespace (phpinspect-cache-group-get-namespace group namespace))) + (cons 'phpinspect-cache-multiresult + (mapcar #'cdr (phpinspect-cache-namespace-types namespace)))) + (cons + 'phpinspect-cache-multiresult + (mapcan + (lambda (namespace) + (mapcar #'cdr (phpinspect-cache-namespace-types namespace))) + (hash-table-values (phpinspect-cache-group-namespaces group)))))) + + +(defun phpinspect-cache-query--do-get-type + (group param type member namespace implements extends) + (let ((result + (if (eq '* param) + (phpinspect-cache-query--do-get-type-wildcard group param type namespace) + (when-let* ((namespace (phpinspect-cache-group-get-namespace + group + (or namespace + (phpinspect--type-namespace param))))) + (phpinspect-cache-namespace-get-type namespace param type))))) + + ;; OPTIMIZE: Performance of these filters won't be very good when using + ;; wildcards without namespace parameter. Probably worth optimizing when + ;; this becomes a frequent use case. + (when implements + (setq result + (let ((implementing (phpinspect-cache-group-get-implementing group implements)) + filtered) + (when result + (if (and (consp result) + (eq 'phpinspect-cache-multiresult (car result))) + (progn + (dolist (res (cdr result)) + (when (memq (phpinspect-cache-type-name res) implementing) + (push res filtered))) + (cons 'phpinspect-cache-multiresult filtered)) + (when (memq (phpinspect-cache-type-name result) implementing) + result)))))) + + (when extends + (setq result + (let ((extending (phpinspect-cache-group-get-extending group extends)) + filtered) + (when result + (if (and (consp result) + (eq 'phpinspect-cache-multiresult (car result))) + (progn + (dolist (res (cdr result)) + (when (memq (phpinspect-cache-type-name res) extending) + (push res filtered))) + (cons 'phpinspect-cache-multiresult filtered)) + (when (memq (phpinspect-cache-type-name result) extending) + result)))))) + result)) (define-inline phpinspect-cache-query--do-get-function (group param type member namespace implements extends) (inline-letevals (group param member namespace implements extends) - (if (and (inline-const-p param) (eq '* (inline-const-val param))) + (if (phpinspect--inline-wildcard-param-p param) (if namespace (inline-quote (when-let ((namespace (phpinspect-cache-group-get-namespace @@ -735,50 +876,64 @@ then returned." (push func resultset))) (cons 'phpinspect-cache-multiresult resultset))))))))) -(define-inline phpinspect-cache-query--do-get +(defun phpinspect-cache-type-get-method (type method-name) + (cdr (assq method-name (phpinspect-cache-type-methods type)))) + +(defun phpinspect-cache-type-get-variable (type method-name) + (cdr (assq method-name (phpinspect-cache-type-variables type)))) + +(define-inline phpinspect-cache-query--do-get-member (cache group param type member namespace) + (inline-letevals (cache group param member namespace) + (setq type (inline-const-val type)) + + (inline-quote + (when-let ((member-type + (car + (phpinspect-cache-transact ,cache (list (phpinspect-cache-group-spec ,group)) + :get ,member + :as @type + :in ,namespace)))) + + ,(pcase type + ((or '@function '@method) + (if (phpinspect--inline-wildcard-param-p param) + `(cons 'phpinspect-cache-multiresult + (phpinspect--alist-values (phpinspect-cache-type-methods member-type))) + `(phpinspect-cache-type-get-method member-type ,param))) + ('@variable + (if (phpinspect--inline-wildcard-param-p param) + `(cons 'phpinspect-cache-multiresult + (phpinspect--alist-values (phpinspect-cache-type-variables member-type))) + `(phpinspect-cache-type-get-variable member-type ,param))) + (_ (error "Get not supported for member entity type %s" type))))))) + +(defmacro phpinspect-cache-query--do-get (cache group param type member namespace implements extends) - (cl-assert (and (inline-const-p type) (symbolp (inline-const-val type)))) - - (let ((type (inline-const-val type)) - get-form) - (inline-letevals (group param member namespace implements extends) - (cond - ((memq type (cons 'type phpinspect-cache-containing-types)) - (setq get-form - (inline-quote - (phpinspect-cache-query--do-get-type - ,group ,param ,type ,member ,namespace ,implements ,extends)))) - ((and (eq 'function type) (not member)) - (setq get-form - (inline-quote - (phpinspect-cache-query--do-get-function - ,group ,param ,type ,member ,namespace ,implements ,extends)))) - (t (inline-error "Get not supported for entity type %s" type)))) - get-form)) + (cl-assert (symbolp type)) + + (cond + ((memq type (cons '@type phpinspect-cache-containing-types)) + `(phpinspect-cache-query--do-get-type + ,group ,param (quote ,type) ,member ,namespace ,implements ,extends)) + ((and (eq '@function type) (not member)) + `(phpinspect-cache-query--do-get-function + ,group ,param ,type ,member ,namespace ,implements ,extends)) + ((and (memq type phpinspect-cache-member-types) member) + `(phpinspect-cache-query--do-get-member + ,cache ,group ,param (quote ,type) ,member ,namespace)) + (t (error "Get not supported for entity type %s" type)))) (defmacro phpinspect-cache-query--wrap-action (action cache group param type member namespace implements extends) - (let ((cache-sym (gensym "cache")) - (group-sym (gensym "group")) - (param-sym (gensym "param")) - (member-sym (gensym "member")) - (namespace-sym (gensym "namespace")) - (implements-sym (gensym "implements")) - (extends-sym (gensym "extends"))) + (let* ((param-sym (gensym "param"))) `(let ((,param-sym ,param)) (if (and (sequencep ,param-sym) (not (phpinspect-name-p ,param-sym))) - (let* ((,cache-sym ,cache) - (,group-sym ,group) - (,member-sym ,member) - (,namespace-sym ,namespace) - (,implements-sym ,implements) - (,extends-sym ,extends) - (result (cons 'phpinspect-cache-multiresult nil)) + (let* ((result (cons 'phpinspect-cache-multiresult nil)) (result-rear result)) (seq-doseq (p ,param-sym) (when-let ((action-result - (,action ,cache-sym ,group-sym p ,type ,member-sym - ,namespace-sym ,implements-sym ,extends-sym))) + (,action ,cache ,group p ,type ,member + ,namespace ,implements ,extends))) (setq result-rear (setcdr result-rear (cons action-result nil))))) @@ -796,7 +951,7 @@ then returned." t "Spec car must be the symbol `project' or `label'") (let ((group (gethash spec (phpinspect-cache-groups cache)))) (when (and (eq :insert intent) (not group)) - (setq group (puthash spec (phpinspect-make-cache-group) + (setq group (puthash spec (phpinspect-make-cache-group :spec spec) (phpinspect-cache-groups cache)))) (push group groups))) (if (eq :insert intent) @@ -805,77 +960,106 @@ then returned." groups)) -(define-inline phpinspect-cache-transact (cache group-specs &rest query) +(defmacro phpinspect-cache-transact (cache group-specs &rest query) (declare (indent 2)) (cl-assert (listp query)) (let (type intent intent-param member namespace implements extends key value) - (condition-case err - (progn - (while (setq key (pop query)) - (cl-assert (keywordp key) t "Query keys must be keywords, %s provided" key) - (setq value (pop query)) - (cl-assert value t "Key %s has no value" key) - - (pcase key - ((or :insert :get :delete) - (when intent - (inline-error "Defined duplicate intent: %s, %s" intent key)) - (setq intent key - intent-param value)) - (:as (cl-assert (and (inline-const-p value) - (memq (inline-const-val value) phpinspect-cache-types)) - t ":type must be one of %s" phpinspect-cache-types) - (setq type (inline-const-val value))) - (:member-of (setq member value)) - (:in (setq namespace value)) - (:implementing (setq implements value)) - (:extending (setq extends value)) - (_ (error "Unexpected query keyword %s" key)))) - - ;; Query validation - (unless type - (error "Providing entity type with keyword :as is required.")) - - (when (and member (not (memq type phpinspect-cache-member-types))) - (error "Keyword :member-of can only be used for types %s" - phpinspect-cache-member-types)) - - (when (and extends (not (memq type '(class trait interface type)))) - (error "Keyword :extending cannot be used for types other than %s" - '(class trait interface))) - - (when (eq :insert intent) - (when (and (memq type '(variable method abstract-method)) (not member)) - (error "Variable and methods must be member of %s." - phpinspect-cache-containing-types)) - - (when (eq 'type type) - (error ":as 'type cannot be used for insertions."))) - - (when (and intent (not intent-param)) - (error "Intent %s must have a parameter %s" intent))) - (t (inline-error "phpinspect-cache-transact: %s" err))) - - - (inline-letevals (group-specs intent-param cache type member namespace implements extends) - (let* ((action-args `(,intent-param (quote ,type) ,member ,namespace ,implements ,extends)) + (while (setq key (pop query)) + (cl-assert (keywordp key) t "Query keys must be keywords, %s provided" key) + (setq value (pop query)) + + ;; Namespace is allowed to be dynamic/nil + (unless (eq :in key) + (cl-assert value t "Key %s has no value" key)) + + (pcase key + ((or :insert :get :delete) + (when intent + (error "Defined duplicate intent: %s, %s" intent key)) + (setq intent key + intent-param value)) + (:as (unless (and (symbolp value) + (memq value phpinspect-cache-types)) + (error ":type must be one of %s, %s provided" + phpinspect-cache-types value)) + (setq type value)) + (:member-of (setq member value)) + (:in (setq namespace value)) + (:implementing (setq implements value)) + (:extending (setq extends value)) + (_ (error "Unexpected query keyword %s" key)))) + + ;; Query validation + (unless type + (error "Providing entity type with keyword :as is required.")) + + (when (and member (not (memq type phpinspect-cache-member-types))) + (error "Keyword :member-of can only be used for types %s" + phpinspect-cache-member-types)) + + (when (and extends (not (memq type '(@class @trait @interface @type)))) + (error "Keyword :extending cannot be used for types other than %s" + '(class trait interface))) + + (when (eq :insert intent) + (when (and (memq type '(@variable @method @abstract-method)) (not member)) + (error "Variable and methods must be member of %s." + phpinspect-cache-containing-types)) + + (when (eq '@type type) + (error ":as @type cannot be used for insertions."))) + + (when (and intent (not intent-param)) + (error "Intent %s must have a parameter %s" intent)) + + (let ((group-specs-sym (make-symbol "group-specs")) + (intent-param-sym (make-symbol "intent-param")) + (cache-sym (make-symbol "cache")) + (member-sym (make-symbol "member")) + (namespace-sym (make-symbol "namespace")) + (implements-sym (make-symbol "implements")) + (extends-sym (make-symbol "extends")) + (resultset-sym (make-symbol "resultset")) + (groups-sym (make-symbol "groups"))) + (let* ((action-args + `(,(if (eq '* intent-param) `(quote ,intent-param) intent-param-sym) + ,type + ,(if member member-sym nil) + ,(if namespace namespace-sym nil) + ,(if implements implements-sym nil) + ,(if extends extends-sym nil))) + (validate-args + `(,(if (eq '* intent-param) `(quote ,intent-param) intent-param-sym) + (quote ,type) + ,(if member member-sym nil) + ,(if namespace namespace-sym nil) + ,(if implements implements-sym nil) + ,(if extends extends-sym nil))) (action (pcase intent (:insert 'phpinspect-cache-query--do-insert) (:delete 'phpinspect-cache-query--do-delete) (:get 'phpinspect-cache-query--do-get) - (_ (inline-error "Invalid intent %s" intent))))) - (inline-quote - (let ((groups (phpinspect-cache-query--compile-groups ,cache ,group-specs ,intent)) - resultset) - ,(cons 'phpinspect-cache-query--validate (cons intent action-args)) - (dolist (group groups) + (_ (error "Invalid intent %s" intent))))) + `(let* ,(seq-filter + (lambda (val) val) + `((,group-specs-sym ,group-specs) + ,(unless (eq '* intent-param) `(,intent-param-sym ,intent-param)) + ,(when cache `(,cache-sym ,cache)) + ,(when member `(,member-sym ,member)) + ,(when namespace `(,namespace-sym ,namespace)) + ,(when implements `(,implements-sym ,implements)) + ,(when extends `(,extends-sym ,extends)) + (,groups-sym (phpinspect-cache-query--compile-groups ,cache ,group-specs ,intent)) + ,resultset-sym)) + ,(cons 'phpinspect-cache-query--validate (cons intent validate-args)) + (dolist (group ,groups-sym) (when-let ((result ,(cons 'phpinspect-cache-query--wrap-action (cons action (cons cache (cons 'group action-args)))))) (if (and (listp result) (eq 'phpinspect-cache-multiresult (car result))) - (setq resultset (nconc resultset (cdr result))) - (push result resultset)))) - resultset)))))) + (setq ,resultset-sym (nconc ,resultset-sym (cdr result))) + (push result ,resultset-sym)))) + ,resultset-sym))))) (defun phpinspect-cache-query--validate (intent intent-param type member namespace implements extends) @@ -884,7 +1068,7 @@ then returned." (cond ((phpinspect--type-p intent-param) (cond - ((not (memq type '(class trait interface type))) + ((not (memq type '(@class @trait @interface @type))) (error "Cannot use intent-param of type phpinspect--type when querying for %s" type)) ((and (phpinspect--type-fully-qualified intent-param) namespace) @@ -893,7 +1077,7 @@ then returned." t) ((phpinspect-name-p intent-param) t) ((listp intent-param) - (if (memq type '(class trait interface type)) + (if (memq type '(@class @trait @interface @type)) (unless (seq-every-p #'phpinspect--type-p intent-param) (error "Each intent param must be of type `phpinspect--type'. Got: %s" intent-param)) (pcase intent @@ -905,9 +1089,7 @@ then returned." (unless (seq-every-p #'phpinspect-name-p intent-param) (error "Each intent param must be a name, got: %s" intent-param))) (:delete - (unless (or (seq-every-p #'phpinspect-name-p intent-param) - (seq-every-p #'phpinspect--variable-p intent-param) - (seq-every-p #'phpinspect--function-p intent-param)) + (unless (or (seq-every-p #'phpinspect-name-p intent-param)) (error "Each intent param must be an instance of `phpinspect--function', `phpinspect--variable' or `phpinspect-name'"))))) t) ((eq '* intent-param) @@ -917,7 +1099,7 @@ then returned." (cond ((not (memq intent '(:insert :delete))) (error "`phpinspect--function' can only be used as parameter for :insert and :delete intents.")) - ((not (memq type '(function method abstract-method))) + ((not (memq type '(@function @method @abstract-method))) (error "Inserting/deleting `phpinspect--function' as type %s is not supported" type))) t) (t (error "Unsupported intent-param %s" intent-param))) diff --git a/phpinspect-type.el b/phpinspect-type.el index ace1605..689f86f 100644 --- a/phpinspect-type.el +++ b/phpinspect-type.el @@ -321,6 +321,9 @@ mutability of the variable") (not (or (phpinspect--variable-static-p variable) (phpinspect--variable-const-p variable)))) +(defun phpinspect--variable-name-symbol (variable) + (phpinspect-intern-name (phpinspect--variable-name variable))) + (defun phpinspect--use-to-type (use) (let* ((fqn (cadr (cadr use))) (type (phpinspect--make-type :name (if (string-match "^\\\\" fqn) diff --git a/test/test-cache.el b/test/test-cache.el index 0956380..1383be8 100644 --- a/test/test-cache.el +++ b/test/test-cache.el @@ -30,11 +30,11 @@ (let ((cache (phpinspect-make-cache)) result) (phpinspect-cache-transact cache '((label test)) - :insert (phpinspect--make-type :name "\\TestClass") :as 'class) + :insert (phpinspect--make-type :name "\\TestClass") :as @class) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestClass") :as 'class)) + :get (phpinspect--make-type :name "\\TestClass") :as @class)) (should result) (should (listp result)) @@ -42,11 +42,11 @@ (should (phpinspect-cache-type-p (car result))) (phpinspect-cache-transact cache '((label test)) - :insert (phpinspect--make-type :name "\\TestInterface") :as 'interface) + :insert (phpinspect--make-type :name "\\TestInterface") :as @interface) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestInterface") :as 'interface)) + :get (phpinspect--make-type :name "\\TestInterface") :as @interface)) (should result) (should (listp result)) @@ -57,13 +57,13 @@ ;; entity was inserted as, nothing should be returned. (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestInterface") :as 'class)) + :get (phpinspect--make-type :name "\\TestInterface") :as @class)) (should-not result) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestInterface") :as 'type)) + :get (phpinspect--make-type :name "\\TestInterface") :as @type)) (should result) @@ -71,7 +71,7 @@ (phpinspect-cache-transact cache '((label test)) :get `(,(phpinspect--make-type :name "\\TestInterface") ,(phpinspect--make-type :name "\\TestClass")) - :as 'type)) + :as @type)) (should result) (should (= 2 (length result))) (should (seq-every-p #'phpinspect-cache-type-p result)) @@ -80,64 +80,64 @@ (phpinspect-cache-transact cache '((label test)) :get `(,(phpinspect--make-type :name "\\TestInterface") ,(phpinspect--make-type :name "\\TestClass")) - :as 'interface)) + :as @interface)) (should result) (should (= 1 (length result))) (should (seq-every-p #'phpinspect-cache-type-p result)) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* :as 'type)) + :get * :as @type)) (should result) (should (= 2 (length result))) (should (seq-every-p #'phpinspect-cache-type-p result)) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestClass") :as 'type)) + :get (phpinspect--make-type :name "\\TestClass") :as @type)) (should result) (setq result (phpinspect-cache-transact cache '((label test)) - :delete (phpinspect--make-type :name "\\TestClass") :as 'type)) + :delete (phpinspect--make-type :name "\\TestClass") :as @type)) (should result) (should (phpinspect-cache-type-p (car result))) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestClass") :as 'type)) + :get (phpinspect--make-type :name "\\TestClass") :as @type)) (should-not result) (setq result (phpinspect-cache-transact cache '((label test)) - :delete (phpinspect--make-type :name "\\TestClass") :as 'type)) + :delete (phpinspect--make-type :name "\\TestClass") :as @type)) (should-not result) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestInterface") :as 'type)) + :get (phpinspect--make-type :name "\\TestInterface") :as @type)) (should result) (setq result (phpinspect-cache-transact cache '((label test)) - :delete (phpinspect--make-type :name "\\TestInterface") :as 'class)) + :delete (phpinspect--make-type :name "\\TestInterface") :as @class)) (should-not result) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestInterface") :as 'type)) + :get (phpinspect--make-type :name "\\TestInterface") :as @type)) (should result) (setq result (phpinspect-cache-transact cache '((label test)) - :delete (phpinspect--make-type :name "\\TestInterface") :as 'interface)) + :delete (phpinspect--make-type :name "\\TestInterface") :as @interface)) (should result) (setq result (phpinspect-cache-transact cache '((label test)) - :get (phpinspect--make-type :name "\\TestInterface") :as 'type)) + :get (phpinspect--make-type :name "\\TestInterface") :as @type)) (should-not result))) (ert-deftest phpinspect-cache-namespace-query () @@ -147,18 +147,18 @@ :insert (list (phpinspect--make-type :name "\\Namespace1\\TestClass") (phpinspect--make-type :name "\\Namespace2\\TestClass") (phpinspect--make-type :name "\\Namespace2\\TestClass1")) - :as 'class) + :as @class) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* :as 'class :in (phpinspect-intern-name "\\Namespace1"))) + :get * :as @class :in (phpinspect-intern-name "\\Namespace1"))) (should result) (should (= 1 (length result))) (should (eq (phpinspect-intern-name "\\Namespace1\\TestClass") (phpinspect-cache-type-name (car result)))) - (setq result (phpinspect-cache-transact cache '((label test)) - :get '* :as 'class :in (phpinspect-intern-name "\\Namespace2"))) + (setq result (phpinspect-cache-transact cache '((label test)) + :get * :as @class :in (phpinspect-intern-name "\\Namespace2"))) (should result) (should (= 2 (length result))))) @@ -170,14 +170,14 @@ :insert (list (phpinspect--make-type :name "\\Namespace1\\TestClass") (phpinspect--make-type :name "\\Namespace2\\TestClass") (phpinspect--make-type :name "\\Namespace2\\TestClass1")) - :as 'class) + :as @class) (phpinspect-cache-transact cache '((label test)) - :delete '* :as 'class) + :delete * :as @class) (should-not (phpinspect-cache-transact cache '((label test)) - :get '* :as 'class)))) + :get * :as @class)))) (ert-deftest phpinspect-cache-delete-wildcard-namespace-types () (let ((cache (phpinspect-make-cache)) @@ -186,13 +186,13 @@ :insert (list (phpinspect--make-type :name "\\Namespace1\\TestClass") (phpinspect--make-type :name "\\Namespace2\\TestClass") (phpinspect--make-type :name "\\Namespace2\\TestClass1")) - :as 'class) + :as @class) (phpinspect-cache-transact cache '((label test)) - :delete '* :as 'class :in (phpinspect-intern-name "\\Namespace2")) + :delete * :as @class :in (phpinspect-intern-name "\\Namespace2")) - (setq result (phpinspect-cache-transact cache '((label test)) :get '* :as 'class)) + (setq result (phpinspect-cache-transact cache '((label test)) :get * :as @class)) (should result) (should (= 1 (length result))) (should (eq (phpinspect-intern-name "\\Namespace1\\TestClass") @@ -203,7 +203,7 @@ result) (setq result (phpinspect-cache-transact cache '((label test)) :insert (phpinspect--make-function :name "test_func") - :as 'function)) + :as @function)) (should result) (should (phpinspect--function-p (car result))) @@ -212,14 +212,15 @@ (setq result (phpinspect-cache-transact cache '((label test)) :insert (list (phpinspect--make-function :name "test_func") (phpinspect--make-function :name "other_func")) - :as 'function + :as @function :in (phpinspect-intern-name "\\Namespace1"))) + (should result) (should (= 2 (length result))) (setq result (phpinspect-cache-transact cache '((label test)) :get (phpinspect-intern-name "\\test_func") - :as 'function)) + :as @function)) (should result) (should (phpinspect--function-p (car result))) @@ -227,22 +228,22 @@ (setq result (phpinspect-cache-transact cache '((label test)) :delete (phpinspect-intern-name "\\test_func") - :as 'function)) + :as @function)) (should result) (should (phpinspect--function-p (car result))) (should (= 1 (length result))) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* - :as 'function + :get * + :as @function :in (phpinspect-intern-name "\\Namespace1"))) (should result) (should (= 2 (length result))) (setq result (phpinspect-cache-transact cache '((label test)) - :delete '* - :as 'function + :delete * + :as @function :in (phpinspect-intern-name "\\Namespace1"))) (should result) (should (= 2 (length result))) @@ -251,25 +252,25 @@ :insert (list (phpinspect--make-function :name "\\Ns\\test_func") (phpinspect--make-function :name "\\Ns\\other_func") (phpinspect--make-function :name "\\root_func")) - :as 'function) + :as @function) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* :as 'function :in (phpinspect-intern-name "\\Ns"))) + :get * :as @function :in (phpinspect-intern-name "\\Ns"))) (should result) (should (= 2 (length result))) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* :as 'function :in (phpinspect-intern-name "\\"))) + :get * :as @function :in (phpinspect-intern-name "\\"))) (should result) (should (= 1 (length result))) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* :as 'function)) + :get * :as @function)) (should result) (should (= 3 (length result))) (setq result (phpinspect-cache-transact cache '((label test)) - :delete '* :as 'function)) + :delete * :as @function)) (should result) (should (= 3 (length result))))) @@ -280,7 +281,7 @@ (setq result (phpinspect-cache-transact cache '((label test)) :insert (phpinspect--make-type :name "\\Namespace1\\TestClass") - :as 'class + :as @class :extending (phpinspect--make-type :name "\\App\\TestClassAbstract") :implementing (phpinspect--make-type :name "\\App\\TestInterface"))) @@ -295,9 +296,9 @@ (car (phpinspect-cache-type-get-implements result)))) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* + :get * :implementing (phpinspect-intern-name "\\App\\TestInterface") - :as 'type)) + :as @type)) (should result) (should (= 1 (length result))) @@ -305,9 +306,9 @@ (phpinspect-cache-type-name (car result)))) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* + :get * :extending (phpinspect-intern-name "\\App\\TestClassAbstract") - :as 'type)) + :as @type)) (should result) (should (= 1 (length result))) @@ -315,8 +316,201 @@ (phpinspect-cache-type-name (car result)))) (setq result (phpinspect-cache-transact cache '((label test)) - :get '* + :get * :extending (phpinspect-intern-name "\\App\\TestClass") - :as 'type)) + :as @type)) + + (should-not result) + + (setq result (phpinspect-cache-transact cache '((label test)) + :delete (phpinspect--make-type :name "\\Namespace1\\TestClass") + :as @type)) + + (should result) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get * + :extending (phpinspect-intern-name "\\App\\TestClassAbstract") + :as @type)) + + (should-not result) + + (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-type :name "\\Namespace1\\TestClass") + :as @class) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get * + :extending (phpinspect-intern-name "\\App\\TestClassAbstract") + :as @type)) + + (should-not result) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get * + :implementing (phpinspect-intern-name "\\App\\TestInterface") + :as @type)) (should-not result))) + +(ert-deftest phpinspect-cache-insert-method () + (let ((cache (phpinspect-make-cache)) + result) + + + (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-type :name "\\TestClass") + :as @class) + + (setq result (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-function :name "testMethod") + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get (phpinspect-intern-name "testMethod") + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + (should (= 1 (length result))) + (should (phpinspect--function-p (car result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get (phpinspect-intern-name "testMethod") + :as @method + :member-of (phpinspect--make-type :name "\\Banana"))) + + (should-not result) + + + (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-function :name "newTestMethod") + :as @method + :member-of (phpinspect--make-type :name "\\TestClass")) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get (phpinspect-intern-name "testMethod") + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + (should (= 1 (length result))) + (should (phpinspect--function-p (car result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get * + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + (should result) + (should (= 2 (length result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :delete (phpinspect-intern-name "testMethod") + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + (should (= 1 (length result))) + + (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-function :name "testMethod") + :as @method + :member-of (phpinspect--make-type :name "\\TestClass")) + + (setq result (phpinspect-cache-transact cache '((label test)) + :delete * + :as @function + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + (should (= 2 (length result))) + + (should-not + (phpinspect-cache-transact cache '((label test)) + :get * + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))))) + +(ert-deftest phpinspect-cache-delete-method-multi () + (let ((cache (phpinspect-make-cache)) + result) + + (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-type :name "\\TestClass") :as @class) + + (phpinspect-cache-transact cache '((label test)) + :insert (list (phpinspect--make-function :name "test1") + (phpinspect--make-function :name "test3") + (phpinspect--make-function :name "test2")) + :as @method + :member-of (phpinspect--make-type :name "\\TestClass")) + + (setq result (phpinspect-cache-transact cache '((label test)) + :delete (list (phpinspect-intern-name "test1") + (phpinspect-intern-name "test2")) + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + (should result) + (should (= 2 (length result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get * + :as @method + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + (should (= 1 (length result))) + (should (string= "test3" (phpinspect--function-name (car result)))))) + +(ert-deftest phpinspect-cache-insert-variable () + (let ((cache (phpinspect-make-cache)) + result) + + (phpinspect-cache-transact cache '((label test)) + :insert (phpinspect--make-type :name "\\TestClass") :as @class) + + (setq result (phpinspect-cache-transact cache '((label test)) + :insert (list (phpinspect--make-variable :name "test1") + (phpinspect--make-variable :name "test3") + (phpinspect--make-variable :name "test2")) + :as @variable + :member-of (phpinspect--make-type :name "\\TestClass"))) + + (should result) + (should (= 3 (length result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get * + :as @variable + :member-of (phpinspect--make-type :name "\\TestClass"))) + (should result) + (should (= 3 (length result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :get (phpinspect-intern-name "test2") + :as @variable + :member-of (phpinspect--make-type :name "\\TestClass"))) + (should result) + (should (= 1 (length result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :delete (phpinspect-intern-name "test2") + :as @variable + :member-of (phpinspect--make-type :name "\\TestClass"))) + (should result) + (should (= 1 (length result))) + + (setq result (phpinspect-cache-transact cache '((label test)) + :delete * + :as @variable + :member-of (phpinspect--make-type :name "\\TestClass"))) + (should result) + (should (= 2 (length result))) + + (should-not (phpinspect-cache-transact cache '((label test)) + :get * + :as @variable + :member-of (phpinspect--make-type :name "\\TestClass")))))