[cfe-commits] [PATCH] PPCallbacks for #if/#ifdef/etc.

Craig Silverstein csilvers at google.com
Wed Oct 27 15:37:09 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/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp	(revision 117443)
+++ lib/Sema/SemaTemplate.cpp	(working copy)
@@ -3445,6 +3445,15 @@
                                             T,
                                             Loc));
 
+  if (const EnumType *Enum = T->getAs<EnumType>()) {
+    QualType IntegerType = Context.getCanonicalType(
+                                            Enum->getDecl()->getIntegerType());
+    Expr *E = IntegerLiteral::Create(Context, *Arg.getAsIntegral(),
+                                     IntegerType, Loc);
+    ImpCastExprToType(E, T, CK_NoOp);
+    return Owned(E);
+  }
+
   return Owned(IntegerLiteral::Create(Context, *Arg.getAsIntegral(), T, Loc));
 }
 
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