PPCallbacks::MacroUndefined, change signature and add test.

Summary:
The PPCallbacks::MacroUndefined callback is currently insufficient for clients that need to track the MacroDirectives.
This patch adds an additional argument to PPCallbacks::MacroUndefined that is the undef MacroDirective.

Reviewers: bruno, manmanren

Reviewed By: bruno

Subscribers: nemanjai, cfe-commits

Differential Revision: https://reviews.llvm.org/D29923

llvm-svn: 301449
This commit is contained in:
Frederich Munch 2017-04-26 19:47:31 +00:00
parent 2074b67ec2
commit b7755111a2
7 changed files with 88 additions and 46 deletions

View File

@ -247,10 +247,14 @@ public:
} }
/// \brief Hook called whenever a macro \#undef is seen. /// \brief Hook called whenever a macro \#undef is seen.
/// \param Token The active Token
/// \param MD A MacroDefinition for the named macro.
/// \param Undef New MacroDirective if the macro was defined, null otherwise.
/// ///
/// MD is released immediately following this callback. /// MD is released immediately following this callback.
virtual void MacroUndefined(const Token &MacroNameTok, virtual void MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MD) { const MacroDefinition &MD,
const MacroDirective *Undef) {
} }
/// \brief Hook called whenever the 'defined' operator is seen. /// \brief Hook called whenever the 'defined' operator is seen.
@ -439,15 +443,17 @@ public:
Second->MacroExpands(MacroNameTok, MD, Range, Args); Second->MacroExpands(MacroNameTok, MD, Range, Args);
} }
void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { void MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) override {
First->MacroDefined(MacroNameTok, MD); First->MacroDefined(MacroNameTok, MD);
Second->MacroDefined(MacroNameTok, MD); Second->MacroDefined(MacroNameTok, MD);
} }
void MacroUndefined(const Token &MacroNameTok, void MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MD) override { const MacroDefinition &MD,
First->MacroUndefined(MacroNameTok, MD); const MacroDirective *Undef) override {
Second->MacroUndefined(MacroNameTok, MD); First->MacroUndefined(MacroNameTok, MD, Undef);
Second->MacroUndefined(MacroNameTok, MD, Undef);
} }
void Defined(const Token &MacroNameTok, const MacroDefinition &MD, void Defined(const Token &MacroNameTok, const MacroDefinition &MD,

View File

@ -488,7 +488,8 @@ namespace clang {
void MacroExpands(const Token &Id, const MacroDefinition &MD, void MacroExpands(const Token &Id, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override; SourceRange Range, const MacroArgs *Args) override;
void MacroDefined(const Token &Id, const MacroDirective *MD) override; void MacroDefined(const Token &Id, const MacroDirective *MD) override;
void MacroUndefined(const Token &Id, const MacroDefinition &MD) override; void MacroUndefined(const Token &Id, const MacroDefinition &MD,
const MacroDirective *Undef) override;
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled, StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange, CharSourceRange FilenameRange,

View File

@ -172,7 +172,8 @@ public:
/// MacroUndefined - This hook is called whenever a macro #undef is seen. /// MacroUndefined - This hook is called whenever a macro #undef is seen.
void MacroUndefined(const Token &MacroNameTok, void MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MD) override; const MacroDefinition &MD,
const MacroDirective *Undef) override;
}; };
} // end anonymous namespace } // end anonymous namespace
@ -389,7 +390,8 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
} }
void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok, void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MD) { const MacroDefinition &MD,
const MacroDirective *Undef) {
// Only print out macro definitions in -dD mode. // Only print out macro definitions in -dD mode.
if (!DumpDefines) return; if (!DumpDefines) return;

View File

@ -2592,25 +2592,26 @@ void Preprocessor::HandleUndefDirective() {
// Okay, we have a valid identifier to undef. // Okay, we have a valid identifier to undef.
auto *II = MacroNameTok.getIdentifierInfo(); auto *II = MacroNameTok.getIdentifierInfo();
auto MD = getMacroDefinition(II); auto MD = getMacroDefinition(II);
UndefMacroDirective *Undef = nullptr;
// If the macro is not defined, this is a noop undef.
if (const MacroInfo *MI = MD.getMacroInfo()) {
if (!MI->isUsed() && MI->isWarnIfUnused())
Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
if (MI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
Undef = AllocateUndefMacroDirective(MacroNameTok.getLocation());
}
// If the callbacks want to know, tell them about the macro #undef. // If the callbacks want to know, tell them about the macro #undef.
// Note: no matter if the macro was defined or not. // Note: no matter if the macro was defined or not.
if (Callbacks) if (Callbacks)
Callbacks->MacroUndefined(MacroNameTok, MD); Callbacks->MacroUndefined(MacroNameTok, MD, Undef);
// If the macro is not defined, this is a noop undef, just return. if (Undef)
const MacroInfo *MI = MD.getMacroInfo(); appendMacroDirective(II, Undef);
if (!MI)
return;
if (!MI->isUsed() && MI->isWarnIfUnused())
Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
if (MI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
appendMacroDirective(MacroNameTok.getIdentifierInfo(),
AllocateUndefMacroDirective(MacroNameTok.getLocation()));
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -422,7 +422,8 @@ void PreprocessingRecord::MacroDefined(const Token &Id,
} }
void PreprocessingRecord::MacroUndefined(const Token &Id, void PreprocessingRecord::MacroUndefined(const Token &Id,
const MacroDefinition &MD) { const MacroDefinition &MD,
const MacroDirective *Undef) {
MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); }); MD.forAllDefinitions([&](MacroInfo *MI) { MacroDefinitions.erase(MI); });
} }

