4 Commits

Author SHA1 Message Date
Carlos Galvez
bd77e9acf0
[clang-tidy] Avoid matching nodes in system headers (#151035)
This commit is a re-do of e4a8969e56572371201863594b3a549de2e23f32,
which got reverted, with the same goal: dramatically speed-up clang-tidy
by avoiding doing work in system headers (which is wasteful as warnings
are later discarded). This proposal was already discussed here with
favorable feedback: https://github.com/llvm/llvm-project/pull/132725

The novelty of this patch is:

- It's less aggressive: it does not fiddle with AST traversal. This
solves the issue with the previous patch, which impacted the ability to
inspect parents of a given node.

- Instead, what we optimize for is exitting early in each `Traverse*`
function of `MatchASTVisitor` if the node is in a system header, thus
avoiding calling the `match()` function with its corresponding callback
(when there is a match).

- It does not cause any failing tests.

- It does not move `MatchFinderOptions` - instead we add a user-defined
default constructor which solves the same problem.

- It introduces a function `shouldSkipNode` which can be extended for
adding more conditions. For example there's a PR open about skipping
modules in clang-tidy where this could come handy:
https://github.com/llvm/llvm-project/pull/145630

As a benchmark, I ran clang-tidy with all checks activated, on a single
.cpp file which #includes all the standard C++ headers, then measure the
time as well as found warnings.

On trunk:

```
Suppressed 75413 warnings (75413 in non-user code).

real	0m12.418s
user	0m12.270s
sys	0m0.129s
```

With this patch:

```
Suppressed 11448 warnings (11448 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.

real	0m1.666s
user	0m1.538s
sys	0m0.129s
```

With the original patch that got reverted:

```
Suppressed 11428 warnings (11428 in non-user code).

real	0m1.193s
user	0m1.096s
sys	0m0.096s
```

We therefore get a dramatic reduction in number of warnings and runtime,
with no change in functionality.

The remaining warnings are due to `PPCallbacks` - implementing a similar
system-header exclusion mechanism there can lead to almost no warnings
left in system headers. This does not bring the runtime down as much,
though, so it's probably not worth the effort.

Fixes #52959

Co-authored-by: Carlos Gálvez <carlos.galvez@zenseact.com>
2025-08-17 11:40:48 +02:00
Carlos Galvez
0fb4ef40b1
Revert "[clang-tidy] Avoid processing declarations in system headers … (#132743)
…(#128150)"

This was too aggressive, and leads to problems for downstream users:
https://github.com/llvm/llvm-project/pull/128150#issuecomment-2739803409

Let's revert and reland it once we have addressed the problems.

This reverts commit e4a8969e56572371201863594b3a549de2e23f32.

Co-authored-by: Carlos Gálvez <carlos.galvez@zenseact.com>
2025-03-24 20:47:57 +01:00
Carlos Galvez
e4a8969e56
[clang-tidy] Avoid processing declarations in system headers (#128150)
[clang-tidy] Avoid processing declarations in system headers

Currently, clang-tidy processes the entire TranslationUnit, including
declarations in system headers. However, the work done in system
headers is discarded at the very end when presenting results, unless
the SystemHeaders option is active.

This is a lot of wasted work, and makes clang-tidy very slow.
In comparison, clangd only processes declarations in the main file,
and it's claimed to be 10x faster than clang-tidy:

https://github.com/lljbash/clangd-tidy

To solve this problem, we can apply a similar solution done in clangd
into clang-tidy. We do this by changing the traversal scope from the
default TranslationUnitDecl, to only contain the top-level declarations
that are _not_ part of system headers. We do this in the
MatchASTConsumer class, so the logic can be reused by other tools.
This behavior is currently off by default, and only clang-tidy
enables skipping system headers. If wanted, this behavior can be
activated by other tools in follow-up patches.

I had to move MatchFinderOptions out of the MatchFinder class,
because otherwise I could not set a default value for the
"bool SkipSystemHeaders" member otherwise. The compiler error message
was "default member initializer required before the end of its
enclosing class".

Note: this behavior is not active if the user requests warnings from
system headers via the SystemHeaders option.

Note2: out of all the unit tests, only one of them fails:

readability/identifier-naming-anon-record-fields.cpp

This is because the limited traversal scope no longer includes the
"CXXRecordDecl" of the global anonymous union, see:
https://github.com/llvm/llvm-project/issues/130618

I have not found a way to make this work. For now, document the
technical debt introduced.

Note3: I have purposely decided to make this new feature enabled by
default, instead of adding a new "opt-in/opt-out" flag. Having a new
flag would mean duplicating all our tests to ensure they work in both
modes, which would be infeasible. Having it enabled by default allow
people to get the benefits immediately. Given that all unit tests pass,
the risk for regressions is low. Even if that's the case, the only
issue would be false negatives (fewer things are detected), which
are much more tolerable than false positives.

Credits: original implementation by @njames93, here:
https://reviews.llvm.org/D150126

This implementation is simpler in the sense that it does not consider
HeaderFilterRegex to filter even further. A follow-up patch could
include the functionality if wanted.

Fixes #52959

Co-authored-by: Carlos Gálvez <carlos.galvez@zenseact.com>
2025-03-14 13:16:17 +01:00
Carlos Galvez
26f476286f [clang-tidy] Support SystemHeaders in .clang-tidy
A previous patch update the clang-tidy documentation
incorrectly claiming that SystemHeaders can be provided
in the .clang-tidy configuration file.

This patch adds support for it, together with tests.

Differential Revision: https://reviews.llvm.org/D149899
2023-05-07 16:36:30 +00:00