[cfe-commits] [PATCH] PPCallbacks for #if/#ifdef/etc.
Craig Silverstein
csilvers2000 at yahoo.com
Wed Oct 27 22:12:47 PDT 2010
This patch adds 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.
(I'm a little chary of submitting this kind of change, when I want the
public API of If() and Elif() to change. Would it be better to put in
a stub now of the information we want? I think we'd have to introduce
a new class to hold the collection of Tokens, as either a list or
tree. We could use the existing PPInfo class, though we'd have to
make it public. Or a new class. Or just leave it like it is now, as
a source-range. Thoughts?)
craig
--cut here--
Index: include/clang/Lex/PPCallbacks.h
===================================================================
--- include/clang/Lex/PPCallbacks.h (revision 117443)
+++ include/clang/Lex/PPCallbacks.h (working copy)
@@ -80,15 +80,17 @@
llvm::StringRef FileName,
bool IsAngled,
const FileEntry *File,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc) {
}
-
+
/// EndOfMainFile - This callback is invoked when the end of the main file is
/// reach, no subsequent callbacks will be made.
virtual void EndOfMainFile() {
}
/// 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 @@
/// 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 @@
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 @@
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
Index: lib/Lex/PPDirectives.cpp
===================================================================
--- lib/Lex/PPDirectives.cpp (revision 117443)
+++ lib/Lex/PPDirectives.cpp (working copy)
@@ -1623,11 +1623,18 @@
/*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,11 +1643,12 @@
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.
if (CurPPLexer->getConditionalStackDepth() == 0) {
@@ -1656,10 +1664,13 @@
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 @@
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 @@
// 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 @@
// 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));
}
More information about the cfe-commits
mailing list