├── .gitignore ├── README.org └── flycheck-clangcheck.el /.gitignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | /README.html 3 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+AUTHOR: kumar8600 2 | #+LANGUAGE: en 3 | 4 | * flycheck-clangcheck 5 | 6 | [[http://melpa.org/#/flycheck-clangcheck][file:http://melpa.org/packages/flycheck-clangcheck-badge.svg]] 7 | 8 | A [[https://github.com/flycheck/flycheck][Flycheck]] checker difinition for [[http://clang.llvm.org/docs/ClangCheck.html][ClangCheck]]. 9 | 10 | ** Installation 11 | 12 | *** Prerequisites 13 | 14 | - clang-check (this is part of clang.) 15 | 16 | *** Setup 17 | 18 | 1. Install: 19 | 20 | MELPA: 21 | 22 | [[http://melpa.org/#/flycheck-clangcheck][file:http://melpa.org/packages/flycheck-clangcheck-badge.svg]] 23 | 24 | or clone this repository: 25 | 26 | : $ git clone https://github.com/kumar8600/flycheck-clangcheck 27 | 28 | 2. Add settings for =~/.emacs.d/init.el=: 29 | 30 | #+BEGIN_SRC emacs-lisp 31 | (add-to-list 'load-path "/path/to/flycheck-clangcheck") ;; if you installed manually 32 | (require 'flycheck-clangcheck) 33 | 34 | (defun my-select-clangcheck-for-checker () 35 | "Select clang-check for flycheck's checker." 36 | (flycheck-set-checker-executable 'c/c++-clangcheck 37 | "/path/to/clang-check") 38 | (flycheck-select-checker 'c/c++-clangcheck)) 39 | 40 | (add-hook 'c-mode-hook #'my-select-clangcheck-for-checker) 41 | (add-hook 'c++-mode-hook #'my-select-clangcheck-for-checker) 42 | 43 | ;; enable static analysis 44 | (setq flycheck-clangcheck-analyze t) 45 | #+END_SRC 46 | 47 | *** Customizable variables 48 | 49 | - =flycheck-clangcheck-analyze= :: Whether to enable Static Analysis to C/C++ in ClangCheck. 50 | 51 | - =flycheck-clangcheck-extra-arg= :: Additional argument to append to the compiler command line for ClangCheck. 52 | 53 | - =flycheck-clangcheck-extra-arg-before= :: Additional argument to prepend to the compiler command line for ClangCheck. 54 | 55 | - =flycheck-clangcheck-fatal-assembler-warnings= :: Whether to enable Considering warning as error to C/C++ in ClangCheck. 56 | 57 | - =flycheck-clangcheck-dbname= :: The name of the [[http://clang.llvm.org/docs/JSONCompilationDatabase.html][JSON Compilation Database]] (default =compile_commands.json=). 58 | 59 | - =flycheck-clangcheck-build-path= :: Build directory for ClangCheck. If this is defined, a [[http://clang.llvm.org/docs/JSONCompilationDatabase.html][JSON Compilation Database]] (=flycheck-clangcheck-dbname=) must be placed to there. 60 | -------------------------------------------------------------------------------- /flycheck-clangcheck.el: -------------------------------------------------------------------------------- 1 | ;;; flycheck-clangcheck.el --- A Flycheck checker difinition for ClangCheck. 2 | 3 | ;; Author: kumar8600 4 | ;; URL: https://github.com/kumar8600/flycheck-clangcheck 5 | ;; Version: 0.21 6 | ;; Package-Requires: ((cl-lib "0.5") (seq "1.7") (flycheck "0.17")) 7 | 8 | ;; Copyright (c) 2015 by kumar8600 9 | 10 | ;; This program is free software: you can redistribute it and/or modify 11 | ;; it under the terms of the GNU General Public License as published by 12 | ;; the Free Software Foundation, either version 3 of the License, or 13 | ;; (at your option) any later version. 14 | 15 | ;; This program is distributed in the hope that it will be useful, 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | ;; GNU General Public License for more details. 19 | 20 | ;; You should have received a copy of the GNU General Public License 21 | ;; along with this program. If not, see . 22 | 23 | ;;; Commentary: 24 | 25 | ;;; Code: 26 | 27 | (require 'cl-lib) 28 | (require 'json) 29 | (require 'seq) 30 | (require 'flycheck) 31 | 32 | (flycheck-def-option-var flycheck-clangcheck-dbname "compile_commands.json" c/c++-clangcheck 33 | "Name of the compile commands database for ClangCheck. 34 | 35 | The value of this variable is a string, describing 36 | a name of the build commands database." 37 | :type '(file :tag "Compile database") 38 | :safe #'stringp) 39 | 40 | (flycheck-def-option-var flycheck-clangcheck-analyze nil c/c++-clangcheck 41 | "Whether to enable Static Analysis to C/C++ in ClangCheck. 42 | 43 | When non-nil, enable Static Analysis to C/C++ via `-analyze'." 44 | :type 'boolean 45 | :safe #'booleanp) 46 | 47 | (flycheck-def-option-var flycheck-clangcheck-extra-arg nil c/c++-clangcheck 48 | "Additional argument to append to the compiler command line for ClangCheck. 49 | 50 | The value of this variable is a list of strings, where each 51 | string is an additional argument to pass to ClangCheck, via 52 | the `-extra-arg' option." 53 | :type '(repeat (string :tag "Argument")) 54 | :safe #'flycheck-string-list-p) 55 | 56 | (flycheck-def-option-var flycheck-clangcheck-extra-arg-before nil c/c++-clangcheck 57 | "Additional argument to prepend to the compiler command line for ClangCheck. 58 | 59 | The value of this variable is a list of strings, where each 60 | string is an additional argument to prepend to the compiler 61 | command line to pass to ClangCheck, via the 62 | `-extra-arg-before' option." 63 | :type '(repeat (string :tag "Prepend argument")) 64 | :safe #'flycheck-string-list-p) 65 | 66 | (flycheck-def-option-var flycheck-clangcheck-fatal-assembler-warnings nil c/c++-clangcheck 67 | "Whether to enable Considering warning as error to C/C++ in ClangCheck. 68 | 69 | When non-nil, enable Considering warning as error to ClangCheck via 70 | `-fatal-assembler-warnings'." 71 | :type 'boolean 72 | :safe #'booleanp) 73 | 74 | (flycheck-def-option-var flycheck-clangcheck-build-path nil c/c++-clangcheck 75 | "Build directory for ClangCheck. 76 | 77 | The value of this variable is a string, describing 78 | a build directory where `compile_commands.json' exists." 79 | :type '(directory :tag "Build directory") 80 | :safe #'stringp) 81 | (make-variable-buffer-local 'flycheck-clangcheck-build-path) 82 | 83 | (defun flycheck-clangcheck-find-compiledb-dir (file-or-dir) 84 | "Given FILE-OR-DIR search up for `flycheck-clangcheck-dbname'. 85 | 86 | Return the directory which contains the database or nil." 87 | (let ((root-dir 88 | (locate-dominating-file 89 | file-or-dir 90 | flycheck-clangcheck-dbname))) 91 | (when root-dir 92 | (expand-file-name root-dir)))) 93 | 94 | (defun flycheck-clangcheck-get-json (build-dir source) 95 | "Get a the compile commands from `flycheck-clangcheck-dbname' at BUILD-DIR for SOURCE." 96 | (let ((commands (json-read-file (expand-file-name flycheck-clangcheck-dbname 97 | build-dir))) 98 | (source-truename (file-truename source))) 99 | (cl-find-if (lambda (item) 100 | (string= source-truename 101 | (file-truename (cdr (assq 'file item))))) 102 | commands))) 103 | 104 | (defun flycheck-clangcheck-get-compile-command (json) 105 | "Return the compile command for a given `JSON' fragment from the 106 | compile database. 107 | 108 | We apply some basic filters to avoid weird cases." 109 | (if json 110 | (let ((raw-cmds (split-string-and-unquote (cdr (assq 'command json)))) 111 | (skip-next nil)) 112 | (seq-filter (lambda (it) 113 | (cond 114 | ;; Don't output dependencies as this will likely confuse 115 | ;; real builds 116 | ((string-match "-MF" it) (not (setq skip-next t))) 117 | ((string-match "-MD" it) nil) 118 | ((string-match "-MMD" it) nil) 119 | ;; skip a positional argument 120 | (skip-next (setq skip-next nil)) 121 | (t t))) 122 | raw-cmds)) 123 | nil)) 124 | 125 | (defun flycheck-clangcheck-set-build-dir (json) 126 | "Set `default-directory' to be that as specified in the `JSON' 127 | fragment. 128 | 129 | This has the unfortunate side effect of trashing the buffer's 130 | `default-directory'." 131 | (setq default-directory (file-name-as-directory (cdr (assq 'directory json))))) 132 | 133 | 134 | (flycheck-define-checker c/c++-clangcheck 135 | "A C/C++ syntax checker using ClangCheck. 136 | 137 | See URL `http://clang.llvm.org/docs/ClangCheck.html'." 138 | :command ("clang-check" 139 | (option-flag "-analyze" flycheck-clangcheck-analyze) 140 | (option-flag "-fatal-assembler-warnings" flycheck-clangcheck-fatal-assembler-warnings) 141 | (option-list "-extra-arg=" flycheck-clangcheck-extra-arg s-prepend) 142 | (option-list "-extra-arg-before=" flycheck-clangcheck-extra-arg-before s-prepend) 143 | "--extra-arg=-Wno-unknown-warning-option" ; silence GCC options 144 | "--extra-arg=-Wno-null-character" ; silence null 145 | ;; We must stay in the same directory, to properly resolve #include 146 | ;; with quotes 147 | source-inplace 148 | "--" 149 | ;; To get works well with `source-inplace', build-directory's 150 | ;; `compile_commands.json' parsing is done by own logic. 151 | (eval 152 | (progn 153 | (unless flycheck-clangcheck-build-path 154 | (setq flycheck-clangcheck-build-path 155 | (flycheck-clangcheck-find-compiledb-dir 156 | (buffer-file-name)))) 157 | (if flycheck-clangcheck-build-path 158 | (progn 159 | (let ((json 160 | (flycheck-clangcheck-get-json 161 | flycheck-clangcheck-build-path 162 | (buffer-file-name)))) 163 | (if json 164 | (progn 165 | ;; for side-effect only 166 | (flycheck-clangcheck-set-build-dir json) 167 | ;; return the commands 168 | (flycheck-clangcheck-get-compile-command 169 | json)) 170 | (progn (message "Couldn't find compile 171 | command from `compile_commands.json' in %s." flycheck-clangcheck-build-path) 172 | nil)))) 173 | (concat "-x" 174 | (cl-case major-mode 175 | (c++-mode "c++") 176 | (c-mode "c")))))) 177 | "-fno-color-diagnostics" ; Do not include color codes in output 178 | "-fno-caret-diagnostics" ; Do not visually indicate the source 179 | ; location 180 | "-fno-diagnostics-show-option") ; Do not show the corresponding 181 | ; warning group 182 | :error-patterns 183 | ((info line-start (file-name) ":" line ":" column 184 | ": note: " (message) line-end) 185 | (warning line-start (file-name) ":" line ":" column 186 | ": warning: " (message) line-end) 187 | (error line-start (file-name) ":" line ":" column 188 | ": " (or "fatal error" "error") ": " (message) line-end)) 189 | :modes (c-mode c++-mode)) 190 | 191 | (add-to-list 'flycheck-checkers 'c/c++-clangcheck) 192 | 193 | (provide 'flycheck-clangcheck) 194 | 195 | ;;; flycheck-clangcheck.el ends here 196 | --------------------------------------------------------------------------------