diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h --- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h +++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h @@ -73,6 +73,10 @@ /// Returns true if the given file is a self-contained file. bool isSelfContained(const FileEntry *File) const; + /// Returns true if the given file is marked with the IWYU private pragma + /// without public mapping. + bool isPrivate(const FileEntry *File) const; + private: class RecordPragma; /// 1-based Line numbers for the #include directives of the main file that @@ -88,6 +92,10 @@ llvm::DenseMap IWYUPublic; + /// Contains all files marked with the IWYU private pragma that + /// do not have public header mapping + llvm::DenseSet IWYUPrivate; + /// A reverse map from the underlying header to its exporter headers. // // There's no way to get a FileEntry from a UniqueID, especially when it diff --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp --- a/clang-tools-extra/include-cleaner/lib/Record.cpp +++ b/clang-tools-extra/include-cleaner/lib/Record.cpp @@ -263,6 +263,8 @@ assert(ExportStack.back().Block); ExportStack.pop_back(); } + } else if (Pragma->startswith("private")) { + Out->IWYUPrivate.insert(SM.getFileEntryForID(CommentFID)->getUniqueID()); } if (InMainFile) { @@ -346,6 +348,10 @@ return !NonSelfContainedFiles.contains(FE->getUniqueID()); } +bool PragmaIncludes::isPrivate(const FileEntry *FE) const { + return IWYUPrivate.contains(FE->getUniqueID()); +} + std::unique_ptr RecordedAST::record() { class Recorder : public ASTConsumer { RecordedAST *Out; diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp --- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp @@ -368,11 +368,18 @@ Inputs.Code = R"cpp( #include "public.h" )cpp"; - Inputs.ExtraFiles["public.h"] = "#include \"private.h\""; + Inputs.ExtraFiles["public.h"] = R"cpp( + #include "private.h"; + #include "private2.h"; + )cpp"; Inputs.ExtraFiles["private.h"] = R"cpp( // IWYU pragma: private, include "public2.h" class Private {}; )cpp"; + Inputs.ExtraFiles["private2.h"] = R"cpp( + // IWYU pragma: private + class Private {}; + )cpp"; TestAST Processed = build(); auto PrivateFE = Processed.fileManager().getFile("private.h"); assert(PrivateFE); @@ -380,6 +387,10 @@ auto PublicFE = Processed.fileManager().getFile("public.h"); assert(PublicFE); EXPECT_EQ(PI.getPublic(PublicFE.get()), ""); // no mapping. + + auto Private2FE = Processed.fileManager().getFile("private2.h"); + assert(Private2FE); + EXPECT_TRUE(PI.isPrivate(Private2FE.get())); } TEST_F(PragmaIncludeTest, IWYUExport) {