diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp --- a/clang-tools-extra/clangd/IncludeCleaner.cpp +++ b/clang-tools-extra/clangd/IncludeCleaner.cpp @@ -223,7 +223,7 @@ // headers are likely to be the Standard Library headers. Until we have a // good support for umbrella headers and Standard Library headers, don't warn // about them. - if (Inc.Written.front() == '<') + if (Inc.Written.front() == '<' || Inc.BehindPragmaKeep) return false; // Headers without include guards have side effects and are not // self-contained, skip them. diff --git a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp --- a/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp +++ b/clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp @@ -397,6 +397,25 @@ UnorderedElementsAre(testPath("foo.h"))); } +TEST(IncludeCleaner, IWYUPragmas) { + TestTU TU; + TU.Code = R"cpp( + #include "behind_keep.h" // IWYU pragma: keep + )cpp"; + TU.AdditionalFiles["behind_keep.h"] = guard(""); + ParsedAST AST = TU.build(); + + auto ReferencedFiles = + findReferencedFiles(findReferencedLocations(AST), + AST.getIncludeStructure(), AST.getSourceManager()); + llvm::StringSet<> ReferencedFileNames; + EXPECT_TRUE(ReferencedFiles.empty()); + auto &Includes = AST.getIncludeStructure(); + EXPECT_THAT(getUnused(AST, translateToHeaderIDs(ReferencedFiles, Includes, + AST.getSourceManager())), + ::testing::IsEmpty()); +} + } // namespace } // namespace clangd } // namespace clang