summaryrefslogtreecommitdiff
path: root/phpinspect-imports.el
diff options
context:
space:
mode:
authorHugo Thunnissen <devel@hugot.nl>2022-11-01 22:13:41 +0100
committerHugo Thunnissen <devel@hugot.nl>2022-11-01 22:13:41 +0100
commitdbf0ec03903e4ec795659c982e772d147ea1144c (patch)
treec29fa08dd1d385f9476bb641ebe60ce8ec2003f3 /phpinspect-imports.el
parentca8d0972ffae56700e662411280af65fa449b8d7 (diff)
Transition from index script to autoloader
Diffstat (limited to 'phpinspect-imports.el')
-rw-r--r--phpinspect-imports.el155
1 files changed, 155 insertions, 0 deletions
diff --git a/phpinspect-imports.el b/phpinspect-imports.el
new file mode 100644
index 0000000..c6c7d09
--- /dev/null
+++ b/phpinspect-imports.el
@@ -0,0 +1,155 @@
+; phpinspect-imports.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:
+
+;; See docstrings for documentation, starting with `phpinspect-mode'.
+
+;;; Code:
+
+(require 'phpinspect-parser)
+(require 'phpinspect-index)
+(require 'phpinspect-autoload)
+(require 'phpinspect-buffer)
+
+(defun phpinspect-insert-at-point (point data)
+ (save-excursion
+ (goto-char point)
+ (insert data)))
+
+(defun phpinspect-add-use (fqn buffer &optional namespace-token)
+ "Add use statement for FQN to BUFFER.
+
+If NAMESPACE-TOKEN is non-nil, it is assumed to be a token that
+was parsed from BUFFER and its location will be used to find a
+buffer position to insert the use statement at."
+ (when (string-match "^\\\\" fqn)
+ (setq fqn (string-trim-left fqn "\\\\")))
+
+ (if namespace-token
+ (let* ((region (gethash
+ namespace-token (phpinspect-buffer-location-map buffer)))
+ (existing-use (seq-find #'phpinspect-use-p
+ (phpinspect-namespace-body namespace-token)))
+ (namespace-block (phpinspect-namespace-block namespace-token)))
+ (if existing-use
+ (phpinspect-insert-at-point
+ (phpinspect-region-start
+ (phpinspect-buffer-token-location buffer existing-use))
+ (format "use %s;%c" fqn ?\n))
+ (if namespace-block
+ (phpinspect-insert-at-point
+ (+ 1 (phpinspect-region-start
+ (phpinspect-buffer-token-location buffer namespace-block)))
+ (format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))
+ (phpinspect-insert-at-point
+ (phpinspect-region-end
+ (phpinspect-buffer-token-location
+ buffer (seq-find #'phpinspect-terminator-p namespace-token)))
+ (format "%c%cuse %s;%c" ?\n ?\n fqn ?\n)))))
+ ;; else
+ (let ((existing-use (seq-find #'phpinspect-use-p
+ (phpinspect-buffer-tree buffer))))
+ (if existing-use
+ (phpinspect-insert-at-point
+ (phpinspect-region-start
+ (phpinspect-buffer-token-location buffer existing-use))
+ (format "use %s;%c" fqn ?\n))
+ (let ((first-token (cadr (phpinspect-buffer-tree buffer))))
+ (if (and (phpinspect-word-p first-token)
+ (string= "declare" (cadr first-token)))
+ (phpinspect-insert-at-point
+ (phpinspect-region-end
+ (phpinspect-buffer-token-location
+ buffer (seq-find #'phpinspect-terminator-p (phpinspect-buffer-tree buffer))))
+ (format "%c%cuse %s;%c" ?\n ?\n fqn ?\n))
+ (phpinspect-insert-at-point
+ (phpinspect-region-start
+ (phpinspect-buffer-token-location buffer first-token))
+ (format "%c%cuse %s;%c%c" ?\n ?\n fqn ?\n ?\n))))))))
+
+(defun phpinspect-add-use-interactive (typename buffer project &optional namespace-token)
+ (let* ((autoloader (phpinspect--project-autoload project))
+ (fqn-bags (phpinspect-autoloader-type-name-fqn-bags autoloader)))
+
+ (let ((fqns (gethash typename fqn-bags)))
+ (cond ((= 1 (length fqns))
+ (phpinspect-add-use (symbol-name (car fqns)) buffer namespace-token))
+ ((> (length fqns) 1)
+ (phpinspect-add-use (symbol-name (completing-read "Class: " fqns))
+ buffer namespace-token))
+ (t (message "No import found for type %s" typename))))))
+
+(defun phpinspect-namespace-part-of-typename (typename)
+ (string-trim-right typename "\\\\?[^\\\\]+"))
+
+(defalias 'phpinspect-fix-uses-interactive #'phpinspect-fix-imports
+ "Alias for backwards compatibility")
+
+(defun phpinspect-fix-imports ()
+ "Find types that are used in the current buffer and make sure
+that there are import (\"use\") statements for them."
+ (interactive)
+ (if phpinspect-current-buffer
+ (let* ((tree (phpinspect-buffer-parse phpinspect-current-buffer))
+ (location-map (phpinspect-buffer-location-map phpinspect-current-buffer))
+ (index (phpinspect--index-tokens
+ tree nil (lambda (token) (gethash token location-map))))
+ (classes (alist-get 'classes index))
+ (imports (alist-get 'imports index))
+ (project (phpinspect--cache-get-project-create
+ (phpinspect--get-or-create-global-cache)
+ (phpinspect-project-root))))
+ (dolist (class classes)
+ (let* ((class-imports (alist-get 'imports class))
+ (used-types (alist-get 'used-types class))
+ (region (alist-get 'location class)))
+ (dolist (type used-types)
+ (let ((namespace
+ (seq-find #'phpinspect-namespace-p
+ (phpinspect-buffer-tokens-enclosing-point
+ phpinspect-current-buffer (phpinspect-region-start region)))))
+ ;; Add use statements for types that aren't imported.
+
+ (unless (or (or (alist-get type class-imports)
+ (alist-get type imports))
+ (gethash (phpinspect-intern-name
+ (concat (phpinspect-namespace-part-of-typename
+ (phpinspect--type-name (alist-get 'class-name class)))
+ "\\"
+ (symbol-name type)))
+ (phpinspect-autoloader-types
+ (phpinspect--project-autoload project))))
+ (phpinspect-add-use-interactive
+ type phpinspect-current-buffer project namespace)
+ ;; Buffer has been modified by adding type, update tree +
+ ;; location map. This is not optimal but will have to do until
+ ;; partial parsing is implemented.
+ ;;
+ ;; Note: this basically implements a bug where the locations
+ ;; of classes are no longer congruent with their location in
+ ;; the buffer's code. In files that contain multiple namespace
+ ;; blocks this could cause problems as a namespace may grow by
+ ;; added import statements and start envelopping the classes
+ ;; below it.
+ (phpinspect-buffer-parse phpinspect-current-buffer)))))))))
+
+(provide 'phpinspect-imports)