include-cleaner removes unused includes and reduces accidental reliance on transitive includes. It is available as a standalone tool (clang-include-cleaner) and is also used by clang-tidy and clangd. Its scope is narrower than IWYU: it does not insert forward declarations, but it does honor them.
At the moment, include-cleaner assumes headers are self-contained. This does not work well for fragment headers: files that are intentionally not self-contained and rely on the including file to provide prerequisites. Common examples are generated .inc files and .def-style includes, particularly in TableGen-heavy code.
In practice, this limits the usefulness of include-cleaner on LLVM-style code, both upstream and in downstream forks. The tool may diagnose includes as unused even when they are required by a fragment included later in the file. The usual workarounds are to add // IWYU pragma: keep to such includes, or to avoid running include-cleaner on that code. Neither scales especially well.
The proposal is to support fragment headers as an explicit, opt-in concept in include-cleaner. The intent is limited: if a project identifies certain files as fragments, include-cleaner should account for dependencies introduced through them when determining whether an include is needed. This is not intended to change the default model, and it is not intended to treat non-self-contained headers as preferred style. It is intended to allow include-cleaner to operate on codebases that already rely on such files.
I initially explored this in a clang-tidy-only change. During review, the main question became whether this belongs in include-cleaner at all, rather than how the clang-tidy patch should look.
A few concerns were raised in that discussion: https://github.com/llvm/llvm-project/pull/180282#issuecomment-3907053475.
One is include ordering. Fragment headers often require certain includes to appear before them, and support in include-cleaner does not solve that ordering problem by itself. That limitation remains. At the same time, the current alternatives are either that the check cannot be used reliably, or that the source accumulates pragma: keep annotations for includes that are only needed indirectly. In TableGen-heavy code, .inc files are often already kept separate from the main include block because of their contextual requirements, so this does not necessarily introduce a new class of constraints.
Another concern is user confusion. If an include is preserved even though nothing in the visible source appears to require it, the result may be surprising. That concern seems valid. The newer version of the patch series improves this compared to the original clang-tidy prototype by allowing users to insert comments on includes that are required solely by fragment headers. This should remain part of the design constraint: fragment-induced dependencies should be handled in a way that keeps diagnostics understandable.
A third concern is that many such files are generated, so the problem should perhaps be solved in the generator instead. In principle, that would be preferable. If generated fragments were self-contained, this issue would mostly disappear. However, it is not clear that such generator-side changes are feasible in the near term for existing TableGen-based patterns or other generated code, while users still need include-cleaner to operate correctly on current code. For that reason, this proposal is framed as an opt-in mechanism for existing codebases, not as a substitute for generator improvements where those are possible.
Support for non-self-contained files has also been requested in other Clang tools, especially clangd, which suggests this is not specific to one check or one codebase. Given that, it seems preferable to support this in the shared include-cleaner library rather than as a clang-tidy-specific extension, to avoid divergent behavior between clang-tidy and clangd.
Based on that, I submitted the following patch series:
At the moment, the main practical issues are that some Windows tests are failing in #189458, and I have not been able to investigate them properly without access to a Windows machine; and that there is currently no active include-cleaner maintainer, which makes review slower and leaves long-term ownership less clear.
So the question for this RFC is: should include-cleaner support fragment headers as an explicit, opt-in concept in the shared library, with support added to clang-tidy and clangd?