[clang-tools-extra] r276853 - [clang-include-fixer] Added Emacs integration for clang-include-fixer.

Benjamin Kramer via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 27 03:11:07 PDT 2016


Author: d0k
Date: Wed Jul 27 05:11:06 2016
New Revision: 276853

URL: http://llvm.org/viewvc/llvm-project?rev=276853&view=rev
Log:
[clang-include-fixer] Added Emacs integration for clang-include-fixer.

Patch by Jens Massberg! Thanks a lot.

Differential Revision: https://reviews.llvm.org/D22805

Added:
    clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.el
Modified:
    clang-tools-extra/trunk/docs/include-fixer.rst

Modified: clang-tools-extra/trunk/docs/include-fixer.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/include-fixer.rst?rev=276853&r1=276852&r2=276853&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/include-fixer.rst (original)
+++ clang-tools-extra/trunk/docs/include-fixer.rst Wed Jul 27 05:11:06 2016
@@ -75,6 +75,25 @@ You can customize the number of headers
 
 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
 ============
 

Added: clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.el
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.el?rev=276853&view=auto
==============================================================================
--- clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.el (added)
+++ clang-tools-extra/trunk/include-fixer/tool/clang-include-fixer.el Wed Jul 27 05:11:06 2016
@@ -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




More information about the cfe-commits mailing list