Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
clang-tools-extra/test/clang-tidy/checkers/google/Inputs/bar.h | ||
---|---|---|
5 ↗ | (On Diff #515323) | Please add. Same in other files. |
I believe this should be discussed in an RFC. We already have the standalone include-cleaner tool, why is that not sufficient? Can it be extended instead? There's also the include-what-you-use tool out there.
On my understanding, include-cleaner is re-implementation of IWYU. Awhile ago IWYU maintainers tried to merge their project to LLVM. Discussion should be in old mailing lists.
Hi folks, the rationale for a clang-tidy check is enabling include-cleaner findings to be applied at scale and integrations into existing workflows (e.g. a lot of people run cleanups using clang-tidy findings hence there's somewhat existing infra for that).
current include-cleaner tool has some downsides when it comes to cleaning-up a whole codebase (e.g. it applies changes as it goes, which might result in breaking builds as it goes if not applied carefully), surely these shortcomings can be addressed by introducing more logic into the standalone tool, but it'd still lack the ecosystem & integrations clang-tidy has, which would be really unfortunate.
Could you give some details about how you're using the existing include-cleaner tool so that we better understand use cases around that one too?
As for the existing IWYU tool, include-cleaner library used in this check has a different interpretation of "use", so despite looking similar they have different implementations and might even disagree at certain cases due to these differences.
thanks, mostly LG at the high level i think one thing we're missing is the ability to suppress analysis for certain headers, similar to what we have in clangd config options. can you add a check option for that?
clang-tools-extra/clang-tidy/CMakeLists.txt | ||
---|---|---|
10 ↗ | (On Diff #520307) | can you move this into clang-tools-extra/clang-tidy/misc/CMakeLists.txt ? in theory it isn't needed by all the checks |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
50 | rather than storing state in ::check and running logic in ::onEndOfTranslationUnit, you can just trigger analysis & finding generation here as we already match only on the translation unit decl. | |
58 | TUDecl can have children that are not part of the main file and we'll just run analysis on these decls for nothing as we discard references spelled outside mainfile inside walkUsed. so can you go over the children of TUDecl, and only pick the ones that are spelled inside the mainfile and feed them as analysis roots? | |
94 | you can use ClangTidyCheck::getCurrentMainFile() instead of Mainfile->tryGetRealPathName() | |
105 | you can have: diag(Inc->HashLocation, "unused include %0") << Inc->quote() << FixItHint::CreateRemoval(..) instead of the string concat above. | |
107–110 | you can use tooling::HeaderIncludes not only for insertions, but also for removals. | |
114 | again you can use ClangTidyCheck::getCurrentMainFile() | |
115 | nit: i'd extract SM->getBufferData(SM->getMainFileID()) into a llvm::StringRef Code and use it in both places | |
117 | no need for braces | |
124–125 | again you can use ClangTidyCheck::getCurrentMainFile() and drop the check | |
126 | constructor of tooling::HeaderIncludes parses the code, so let's create it once outside the loop? | |
140 | you can use the substitution alternative mentioned above here as well | |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
26 | can you move this struct into the implementation file? as it isn't exposed in the interfaces | |
clang-tools-extra/docs/ReleaseNotes.rst | ||
200 | Enforces include-what-you-use on headers using include-cleaner. ? | |
clang-tools-extra/docs/clang-tidy/checks/list.rst | ||
296 | could you revert this change? | |
485 | could you revert this change? | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
7 | can you also mention that this only generates findings for the main file of a translation unit? | |
clang-tools-extra/include-cleaner/lib/Record.cpp | ||
152–153 | can you change this constructor to : RecordPragma(CI.getSourceManager(), CI.getPreprocessor(), Out) ? | |
158 | no need to pass SM seperately, you can get it out of pre-processor via PP.getSourceManager() | |
348 | same here, no need to pass SM separately |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
62 | after storing them in the class state on construction, we should provide them with current values here: /// Should store all options supported by this check with their /// current values or default values for options that haven't been overridden. | |
67 | as mentioned above, rather than doing this on demand, we should run the logic on construction and store in the class state | |
67 | s/Suppress/IgnoreHeader to be consistent with option in clangd | |
82 | we should actually use FileLoc of the decl location here (i.e. map it back to spelling location) as the decl might be introduced by a macro expansion, but if the spelling of "primary" location belongs to the main file we should still analyze it (e.g. decls introduced via TEST macros) also SourceManager::isInMainFile will follow #line directives, which can create confusion (a declaration from some other file will create a diagnostic in the main file), so let's use isWrittenInMainFile instead? | |
102 | we should also respect IgnoreHeaders here | |
127 | sorry i guess i wasn't explicit about this one, but it should actually be a suffix match based regex (e.g. foo/.* disables analysis for all sources under a directory called foo) on the resolved path of the include (similar to what we do in clangd). as headers can be spelled differently based on the translation unit and this option is mentioned for the whole codebase. | |
132 | FileData makes it sound like this is some other data about the file rather than its contents. maybe just Code? | |
145 | sorry I know I suggested using HeaderIncludes for removals too, but this seems to cause more trouble actually; we should actually go over rest of the replacements too, HeaderIncludes will generate removals for all the includes that match this (spelling, quoting). hence we can't just apply the first removal. it might be easier to just use line number we have in Inc and use SourceManager:: translateFileLineCol to drop the whole line (up until start of the next line). | |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
44 | the convention is to rather store options in check's state on construction. see documentation on ClangTidyCheck::ClangTidyCheck: /// Initializes the check with \p CheckName and \p Context. /// /// Derived classes must implement the constructor with this signature or /// delegate it. If a check needs to read options, it can do this in the /// constructor using the Options.get() methods below. | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
9 | can you also mention the check options for ignoring analysis? | |
clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp | ||
19 | can you have the includes multiple times and make sure all of them are being dropped? | |
38 | can you also test for insertion suppressions ? |
Drive-by nit: want add this to the disableUnusableChecks() blocklist in clangd/TidyProvider.cpp?
Since inside clangd we want to use the direct feature instead.
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
43 | let's put this struct into anon namespace | |
49 | in theory this is not enough to disable the check for objc++, it'll have both objc and cplusplus set. so we should check ObjC is false (there's no need to disable it for c, right?) nit: we can also override isLanguageVersionSupported to disable check for non-c++. | |
68 | let's make sure we're only going to match suffixes by appending $ to the Header here. also before pushing into IgnoreHeadersRegex can you verify the regex isValid and report a diagnostic via configurationDiag if regex is invalid. | |
73 | check is performed only once for this check so it doesn't matter, but it might be better to perform this in constructor and store as class state to make sure we're only parsing options and creating the regexes once (also possibly reporting diagnostics once). as regex creation is actually expensive | |
84 | instead of const_cast here, you can just drop the const in const auto *D in for loop variable | |
108 | we're running this against spelled include of the file, not resolved path. we should instead use the spelling + trimmed version for verbatim/standard headers and use FileEntry::tryGetRealPathName for phyiscal headers. we can even do the filtering before spelling the header to not spell redundantly. | |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
49 | let's make a full copy here and store a std::string instead, as reference from options might become dangling. also the copy is cheap, we do that once per check instantiation. | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
16 |
Thanks for the comments! I'll re-assign the review to Haojian for now, so that we can hopefully make more progress this week.
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
49 | Ah thanks for the tip with isLanguageVersionSupported, doing that now. | |
68 | Thanks, good ideas! | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
16 | You probably wanted to say insertion/removal instead of inclusion/insertion. |
Not too bad, you on a right road. Tests failed on windows, and clang-format failed.
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
87 | auto -> const Decl* | |
171–176 | Use IncludeInserter::createIncludeInsertion if possible... | |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
29–30 | this description does not match first sentence in check documentation. | |
43 | many check uses ; as separator, and uses parseStringList function to do that from OptionsUtils. | |
45 | if someone will put empty string like this ,, you will end up with $ as regex, wont it match "everything" ? | |
48 | llvm::Regex got constructor, use emplace_back | |
56 | Missing "void storeOptions(ClangTidyOptions::OptionMap &Opts) override;" | |
clang-tools-extra/docs/ReleaseNotes.rst | ||
200 | is this actually a "include-what-you-use" ? | |
200 | This description does not match first sentence in check documentation. | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
7 | avoid "The check" | |
10 | Try adding some very simple "example" | |
18 | add some info about default value, is there any ? | |
clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp | ||
10 | this test file is fine, but there is no validation of output warning. |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
46 | storing a string instance for header per system reference is expensive (we might have many missing-include symbols, and we might have many duplications). We can store the a clang::include_cleaner::Header in the struct here, and call the spellHeader when generating the FixIts. | |
89 | We should use the getExpansionLoc rather than the SpellingLoc here, otherwise we might miss the case like TEST_F(WalkUsedTest, MultipleProviders) {... } where the decl location is spelled in another file, but the function body is spelled in main-file. | |
90 | and we probably need the same logic to filtering out implicit template specialization, similar to https://github.com/llvm/llvm-project/blob/main/clang-tools-extra/include-cleaner/lib/Record.cpp#L408-L410. It is fine to leave it in this patch, but please add a FIXME. | |
131 | nit: the prefix ClangTidyCheck:: qualifier is not needed, you can remove it. | |
150 | The diagnostic message "unused include ..." seems too short for users to understand what's the issue here, it would be better to make it more descriptive, in clangd, we emit included header ... is not used directly, we can follow this pattern. The same for the missing-includes. | |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
37 | nit: the function body is long, consider moving it to .cpp file. | |
clang-tools-extra/clangd/TidyProvider.cpp | ||
220 | nit: the entry here is under the Crashing Checks category, this doesn't seem a good fit. Maybe move it right after the above empty string "". | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
14 | IgnoreHeader => IgnoreHeaders, in the implementation, we use the plural form. |
clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp | ||
---|---|---|
2 | nit: missing the license file comment. |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
171–176 | tooling::HeaderIncludes already handles the include style well (and more). In general, we recommend to use tooling::headerIncludes -- it was built for generic toolings that need to perform #include manipulations, it has been heavily used in clangd/clang-format/clang-include-cleaner etc. IncludeInserter::createIncludeInsertion is an old implementation in clang-tidy, and it was built before tooling::HeaderIncludes is thing. In the long-term, I think we should probably consider deprecating it and replacing it with tooling::HeaderIncludes. |
Thanks for the comments!
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
82 |
| |
87 | const will not work, since the container I need to populate has to have llvm::SmallVector<Decl *> type due to the include-cleaner library interfaces. | |
89 |
These are earlier comments from Kadir on this topic. AFAIU we want the spelling location for TEST_F(WalkUsedTest, MultipleProviders) {... } because:
| |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
43 | Thanks for the tip, I can use the OptionsUtils infrastructure indeed. | |
clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp | ||
20 | they don't, adding a declaration to the custom "vector.h" and then using it in the main file makes vector disappear from the list of unused includes. |
The only thing is the source location, see my comments for details, otherwise looks good in general.
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
89 | I think I'm not convinced, see my comments below.
I think it is true for some cases. For example, a function decl has different parts (declarator, and function body), if the declarator is introduced by a macro which defined in a header, and the function body is spelled in the main-file, we still want to analyze the function body, see a simple example below: // foo.h #define DECLARE(X) void X() // main.cpp #include "foo.h" DECLARE(myfunc) { int a; ... } Moreover, we have use ExpansionLoc pattern in other places when we collect the main-file top-level decl (include-cleaner, clangd), and I don't see a special reason to change the pattern in the clang-tidy check. | |
117 | it is sad that we duplicate the include-cleaner analyse implementation (the only difference is that here we record the references for missing-includes), I think we should find a way to share the code in the future. No action required in this patch, can you add a FIXME? | |
195 | I think we should use the spelling location -- Inc.SymRefLocation can be a macro location which can points to another file, we intend to show diagnostics for main-file only, and walkUsed has some internal logic which guarantees that the spelling loc of returned refs is main-file. | |
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h | ||
22 | can you cleanup the includes here? looks like there are some unused-includes now, at least Syntax/Tokens.h from the first glance. | |
clang-tools-extra/docs/clang-tidy/checks/misc/include-cleaner.rst | ||
5 | nit: remove extra trailing == | |
clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp | ||
2 | nit: IncludeCleanerTest.cpp |
Thanks for the comments!
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
89 | Is the expansion location of myfunc in the main file? If that's the case, we need the expansion location indeed. |
Thanks, just a few nits. I think it is in a good shape, let's ship it!
Please make sure the premerge-test is happy before landing the patch, the windows premerge test is failing now (https://buildkite.com/llvm-project/premerge-checks/builds/155660#0188764d-dc9f-4e8f-b489-c7b8f8b0c52a)
clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp | ||
---|---|---|
89 |
Right. The expansion location here is a file location which points to the main-file. Would be nice if you add the above test into the unittest. | |
190–194 | nit: we can simplify it like if (auto Replacement = HeaderIncludes.insert(...)) diag(...); | |
clang-tools-extra/unittests/clang-tidy/IncludeCleanerTest.cpp | ||
28 | wrap all things into an anonymous namespace to avoid potential ODR violations. | |
71 | Instead of using 4 += statements, I think it is a bit clearer to use llvm::formatv("bar.h;{1};{2};...", appendPathSystemIndependent(...), ....); |
I'm getting completely incomprehensible build errors on Gentoo from this, as of aa7eace8431ba213c5431638b894b0e1b4b481c7:
samu: job failed: : && /usr/lib/ccache/bin/x86_64-pc-linux-gnu-g++ -march=znver2 --param=l1-cache-size=32 --param=l1-cache-line-size=64 -O2 -pipe -frecord-gcc-switches -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -fno-lifetime-dse -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -Wimplicit-fallthrough -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -fno-strict-aliasing -pedantic -Wno-long-long -Wl,-O1 -Wl,--as-needed -Wl,--hash-style=gnu -Wl,--export-dynamic -rdynamic -Wl,-rpath-link,/var/tmp/portage/sys-devel/clang-17.0.0_pre20230603/work/x/y/clang-abi_x86_64.amd64/./lib64 tools/extra/clang-tidy/tool/CMakeFiles/clang-tidy.dir/ClangTidyToolMain.cpp.o -o bin/clang-tidy -L/usr/lib/llvm/17/lib64 -Wl,-rpath,"\$ORIGIN/../lib64:/usr/lib/llvm/17/lib64:/var/tmp/portage/sys-devel/clang-17.0.0_pre20230603/work/x/y/clang-abi_x86_64.amd64/lib64:" lib64/libclangTidy.a lib64/libclangTidyMain.a lib64/libclangTidyAndroidModule.a lib64/libclangTidyAbseilModule.a lib64/libclangTidyAlteraModule.a lib64/libclangTidyBoostModule.a lib64/libclangTidyBugproneModule.a lib64/libclangTidyCERTModule.a lib64/libclangTidyConcurrencyModule.a lib64/libclangTidyCppCoreGuidelinesModule.a lib64/libclangTidyDarwinModule.a lib64/libclangTidyFuchsiaModule.a lib64/libclangTidyGoogleModule.a lib64/libclangTidyHICPPModule.a lib64/libclangTidyLinuxKernelModule.a lib64/libclangTidyLLVMModule.a lib64/libclangTidyLLVMLibcModule.a lib64/libclangTidyMiscModule.a lib64/libclangTidyModernizeModule.a lib64/libclangTidyObjCModule.a lib64/libclangTidyOpenMPModule.a lib64/libclangTidyPerformanceModule.a lib64/libclangTidyPortabilityModule.a lib64/libclangTidyReadabilityModule.a lib64/libclangTidyZirconModule.a lib64/libclangTidyMPIModule.a lib64/libclangTidyBugproneModule.a lib64/libclangTidyCppCoreGuidelinesModule.a lib64/libclangTidyGoogleModule.a lib64/libclangTidyMiscModule.a lib64/libclangAnalysis.a lib64/libclangASTMatchers.a lib64/libclangAST.a lib64/libclangLex.a lib64/libclangBasic.a lib64/libclangTidyModernizeModule.a lib64/libclangTidyReadabilityModule.a lib64/libclangTidyUtils.a lib64/libclangTidy.a lib64/libclang-cpp.so.17gitaa7eace8 /usr/lib/llvm/17/lib64/libLLVM-17gitaa7eace8.so && : /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: lib64/libclangTidyMiscModule.a(IncludeCleanerCheck.cpp.o): in function `clang::tidy::misc::IncludeCleanerCheck::registerPPCallbacks(clang::SourceManager const&, clang::Preprocessor*, clang::Preprocessor*) [clone .localalias]': IncludeCleanerCheck.cpp:(.text._ZN5clang4tidy4misc19IncludeCleanerCheck19registerPPCallbacksERKNS_13SourceManagerEPNS_12PreprocessorES7_+0x24): undefined reference to `clang::include_cleaner::RecordedPP::record(clang::Preprocessor const&)' /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: IncludeCleanerCheck.cpp:(.text._ZN5clang4tidy4misc19IncludeCleanerCheck19registerPPCallbacksERKNS_13SourceManagerEPNS_12PreprocessorES7_+0x94): undefined reference to `clang::include_cleaner::PragmaIncludes::record(clang::Preprocessor&)' /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: lib64/libclangTidyMiscModule.a(IncludeCleanerCheck.cpp.o): in function `clang::tidy::misc::IncludeCleanerCheck::check(clang::ast_matchers::MatchFinder::MatchResult const&) [clone .localalias]': IncludeCleanerCheck.cpp:(.text._ZN5clang4tidy4misc19IncludeCleanerCheck5checkERKNS_12ast_matchers11MatchFinder11MatchResultE+0x508): undefined reference to `clang::include_cleaner::walkUsed(llvm::ArrayRef<clang::Decl*>, llvm::ArrayRef<clang::include_cleaner::SymbolReference>, clang::include_cleaner::PragmaIncludes const*, clang::SourceManager const&, llvm::function_ref<void (clang::include_cleaner::SymbolReference const&, llvm::ArrayRef<clang::include_cleaner::Header>)>)' /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: IncludeCleanerCheck.cpp:(.text._ZN5clang4tidy4misc19IncludeCleanerCheck5checkERKNS_12ast_matchers11MatchFinder11MatchResultE+0x604): undefined reference to `clang::include_cleaner::PragmaIncludes::getPublic(clang::FileEntry const*) const' /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: IncludeCleanerCheck.cpp:(.text._ZN5clang4tidy4misc19IncludeCleanerCheck5checkERKNS_12ast_matchers11MatchFinder11MatchResultE+0x9e8): undefined reference to `clang::include_cleaner::Include::quote[abi:cxx11]() const' /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: IncludeCleanerCheck.cpp:(.text._ZN5clang4tidy4misc19IncludeCleanerCheck5checkERKNS_12ast_matchers11MatchFinder11MatchResultE+0xd15): undefined reference to `clang::include_cleaner::spellHeader[abi:cxx11](clang::include_cleaner::Header const&, clang::HeaderSearch const&, clang::FileEntry const*)' /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: lib64/libclangTidyMiscModule.a(IncludeCleanerCheck.cpp.o): in function `void llvm::function_ref<void (clang::include_cleaner::SymbolReference const&, llvm::ArrayRef<clang::include_cleaner::Header>)>::callback_fn<clang::tidy::misc::IncludeCleanerCheck::check(clang::ast_matchers::MatchFinder::MatchResult const&)::{lambda(clang::include_cleaner::SymbolReference const&, llvm::ArrayRef<clang::include_cleaner::Header>)#1}>(long, clang::include_cleaner::SymbolReference const&, llvm::ArrayRef<clang::include_cleaner::Header>)': IncludeCleanerCheck.cpp:(.text._ZN4llvm12function_refIFvRKN5clang15include_cleaner15SymbolReferenceENS_8ArrayRefINS2_6HeaderEEEEE11callback_fnIZNS1_4tidy4misc19IncludeCleanerCheck5checkERKNS1_12ast_matchers11MatchFinder11MatchResultEEUlS5_S8_E_EEvlS5_S8_+0xd1): undefined reference to `clang::include_cleaner::Includes::match(clang::include_cleaner::Header) const' collect2: error: ld returned 1 exit status
I'm also hitting this; it only seems to happen if building with -DLLVM_LINK_LLVM_DYLIB=ON.
My educated guess would be that clangIncludeCleaner is being linked via clang_target_link_libraries while it's not part of libclang-cpp, so it should go into regular target_link_libraries.
Yes, that does seem to do the trick. LGTM from my PoV if you can push such a fix, otherwise I can try to do it in a little while...
Looks like it is fixed in https://github.com/llvm/llvm-project/commit/ac0ea7555ee4ae872bcd153e04513ba0b88b8985, thanks!
can you cleanup the includes here? looks like there are some unused-includes now, at least Syntax/Tokens.h from the first glance.