You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
558 lines
29 KiB
EmacsLisp
558 lines
29 KiB
EmacsLisp
;;; phpinspect-buffer.el --- PHP parsing and completion package -*- lexical-binding: t; -*-
|
|
|
|
;; Copyright (C) 2021-2023 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-class)
|
|
(require 'phpinspect-parser)
|
|
(require 'phpinspect-bmap)
|
|
(require 'phpinspect-edtrack)
|
|
(require 'phpinspect-index)
|
|
(require 'phpinspect-toc)
|
|
(require 'phpinspect-resolvecontext)
|
|
(require 'phpinspect-resolve)
|
|
(require 'phpinspect-util)
|
|
|
|
(phpinspect--declare-log-group 'buffer)
|
|
|
|
(defvar-local phpinspect-current-buffer nil
|
|
"An instance of `phpinspect-buffer' local to the active
|
|
buffer. This variable is only set for buffers where
|
|
`phpinspect-mode' is active. Also see `phpinspect-buffer'.")
|
|
|
|
(cl-defstruct (phpinspect-buffer (:constructor phpinspect-make-buffer))
|
|
"An object containing phpinspect related metadata linked to an
|
|
emacs buffer."
|
|
(buffer nil
|
|
:type buffer
|
|
:documentation "The associated emacs buffer")
|
|
(tree nil
|
|
:documentation
|
|
"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))
|
|
|
|
(defun phpinspect-buffer-project (buffer)
|
|
(or (phpinspect-buffer--project buffer)
|
|
(with-current-buffer (phpinspect-buffer-buffer buffer)
|
|
(phpinspect--cache-get-project-create (phpinspect--get-or-create-global-cache)
|
|
(phpinspect-current-project-root)))))
|
|
|
|
(defun phpinspect-buffer-tainted-p (buffer)
|
|
"Whether or not BUFFER's current tree needs updating to incorporate edits."
|
|
(and (phpinspect-edtrack-taint-pool (phpinspect-buffer-edit-tracker buffer)) t))
|
|
|
|
(defun phpinspect-buffer-needs-parse-p (buffer)
|
|
"Whether or not BUFFER needs to be parsed for an updated tree to be present."
|
|
(or (not (phpinspect-buffer-tree buffer))
|
|
(phpinspect-buffer-tainted-p buffer)))
|
|
|
|
(defun phpinspect-buffer-fresh-p (buffer)
|
|
"Whether or not BUFFER's metadata is fresh.
|
|
|
|
A buffer's metadata is fresh when the buffer's last parsed tree
|
|
was parsed from scratch and no edits have been applied
|
|
afterwards. An incrementally parsed tree that has incorporated
|
|
edits does not count as fresh (because incremental parsing has its flaws)."
|
|
(and (not (phpinspect-buffer-needs-parse-p buffer))
|
|
;; If the buffer map has overlays, the last parsed tree has incorporated
|
|
;; edits and is not fresh.
|
|
(phpinspect-splayt-empty-p (phpinspect-bmap-overlays (phpinspect-buffer-map buffer)))))
|
|
|
|
(defun phpinspect-buffer-reparse-if-not-fresh (buffer)
|
|
"If BUFFER's tree is fresh, return it. Otherwise reparse the
|
|
buffer and return the result."
|
|
(if (phpinspect-buffer-fresh-p buffer)
|
|
(phpinspect-buffer-tree buffer)
|
|
(phpinspect-buffer-reparse buffer)))
|
|
|
|
(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))
|
|
(if (phpinspect-buffer-needs-parse-p buffer)
|
|
(with-current-buffer (phpinspect-buffer-buffer buffer)
|
|
(let* ((map (phpinspect-make-bmap))
|
|
(buffer-map (phpinspect-buffer-map buffer))
|
|
(ctx (phpinspect-make-pctx
|
|
:interrupt-predicate (unless no-interrupt #'phpinspect--input-pending-p)
|
|
:bmap map
|
|
:incremental t
|
|
:previous-bmap buffer-map
|
|
:edtrack (phpinspect-buffer-edit-tracker buffer))))
|
|
(phpinspect-with-parse-context ctx
|
|
(phpinspect--log "Parsing buffer")
|
|
(let ((parsed (phpinspect-parse-current-buffer)))
|
|
(setf (phpinspect-buffer-map buffer) map)
|
|
(setf (phpinspect-buffer-tree buffer) parsed)
|
|
(phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer))
|
|
|
|
;; set return value
|
|
(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)
|
|
(phpinspect--log "Setting index reference for token %s" token)
|
|
(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)
|
|
(phpinspect--log "Updating index reference for old token %s to new token %s" 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))
|
|
|
|
(phpinspect--log "Deleting index for token %s" 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)
|
|
(let (imports namespace-name class-name class-obj)
|
|
(pcase-setq `(,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)))
|
|
(when class-name
|
|
(setq 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))
|
|
(when class-name
|
|
(setq 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)))
|
|
(unless (phpinspect--function-anonyous-p indexed)
|
|
(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)
|
|
;; We have left the class we were previously indexing properties
|
|
;; for.
|
|
(when (and class (> (phpinspect-meta-start var) (phpinspect-meta-end class)))
|
|
(setq class nil))
|
|
|
|
;; Retrieve the class that the property belongs to. In a lot of cases only
|
|
;; one class will be in the current buffer. But PHP allows the definition
|
|
;; of multiple classes in the same file so this should be supported.
|
|
(unless class
|
|
(setq class (phpinspect-toc-token-at-point classes (phpinspect-meta-start var))))
|
|
|
|
;; Fetch the index for the current class
|
|
(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)))
|
|
;; Variable is defined as [scope?] static [type?] $variable
|
|
(progn
|
|
(setq static (phpinspect-meta-parent var))
|
|
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent static)))
|
|
;; Variable is defined as scope static [type?] $variable
|
|
(setq scope `(,(car (phpinspect-meta-token (phpinspect-meta-parent static)))
|
|
,@(phpinspect-meta-token-with-left-siblings var))
|
|
comment-before (phpinspect-meta-find-left-sibling (phpinspect-meta-parent static)))))
|
|
(when (phpinspect-scope-p (phpinspect-meta-token (phpinspect-meta-parent var)))
|
|
;; Variable is defined as scope [type?] $variable
|
|
(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 ,@(mapcar #'phpinspect-meta-token (phpinspect-meta-left-siblings var))
|
|
,(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)))
|
|
(setf (phpinspect--variable-type indexed)
|
|
(phpinspect--class-resolve-property-type
|
|
class-obj (phpinspect-buffer-project buffer)
|
|
(cadr (phpinspect-meta-token var)) type-resolver class)))
|
|
|
|
(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-reset ((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)
|
|
(setf (phpinspect-buffer-namespaces buffer) nil)
|
|
(setf (phpinspect-buffer-classes buffer) nil)
|
|
(setf (phpinspect-buffer-class-variables buffer) nil)
|
|
(setf (phpinspect-buffer-functions buffer) nil)
|
|
(setf (phpinspect-buffer-token-index buffer)
|
|
(make-hash-table :test 'eq :size 100 :rehash-size 1.5))
|
|
(phpinspect-edtrack-clear (phpinspect-buffer-edit-tracker buffer)))
|
|
|
|
(cl-defmethod phpinspect-buffer-reparse ((buffer phpinspect-buffer))
|
|
(phpinspect-buffer-reset buffer)
|
|
(phpinspect-buffer-parse buffer 'no-interrupt))
|
|
|
|
(cl-defmethod phpinspect-buffer-reindex ((buffer phpinspect-buffer))
|
|
(dolist (token (hash-table-keys (phpinspect-buffer-token-index buffer)))
|
|
(phpinspect-buffer-delete-index-for-token buffer token))
|
|
|
|
(phpinspect-buffer-reparse buffer)
|
|
(phpinspect-buffer-update-project-index buffer))
|
|
|
|
(cl-defmethod phpinspect-buffer-update-project-index ((buffer phpinspect-buffer))
|
|
"Update project index using the last parsed token map of this
|
|
buffer. When `phpinspect-buffer-parse' has been executed before
|
|
and a map is available from the previous parse, this is used. If
|
|
none is available `phpinspect-buffer-parse' is called before
|
|
continuing execution."
|
|
|
|
;; Parse buffer if no map is available.
|
|
(unless (phpinspect-buffer-map buffer)
|
|
(phpinspect-buffer-parse buffer))
|
|
|
|
(phpinspect--log "Preparing to update project index")
|
|
;; Use inhibit-quit to prevent index corruption though partial index
|
|
;; application.
|
|
(let ((inhibit-quit t))
|
|
(when (phpinspect-buffer-project buffer)
|
|
(let ((map (phpinspect-buffer-map buffer)))
|
|
(unless (eq map (phpinspect-buffer--last-indexed-bmap buffer))
|
|
(phpinspect--log "Updating project index")
|
|
(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))
|
|
|
|
(cl-defmethod phpinspect-buffer-register-edit
|
|
((buffer phpinspect-buffer) (start integer) (end integer) (pre-change-length integer))
|
|
"Mark a region of the buffer as edited."
|
|
|
|
;; Take into account "atoms" (tokens without clear delimiters like words,
|
|
;; variables and object attributes. The meaning of these tokens will change as
|
|
;; they grow or shrink, so their full regions need to be marked for a reparse).
|
|
(save-excursion
|
|
(goto-char start)
|
|
(when (looking-back "\\(\\$\\|->\\|::\\)?[^][)(}{[:blank:]\n;'\"]+" nil t)
|
|
(setq start (- start (length (match-string 0))))
|
|
(setq pre-change-length (+ pre-change-length (length (match-string 0))))))
|
|
|
|
(phpinspect-edtrack-register-edit
|
|
(phpinspect-buffer-edit-tracker buffer) start end pre-change-length))
|
|
|
|
(cl-defmethod phpinspect-buffer-tokens-enclosing-point ((buffer phpinspect-buffer) point)
|
|
(phpinspect-bmap-tokens-overlapping (phpinspect-buffer-map buffer) point))
|
|
|
|
(cl-defmethod phpinspect-buffer-token-meta ((buffer phpinspect-buffer) token)
|
|
(phpinspect-bmap-token-meta (phpinspect-buffer-map buffer) token))
|
|
|
|
(cl-defmethod phpinspect-buffer-location-resolver ((buffer phpinspect-buffer))
|
|
"Derive location resolver from BUFFER's buffer map. Guarantees to
|
|
retrieve the lastest available map of BUFFER upon first
|
|
invocation, but subsequent invocations will not update the used
|
|
map afterwards, so don't keep the resolver around for long term
|
|
use."
|
|
(let ((bmap-resolver))
|
|
(lambda (token)
|
|
(funcall (with-memoization bmap-resolver
|
|
(phpinspect-bmap-make-location-resolver (phpinspect-buffer-map buffer)))
|
|
token))))
|
|
|
|
(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
|
|
(let ((buffer phpinspect-current-buffer))
|
|
(pop-to-buffer (generate-new-buffer "phpinspect-buffer-index"))
|
|
(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)
|