forked from OSchip/llvm-project
[clang-include-fixer] Added Emacs integration for clang-include-fixer.
Patch by Jens Massberg! Thanks a lot. Differential Revision: https://reviews.llvm.org/D22805 llvm-svn: 276853
This commit is contained in:
parent
470b81ca69
commit
57d070e6fd
|
@ -75,6 +75,25 @@ You can customize the number of headers being shown by setting
|
||||||
|
|
||||||
See ``clang-include-fixer.py`` for more details.
|
See ``clang-include-fixer.py`` for more details.
|
||||||
|
|
||||||
|
Integrate with Emacs
|
||||||
|
--------------------
|
||||||
|
To run `clang-include-fixer` on a potentially unsaved buffer in Emacs.
|
||||||
|
Ensure that Emacs finds ``clang-include-fixer.el`` by adding the directory containing the file to the ``load-path``
|
||||||
|
and requiring the `clang-include-fixer` in your ```.emacs``:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
(add-to-list 'load-path "path/to/llvm/source/tools/clang/tools/extra/include-fixer/tool/"
|
||||||
|
(require 'clang-include-fixer)
|
||||||
|
|
||||||
|
Within Emacs the tool can be invoked with the command ``M-x clang-include-fixer``.
|
||||||
|
|
||||||
|
Make sure Emacs can find :program:`clang-include-fixer`:
|
||||||
|
|
||||||
|
- Add the path to :program:`clang-include-fixer` to the PATH environment variable.
|
||||||
|
|
||||||
|
See ``clang-include-fixer.el`` for more details.
|
||||||
|
|
||||||
How it Works
|
How it Works
|
||||||
============
|
============
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
;;; clang-include-fxier.el --- Emacs integration of the clang include fixer
|
||||||
|
|
||||||
|
;; Keywords: tools, c
|
||||||
|
;; Package-Requires: ((json "1.2"))
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; This package allows to invoke the 'clang-include-fixer' within Emacs.
|
||||||
|
;; 'clang-include-fixer' provides an automated way of adding #include
|
||||||
|
;; directives for missing symbols in one translation unit, see
|
||||||
|
;; <http://clang.llvm.org/extra/include-fixer.html>.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'json)
|
||||||
|
|
||||||
|
(defgroup clang-include-fixer nil
|
||||||
|
"Include fixer."
|
||||||
|
:group 'tools)
|
||||||
|
|
||||||
|
(defcustom clang-include-fixer-executable
|
||||||
|
"clang-include-fixer"
|
||||||
|
"Location of the `clang-include-fixer' executable.
|
||||||
|
|
||||||
|
A string containing the name or the full path of the executable."
|
||||||
|
:group 'clang-include-fixer
|
||||||
|
:type 'string
|
||||||
|
:risky t)
|
||||||
|
|
||||||
|
(defcustom clang-include-fixer-input-format
|
||||||
|
"yaml"
|
||||||
|
"clang-include-fixer input format."
|
||||||
|
:group 'clang-include-fixer
|
||||||
|
:type 'string
|
||||||
|
:risky t)
|
||||||
|
|
||||||
|
(defcustom clang-include-fixer-init-string
|
||||||
|
""
|
||||||
|
"clang-include-fixer input format."
|
||||||
|
:group 'clang-include-fixer
|
||||||
|
:type 'string
|
||||||
|
:risky t)
|
||||||
|
|
||||||
|
|
||||||
|
(defun clang-include-fixer-call-executable (callee
|
||||||
|
include-fixer-parameter-a
|
||||||
|
&optional include-fixer-parameter-b
|
||||||
|
&optional include-fixer-parameter-c
|
||||||
|
)
|
||||||
|
"Calls clang-include-fixer with parameters INCLUDE-FIXER-PARAMETER-[ABC].
|
||||||
|
If the call was successful the returned result is stored in a temp buffer
|
||||||
|
and the function CALLEE is called on this temp buffer."
|
||||||
|
|
||||||
|
(let ((temp-buffer (generate-new-buffer " *clang-include-fixer-temp*"))
|
||||||
|
(temp-file (make-temp-file "clang-include-fixer")))
|
||||||
|
(unwind-protect
|
||||||
|
(let (status stderr operations)
|
||||||
|
(if (eq include-fixer-parameter-c nil)
|
||||||
|
(setq status
|
||||||
|
(call-process-region
|
||||||
|
(point-min) (point-max) clang-include-fixer-executable
|
||||||
|
nil `(,temp-buffer ,temp-file) nil
|
||||||
|
|
||||||
|
"-stdin"
|
||||||
|
include-fixer-parameter-a
|
||||||
|
(buffer-file-name)
|
||||||
|
))
|
||||||
|
(setq status
|
||||||
|
(call-process-region
|
||||||
|
(point-min) (point-max) clang-include-fixer-executable
|
||||||
|
nil `(,temp-buffer ,temp-file) nil
|
||||||
|
|
||||||
|
"-stdin"
|
||||||
|
include-fixer-parameter-a
|
||||||
|
include-fixer-parameter-b
|
||||||
|
include-fixer-parameter-c
|
||||||
|
(buffer-file-name)
|
||||||
|
)))
|
||||||
|
|
||||||
|
(setq stderr
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert-file-contents temp-file)
|
||||||
|
(when (> (point-max) (point-min))
|
||||||
|
(insert ": "))
|
||||||
|
(buffer-substring-no-properties
|
||||||
|
(point-min) (line-end-position))))
|
||||||
|
|
||||||
|
(cond
|
||||||
|
((stringp status)
|
||||||
|
(error "(clang-include-fixer killed by signal %s%s)" status
|
||||||
|
stderr))
|
||||||
|
((not (equal 0 status))
|
||||||
|
(error "(clang-include-fixer failed with code %d%s)" status
|
||||||
|
stderr)))
|
||||||
|
(funcall callee temp-buffer))
|
||||||
|
(delete-file temp-file)
|
||||||
|
(when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun clang-include-fixer-replace_buffer (temp-buffer)
|
||||||
|
"Replace current buffer by content of TEMP-BUFFER"
|
||||||
|
|
||||||
|
(with-current-buffer temp-buffer
|
||||||
|
(setq temp-start (point-min))
|
||||||
|
(setq temp-end (point-max))
|
||||||
|
)
|
||||||
|
(barf-if-buffer-read-only)
|
||||||
|
(erase-buffer)
|
||||||
|
(save-excursion
|
||||||
|
(insert-buffer-substring temp-buffer temp-start temp-end)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun clang-include-fixer-add-header (temp-buffer)
|
||||||
|
"Analyse the result of include-fixer stored in TEMP_BUFFER and add a
|
||||||
|
missing header if there is any. If there are multiple possible headers
|
||||||
|
the user can select one of them to be included."
|
||||||
|
|
||||||
|
(with-current-buffer temp-buffer
|
||||||
|
(setq result (buffer-substring (point-min) (point-max)))
|
||||||
|
(setq include-fixer-context
|
||||||
|
(let ((json-object-type 'plist))
|
||||||
|
(json-read-from-string result))))
|
||||||
|
|
||||||
|
;; The header-infos is already sorted by include-fixer.
|
||||||
|
(setq header-infos (plist-get include-fixer-context :HeaderInfos))
|
||||||
|
(setq query-symbol-infos (plist-get include-fixer-context :QuerySymbolInfos))
|
||||||
|
|
||||||
|
(if (eq 0 (length query-symbol-infos))
|
||||||
|
(message "The file is fine, no need to add a header.")
|
||||||
|
|
||||||
|
(setq symbol-info (elt query-symbol-infos 0))
|
||||||
|
(setq symbol (plist-get symbol-info :RawIdentifier))
|
||||||
|
(setq symbol-offset (plist-get (plist-get symbol-info :Range)
|
||||||
|
:Offset))
|
||||||
|
|
||||||
|
;; Check the number of choices
|
||||||
|
(if (eq 0 (length header-infos))
|
||||||
|
(progn
|
||||||
|
(goto-char (1+ symbol-offset))
|
||||||
|
(message (concat "Couldn't find header for '" symbol "'.")))
|
||||||
|
|
||||||
|
(setq symbol-length (plist-get (plist-get symbol-info :Range)
|
||||||
|
:Length))
|
||||||
|
(goto-char (1+ symbol-offset))
|
||||||
|
(setq symbol-overlay (make-overlay (1+ symbol-offset)
|
||||||
|
(+ symbol-offset symbol-length +1)))
|
||||||
|
(overlay-put symbol-overlay 'face '(:background "green" :foreground
|
||||||
|
"black"))
|
||||||
|
|
||||||
|
(message (number-to-string symbol-offset))
|
||||||
|
(message (number-to-string symbol-length))
|
||||||
|
|
||||||
|
(if (eq 1 (length header-infos))
|
||||||
|
(progn
|
||||||
|
(setq missing-header
|
||||||
|
(plist-get (elt header-infos 0) :Header))
|
||||||
|
(message (concat "Only one include is missing: "
|
||||||
|
missing-header )))
|
||||||
|
|
||||||
|
;; Now iterate over vector and add items to list
|
||||||
|
(setq include-list '())
|
||||||
|
(setq index 0)
|
||||||
|
(while (< index (length header-infos))
|
||||||
|
(setq entry (elt header-infos index))
|
||||||
|
(add-to-list 'include-list (plist-get entry :Header))
|
||||||
|
(setq index (1+ index))
|
||||||
|
)
|
||||||
|
|
||||||
|
(setq option-message (concat "Select include for '"
|
||||||
|
symbol
|
||||||
|
"' :"))
|
||||||
|
(setq missing-header (ido-completing-read
|
||||||
|
option-message include-list)))
|
||||||
|
|
||||||
|
;; Now select set correct header info.
|
||||||
|
(setq header-plist '())
|
||||||
|
(setq index 0)
|
||||||
|
(while (< index (length header-infos))
|
||||||
|
(setq entry (elt header-infos index))
|
||||||
|
(setq index (1+ index))
|
||||||
|
(if (eq (plist-get entry :Header) missing-header)
|
||||||
|
(setq header-plist entry)))
|
||||||
|
(setq include-fixer-context (plist-put
|
||||||
|
include-fixer-context
|
||||||
|
':HeaderInfos (vector header-plist)))
|
||||||
|
|
||||||
|
(clang-include-fixer-call-executable
|
||||||
|
'clang-include-fixer-replace_buffer
|
||||||
|
(concat "-insert-header=" (json-encode include-fixer-context)))
|
||||||
|
(delete-overlay symbol-overlay))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun clang-include-fixer ()
|
||||||
|
"Invokes the Include Fixer to insert missing C++ headers."
|
||||||
|
(interactive)
|
||||||
|
|
||||||
|
(message (concat "Calling the include fixer. "
|
||||||
|
"This might take some seconds. Please wait."))
|
||||||
|
|
||||||
|
(clang-include-fixer-call-executable
|
||||||
|
'clang-include-fixer-add-header
|
||||||
|
(concat "-db=" clang-include-fixer-input-format)
|
||||||
|
(concat "-input=" clang-include-fixer-init-string)
|
||||||
|
"-output-headers"))
|
||||||
|
|
||||||
|
(provide 'clang-include-fixer)
|
||||||
|
;;; clang-include-fixer.el ends here
|
Loading…
Reference in New Issue