View File

@ -262,7 +262,8 @@ public:
/// MacroUndefined - This hook is called whenever a macro #undef is seen. /// MacroUndefined - This hook is called whenever a macro #undef is seen.
/// MI is released immediately following this callback. /// MI is released immediately following this callback.
void MacroUndefined(const Token &MacroNameTok, void MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MD) override {} const MacroDefinition &MD,
const MacroDirective *UD) override {}
/// MacroExpands - This is called by when a macro invocation is found. /// MacroExpands - This is called by when a macro invocation is found.
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,

View File

@ -249,12 +249,18 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
namespace { namespace {
struct MacroAction { struct MacroAction {
enum Kind { kExpansion, kDefinition, kUnDefinition};
SourceLocation Loc; SourceLocation Loc;
std::string Name; std::string Name;
bool isDefinition; // if false, it is expansion. unsigned MAKind : 3;
MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition) MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
: Loc(Loc), Name(Name), isDefinition(isDefinition) { } : Loc(Loc), Name(Name), MAKind(K) { }
bool isExpansion() const { return MAKind == kExpansion; }
bool isDefinition() const { return MAKind & kDefinition; }
bool isUnDefinition() const { return MAKind & kUnDefinition; }
}; };
class MacroTracker : public PPCallbacks { class MacroTracker : public PPCallbacks {
@ -267,13 +273,22 @@ public:
const MacroDirective *MD) override { const MacroDirective *MD) override {
Macros.push_back(MacroAction(MD->getLocation(), Macros.push_back(MacroAction(MD->getLocation(),
MacroNameTok.getIdentifierInfo()->getName(), MacroNameTok.getIdentifierInfo()->getName(),
true)); MacroAction::kDefinition));
}
void MacroUndefined(const Token &MacroNameTok,
const MacroDefinition &MD,
const MacroDirective *UD) override {
Macros.push_back(
MacroAction(UD ? UD->getLocation() : SourceLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
: MacroAction::kUnDefinition));
} }
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
SourceRange Range, const MacroArgs *Args) override { SourceRange Range, const MacroArgs *Args) override {
Macros.push_back(MacroAction(MacroNameTok.getLocation(), Macros.push_back(MacroAction(MacroNameTok.getLocation(),
MacroNameTok.getIdentifierInfo()->getName(), MacroNameTok.getIdentifierInfo()->getName(),
false)); MacroAction::kExpansion));
} }
}; };
@ -281,7 +296,10 @@ public:
TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
const char *header = const char *header =
"#define MACRO_IN_INCLUDE 0\n"; "#define MACRO_IN_INCLUDE 0\n"
"#define MACRO_DEFINED\n"
"#undef MACRO_DEFINED\n"
"#undef MACRO_UNDEFINED\n";
const char *main = const char *main =
"#define M(x) x\n" "#define M(x) x\n"
@ -327,34 +345,46 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
// Make sure we got the tokens that we expected. // Make sure we got the tokens that we expected.
ASSERT_EQ(0U, toks.size()); ASSERT_EQ(0U, toks.size());
ASSERT_EQ(9U, Macros.size()); ASSERT_EQ(15U, Macros.size());
// #define M(x) x // #define M(x) x
ASSERT_TRUE(Macros[0].isDefinition); ASSERT_TRUE(Macros[0].isDefinition());
ASSERT_EQ("M", Macros[0].Name); ASSERT_EQ("M", Macros[0].Name);
// #define INC "/test-header.h" // #define INC "/test-header.h"
ASSERT_TRUE(Macros[1].isDefinition); ASSERT_TRUE(Macros[1].isDefinition());
ASSERT_EQ("INC", Macros[1].Name); ASSERT_EQ("INC", Macros[1].Name);
// M expansion in #include M(INC) // M expansion in #include M(INC)
ASSERT_FALSE(Macros[2].isDefinition); ASSERT_FALSE(Macros[2].isDefinition());
ASSERT_EQ("M", Macros[2].Name); ASSERT_EQ("M", Macros[2].Name);
// INC expansion in #include M(INC) // INC expansion in #include M(INC)
ASSERT_FALSE(Macros[3].isDefinition); ASSERT_TRUE(Macros[3].isExpansion());
ASSERT_EQ("INC", Macros[3].Name); ASSERT_EQ("INC", Macros[3].Name);
// #define MACRO_IN_INCLUDE 0 // #define MACRO_IN_INCLUDE 0
ASSERT_TRUE(Macros[4].isDefinition); ASSERT_TRUE(Macros[4].isDefinition());
ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
// #define MACRO_DEFINED
ASSERT_TRUE(Macros[5].isDefinition());
ASSERT_FALSE(Macros[5].isUnDefinition());
ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
// #undef MACRO_DEFINED
ASSERT_TRUE(Macros[6].isDefinition());
ASSERT_TRUE(Macros[6].isUnDefinition());
ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
// #undef MACRO_UNDEFINED
ASSERT_FALSE(Macros[7].isDefinition());
ASSERT_TRUE(Macros[7].isUnDefinition());
ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
// #define INC2 </test-header.h> // #define INC2 </test-header.h>
ASSERT_TRUE(Macros[5].isDefinition); ASSERT_TRUE(Macros[8].isDefinition());
ASSERT_EQ("INC2", Macros[5].Name); ASSERT_EQ("INC2", Macros[8].Name);
// M expansion in #include M(INC2) // M expansion in #include M(INC2)
ASSERT_FALSE(Macros[6].isDefinition); ASSERT_FALSE(Macros[9].isDefinition());
ASSERT_EQ("M", Macros[6].Name); ASSERT_EQ("M", Macros[9].Name);
// INC2 expansion in #include M(INC2) // INC2 expansion in #include M(INC2)
ASSERT_FALSE(Macros[7].isDefinition); ASSERT_TRUE(Macros[10].isExpansion());
ASSERT_EQ("INC2", Macros[7].Name); ASSERT_EQ("INC2", Macros[10].Name);
// #define MACRO_IN_INCLUDE 0 // #define MACRO_IN_INCLUDE 0
ASSERT_TRUE(Macros[8].isDefinition); ASSERT_TRUE(Macros[11].isDefinition());
ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name); ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
// The INC expansion in #include M(INC) comes before the first // The INC expansion in #include M(INC) comes before the first
// MACRO_IN_INCLUDE definition of the included file. // MACRO_IN_INCLUDE definition of the included file.
@ -362,7 +392,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
// The INC2 expansion in #include M(INC2) comes before the second // The INC2 expansion in #include M(INC2) comes before the second
// MACRO_IN_INCLUDE definition of the included file. // MACRO_IN_INCLUDE definition of the included file.
EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc)); EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
} }
#endif #endif