From 8e3d95e7dfb44fcd2d7fbf94f104fe821c42268e Mon Sep 17 00:00:00 2001 From: Craig Silverstein Date: Sat, 6 Nov 2010 01:19:03 +0000 Subject: [PATCH] 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 --- clang/include/clang/Lex/PPCallbacks.h | 76 ++++++++++++++++++++++++++- clang/lib/Lex/PPDirectives.cpp | 51 +++++++++++++----- 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h index 1bcc364e67f9..10bf6779f497 100644 --- a/clang/include/clang/Lex/PPCallbacks.h +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -80,15 +80,17 @@ public: 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 @@ 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 diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index d5abc20a3da2..7d428402db48 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -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)); }