rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 1 | # Clang Tidy |
| 2 | |
| 3 | [TOC] |
| 4 | |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 5 | ## Introduction |
| 6 | |
| 7 | [clang-tidy](http://clang.llvm.org/extra/clang-tidy/) is a clang-based C++ |
| 8 | “linter” tool. Its purpose is to provide an extensible framework for diagnosing |
| 9 | and fixing typical programming errors, like style violations, interface misuse, |
| 10 | or bugs that can be deduced via static analysis. |
| 11 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 12 | ## Where is it? |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 13 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 14 | clang-tidy is available in two places in Chromium: |
Daniel McArdle | b26068f | 2019-03-07 16:29:32 | [diff] [blame] | 15 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 16 | - In Chromium checkouts |
| 17 | - In code review on Gerrit |
Daniel McArdle | b26068f | 2019-03-07 16:29:32 | [diff] [blame] | 18 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 19 | Clang-tidy automatically runs on any CL that Chromium committers upload to |
| 20 | Gerrit, and will leave code review comments there. This is the recommended way |
| 21 | of using clang-tidy. |
Daniel McArdle | b26068f | 2019-03-07 16:29:32 | [diff] [blame] | 22 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 23 | ## Enabled checks |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 24 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 25 | Chromium globally enables a subset of all of clang-tidy's checks (see |
| 26 | `${chromium}/src/.clang-tidy`). We want these checks to cover as much as we |
| 27 | reasonably can, but we also strive to strike a reasonable balance between signal |
| 28 | and noise on code reviews. Hence, a large number of clang-tidy checks are |
| 29 | disabled. |
| 30 | |
| 31 | ### Adding a new check |
| 32 | |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 33 | New checks require review from [email protected]. If you propose a check and it |
| 34 | gets approved, you may turn it on, though please note that this is only |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 35 | provisional approval: we get signal from users clicking "Not Useful" on |
| 36 | comments. If feedback is overwhelmingly "users don't find this useful," the |
| 37 | check may be removed. |
| 38 | |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 39 | Traditionally, petitions to add checks include [an |
| 40 | evaluation](https://docs.google.com/document/d/1i1KmXtDD4j_qjhmAdGlJ6UkYXByVX1Kp952Zusdcl5k/edit?usp=sharing) |
| 41 | of the check under review. Crucially, this includes two things: |
| 42 | |
| 43 | - a count of how many times this check fires across Chromium |
| 44 | - a random sample (>30) of places where the check fires across Chromium |
| 45 | |
| 46 | It's expected that the person proposing the check has manually surveyed every |
| 47 | clang-tidy diagnostic in the sample, noting any bugs, odd behaviors, or |
| 48 | interesting patterns they've noticed. If clang-tidy emits FixIts, these are |
| 49 | expected to be considered by the evaluation, too. |
| 50 | |
| 51 | An example of a previous proposal email thread is |
| 52 | [here](https://groups.google.com/a/chromium.org/g/cxx/c/iZ6-Y9ZhC3Q/m/g-8HzqmbAAAJ). |
| 53 | |
| 54 | #### Evaluating: running clang-tidy across Chromium |
| 55 | |
| 56 | Running clang-tidy requires some setup. First, you'll need to sync clang-tidy, |
| 57 | which requires adding `checkout_clang_tidy` to your `.gclient` file: |
| 58 | |
| 59 | ``` |
| 60 | solutions = [ |
| 61 | { |
| 62 | 'custom_vars': { |
| 63 | 'checkout_clang_tidy': True, |
| 64 | }, |
| 65 | } |
| 66 | ] |
| 67 | ``` |
| 68 | |
| 69 | Your next run of `gclient runhooks` should cause clang-tidy to be synced. |
| 70 | |
| 71 | To run clang-tidy across all of Chromium, you'll need a checkout of Chromium's |
dan sinclair | 050e59af | 2023-08-10 19:04:21 | [diff] [blame] | 72 | [tools/build/](https://chromium.googlesource.com/chromium/tools/build) repository. |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 73 | Once you have that and a Chromium `out/` dir with an `args.gn`, running |
| 74 | clang-tidy across all of Chromium is a single command: |
| 75 | |
| 76 | ``` |
| 77 | $ cd ${chromium}/src |
dan sinclair | 050e59af | 2023-08-10 19:04:21 | [diff] [blame] | 78 | $ ${chromium_tools_build}/recipes/recipe_modules/tricium_clang_tidy/resources/tricium_clang_tidy_script.py \ |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 79 | --base_path $PWD \ |
| 80 | --out_dir out/Linux \ |
| 81 | --findings_file all_findings.json \ |
| 82 | --clang_tidy_binary $PWD/third_party/llvm-build/Release+Asserts/bin/clang-tidy \ |
| 83 | --all |
| 84 | ``` |
| 85 | |
Andrew Williams | 042e060 | 2022-01-27 13:56:23 | [diff] [blame] | 86 | To only run clang-tidy against certain files, replace the `--all` parameter with |
| 87 | the individual file paths. |
| 88 | |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 89 | All clang-tidy checks are run on Linux builds of Chromium, so please set up your |
| 90 | `args.gn` to build Linux. |
| 91 | |
| 92 | `all_findings.json` is where all of clang-tidy's findings will be dumped. The |
Maksim Ivanov | 80b89670 | 2022-05-02 16:27:32 | [diff] [blame] | 93 | format of this file is detailed in `tricium_clang_tidy_script.py`. |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 94 | |
| 95 | **Note** that the above command will use Chromium's top-level `.clang-tidy` file |
| 96 | (or `.clang-tidy` files scattered throughout `third_party/`, depending on the |
George Burgess IV | 1b740185 | 2022-08-22 02:19:25 | [diff] [blame] | 97 | files we lint. In order to test a *new* check, it's recommended that you use |
| 98 | `tricium_clang_tidy_script.py`'s `--tidy_checks` flag. Usage of this looks like: |
| 99 | |
| 100 | ``` |
| 101 | $ cd ${chromium}/src |
| 102 | $ ${chromium_build}/recipes/recipe_modules/tricium_clang_tidy/resources/tricium_clang_tidy_script.py \ |
| 103 | --base_path $PWD \ |
| 104 | --out_dir out/Linux \ |
| 105 | --findings_file all_findings.json \ |
| 106 | --clang_tidy_binary $PWD/third_party/llvm-build/Release+Asserts/bin/clang-tidy \ |
dan sinclair | c042c6f2 | 2023-08-24 20:32:48 | [diff] [blame] | 107 | --tidy_checks='-*,YOUR-NEW-CHECK-NAME-HERE' |
George Burgess IV | 1b740185 | 2022-08-22 02:19:25 | [diff] [blame] | 108 | --all |
| 109 | ``` |
George Burgess IV | 8043034 | 2020-06-05 19:16:17 | [diff] [blame] | 110 | |
George Burgess IV | 898f7c8 | 2020-01-21 21:04:06 | [diff] [blame] | 111 | ### Ignoring a check |
| 112 | |
| 113 | If a check is invalid on a particular piece of code, clang-tidy supports `// |
| 114 | NOLINT` and `// NOLINTNEXTLINE` for ignoring all lint checks in the current and |
| 115 | next lines, respectively. To suppress a specific lint, you can put it in |
| 116 | parenthesis, e.g., `// NOLINTNEXTLINE(modernize-use-nullptr)`. For more, please |
| 117 | see [the documentation]( |
| 118 | https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics). |
| 119 | |
| 120 | **Please note** that adding comments that exist only to silence clang-tidy is |
| 121 | actively discouraged. These comments clutter code, can easily get |
| 122 | out-of-date, and don't provide much value to readers. Moreover, clang-tidy only |
| 123 | complains on Gerrit when lines are touched, and making Chromium clang-tidy clean |
| 124 | is an explicit non-goal; making code less readable in order to silence a |
| 125 | rarely-surfaced complaint isn't a good trade-off. |
| 126 | |
| 127 | If clang-tidy emits a diagnostic that's incorrect due to a subtlety in the code, |
| 128 | adding an explanantion of what the code is doing with a trailing `NOLINT` may be |
| 129 | fine. Put differently, the comment should be able to stand on its own even if we |
| 130 | removed the `NOLINT`. The fact that the comment also silences clang-tidy is a |
| 131 | convenient side-effect. |
| 132 | |
| 133 | For example: |
| 134 | |
| 135 | Not OK; comment exists just to silence clang-tidy: |
| 136 | |
| 137 | ``` |
| 138 | // NOLINTNEXTLINE |
| 139 | for (int i = 0; i < arr.size(); i++) { |
| 140 | // ... |
| 141 | } |
| 142 | ``` |
| 143 | |
| 144 | Not OK; comment exists just to verbosely silence clang-tidy: |
| 145 | |
| 146 | ``` |
| 147 | // Clang-tidy doesn't get that we can't range-for-ize this loop. NOLINTNEXTLINE |
| 148 | for (int i = 0; i < arr.size(); i++) { |
| 149 | // ... |
| 150 | } |
| 151 | ``` |
| 152 | |
| 153 | Not OK; it's obvious that this loop modifies `arr`, so the comment doesn't |
| 154 | actually clarify anything: |
| 155 | |
| 156 | ``` |
| 157 | // It'd be invalid to make this into a range-for loop, since the body might add |
| 158 | // elements to `arr`. NOLINTNEXTLINE |
| 159 | for (int i = 0; i < arr.size(); i++) { |
| 160 | if (i % 4) { |
| 161 | arr.push_back(4); |
| 162 | arr.push_back(2); |
| 163 | } |
| 164 | } |
| 165 | ``` |
| 166 | |
| 167 | OK; comment calls out a non-obvious property of this loop's body. As an |
| 168 | afterthought, it silences clang-tidy: |
| 169 | |
| 170 | ``` |
| 171 | // It'd be invalid to make this into a range-for loop, since the call to `foo` |
| 172 | // here might add elements to `arr`. NOLINTNEXTLINE |
| 173 | for (int i = 0; i < arr.size(); i++) { |
| 174 | foo(); |
| 175 | bar(); |
| 176 | } |
| 177 | ``` |
| 178 | |
| 179 | In the end, as always, what is and isn't obvious at some point is highly |
| 180 | context-dependent. Please use your best judgement. |
| 181 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 182 | ## But I want to run it locally |
| 183 | |
| 184 | If you want to sync the officially-supported `clang-tidy` to your workstation, |
| 185 | add the following to your .gclient file: |
| 186 | |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 187 | ``` |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 188 | solutions = [ |
| 189 | { |
| 190 | 'custom_vars': { |
| 191 | 'checkout_clang_tidy': True, |
| 192 | }, |
| 193 | }, |
| 194 | ] |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 195 | ``` |
| 196 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 197 | If you already have `solutions` and `custom_vars`, just add |
| 198 | `checkout_clang_tidy` to the existing `custom_vars` map. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 199 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 200 | Once the above update has been made, run `gclient runhooks`, and clang-tidy |
| 201 | should appear at `src/third_party/llvm-build/Release+Asserts/bin/clang-tidy` if |
| 202 | your Chromium tree is sufficiently up-to-date. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 203 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 204 | ### Running clang-tidy locally |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 205 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 206 | **Note** that the local flows with clang-tidy are experimental, and require an |
| 207 | LLVM checkout. Tricium is happy to run on WIP CLs, and we strongly encourage its |
| 208 | use. |
| 209 | |
| 210 | That said, assuming you have the LLVM sources available, you'll need to bring |
| 211 | your own `clang-apply-replacements` binary if you want to use the `-fix` option |
| 212 | noted below. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 213 | |
Jan Wilken Dörrie | c0a93c17 | 2021-04-12 17:12:05 | [diff] [blame] | 214 | **Note:** If you're on a system that offers a clang tools through its package |
| 215 | manager (e.g., on Debian/Ubuntu, `sudo apt-get install clang-tidy clang-tools`), |
| 216 | you might not need an LLVM checkout to make the required binaries and scripts |
| 217 | (`clang-tidy`, `run-clang-tidy` and `clang-apply-replacements`) available in |
| 218 | your `$PATH`. However, the system packaged binaries might be several versions |
| 219 | behind Chromium's toolchain, so not all flags are guaranteed to work. If this is |
| 220 | a problem, consider building clang-tidy from the same revision the current |
| 221 | toolchain is using, rather than filing a bug against the toolchain component. |
Victor Vianna | 795669a | 2022-05-17 09:04:35 | [diff] [blame] | 222 | This can be done as follows: |
| 223 | ``` |
| 224 | tools/clang/scripts/build_clang_tools_extra.py \ |
| 225 | --fetch out/Release clang-tidy clang-apply-replacements |
| 226 | ``` |
| 227 | Running clang-tidy is then (hopefully) simple. |
Dirk Pranke | 6e1ce9f | 2019-10-29 22:53:53 | [diff] [blame] | 228 | 1. Build chrome normally. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 229 | ``` |
| 230 | ninja -C out/Release chrome |
| 231 | ``` |
Daniel Cheng | 0241e1c | 2023-09-07 21:07:32 | [diff] [blame] | 232 | 2. Export Chrome's compile command database |
| 233 | ``` |
| 234 | gn gen out/Release --export-compile-commands |
| 235 | ``` |
| 236 | 3. Enter the build directory |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 237 | ``` |
| 238 | cd out/Release |
| 239 | ``` |
| 240 | 4. Run clang-tidy. |
| 241 | ``` |
Peter Kasting | 0dc3348 | 2020-10-19 01:48:29 | [diff] [blame] | 242 | <PATH_TO_LLVM_SRC>/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py \ |
Takuto Ikuta | 2800dd8 | 2018-04-24 09:19:37 | [diff] [blame] | 243 | -p . \# Set the root project directory, where compile_commands.json is. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 244 | # Set the clang-tidy binary path, if it's not in your $PATH. |
| 245 | -clang-tidy-binary <PATH_TO_LLVM_BUILD>/bin/clang-tidy \ |
| 246 | # Set the clang-apply-replacements binary path, if it's not in your $PATH |
| 247 | # and you are using the `fix` behavior of clang-tidy. |
| 248 | -clang-apply-replacements-binary \ |
| 249 | <PATH_TO_LLVM_BUILD>/bin/clang-apply-replacements \ |
Peter Kasting | 0dc3348 | 2020-10-19 01:48:29 | [diff] [blame] | 250 | # The checks to employ in the build. Use `-*,...` to omit default checks. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 251 | -checks=<CHECKS> \ |
| 252 | -header-filter=<FILTER> \# Optional, limit results to only certain files. |
| 253 | -fix \# Optional, used if you want to have clang-tidy auto-fix errors. |
Peter Kasting | 0dc3348 | 2020-10-19 01:48:29 | [diff] [blame] | 254 | 'chrome/browser/.*' # A regex of the files you want to check. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 255 | |
| 256 | Copy-Paste Friendly (though you'll still need to stub in the variables): |
Raul Tambre | e1c8801 | 2019-03-11 15:28:20 | [diff] [blame] | 257 | <PATH_TO_LLVM_SRC>/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py \ |
Takuto Ikuta | 2800dd8 | 2018-04-24 09:19:37 | [diff] [blame] | 258 | -p . \ |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 259 | -clang-tidy-binary <PATH_TO_LLVM_BUILD>/bin/clang-tidy \ |
| 260 | -clang-apply-replacements-binary \ |
| 261 | <PATH_TO_LLVM_BUILD>/bin/clang-apply-replacements \ |
| 262 | -checks=<CHECKS> \ |
| 263 | -header-filter=<FILTER> \ |
| 264 | -fix \ |
Peter Kasting | 0dc3348 | 2020-10-19 01:48:29 | [diff] [blame] | 265 | 'chrome/browser/.*' |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 266 | ``` |
| 267 | |
Peter Kasting | 0dc3348 | 2020-10-19 01:48:29 | [diff] [blame] | 268 | Note that the source file regex must match how the build specified the file. |
| 269 | This means that on Windows, you must use (escaped) backslashes even from a bash |
| 270 | shell. |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 271 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 272 | ### Questions |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 273 | |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 274 | Questions about the local flow? Reach out to [email protected], |
| 275 | [email protected], or [email protected]. |
| 276 | |
| 277 | Questions about the Gerrit flow? Email [email protected] or |
Eric Foo | d0430a9 | 2022-01-24 17:54:54 | [diff] [blame] | 278 | [email protected], or file a bug against `Infra>LUCI>BuildService>PreSubmit>Tricium`. |
George Burgess IV | 31910be | 2023-04-27 20:31:12 | [diff] [blame] | 279 | Please CC [email protected] and [email protected] on any of these. |
George Burgess IV | 288fcf5 | 2019-12-18 02:19:46 | [diff] [blame] | 280 | |
rdevlin.cronin | be2898eb | 2016-07-13 01:20:36 | [diff] [blame] | 281 | Discoveries? Update the doc! |