blob: 76c73fde76db8559d23145e556502d4f60bdbdcc [file] [log] [blame] [view]
rdevlin.croninbe2898eb2016-07-13 01:20:361# Clang Tidy
2
3[TOC]
4
rdevlin.croninbe2898eb2016-07-13 01:20:365## 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
9and fixing typical programming errors, like style violations, interface misuse,
10or bugs that can be deduced via static analysis.
11
George Burgess IV288fcf52019-12-18 02:19:4612## Where is it?
rdevlin.croninbe2898eb2016-07-13 01:20:3613
George Burgess IV288fcf52019-12-18 02:19:4614clang-tidy is available in two places in Chromium:
Daniel McArdleb26068f2019-03-07 16:29:3215
George Burgess IV288fcf52019-12-18 02:19:4616- In Chromium checkouts
17- In code review on Gerrit
Daniel McArdleb26068f2019-03-07 16:29:3218
George Burgess IV288fcf52019-12-18 02:19:4619Clang-tidy automatically runs on any CL that Chromium committers upload to
20Gerrit, and will leave code review comments there. This is the recommended way
21of using clang-tidy.
Daniel McArdleb26068f2019-03-07 16:29:3222
George Burgess IV288fcf52019-12-18 02:19:4623## Enabled checks
rdevlin.croninbe2898eb2016-07-13 01:20:3624
George Burgess IV288fcf52019-12-18 02:19:4625Chromium 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
27reasonably can, but we also strive to strike a reasonable balance between signal
28and noise on code reviews. Hence, a large number of clang-tidy checks are
29disabled.
30
31### Adding a new check
32
George Burgess IV80430342020-06-05 19:16:1733New checks require review from [email protected]. If you propose a check and it
34gets approved, you may turn it on, though please note that this is only
George Burgess IV288fcf52019-12-18 02:19:4635provisional approval: we get signal from users clicking "Not Useful" on
36comments. If feedback is overwhelmingly "users don't find this useful," the
37check may be removed.
38
George Burgess IV80430342020-06-05 19:16:1739Traditionally, petitions to add checks include [an
40evaluation](https://docs.google.com/document/d/1i1KmXtDD4j_qjhmAdGlJ6UkYXByVX1Kp952Zusdcl5k/edit?usp=sharing)
41of 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
46It's expected that the person proposing the check has manually surveyed every
47clang-tidy diagnostic in the sample, noting any bugs, odd behaviors, or
48interesting patterns they've noticed. If clang-tidy emits FixIts, these are
49expected to be considered by the evaluation, too.
50
51An 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
56Running clang-tidy requires some setup. First, you'll need to sync clang-tidy,
57which requires adding `checkout_clang_tidy` to your `.gclient` file:
58
59```
60solutions = [
61 {
62 'custom_vars': {
63 'checkout_clang_tidy': True,
64 },
65 }
66]
67```
68
69Your next run of `gclient runhooks` should cause clang-tidy to be synced.
70
71To run clang-tidy across all of Chromium, you'll need a checkout of Chromium's
dan sinclair050e59af2023-08-10 19:04:2172[tools/build/](https://chromium.googlesource.com/chromium/tools/build) repository.
George Burgess IV80430342020-06-05 19:16:1773Once you have that and a Chromium `out/` dir with an `args.gn`, running
74clang-tidy across all of Chromium is a single command:
75
76```
77$ cd ${chromium}/src
dan sinclair050e59af2023-08-10 19:04:2178$ ${chromium_tools_build}/recipes/recipe_modules/tricium_clang_tidy/resources/tricium_clang_tidy_script.py \
George Burgess IV80430342020-06-05 19:16:1779 --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 Williams042e0602022-01-27 13:56:2386To only run clang-tidy against certain files, replace the `--all` parameter with
87the individual file paths.
88
George Burgess IV80430342020-06-05 19:16:1789All 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 Ivanov80b896702022-05-02 16:27:3293format of this file is detailed in `tricium_clang_tidy_script.py`.
George Burgess IV80430342020-06-05 19:16:1794
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 IV1b7401852022-08-22 02:19:2597files 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 sinclairc042c6f22023-08-24 20:32:48107 --tidy_checks='-*,YOUR-NEW-CHECK-NAME-HERE'
George Burgess IV1b7401852022-08-22 02:19:25108 --all
109```
George Burgess IV80430342020-06-05 19:16:17110
George Burgess IV898f7c82020-01-21 21:04:06111### Ignoring a check
112
113If a check is invalid on a particular piece of code, clang-tidy supports `//
114NOLINT` and `// NOLINTNEXTLINE` for ignoring all lint checks in the current and
115next lines, respectively. To suppress a specific lint, you can put it in
116parenthesis, e.g., `// NOLINTNEXTLINE(modernize-use-nullptr)`. For more, please
117see [the documentation](
118https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics).
119
120**Please note** that adding comments that exist only to silence clang-tidy is
121actively discouraged. These comments clutter code, can easily get
122out-of-date, and don't provide much value to readers. Moreover, clang-tidy only
123complains on Gerrit when lines are touched, and making Chromium clang-tidy clean
124is an explicit non-goal; making code less readable in order to silence a
125rarely-surfaced complaint isn't a good trade-off.
126
127If clang-tidy emits a diagnostic that's incorrect due to a subtlety in the code,
128adding an explanantion of what the code is doing with a trailing `NOLINT` may be
129fine. Put differently, the comment should be able to stand on its own even if we
130removed the `NOLINT`. The fact that the comment also silences clang-tidy is a
131convenient side-effect.
132
133For example:
134
135Not OK; comment exists just to silence clang-tidy:
136
137```
138// NOLINTNEXTLINE
139for (int i = 0; i < arr.size(); i++) {
140 // ...
141}
142```
143
144Not 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
148for (int i = 0; i < arr.size(); i++) {
149 // ...
150}
151```
152
153Not OK; it's obvious that this loop modifies `arr`, so the comment doesn't
154actually 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
159for (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
167OK; comment calls out a non-obvious property of this loop's body. As an
168afterthought, 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
173for (int i = 0; i < arr.size(); i++) {
174 foo();
175 bar();
176}
177```
178
179In the end, as always, what is and isn't obvious at some point is highly
180context-dependent. Please use your best judgement.
181
George Burgess IV288fcf52019-12-18 02:19:46182## But I want to run it locally
183
184If you want to sync the officially-supported `clang-tidy` to your workstation,
185add the following to your .gclient file:
186
rdevlin.croninbe2898eb2016-07-13 01:20:36187```
George Burgess IV288fcf52019-12-18 02:19:46188solutions = [
189 {
190 'custom_vars': {
191 'checkout_clang_tidy': True,
192 },
193 },
194]
rdevlin.croninbe2898eb2016-07-13 01:20:36195```
196
George Burgess IV288fcf52019-12-18 02:19:46197If you already have `solutions` and `custom_vars`, just add
198`checkout_clang_tidy` to the existing `custom_vars` map.
rdevlin.croninbe2898eb2016-07-13 01:20:36199
George Burgess IV288fcf52019-12-18 02:19:46200Once the above update has been made, run `gclient runhooks`, and clang-tidy
201should appear at `src/third_party/llvm-build/Release+Asserts/bin/clang-tidy` if
202your Chromium tree is sufficiently up-to-date.
rdevlin.croninbe2898eb2016-07-13 01:20:36203
George Burgess IV288fcf52019-12-18 02:19:46204### Running clang-tidy locally
rdevlin.croninbe2898eb2016-07-13 01:20:36205
George Burgess IV288fcf52019-12-18 02:19:46206**Note** that the local flows with clang-tidy are experimental, and require an
207LLVM checkout. Tricium is happy to run on WIP CLs, and we strongly encourage its
208use.
209
210That said, assuming you have the LLVM sources available, you'll need to bring
211your own `clang-apply-replacements` binary if you want to use the `-fix` option
212noted below.
rdevlin.croninbe2898eb2016-07-13 01:20:36213
Jan Wilken Dörriec0a93c172021-04-12 17:12:05214**Note:** If you're on a system that offers a clang tools through its package
215manager (e.g., on Debian/Ubuntu, `sudo apt-get install clang-tidy clang-tools`),
216you 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
218your `$PATH`. However, the system packaged binaries might be several versions
219behind Chromium's toolchain, so not all flags are guaranteed to work. If this is
220a problem, consider building clang-tidy from the same revision the current
221toolchain is using, rather than filing a bug against the toolchain component.
Victor Vianna795669a2022-05-17 09:04:35222This can be done as follows:
223```
224tools/clang/scripts/build_clang_tools_extra.py \
225 --fetch out/Release clang-tidy clang-apply-replacements
226```
227Running clang-tidy is then (hopefully) simple.
Dirk Pranke6e1ce9f2019-10-29 22:53:532281. Build chrome normally.
rdevlin.croninbe2898eb2016-07-13 01:20:36229```
230ninja -C out/Release chrome
231```
Daniel Cheng0241e1c2023-09-07 21:07:322322. Export Chrome's compile command database
233```
234gn gen out/Release --export-compile-commands
235```
2363. Enter the build directory
rdevlin.croninbe2898eb2016-07-13 01:20:36237```
238cd out/Release
239```
2404. Run clang-tidy.
241```
Peter Kasting0dc33482020-10-19 01:48:29242<PATH_TO_LLVM_SRC>/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py \
Takuto Ikuta2800dd82018-04-24 09:19:37243 -p . \# Set the root project directory, where compile_commands.json is.
rdevlin.croninbe2898eb2016-07-13 01:20:36244 # 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 Kasting0dc33482020-10-19 01:48:29250 # The checks to employ in the build. Use `-*,...` to omit default checks.
rdevlin.croninbe2898eb2016-07-13 01:20:36251 -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 Kasting0dc33482020-10-19 01:48:29254 'chrome/browser/.*' # A regex of the files you want to check.
rdevlin.croninbe2898eb2016-07-13 01:20:36255
256Copy-Paste Friendly (though you'll still need to stub in the variables):
Raul Tambree1c88012019-03-11 15:28:20257<PATH_TO_LLVM_SRC>/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py \
Takuto Ikuta2800dd82018-04-24 09:19:37258 -p . \
rdevlin.croninbe2898eb2016-07-13 01:20:36259 -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 Kasting0dc33482020-10-19 01:48:29265 'chrome/browser/.*'
rdevlin.croninbe2898eb2016-07-13 01:20:36266```
267
Peter Kasting0dc33482020-10-19 01:48:29268Note that the source file regex must match how the build specified the file.
269This means that on Windows, you must use (escaped) backslashes even from a bash
270shell.
rdevlin.croninbe2898eb2016-07-13 01:20:36271
George Burgess IV288fcf52019-12-18 02:19:46272### Questions
rdevlin.croninbe2898eb2016-07-13 01:20:36273
George Burgess IV288fcf52019-12-18 02:19:46274Questions about the local flow? Reach out to [email protected],
275[email protected], or [email protected].
276
277Questions about the Gerrit flow? Email [email protected] or
Eric Food0430a92022-01-24 17:54:54278[email protected], or file a bug against `Infra>LUCI>BuildService>PreSubmit>Tricium`.
George Burgess IV31910be2023-04-27 20:31:12279Please CC [email protected] and [email protected] on any of these.
George Burgess IV288fcf52019-12-18 02:19:46280
rdevlin.croninbe2898eb2016-07-13 01:20:36281Discoveries? Update the doc!