Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

Commit

Permalink
[include-cleaner] Follow IWYU pragma: export links transitively.
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D157395
  • Loading branch information
VitaNuo committed Aug 9, 2023
1 parent 4434bc5 commit c3ad4b7
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 2 deletions.
20 changes: 18 additions & 2 deletions clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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: {
Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/include-cleaner/lib/Record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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>

Expand Down
49 changes: 49 additions & 0 deletions clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit c3ad4b7

Please sign in to comment.