diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp index a1781f4e24f2..e48a380211af 100644 --- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp +++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp @@ -58,7 +58,19 @@ void walkUsed(llvm::ArrayRef ASTRoots, tooling::stdlib::Recognizer Recognizer; for (auto *Root : ASTRoots) { walkAST(*Root, [&](SourceLocation Loc, NamedDecl &ND, RefType RT) { - auto FID = SM.getFileID(SM.getSpellingLoc(Loc)); + auto SpellLoc = SM.getSpellingLoc(Loc); + // Tokens resulting from macro concatenation ends up in scratch space and + // clang currently doesn't have a good/simple APIs for tracking where + // pieces of a concataned token originated from. + // So we use the macro expansion location instead, and downgrade reference + // type to ambigious to prevent false negatives. + if (SM.isWrittenInScratchSpace(SpellLoc)) { + Loc = SM.getExpansionLoc(Loc); + if (RT == RefType::Explicit) + RT = RefType::Ambiguous; + SpellLoc = SM.getSpellingLoc(Loc); + } + auto FID = SM.getFileID(SpellLoc); if (FID != SM.getMainFileID() && FID != SM.getPreambleFileID()) return; // FIXME: Most of the work done here is repetitive. It might be useful to diff --git a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp index 74321c312cb7..ba5a3fbbcaeb 100644 --- a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp @@ -680,5 +680,31 @@ TEST_F(WalkUsedTest, IgnoresIdentityMacros) { // FIXME: we should have a reference from stdin to header.h Pair(Code.point("bar"), UnorderedElementsAre(MainFile)))); } + +TEST_F(WalkUsedTest, MacroConcat) { + llvm::Annotations Code(R"cpp( + #include "header.h" + void f() { + $xyz^FOO(xyz) = 1; + $bar^BAR = 2; + } + )cpp"); + Inputs.Code = Code.code(); + Inputs.ExtraFiles["header.h"] = guard(R"cpp( + #define FOO(x) FLAGS_##x + #define BAR FOO(bb) + + int FLAGS_xyz; + int FLAGS_bb; + )cpp"); + + TestAST AST(Inputs); + auto &SM = AST.sourceManager(); + auto Header = *SM.getFileManager().getOptionalFileRef("header.h"); + EXPECT_THAT( + offsetToProviders(AST), + AllOf(Contains(Pair(Code.point("bar"), UnorderedElementsAre(Header))), + Contains(Pair(Code.point("xyz"), UnorderedElementsAre(Header))))); +} } // namespace } // namespace clang::include_cleaner