forked from OSchip/llvm-project
Add PPCallbacks for #if/#ifdef/etc.
The callback info for #if/#elif is not great -- ideally it would give us a list of tokens in the #if, or even better, a little parse tree. But that's a lot more work. Instead, clients can retokenize using Lexer::LexFromRawLexer(). Reviewed by nlewycky. llvm-svn: 118318
This commit is contained in:
parent
c52df286ea
commit
8e3d95e7df
|
@ -89,6 +89,8 @@ public:
|
|||
}
|
||||
|
||||
/// Ident - This callback is invoked when a #ident or #sccs directive is read.
|
||||
/// \param Loc The location of the directive.
|
||||
/// \param str The text of the directive.
|
||||
///
|
||||
virtual void Ident(SourceLocation Loc, const std::string &str) {
|
||||
}
|
||||
|
@ -102,6 +104,8 @@ public:
|
|||
|
||||
/// PragmaMessage - This callback is invoked when a #pragma message directive
|
||||
/// is read.
|
||||
/// \param Loc The location of the message directive.
|
||||
/// \param str The text of the message directive.
|
||||
///
|
||||
virtual void PragmaMessage(SourceLocation Loc, llvm::StringRef Str) {
|
||||
}
|
||||
|
@ -121,6 +125,38 @@ public:
|
|||
virtual void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II,
|
||||
const MacroInfo *MI) {
|
||||
}
|
||||
|
||||
/// If -- This hook is called whenever an #if is seen.
|
||||
/// \param Range The SourceRange of the expression being tested.
|
||||
// FIXME: better to pass in a list (or tree!) of Tokens.
|
||||
virtual void If(SourceRange Range) {
|
||||
}
|
||||
|
||||
/// Elif -- This hook is called whenever an #elif is seen.
|
||||
/// \param Range The SourceRange of the expression being tested.
|
||||
// FIXME: better to pass in a list (or tree!) of Tokens.
|
||||
virtual void Elif(SourceRange Range) {
|
||||
}
|
||||
|
||||
/// Ifdef -- This hook is called whenever an #ifdef is seen.
|
||||
/// \param Loc The location of the token being tested.
|
||||
/// \param II Information on the token being tested.
|
||||
virtual void Ifdef(SourceLocation Loc, const IdentifierInfo* II) {
|
||||
}
|
||||
|
||||
/// Ifndef -- This hook is called whenever an #ifndef is seen.
|
||||
/// \param Loc The location of the token being tested.
|
||||
/// \param II Information on the token being tested.
|
||||
virtual void Ifndef(SourceLocation Loc, const IdentifierInfo* II) {
|
||||
}
|
||||
|
||||
/// Else -- This hook is called whenever an #else is seen.
|
||||
virtual void Else() {
|
||||
}
|
||||
|
||||
/// Endif -- This hook is called whenever an #endif is seen.
|
||||
virtual void Endif() {
|
||||
}
|
||||
};
|
||||
|
||||
/// PPChainedCallbacks - Simple wrapper class for chaining callbacks.
|
||||
|
@ -184,6 +220,42 @@ public:
|
|||
First->MacroUndefined(Loc, II, MI);
|
||||
Second->MacroUndefined(Loc, II, MI);
|
||||
}
|
||||
|
||||
/// If -- This hook is called whenever an #if is seen.
|
||||
virtual void If(SourceRange Range) {
|
||||
First->If(Range);
|
||||
Second->If(Range);
|
||||
}
|
||||
|
||||
/// Elif -- This hook is called whenever an #if is seen.
|
||||
virtual void ElfIf(SourceRange Range) {
|
||||
First->Elif(Range);
|
||||
Second->Elif(Range);
|
||||
}
|
||||
|
||||
/// Ifdef -- This hook is called whenever an #ifdef is seen.
|
||||
virtual void Ifdef(SourceLocation Loc, const IdentifierInfo* II) {
|
||||
First->Ifdef(Loc, II);
|
||||
Second->Ifdef(Loc, II);
|
||||
}
|
||||
|
||||
/// Ifndef -- This hook is called whenever an #ifndef is seen.
|
||||
virtual void Ifndef(SourceLocation Loc, const IdentifierInfo* II) {
|
||||
First->Ifndef(Loc, II);
|
||||
Second->Ifndef(Loc, II);
|
||||
}
|
||||
|
||||
/// Else -- This hook is called whenever an #else is seen.
|
||||
virtual void Else() {
|
||||
First->Else();
|
||||
Second->Else();
|
||||
}
|
||||
|
||||
/// Endif -- This hook is called whenever an #endif is seen.
|
||||
virtual void Endif() {
|
||||
First->Endif();
|
||||
Second->Endif();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -1623,11 +1623,18 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
|
|||
/*wasskip*/false, /*foundnonskip*/true,
|
||||
/*foundelse*/false);
|
||||
} else {
|
||||
// No, skip the contents of this block and return the first token after it.
|
||||
// No, skip the contents of this block.
|
||||
SkipExcludedConditionalBlock(DirectiveTok.getLocation(),
|
||||
/*Foundnonskip*/false,
|
||||
/*FoundElse*/false);
|
||||
}
|
||||
|
||||
if (Callbacks) {
|
||||
if (isIfndef)
|
||||
Callbacks->Ifndef(MacroNameTok.getLocation(), MII);
|
||||
else
|
||||
Callbacks->Ifdef(MacroNameTok.getLocation(), MII);
|
||||
}
|
||||
}
|
||||
|
||||
/// HandleIfDirective - Implements the #if directive.
|
||||
|
@ -1636,10 +1643,11 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
|
|||
bool ReadAnyTokensBeforeDirective) {
|
||||
++NumIf;
|
||||
|
||||
// Parse and evaluation the conditional expression.
|
||||
// Parse and evaluate the conditional expression.
|
||||
IdentifierInfo *IfNDefMacro = 0;
|
||||
bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
|
||||
|
||||
const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
|
||||
const bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro);
|
||||
const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
|
||||
|
||||
// If this condition is equivalent to #ifndef X, and if this is the first
|
||||
// directive seen, handle it for the multiple-include optimization.
|
||||
|
@ -1656,10 +1664,13 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
|
|||
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
|
||||
/*foundnonskip*/true, /*foundelse*/false);
|
||||
} else {
|
||||
// No, skip the contents of this block and return the first token after it.
|
||||
// No, skip the contents of this block.
|
||||
SkipExcludedConditionalBlock(IfToken.getLocation(), /*Foundnonskip*/false,
|
||||
/*FoundElse*/false);
|
||||
}
|
||||
|
||||
if (Callbacks)
|
||||
Callbacks->If(SourceRange(ConditionalBegin, ConditionalEnd));
|
||||
}
|
||||
|
||||
/// HandleEndifDirective - Implements the #endif directive.
|
||||
|
@ -1683,9 +1694,13 @@ void Preprocessor::HandleEndifDirective(Token &EndifToken) {
|
|||
|
||||
assert(!CondInfo.WasSkipping && !CurPPLexer->LexingRawMode &&
|
||||
"This code should only be reachable in the non-skipping case!");
|
||||
|
||||
if (Callbacks)
|
||||
Callbacks->Endif();
|
||||
}
|
||||
|
||||
|
||||
/// HandleElseDirective - Implements the #else directive.
|
||||
///
|
||||
void Preprocessor::HandleElseDirective(Token &Result) {
|
||||
++NumElse;
|
||||
|
||||
|
@ -1705,19 +1720,25 @@ void Preprocessor::HandleElseDirective(Token &Result) {
|
|||
// If this is a #else with a #else before it, report the error.
|
||||
if (CI.FoundElse) Diag(Result, diag::pp_err_else_after_else);
|
||||
|
||||
// Finally, skip the rest of the contents of this block and return the first
|
||||
// token after it.
|
||||
return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
|
||||
/*FoundElse*/true);
|
||||
// Finally, skip the rest of the contents of this block.
|
||||
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
|
||||
/*FoundElse*/true);
|
||||
|
||||
if (Callbacks)
|
||||
Callbacks->Else();
|
||||
}
|
||||
|
||||
/// HandleElifDirective - Implements the #elif directive.
|
||||
///
|
||||
void Preprocessor::HandleElifDirective(Token &ElifToken) {
|
||||
++NumElse;
|
||||
|
||||
// #elif directive in a non-skipping conditional... start skipping.
|
||||
// We don't care what the condition is, because we will always skip it (since
|
||||
// the block immediately before it was included).
|
||||
const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation();
|
||||
DiscardUntilEndOfDirective();
|
||||
const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation();
|
||||
|
||||
PPConditionalInfo CI;
|
||||
if (CurPPLexer->popConditionalLevel(CI)) {
|
||||
|
@ -1732,8 +1753,10 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) {
|
|||
// If this is a #elif with a #else before it, report the error.
|
||||
if (CI.FoundElse) Diag(ElifToken, diag::pp_err_elif_after_else);
|
||||
|
||||
// Finally, skip the rest of the contents of this block and return the first
|
||||
// token after it.
|
||||
return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
|
||||
/*FoundElse*/CI.FoundElse);
|
||||
// Finally, skip the rest of the contents of this block.
|
||||
SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true,
|
||||
/*FoundElse*/CI.FoundElse);
|
||||
|
||||
if (Callbacks)
|
||||
Callbacks->Elif(SourceRange(ConditionalBegin, ConditionalEnd));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue