[clang-tools-extra] 29a8eec - [include-cleaner] Make use of locateSymbol in WalkUsed and HTMLReport
Kadir Cetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 6 06:03:25 PST 2022
Author: Kadir Cetinkaya
Date: 2022-12-06T15:03:11+01:00
New Revision: 29a8eec1f9eb6df8d52d8621415754989595fb6a
URL: https://github.com/llvm/llvm-project/commit/29a8eec1f9eb6df8d52d8621415754989595fb6a
DIFF: https://github.com/llvm/llvm-project/commit/29a8eec1f9eb6df8d52d8621415754989595fb6a.diff
LOG: [include-cleaner] Make use of locateSymbol in WalkUsed and HTMLReport
Depens on D135953
Differential Revision: https://reviews.llvm.org/D138200
Added:
clang-tools-extra/include-cleaner/test/Inputs/foo2.h
clang-tools-extra/include-cleaner/test/multiple-providers.cpp
Modified:
clang-tools-extra/include-cleaner/lib/Analysis.cpp
clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
index c83b4d5a25be0..95cf8ab7550a5 100644
--- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp
+++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
@@ -8,8 +8,10 @@
#include "clang-include-cleaner/Analysis.h"
#include "AnalysisInternal.h"
+#include "clang-include-cleaner/Record.h"
#include "clang-include-cleaner/Types.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Lex/HeaderSearch.h"
@@ -21,6 +23,18 @@
namespace clang::include_cleaner {
+namespace {
+// Gets all the providers for a symbol by tarversing each location.
+llvm::SmallVector<Header> headersForSymbol(const Symbol &S,
+ const SourceManager &SM,
+ const PragmaIncludes *PI) {
+ llvm::SmallVector<Header> Headers;
+ for (auto &Loc : locateSymbol(S))
+ Headers.append(findHeaders(Loc, SM, PI));
+ return Headers;
+}
+} // namespace
+
void walkUsed(llvm::ArrayRef<Decl *> ASTRoots,
llvm::ArrayRef<SymbolReference> MacroRefs,
const PragmaIncludes *PI, const SourceManager &SM,
@@ -30,19 +44,15 @@ void walkUsed(llvm::ArrayRef<Decl *> ASTRoots,
for (auto *Root : ASTRoots) {
auto &SM = Root->getASTContext().getSourceManager();
walkAST(*Root, [&](SourceLocation Loc, NamedDecl &ND, RefType RT) {
+ // FIXME: Most of the work done here is repetative. It might be useful to
+ // have a cache/batching.
SymbolReference SymRef{Loc, ND, RT};
- if (auto SS = Recognizer(&ND)) {
- // FIXME: Also report forward decls from main-file, so that the caller
- // can decide to insert/ignore a header.
- return CB(SymRef, findHeaders(*SS, SM, PI));
- }
- // FIXME: Extract locations from redecls.
- return CB(SymRef, findHeaders(ND.getLocation(), SM, PI));
+ return CB(SymRef, headersForSymbol(ND, SM, PI));
});
}
for (const SymbolReference &MacroRef : MacroRefs) {
assert(MacroRef.Target.kind() == Symbol::Macro);
- CB(MacroRef, findHeaders(MacroRef.Target.macro().Definition, SM, PI));
+ return CB(MacroRef, headersForSymbol(MacroRef.Target, SM, PI));
}
}
diff --git a/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp b/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
index 4d109d5f6d206..6d165b5d22ded 100644
--- a/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
+++ b/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
@@ -154,7 +154,7 @@ class Reporter {
};
std::vector<Ref> Refs;
llvm::DenseMap<const Include *, std::vector<unsigned>> IncludeRefs;
- llvm::StringMap<std::vector</*RefIndex*/unsigned>> Insertion;
+ llvm::StringMap<std::vector</*RefIndex*/ unsigned>> Insertion;
llvm::StringRef includeType(const Include *I) {
auto &List = IncludeRefs[I];
@@ -185,17 +185,8 @@ class Reporter {
void fillTarget(Ref &R) {
// Duplicates logic from walkUsed(), which doesn't expose SymbolLocations.
- // FIXME: use locateDecl and friends once implemented.
- // This doesn't use stdlib::Recognizer, but locateDecl will soon do that.
- switch (R.Sym.kind()) {
- case Symbol::Declaration:
- R.Locations.push_back(R.Sym.declaration().getLocation());
- break;
- case Symbol::Macro:
- R.Locations.push_back(R.Sym.macro().Definition);
- break;
- }
-
+ for (auto &Loc : locateSymbol(R.Sym))
+ R.Locations.push_back(Loc);
for (const auto &Loc : R.Locations)
R.Headers.append(findHeaders(Loc, SM, PI));
@@ -220,8 +211,8 @@ class Reporter {
public:
Reporter(llvm::raw_ostream &OS, ASTContext &Ctx, HeaderSearch &HS,
- const include_cleaner::Includes &Includes,
- const PragmaIncludes *PI, FileID MainFile)
+ const include_cleaner::Includes &Includes, const PragmaIncludes *PI,
+ FileID MainFile)
: OS(OS), Ctx(Ctx), SM(Ctx.getSourceManager()), HS(HS),
Includes(Includes), PI(PI), MainFile(MainFile),
MainFE(SM.getFileEntryForID(MainFile)) {}
@@ -321,7 +312,7 @@ class Reporter {
printFilename(SM.getSpellingLoc(Loc).printToString(SM));
OS << ">";
}
-
+
// Write "Provides: " rows of an include or include-insertion table.
// These describe the symbols the header provides, referenced by RefIndices.
void writeProvides(llvm::ArrayRef<unsigned> RefIndices) {
@@ -366,7 +357,7 @@ class Reporter {
}
OS << "</table>";
}
-
+
void writeInsertion(llvm::StringRef Text, llvm::ArrayRef<unsigned> Refs) {
OS << "<table class='insertion'>";
writeProvides(Refs);
@@ -440,7 +431,7 @@ class Reporter {
llvm::sort(Insertions);
for (llvm::StringRef Insertion : Insertions) {
OS << "<code class='line added'>"
- << "<span class='inc sel inserted' data-hover='i";
+ << "<span class='inc sel inserted' data-hover='i";
escapeString(Insertion);
OS << "'>#include ";
escapeString(Insertion);
diff --git a/clang-tools-extra/include-cleaner/test/Inputs/foo2.h b/clang-tools-extra/include-cleaner/test/Inputs/foo2.h
new file mode 100644
index 0000000000000..00b6b8448ec0b
--- /dev/null
+++ b/clang-tools-extra/include-cleaner/test/Inputs/foo2.h
@@ -0,0 +1,6 @@
+#ifndef FOO2_H
+#define FOO2_H
+
+int foo();
+
+#endif
diff --git a/clang-tools-extra/include-cleaner/test/multiple-providers.cpp b/clang-tools-extra/include-cleaner/test/multiple-providers.cpp
new file mode 100644
index 0000000000000..0873f5135e4b0
--- /dev/null
+++ b/clang-tools-extra/include-cleaner/test/multiple-providers.cpp
@@ -0,0 +1,8 @@
+// RUN: clang-include-cleaner --print=changes %s -- -I %S/Inputs | FileCheck --allow-empty %s
+#include "foo.h"
+#include "foo2.h"
+
+int n = foo();
+// Make sure both providers are preserved.
+// CHECK-NOT: - "foo.h"
+// CHECK-NOT: - "foo2.h"
diff --git a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
index c6b4801bc2fb9..9a1f4fce801c3 100644
--- a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -18,7 +18,6 @@
#include "clang/Tooling/Inclusions/StandardLibrary.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Testing/Support/Annotations.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -26,6 +25,7 @@
namespace clang::include_cleaner {
namespace {
+using testing::Contains;
using testing::ElementsAre;
using testing::Pair;
using testing::UnorderedElementsAre;
@@ -34,8 +34,48 @@ std::string guard(llvm::StringRef Code) {
return "#pragma once\n" + Code.str();
}
-TEST(WalkUsed, Basic) {
- // FIXME: Have a fixture for setting up tests.
+class WalkUsedTest : public testing::Test {
+protected:
+ TestInputs Inputs;
+ PragmaIncludes PI;
+ WalkUsedTest() {
+ Inputs.MakeAction = [this] {
+ struct Hook : public SyntaxOnlyAction {
+ public:
+ Hook(PragmaIncludes *Out) : Out(Out) {}
+ bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
+ Out->record(CI);
+ return true;
+ }
+
+ PragmaIncludes *Out;
+ };
+ return std::make_unique<Hook>(&PI);
+ };
+ }
+
+ llvm::DenseMap<size_t, std::vector<Header>>
+ offsetToProviders(TestAST &AST, SourceManager &SM,
+ llvm::ArrayRef<SymbolReference> MacroRefs = {}) {
+ llvm::SmallVector<Decl *> TopLevelDecls;
+ for (Decl *D : AST.context().getTranslationUnitDecl()->decls()) {
+ if (!SM.isWrittenInMainFile(SM.getExpansionLoc(D->getLocation())))
+ continue;
+ TopLevelDecls.emplace_back(D);
+ }
+ llvm::DenseMap<size_t, std::vector<Header>> OffsetToProviders;
+ walkUsed(TopLevelDecls, MacroRefs, &PI, SM,
+ [&](const SymbolReference &Ref, llvm::ArrayRef<Header> Providers) {
+ auto [FID, Offset] = SM.getDecomposedLoc(Ref.RefLocation);
+ if (FID != SM.getMainFileID())
+ ADD_FAILURE() << "Reference outside of the main file!";
+ OffsetToProviders.try_emplace(Offset, Providers.vec());
+ });
+ return OffsetToProviders;
+ }
+};
+
+TEST_F(WalkUsedTest, Basic) {
llvm::Annotations Code(R"cpp(
#include "header.h"
#include "private.h"
@@ -45,7 +85,7 @@ TEST(WalkUsed, Basic) {
std::$vector^vector $vconstructor^v;
}
)cpp");
- TestInputs Inputs(Code.code());
+ Inputs.Code = Code.code();
Inputs.ExtraFiles["header.h"] = guard(R"cpp(
void foo();
namespace std { class vector {}; }
@@ -55,85 +95,75 @@ TEST(WalkUsed, Basic) {
class Private {};
)cpp");
- PragmaIncludes PI;
- Inputs.MakeAction = [&PI] {
- struct Hook : public SyntaxOnlyAction {
- public:
- Hook(PragmaIncludes *Out) : Out(Out) {}
- bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
- Out->record(CI);
- return true;
- }
-
- PragmaIncludes *Out;
- };
- return std::make_unique<Hook>(&PI);
- };
TestAST AST(Inputs);
-
- llvm::SmallVector<Decl *> TopLevelDecls;
- for (Decl *D : AST.context().getTranslationUnitDecl()->decls()) {
- TopLevelDecls.emplace_back(D);
- }
-
auto &SM = AST.sourceManager();
- llvm::DenseMap<size_t, std::vector<Header>> OffsetToProviders;
- walkUsed(TopLevelDecls, /*MacroRefs=*/{}, &PI, SM,
- [&](const SymbolReference &Ref, llvm::ArrayRef<Header> Providers) {
- auto [FID, Offset] = SM.getDecomposedLoc(Ref.RefLocation);
- EXPECT_EQ(FID, SM.getMainFileID());
- OffsetToProviders.try_emplace(Offset, Providers.vec());
- });
- auto &FM = AST.fileManager();
- auto HeaderFile = Header(FM.getFile("header.h").get());
+ auto HeaderFile = Header(AST.fileManager().getFile("header.h").get());
+ auto PrivateFile = Header(AST.fileManager().getFile("private.h").get());
+ auto PublicFile = Header("\"path/public.h\"");
auto MainFile = Header(SM.getFileEntryForID(SM.getMainFileID()));
auto VectorSTL = Header(tooling::stdlib::Header::named("<vector>").value());
EXPECT_THAT(
- OffsetToProviders,
+ offsetToProviders(AST, SM),
UnorderedElementsAre(
Pair(Code.point("bar"), UnorderedElementsAre(MainFile)),
Pair(Code.point("private"),
- UnorderedElementsAre(Header("\"path/public.h\""),
- Header(FM.getFile("private.h").get()))),
+ UnorderedElementsAre(PublicFile, PrivateFile)),
Pair(Code.point("foo"), UnorderedElementsAre(HeaderFile)),
Pair(Code.point("vector"), UnorderedElementsAre(VectorSTL)),
Pair(Code.point("vconstructor"), UnorderedElementsAre(VectorSTL))));
}
-TEST(WalkUsed, MacroRefs) {
- llvm::Annotations Hdr(R"cpp(
- #define ^ANSWER 42
+TEST_F(WalkUsedTest, MultipleProviders) {
+ llvm::Annotations Code(R"cpp(
+ #include "header1.h"
+ #include "header2.h"
+ void foo();
+
+ void bar() {
+ $foo^foo();
+ }
+ )cpp");
+ Inputs.Code = Code.code();
+ Inputs.ExtraFiles["header1.h"] = guard(R"cpp(
+ void foo();
+ )cpp");
+ Inputs.ExtraFiles["header2.h"] = guard(R"cpp(
+ void foo();
)cpp");
- llvm::Annotations Main(R"cpp(
+
+ TestAST AST(Inputs);
+ auto &SM = AST.sourceManager();
+ auto HeaderFile1 = Header(AST.fileManager().getFile("header1.h").get());
+ auto HeaderFile2 = Header(AST.fileManager().getFile("header2.h").get());
+ auto MainFile = Header(SM.getFileEntryForID(SM.getMainFileID()));
+ EXPECT_THAT(
+ offsetToProviders(AST, SM),
+ Contains(Pair(Code.point("foo"),
+ UnorderedElementsAre(HeaderFile1, HeaderFile2, MainFile))));
+}
+
+TEST_F(WalkUsedTest, MacroRefs) {
+ llvm::Annotations Code(R"cpp(
#include "hdr.h"
int x = ^ANSWER;
)cpp");
-
- SourceManagerForFile SMF("main.cpp", Main.code());
- auto &SM = SMF.get();
- const FileEntry *HdrFile =
- SM.getFileManager().getVirtualFile("hdr.h", Hdr.code().size(), 0);
- SM.overrideFileContents(HdrFile,
- llvm::MemoryBuffer::getMemBuffer(Hdr.code().str()));
- FileID HdrID = SM.createFileID(HdrFile, SourceLocation(), SrcMgr::C_User);
+ llvm::Annotations Hdr(guard("#define ^ANSWER 42"));
+ Inputs.Code = Code.code();
+ Inputs.ExtraFiles["hdr.h"] = Hdr.code();
+ TestAST AST(Inputs);
+ auto &SM = AST.sourceManager();
+ auto HdrFile = SM.getFileManager().getFile("hdr.h").get();
+ auto HdrID = SM.translateFile(HdrFile);
IdentifierTable Idents;
Symbol Answer =
Macro{&Idents.get("ANSWER"), SM.getComposedLoc(HdrID, Hdr.point())};
- llvm::DenseMap<size_t, std::vector<Header>> OffsetToProviders;
- walkUsed(/*ASTRoots=*/{}, /*MacroRefs=*/
- {SymbolReference{SM.getComposedLoc(SM.getMainFileID(), Main.point()),
- Answer, RefType::Explicit}},
- /*PI=*/nullptr, SM,
- [&](const SymbolReference &Ref, llvm::ArrayRef<Header> Providers) {
- auto [FID, Offset] = SM.getDecomposedLoc(Ref.RefLocation);
- EXPECT_EQ(FID, SM.getMainFileID());
- OffsetToProviders.try_emplace(Offset, Providers.vec());
- });
-
EXPECT_THAT(
- OffsetToProviders,
- UnorderedElementsAre(Pair(Main.point(), UnorderedElementsAre(HdrFile))));
+ offsetToProviders(
+ AST, SM,
+ {SymbolReference{SM.getComposedLoc(SM.getMainFileID(), Code.point()),
+ Answer, RefType::Explicit}}),
+ UnorderedElementsAre(Pair(Code.point(), UnorderedElementsAre(HdrFile))));
}
TEST(Analyze, Basic) {
More information about the cfe-commits
mailing list