diff --git a/clang-tools-extra/include-cleaner/lib/Record.cpp b/clang-tools-extra/include-cleaner/lib/Record.cpp --- a/clang-tools-extra/include-cleaner/lib/Record.cpp +++ b/clang-tools-extra/include-cleaner/lib/Record.cpp @@ -83,14 +83,54 @@ recordMacroRef(MacroName, *MI); } + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + if (!Active) + return; + if (const auto *MI = MD.getMacroInfo()) + recordMacroRef(MacroNameTok, *MI, RefType::Ambiguous); + } + + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + if (!Active) + return; + if (const auto *MI = MD.getMacroInfo()) + recordMacroRef(MacroNameTok, *MI, RefType::Ambiguous); + } + + void Elifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + if (!Active) + return; + if (const auto *MI = MD.getMacroInfo()) + recordMacroRef(MacroNameTok, *MI, RefType::Ambiguous); + } + + void Elifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) override { + if (!Active) + return; + if (const auto *MI = MD.getMacroInfo()) + recordMacroRef(MacroNameTok, *MI, RefType::Ambiguous); + } + + void Defined(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range) override { + if (!Active) + return; + if (const auto *MI = MD.getMacroInfo()) + recordMacroRef(MacroNameTok, *MI, RefType::Ambiguous); + } + private: - void recordMacroRef(const Token &Tok, const MacroInfo &MI) { + void recordMacroRef(const Token &Tok, const MacroInfo &MI, + RefType RT = RefType::Explicit) { if (MI.isBuiltinMacro()) return; // __FILE__ is not a reference. - Recorded.MacroReferences.push_back( - SymbolReference{Tok.getLocation(), - Macro{Tok.getIdentifierInfo(), MI.getDefinitionLoc()}, - RefType::Explicit}); + Recorded.MacroReferences.push_back(SymbolReference{ + Tok.getLocation(), + Macro{Tok.getIdentifierInfo(), MI.getDefinitionLoc()}, RT}); } bool Active = false; diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp --- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp @@ -7,12 +7,13 @@ //===----------------------------------------------------------------------===// #include "clang-include-cleaner/Record.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Testing/TestAST.h" #include "clang/Tooling/Inclusions/StandardLibrary.h" -#include "llvm/Support/VirtualFileSystem.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Testing/Support/Annotations.h" #include "gmock/gmock.h" @@ -218,6 +219,49 @@ EXPECT_THAT(ExpOffsets, ElementsAreArray(MainFile.points("exp"))); } +TEST_F(RecordPPTest, CapturesConditionalMacroRefs) { + llvm::Annotations MainFile(R"cpp( + #define X 1 + + #ifdef ^X + #endif + + #if defined(^X) + #endif + + #ifndef ^X + #endif + + int main() { + #ifdef Y + #elifdef ^X + #else + #endif + + #ifndef ^X + #elifndef ^X + #else + #endif + return 0; + } + )cpp"); + + Inputs.Code = MainFile.code(); + auto AST = build(); + + std::vector RefOffsets; + SourceManager &SM = AST.sourceManager(); + ASSERT_THAT(Recorded.MacroReferences, Not(IsEmpty())); + for (const auto &Ref : Recorded.MacroReferences) { + auto [FID, Off] = SM.getDecomposedLoc(Ref.RefLocation); + ASSERT_EQ(FID, SM.getMainFileID()); + EXPECT_EQ(Ref.RT, RefType::Ambiguous); + EXPECT_EQ("X", Ref.Target.macro().Name->getName()); + RefOffsets.push_back(Off); + } + EXPECT_THAT(RefOffsets, ElementsAreArray(MainFile.points())); +} + // Matches an Include* on the specified line; MATCHER_P(line, N, "") { return arg->Line == (unsigned)N; }