[clang-tools-extra] c3ad4b7 - [include-cleaner] Follow `IWYU pragma: export` links transitively.
Viktoriia Bakalova via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 9 05:10:20 PDT 2023
Author: Viktoriia Bakalova
Date: 2023-08-09T12:10:13Z
New Revision: c3ad4b7636022db387e33ab03247a93aa63d7488
URL: https://github.com/llvm/llvm-project/commit/c3ad4b7636022db387e33ab03247a93aa63d7488
DIFF: https://github.com/llvm/llvm-project/commit/c3ad4b7636022db387e33ab03247a93aa63d7488.diff
LOG: [include-cleaner] Follow `IWYU pragma: export` links transitively.
Differential Revision: https://reviews.llvm.org/D157395
Added:
Modified:
clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
clang-tools-extra/include-cleaner/lib/Record.cpp
clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
index a1d9d3b5fb2154..f9438a2c8c49e4 100644
--- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
+++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
@@ -25,6 +25,8 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <optional>
+#include <queue>
+#include <set>
#include <utility>
namespace clang::include_cleaner {
@@ -188,13 +190,13 @@ llvm::SmallVector<Hinted<Header>> findHeaders(const SymbolLocation &Loc,
if (!PI)
return {{FE, Hints::PublicHeader | Hints::OriginHeader}};
bool IsOrigin = true;
+ std::queue<const FileEntry *> Exporters;
while (FE) {
Results.emplace_back(FE,
isPublicHeader(FE, *PI) |
(IsOrigin ? Hints::OriginHeader : Hints::None));
- // FIXME: compute transitive exporter headers.
for (const auto *Export : PI->getExporters(FE, SM.getFileManager()))
- Results.emplace_back(Export, isPublicHeader(Export, *PI));
+ Exporters.push(Export);
if (auto Verbatim = PI->getPublic(FE); !Verbatim.empty()) {
Results.emplace_back(Verbatim,
@@ -209,6 +211,20 @@ llvm::SmallVector<Hinted<Header>> findHeaders(const SymbolLocation &Loc,
FE = SM.getFileEntryForID(FID);
IsOrigin = false;
}
+ // Now traverse provider trees rooted at exporters.
+ // Note that we only traverse export edges, and ignore private -> public
+ // mappings, as those pragmas apply to exporter, and not the main provider
+ // being exported in this header.
+ std::set<const FileEntry *> SeenExports;
+ while (!Exporters.empty()) {
+ auto *Export = Exporters.front();
+ Exporters.pop();
+ if (!SeenExports.insert(Export).second) // In case of cyclic exports
+ continue;
+ Results.emplace_back(Export, isPublicHeader(Export, *PI));
+ for (const auto *Export : PI->getExporters(Export, SM.getFileManager()))
+ Exporters.push(Export);
+ }
return Results;
}
case SymbolLocation::Standard: {
diff --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp
index 62eaa16dbf3373..d7237325f701bb 100644
--- a/clang-tools-extra/include-cleaner/lib/Record.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Record.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/FileEntry.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -24,16 +25,21 @@
#include "clang/Tooling/Inclusions/HeaderAnalysis.h"
#include "clang/Tooling/Inclusions/StandardLibrary.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem/UniqueID.h"
#include "llvm/Support/StringSaver.h"
#include <algorithm>
#include <assert.h>
#include <memory>
#include <optional>
+#include <set>
#include <utility>
#include <vector>
diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
index cbe1f67d9bf7e5..be97eb13a704ee 100644
--- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
@@ -481,6 +481,55 @@ TEST_F(HeadersForSymbolTest, PublicOverPrivateWithoutUmbrella) {
ElementsAre(physicalHeader("bar.h"), physicalHeader("foo.h")));
}
+TEST_F(HeadersForSymbolTest, IWYUTransitiveExport) {
+ Inputs.Code = R"cpp(
+ #include "export1.h"
+ )cpp";
+ Inputs.ExtraFiles["export1.h"] = guard(R"cpp(
+ #include "export2.h" // IWYU pragma: export
+ )cpp");
+ Inputs.ExtraFiles["export2.h"] = guard(R"cpp(
+ #include "foo.h" // IWYU pragma: export
+ )cpp");
+ Inputs.ExtraFiles["foo.h"] = guard(R"cpp(
+ struct foo {};
+ )cpp");
+ buildAST();
+ EXPECT_THAT(headersForFoo(),
+ ElementsAre(physicalHeader("foo.h"), physicalHeader("export1.h"),
+ physicalHeader("export2.h")));
+}
+
+TEST_F(HeadersForSymbolTest, IWYUTransitiveExportWithPrivate) {
+ Inputs.Code = R"cpp(
+ #include "export1.h"
+ void bar() { foo();}
+ )cpp";
+ Inputs.ExtraFiles["export1.h"] = guard(R"cpp(
+ // IWYU pragma: private, include "public1.h"
+ #include "export2.h" // IWYU pragma: export
+ void foo();
+ )cpp");
+ Inputs.ExtraFiles["export2.h"] = guard(R"cpp(
+ // IWYU pragma: private, include "public2.h"
+ #include "export3.h" // IWYU pragma: export
+ )cpp");
+ Inputs.ExtraFiles["export3.h"] = guard(R"cpp(
+ // IWYU pragma: private, include "public3.h"
+ #include "foo.h" // IWYU pragma: export
+ )cpp");
+ Inputs.ExtraFiles["foo.h"] = guard(R"cpp(
+ void foo();
+ )cpp");
+ buildAST();
+ EXPECT_THAT(headersForFoo(),
+ ElementsAre(physicalHeader("foo.h"),
+ Header(StringRef("\"public1.h\"")),
+ physicalHeader("export1.h"),
+ physicalHeader("export2.h"),
+ physicalHeader("export3.h")));
+}
+
TEST_F(HeadersForSymbolTest, AmbiguousStdSymbols) {
struct {
llvm::StringRef Code;
More information about the cfe-commits
mailing list