diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp --- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp +++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp @@ -19,7 +19,7 @@ switch (Loc.kind()) { case SymbolLocation::Physical: { // FIXME: Handle macro locations. - FileID FID = SM.getFileID(Loc.physical()); + FileID FID = SM.getFileID(SM.getExpansionLoc(Loc.physical())); const FileEntry *FE = SM.getFileEntryForID(FID); if (!PI) { return FE ? llvm::SmallVector
{Header(FE)} diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp --- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp @@ -7,11 +7,16 @@ //===----------------------------------------------------------------------===// #include "AnalysisInternal.h" +#include "clang-include-cleaner/Analysis.h" #include "clang-include-cleaner/Record.h" +#include "clang-include-cleaner/Types.h" #include "clang/Basic/FileEntry.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Testing/TestAST.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Testing/Support/Annotations.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include @@ -31,7 +36,7 @@ std::unique_ptr AST; FindHeadersTest() { Inputs.MakeAction = [this] { - struct Hook : public PreprocessOnlyAction { + struct Hook : public SyntaxOnlyAction { public: Hook(PragmaIncludes *Out) : Out(Out) {} bool BeginSourceFileAction(clang::CompilerInstance &CI) override { @@ -153,5 +158,121 @@ physicalHeader("exporter.h"))); } +TEST_F(FindHeadersTest, TargetIsArgumentExpandedFromMacroInHeader) { + llvm::Annotations MainFile(R"cpp( + #include "declare.h" + Foo foo; + )cpp"); + Inputs.Code = MainFile.code(); + Inputs.ExtraFiles["declare.h"] = R"cpp( + #include "macro.h" + DEFINE_CLASS(Foo) + )cpp"; + Inputs.ExtraFiles["macro.h"] = R"cpp( + #define DEFINE_CLASS(name) class name {}; + )cpp"; + + buildAST(); + llvm::SmallVector TopLevelDecls; + for (Decl *D : AST->context().getTranslationUnitDecl()->decls()) { + if (!AST->sourceManager().isWrittenInMainFile( + AST->sourceManager().getExpansionLoc(D->getLocation()))) + continue; + TopLevelDecls.emplace_back(D); + } + EXPECT_EQ(TopLevelDecls.size(), 1u); + + std::vector
Headers; + walkUsed( + TopLevelDecls, {}, nullptr, AST->sourceManager(), + [&Headers](const SymbolReference &Ref, llvm::ArrayRef
Providers) { + if (!llvm::isa(Ref.Target.declaration())) + return; + for (const Header &Header : Providers) + Headers.push_back(Header); + }); + + EXPECT_EQ(Headers.size(), 1u); + EXPECT_THAT(Headers, UnorderedElementsAre(physicalHeader("declare.h"))); +} + +TEST_F(FindHeadersTest, TargetIsBodyExpandedFromMacroInHeader) { + llvm::Annotations MainFile(R"cpp( + #include "declare.h" + void test(Foo foo); + )cpp"); + Inputs.Code = MainFile.code(); + Inputs.ExtraFiles["declare.h"] = R"cpp( + #include "macro.h" + DEFINE_Foo + )cpp"; + Inputs.ExtraFiles["macro.h"] = R"cpp( + #define DEFINE_Foo class Foo {}; + )cpp"; + + buildAST(); + llvm::SmallVector TopLevelDecls; + for (Decl *D : AST->context().getTranslationUnitDecl()->decls()) { + if (!AST->sourceManager().isWrittenInMainFile( + AST->sourceManager().getExpansionLoc(D->getLocation()))) + continue; + TopLevelDecls.emplace_back(D); + } + EXPECT_EQ(TopLevelDecls.size(), 1u); + + std::vector
Headers; + walkUsed( + TopLevelDecls, {}, nullptr, AST->sourceManager(), + [&Headers](const SymbolReference &Ref, llvm::ArrayRef
Providers) { + if (!llvm::isa(Ref.Target.declaration())) + return; + for (const Header &Header : Providers) + Headers.push_back(Header); + }); + + EXPECT_EQ(Headers.size(), 1u); + EXPECT_THAT(Headers, UnorderedElementsAre(physicalHeader("declare.h"))); +} + +TEST_F(FindHeadersTest, TargetIsTokenPasted) { + llvm::Annotations MainFile(R"cpp( + #include "declare.h" + void foo() { + FLAG_foo; + } + )cpp"); + Inputs.Code = MainFile.code(); + Inputs.ExtraFiles["declare.h"] = R"cpp( + #include "flag.h" + DECLARE_FLAGS(foo); + )cpp"; + Inputs.ExtraFiles["flag.h"] = R"cpp( + #define DECLARE_FLAGS(name) extern int FLAG_##name + )cpp"; + + buildAST(); + llvm::SmallVector TopLevelDecls; + for (Decl *D : AST->context().getTranslationUnitDecl()->decls()) { + if (!AST->sourceManager().isWrittenInMainFile( + AST->sourceManager().getExpansionLoc(D->getLocation()))) + continue; + TopLevelDecls.emplace_back(D); + } + EXPECT_EQ(TopLevelDecls.size(), 1u); + + std::vector
Headers; + walkUsed( + TopLevelDecls, {}, nullptr, AST->sourceManager(), + [&Headers](const SymbolReference &Ref, llvm::ArrayRef
Providers) { + if (!llvm::isa(Ref.Target.declaration())) + return; + for (const Header &Header : Providers) + Headers.push_back(Header); + }); + + EXPECT_EQ(Headers.size(), 1u); + EXPECT_THAT(Headers, UnorderedElementsAre(physicalHeader("declare.h"))); +} + } // namespace } // namespace clang::include_cleaner \ No newline at end of file