[cfe-commits] r116952 - in /cfe/trunk: include/clang-c/ include/clang/Lex/ include/clang/Serialization/ lib/Lex/ lib/Serialization/ test/Index/ tools/c-index-test/ tools/libclang/

Douglas Gregor dgregor at apple.com
Wed Oct 20 15:00:55 PDT 2010


Author: dgregor
Date: Wed Oct 20 17:00:55 2010
New Revision: 116952

URL: http://llvm.org/viewvc/llvm-project?rev=116952&view=rev
Log:
Extend the preprocessing record and libclang with support for
inclusion directives, keeping track of every #include, #import,
etc. in the translation unit. We keep track of the source location and
kind of the inclusion, how the file name was spelled, and the
underlying file to which the inclusion resolved.


Modified:
    cfe/trunk/include/clang-c/Index.h
    cfe/trunk/include/clang/Lex/PPCallbacks.h
    cfe/trunk/include/clang/Lex/PreprocessingRecord.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Lex/PreprocessingRecord.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/Index/annotate-tokens-include.c
    cfe/trunk/test/Index/annotate-tokens-pp.c
    cfe/trunk/tools/c-index-test/c-index-test.c
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/tools/libclang/CXCursor.cpp
    cfe/trunk/tools/libclang/CXCursor.h
    cfe/trunk/tools/libclang/libclang.darwin.exports
    cfe/trunk/tools/libclang/libclang.exports

Modified: cfe/trunk/include/clang-c/Index.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/include/clang-c/Index.h (original)
+++ cfe/trunk/include/clang-c/Index.h Wed Oct 20 17:00:55 2010
@@ -1190,8 +1190,9 @@
   CXCursor_PreprocessingDirective        = 500,
   CXCursor_MacroDefinition               = 501,
   CXCursor_MacroInstantiation            = 502,
+  CXCursor_InclusionDirective            = 503,
   CXCursor_FirstPreprocessing            = CXCursor_PreprocessingDirective,
-  CXCursor_LastPreprocessing             = CXCursor_MacroInstantiation
+  CXCursor_LastPreprocessing             = CXCursor_InclusionDirective
 };
 
 /**
@@ -1466,6 +1467,12 @@
 CINDEX_LINKAGE void clang_disposeOverriddenCursors(CXCursor *overridden);
 
 /**
+ * \brief Retrieve the file that is included by the given inclusion directive
+ * cursor.
+ */
+CINDEX_LINKAGE CXFile clang_getIncludedFile(CXCursor cursor);
+  
+/**
  * @}
  */
 

Modified: cfe/trunk/include/clang/Lex/PPCallbacks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PPCallbacks.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/PPCallbacks.h (original)
+++ cfe/trunk/include/clang/Lex/PPCallbacks.h Wed Oct 20 17:00:55 2010
@@ -54,6 +54,35 @@
                            SrcMgr::CharacteristicKind FileType) {
   }
 
+  /// \brief This callback is invoked whenever an inclusion directive of
+  /// any kind (\c #include, \c #import, etc.) has been processed, regardless
+  /// of whether the inclusion will actually result in an inclusion.
+  ///
+  /// \param HashLoc The location of the '#' that starts the inclusion 
+  /// directive.
+  ///
+  /// \param IncludeTok The token that indicates the kind of inclusion 
+  /// directive, e.g., 'include' or 'import'.
+  ///
+  /// \param FileName The name of the file being included, as written in the 
+  /// source code.
+  ///
+  /// \param IsAngled Whether the file name was enclosed in angle brackets;
+  /// otherwise, it was enclosed in quotes.
+  ///
+  /// \param File The actual file that may be included by this inclusion 
+  /// directive.
+  ///
+  /// \param EndLoc The location of the last token within the inclusion
+  /// directive.
+  virtual void InclusionDirective(SourceLocation HashLoc,
+                                  const Token &IncludeTok,
+                                  llvm::StringRef FileName,
+                                  bool IsAngled,
+                                  const FileEntry *File,
+                                  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() {

Modified: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PreprocessingRecord.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/PreprocessingRecord.h (original)
+++ cfe/trunk/include/clang/Lex/PreprocessingRecord.h Wed Oct 20 17:00:55 2010
@@ -35,6 +35,7 @@
 
 namespace clang {
   class MacroDefinition;
+  class FileEntry;
 
   /// \brief Base class that describes a preprocessed entity, which may be a
   /// preprocessor directive or macro instantiation.
@@ -54,8 +55,12 @@
       /// \brief A macro definition.
       MacroDefinitionKind,
       
+      /// \brief An inclusion directive, such as \c #include, \c
+      /// #import, or \c #include_next.
+      InclusionDirectiveKind,
+
       FirstPreprocessingDirective = PreprocessingDirectiveKind,
-      LastPreprocessingDirective = MacroDefinitionKind
+      LastPreprocessingDirective = InclusionDirectiveKind
     };
 
   private:
@@ -173,6 +178,68 @@
     }
     static bool classof(const MacroDefinition *) { return true; }
   };
+
+  /// \brief Record the location of an inclusion directive, such as an
+  /// \c #include or \c #import statement.
+  class InclusionDirective : public PreprocessingDirective {
+  public:
+    /// \brief The kind of inclusion directives known to the
+    /// preprocessor.
+    enum InclusionKind {
+      /// \brief An \c #include directive.
+      Include,
+      /// \brief An Objective-C \c #import directive.
+      Import,
+      /// \brief A GNU \c #include_next directive.
+      IncludeNext,
+      /// \brief A Clang \c #__include_macros directive.
+      IncludeMacros
+    };
+
+  private:
+    /// \brief The name of the file that was included, as written in
+    /// the source.
+    std::string FileName;
+
+    /// \brief Whether the file name was in quotation marks; otherwise, it was
+    /// in angle brackets.
+    unsigned InQuotes : 1;
+
+    /// \brief The kind of inclusion directive we have.
+    ///
+    /// This is a value of type InclusionKind.
+    unsigned Kind : 2;
+
+    /// \brief The file that was included.
+    const FileEntry *File;
+
+  public:
+    explicit InclusionDirective(InclusionKind Kind,
+                                const std::string &FileName, bool InQuotes,
+                                const FileEntry *File, SourceRange Range)
+      : PreprocessingDirective(InclusionDirectiveKind, Range), 
+        FileName(FileName), InQuotes(InQuotes), Kind(Kind), File(File) { }
+    
+    /// \brief Determine what kind of inclusion directive this is.
+    InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); }
+    
+    /// \brief Retrieve the included file name as it was written in the source.
+    llvm::StringRef getFileName() const { return FileName; }
+    
+    /// \brief Determine whether the included file name was written in quotes;
+    /// otherwise, it was written in angle brackets.
+    bool wasInQuotes() const { return InQuotes; }
+    
+    /// \brief Retrieve the file entry for the actual file that was included
+    /// by this directive.
+    const FileEntry *getFile() const { return File; }
+        
+    // Implement isa/cast/dyncast/etc.
+    static bool classof(const PreprocessedEntity *PE) {
+      return PE->getKind() == InclusionDirectiveKind;
+    }
+    static bool classof(const InclusionDirective *) { return true; }
+  };
   
   /// \brief An abstract class that should be subclassed by any external source
   /// of preprocessing record entries.
@@ -263,6 +330,12 @@
     virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
     virtual void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II,
                                 const MacroInfo *MI);
+    virtual void InclusionDirective(SourceLocation HashLoc,
+                                    const Token &IncludeTok,
+                                    llvm::StringRef FileName,
+                                    bool IsAngled,
+                                    const FileEntry *File,
+                                    SourceLocation EndLoc);
   };
 } // end namespace clang
 

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed Oct 20 17:00:55 2010
@@ -823,7 +823,8 @@
   /// This code concatenates and consumes tokens up to the '>' token.  It
   /// returns false if the > was found, otherwise it returns true if it finds
   /// and consumes the EOM marker.
-  bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer);
+  bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer,
+                              SourceLocation &End);
 
 private:
 
@@ -972,12 +973,13 @@
   void HandleIdentSCCSDirective(Token &Tok);
 
   // File inclusion.
-  void HandleIncludeDirective(Token &Tok,
+  void HandleIncludeDirective(SourceLocation HashLoc,
+                              Token &Tok,
                               const DirectoryLookup *LookupFrom = 0,
                               bool isImport = false);
-  void HandleIncludeNextDirective(Token &Tok);
-  void HandleIncludeMacrosDirective(Token &Tok);
-  void HandleImportDirective(Token &Tok);
+  void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok);
+  void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok);
+  void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
 
   // Macro handling.
   void HandleDefineDirective(Token &Tok);

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed Oct 20 17:00:55 2010
@@ -372,7 +372,11 @@
       PP_MACRO_INSTANTIATION = 4,
       
       /// \brief Describes a macro definition within the preprocessing record.
-      PP_MACRO_DEFINITION = 5
+      PP_MACRO_DEFINITION = 5,
+      
+      /// \brief Describes am inclusion directive within the preprocessing
+      /// record.
+      PP_INCLUSION_DIRECTIVE = 6
     };
 
     /// \defgroup ASTAST AST file AST constants

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Wed Oct 20 17:00:55 2010
@@ -277,6 +277,9 @@
     /// all of the macro definitions.
     llvm::BitstreamCursor MacroCursor;
 
+    /// \brief The offset of the start of the set of defined macros.
+    uint64_t MacroStartOffset;
+    
     /// \brief The number of macro definitions in this file.
     unsigned LocalNumMacroDefinitions;
 

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Wed Oct 20 17:00:55 2010
@@ -591,9 +591,11 @@
 
     // C99 6.10.2 - Source File Inclusion.
     case tok::pp_include:
-      return HandleIncludeDirective(Result);       // Handle #include.
+      // Handle #include.
+      return HandleIncludeDirective(SavedHash.getLocation(), Result);
     case tok::pp___include_macros:
-      return HandleIncludeMacrosDirective(Result); // Handle -imacros.
+      // Handle -imacros.
+      return HandleIncludeMacrosDirective(SavedHash.getLocation(), Result); 
 
     // C99 6.10.3 - Macro Replacement.
     case tok::pp_define:
@@ -615,9 +617,9 @@
 
     // GNU Extensions.
     case tok::pp_import:
-      return HandleImportDirective(Result);
+      return HandleImportDirective(SavedHash.getLocation(), Result);
     case tok::pp_include_next:
-      return HandleIncludeNextDirective(Result);
+      return HandleIncludeNextDirective(SavedHash.getLocation(), Result);
 
     case tok::pp_warning:
       Diag(Result, diag::ext_pp_warning_directive);
@@ -1034,11 +1036,14 @@
 /// false if the > was found, otherwise it returns true if it finds and consumes
 /// the EOM marker.
 bool Preprocessor::ConcatenateIncludeName(
-  llvm::SmallString<128> &FilenameBuffer) {
+                                        llvm::SmallString<128> &FilenameBuffer,
+                                          SourceLocation &End) {
   Token CurTok;
 
   Lex(CurTok);
   while (CurTok.isNot(tok::eom)) {
+    End = CurTok.getLocation();
+    
     // Append the spelling of this token to the buffer. If there was a space
     // before it, add it now.
     if (CurTok.hasLeadingSpace())
@@ -1077,7 +1082,8 @@
 /// routine with functionality shared between #include, #include_next and
 /// #import.  LookupFrom is set when this is a #include_next directive, it
 /// specifies the file to start searching from.
-void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
+void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, 
+                                          Token &IncludeTok,
                                           const DirectoryLookup *LookupFrom,
                                           bool isImport) {
 
@@ -1087,7 +1093,8 @@
   // Reserve a buffer to get the spelling.
   llvm::SmallString<128> FilenameBuffer;
   llvm::StringRef Filename;
-
+  SourceLocation End;
+  
   switch (FilenameTok.getKind()) {
   case tok::eom:
     // If the token kind is EOM, the error has already been diagnosed.
@@ -1096,13 +1103,14 @@
   case tok::angle_string_literal:
   case tok::string_literal:
     Filename = getSpelling(FilenameTok, FilenameBuffer);
+    End = FilenameTok.getLocation();
     break;
 
   case tok::less:
     // This could be a <foo/bar.h> file coming from a macro expansion.  In this
     // case, glue the tokens together into FilenameBuffer and interpret those.
     FilenameBuffer.push_back('<');
-    if (ConcatenateIncludeName(FilenameBuffer))
+    if (ConcatenateIncludeName(FilenameBuffer, End))
       return;   // Found <eom> but no ">"?  Diagnostic already emitted.
     Filename = FilenameBuffer.str();
     break;
@@ -1141,6 +1149,11 @@
     return;
   }
 
+  // Notify the callback object that we've seen an inclusion directive.
+  if (Callbacks)
+    Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File, 
+                                  End);
+  
   // The #included file will be considered to be a system header if either it is
   // in a system include directory, or if the #includer is a system include
   // header.
@@ -1170,7 +1183,8 @@
 
 /// HandleIncludeNextDirective - Implements #include_next.
 ///
-void Preprocessor::HandleIncludeNextDirective(Token &IncludeNextTok) {
+void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc,
+                                              Token &IncludeNextTok) {
   Diag(IncludeNextTok, diag::ext_pp_include_next_directive);
 
   // #include_next is like #include, except that we start searching after
@@ -1187,23 +1201,25 @@
     ++Lookup;
   }
 
-  return HandleIncludeDirective(IncludeNextTok, Lookup);
+  return HandleIncludeDirective(HashLoc, IncludeNextTok, Lookup);
 }
 
 /// HandleImportDirective - Implements #import.
 ///
-void Preprocessor::HandleImportDirective(Token &ImportTok) {
+void Preprocessor::HandleImportDirective(SourceLocation HashLoc,
+                                         Token &ImportTok) {
   if (!Features.ObjC1)  // #import is standard for ObjC.
     Diag(ImportTok, diag::ext_pp_import_directive);
 
-  return HandleIncludeDirective(ImportTok, 0, true);
+  return HandleIncludeDirective(HashLoc, ImportTok, 0, true);
 }
 
 /// HandleIncludeMacrosDirective - The -imacros command line option turns into a
 /// pseudo directive in the predefines buffer.  This handles it by sucking all
 /// tokens through the preprocessor and discarding them (only keeping the side
 /// effects on the preprocessor).
-void Preprocessor::HandleIncludeMacrosDirective(Token &IncludeMacrosTok) {
+void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc,
+                                                Token &IncludeMacrosTok) {
   // This directive should only occur in the predefines buffer.  If not, emit an
   // error and reject it.
   SourceLocation Loc = IncludeMacrosTok.getLocation();
@@ -1216,7 +1232,7 @@
 
   // Treat this as a normal #include for checking purposes.  If this is
   // successful, it will push a new lexer onto the include stack.
-  HandleIncludeDirective(IncludeMacrosTok, 0, false);
+  HandleIncludeDirective(HashLoc, IncludeMacrosTok, 0, false);
 
   Token TmpTok;
   do {

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Oct 20 17:00:55 2010
@@ -570,7 +570,8 @@
   // Reserve a buffer to get the spelling.
   llvm::SmallString<128> FilenameBuffer;
   llvm::StringRef Filename;
-
+  SourceLocation EndLoc;
+  
   switch (Tok.getKind()) {
   case tok::eom:
     // If the token kind is EOM, the error has already been diagnosed.
@@ -589,7 +590,7 @@
     // This could be a <foo/bar.h> file coming from a macro expansion.  In this
     // case, glue the tokens together into FilenameBuffer and interpret those.
     FilenameBuffer.push_back('<');
-    if (PP.ConcatenateIncludeName(FilenameBuffer))
+    if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc))
       return false;   // Found <eom> but no ">"?  Diagnostic already emitted.
     Filename = FilenameBuffer.str();
     break;

Modified: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PreprocessingRecord.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PreprocessingRecord.cpp (original)
+++ cfe/trunk/lib/Lex/PreprocessingRecord.cpp Wed Oct 20 17:00:55 2010
@@ -14,6 +14,8 @@
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/Token.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/Support/ErrorHandling.h"
 
 using namespace clang;
 
@@ -127,3 +129,38 @@
     MacroDefinitions.erase(Pos);
 }
 
+void PreprocessingRecord::InclusionDirective(SourceLocation HashLoc,
+                                             const clang::Token &IncludeTok, 
+                                             llvm::StringRef FileName, 
+                                             bool IsAngled, 
+                                             const FileEntry *File,
+                                           clang::SourceLocation EndLoc) {
+  InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
+  
+  switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
+  case tok::pp_include: 
+    Kind = InclusionDirective::Include; 
+    break;
+    
+  case tok::pp_import: 
+    Kind = InclusionDirective::Import; 
+    break;
+    
+  case tok::pp_include_next: 
+    Kind = InclusionDirective::IncludeNext; 
+    break;
+    
+  case tok::pp___include_macros: 
+    Kind = InclusionDirective::IncludeMacros;
+    break;
+    
+  default:
+    llvm_unreachable("Unknown include directive kind");
+    return;
+  }
+  
+  clang::InclusionDirective *ID
+    = new (*this) clang::InclusionDirective(Kind, FileName, !IsAngled, File, 
+                                            SourceRange(HashLoc, EndLoc));
+  PreprocessedEntities.push_back(ID);
+}

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed Oct 20 17:00:55 2010
@@ -1337,18 +1337,21 @@
   }
 
   while (true) {
+    uint64_t Offset = Cursor.GetCurrentBitNo();
     unsigned Code = Cursor.ReadCode();
-
+    
     // We expect all abbrevs to be at the start of the block.
-    if (Code != llvm::bitc::DEFINE_ABBREV)
+    if (Code != llvm::bitc::DEFINE_ABBREV) {
+      Cursor.JumpToBit(Offset);
       return false;
+    }
     Cursor.ReadAbbrevRecord();
   }
 }
 
 void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
   assert(PP && "Forgot to set Preprocessor ?");
-  llvm::BitstreamCursor &Stream = F.Stream;
+  llvm::BitstreamCursor &Stream = F.MacroCursor;
 
   // Keep track of where we are in the stream, then jump back there
   // after reading this macro.
@@ -1381,9 +1384,12 @@
     }
 
     // Read a record.
+    const char *BlobStart = 0;
+    unsigned BlobLen = 0;
     Record.clear();
     PreprocessorRecordTypes RecType =
-      (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record);
+      (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart, 
+                                                 BlobLen);
     switch (RecType) {
     case PP_MACRO_OBJECT_LIKE:
     case PP_MACRO_FUNCTION_LIKE: {
@@ -1524,6 +1530,41 @@
       
       return;
     }
+        
+    case PP_INCLUSION_DIRECTIVE: {
+      // If we already have a macro, that means that we've hit the end
+      // of the definition of the macro we were looking for. We're
+      // done.
+      if (Macro)
+        return;
+      
+      if (!PP->getPreprocessingRecord()) {
+        Error("missing preprocessing record in AST file");
+        return;
+      }
+      
+      PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+      if (PPRec.getPreprocessedEntity(Record[0]))
+        return;
+
+      const char *FullFileNameStart = BlobStart + Record[3];
+      const FileEntry *File 
+        = PP->getFileManager().getFile(FullFileNameStart,
+                                     FullFileNameStart + (BlobLen - Record[3]));
+      
+      // FIXME: Stable encoding
+      InclusionDirective::InclusionKind Kind
+        = static_cast<InclusionDirective::InclusionKind>(Record[5]);
+      InclusionDirective *ID
+        = new (PPRec) InclusionDirective(Kind,
+                             llvm::StringRef(BlobStart, Record[3]),
+                                         Record[4],
+                                         File,
+                                 SourceRange(ReadSourceLocation(F, Record[1]),
+                                             ReadSourceLocation(F, Record[2])));
+      PPRec.SetPreallocatedEntity(Record[0], ID);
+      return;
+    }
     }
   }
 }
@@ -1538,22 +1579,14 @@
       continue;
 
     llvm::BitstreamCursor Cursor = MacroCursor;
-    if (Cursor.EnterSubBlock(PREPROCESSOR_BLOCK_ID)) {
-      Error("malformed preprocessor block record in AST file");
-      return;
-    }
-
+    Cursor.JumpToBit(F.MacroStartOffset);
+    
     RecordData Record;
     while (true) {
       uint64_t Offset = Cursor.GetCurrentBitNo();
       unsigned Code = Cursor.ReadCode();
-      if (Code == llvm::bitc::END_BLOCK) {
-        if (Cursor.ReadBlockEnd()) {
-          Error("error at end of preprocessor block in AST file");
-          return;
-        }
+      if (Code == llvm::bitc::END_BLOCK)
         break;
-      }
 
       if (Code == llvm::bitc::ENTER_SUBBLOCK) {
         // No known subblocks, always skip them.
@@ -1589,6 +1622,7 @@
         
       case PP_MACRO_INSTANTIATION:
       case PP_MACRO_DEFINITION:
+      case PP_INCLUSION_DIRECTIVE:
         // Read the macro record.
         // FIXME: That's a stupid way to do this. We should reuse this cursor.
         ReadMacroRecord(F, Offset);
@@ -1686,10 +1720,12 @@
         if (PP)
           PP->setExternalSource(this);
 
-        if (Stream.SkipBlock()) {
+        if (Stream.SkipBlock() ||
+            ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
           Error("malformed block record in AST file");
           return Failure;
         }
+        F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
         break;
 
       case SOURCE_MANAGER_BLOCK_ID:

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Oct 20 17:00:55 2010
@@ -1256,16 +1256,32 @@
   }
 
   // Enter the preprocessor block.
-  Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 2);
+  Stream.EnterSubblock(PREPROCESSOR_BLOCK_ID, 3);
 
   // If the AST file contains __DATE__ or __TIME__ emit a warning about this.
   // FIXME: use diagnostics subsystem for localization etc.
   if (PP.SawDateOrTime())
     fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
 
+
   // Loop over all the macro definitions that are live at the end of the file,
   // emitting each to the PP section.
   PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+  unsigned InclusionAbbrev = 0;
+  if (PPRec) {
+    using namespace llvm;
+    BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+    Abbrev->Add(BitCodeAbbrevOp(PP_INCLUSION_DIRECTIVE));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // start location
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // end location
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+    InclusionAbbrev = Stream.EmitAbbrev(Abbrev);    
+  }
+  
   for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
        I != E; ++I) {
     // FIXME: This emits macros in hash table order, we should do it in a stable
@@ -1381,6 +1397,21 @@
         Stream.EmitRecord(PP_MACRO_DEFINITION, Record);
         continue;
       }
+      
+      if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+        Record.push_back(PP_INCLUSION_DIRECTIVE);
+        Record.push_back(IndexBase + NumPreprocessingRecords++);
+        AddSourceLocation(ID->getSourceRange().getBegin(), Record);
+        AddSourceLocation(ID->getSourceRange().getEnd(), Record);
+        Record.push_back(ID->getFileName().size());
+        Record.push_back(ID->wasInQuotes());
+        Record.push_back(static_cast<unsigned>(ID->getKind()));
+        llvm::SmallString<64> Buffer;
+        Buffer += ID->getFileName();
+        Buffer += ID->getFile()->getName();
+        Stream.EmitRecordWithBlob(InclusionAbbrev, Record, Buffer);
+        continue;
+      }
     }
   }
   

Modified: cfe/trunk/test/Index/annotate-tokens-include.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-tokens-include.c?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-tokens-include.c (original)
+++ cfe/trunk/test/Index/annotate-tokens-include.c Wed Oct 20 17:00:55 2010
@@ -1,6 +1,7 @@
 #include "annotate-tokens-include.h"
 
 // RUN: c-index-test -test-annotate-tokens=%s:1:1:2:1 %s | FileCheck %s
+// CHECK: Punctuation: "#" [1:1 - 1:2] inclusion directive=annotate-tokens-include.h
 // CHECK: Identifier: "include" [1:2 - 1:9] preprocessing directive=
 // CHECK: Literal: ""annotate-tokens-include.h"" [1:10 - 1:37] preprocessing directive=
 

Modified: cfe/trunk/test/Index/annotate-tokens-pp.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-tokens-pp.c?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-tokens-pp.c (original)
+++ cfe/trunk/test/Index/annotate-tokens-pp.c Wed Oct 20 17:00:55 2010
@@ -68,7 +68,7 @@
 // CHECK: Identifier: "BAR" [6:5 - 6:8] macro instantiation=BAR:3:9
 // CHECK: Identifier: "STILL_NOTHING" [6:9 - 6:22] macro instantiation=STILL_NOTHING:2:9
 // CHECK: Punctuation: ";" [6:22 - 6:23]
-// CHECK: Punctuation: "#" [7:1 - 7:2] preprocessing directive=
+// CHECK: Punctuation: "#" [7:1 - 7:2] inclusion directive=foo.h
 // CHECK: Identifier: "include" [7:2 - 7:9] preprocessing directive=
 // CHECK: Literal: ""foo.h"" [7:10 - 7:17] preprocessing directive=
 // CHECK: Punctuation: "#" [8:1 - 8:2] preprocessing directive=

Modified: cfe/trunk/tools/c-index-test/c-index-test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/tools/c-index-test/c-index-test.c (original)
+++ cfe/trunk/tools/c-index-test/c-index-test.c Wed Oct 20 17:00:55 2010
@@ -271,6 +271,13 @@
       printf("]");
       clang_disposeOverriddenCursors(overridden);
     }
+    
+    if (Cursor.kind == CXCursor_InclusionDirective) {
+      CXFile File = clang_getIncludedFile(Cursor);
+      CXString Included = clang_getFileName(File);
+      printf(" (%s)", clang_getCString(Included));
+      clang_disposeString(Included);
+    }
   }
 }
 

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Wed Oct 20 17:00:55 2010
@@ -555,6 +555,13 @@
           
           continue;
         }
+        
+        if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*E)) {
+          if (Visit(MakeInclusionDirectiveCursor(ID, CXXUnit)))
+            return true;
+          
+          continue;
+        }
       }
     }
     return false;
@@ -2565,6 +2572,9 @@
     return createCXString(getCursorMacroDefinition(C)->getName()
                                                            ->getNameStart());
 
+  if (C.kind == CXCursor_InclusionDirective)
+    return createCXString(getCursorInclusionDirective(C)->getFileName());
+      
   if (clang_isDeclaration(C.kind))
     return getDeclSpelling(getCursorDecl(C));
 
@@ -2757,6 +2767,8 @@
     return createCXString("macro definition");
   case CXCursor_MacroInstantiation:
     return createCXString("macro instantiation");
+  case CXCursor_InclusionDirective:
+    return createCXString("inclusion directive");
   case CXCursor_Namespace:
     return createCXString("Namespace");
   case CXCursor_LinkageSpec:
@@ -2977,7 +2989,13 @@
     SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation();
     return cxloc::translateSourceLocation(getCursorContext(C), L);
   }
-  
+
+  if (C.kind == CXCursor_InclusionDirective) {
+    SourceLocation L
+      = cxcursor::getCursorInclusionDirective(C)->getSourceRange().getBegin();
+    return cxloc::translateSourceLocation(getCursorContext(C), L);
+  }
+
   if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
     return clang_getNullLocation();
 
@@ -3043,12 +3061,14 @@
 
   if (C.kind == CXCursor_MacroDefinition)
     return cxcursor::getCursorMacroDefinition(C)->getSourceRange();
-  
+
+  if (C.kind == CXCursor_InclusionDirective)
+    return cxcursor::getCursorInclusionDirective(C)->getSourceRange();
+
   if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl)
     return getCursorDecl(C)->getSourceRange();
 
-  return SourceRange();
-}
+  return SourceRange();}
 
 extern "C" {
 
@@ -4149,6 +4169,14 @@
   delete [] overridden;
 }
 
+CXFile clang_getIncludedFile(CXCursor cursor) {
+  if (cursor.kind != CXCursor_InclusionDirective)
+    return 0;
+  
+  InclusionDirective *ID = getCursorInclusionDirective(cursor);
+  return (void *)ID->getFile();
+}
+  
 } // end: extern "C"
 
 

Modified: cfe/trunk/tools/libclang/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.cpp?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.cpp (original)
+++ cfe/trunk/tools/libclang/CXCursor.cpp Wed Oct 20 17:00:55 2010
@@ -363,6 +363,17 @@
   return static_cast<MacroInstantiation *>(C.data[0]);
 }
 
+CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID, 
+                                                ASTUnit *TU) {
+  CXCursor C = { CXCursor_InclusionDirective, { ID, 0, TU } };
+  return C;
+}
+
+InclusionDirective *cxcursor::getCursorInclusionDirective(CXCursor C) {
+  assert(C.kind == CXCursor_InclusionDirective);
+  return static_cast<InclusionDirective *>(C.data[0]);  
+}
+
 CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, 
                                       ASTUnit *TU) {
   

Modified: cfe/trunk/tools/libclang/CXCursor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXCursor.h?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXCursor.h (original)
+++ cfe/trunk/tools/libclang/CXCursor.h Wed Oct 20 17:00:55 2010
@@ -28,6 +28,7 @@
 class Decl;
 class Expr;
 class FieldDecl;
+class InclusionDirective;
 class LabelStmt;
 class MacroDefinition;
 class MacroInstantiation;
@@ -133,6 +134,13 @@
 /// source range.
 MacroInstantiation *getCursorMacroInstantiation(CXCursor C);
 
+/// \brief Create an inclusion directive cursor.
+CXCursor MakeInclusionDirectiveCursor(InclusionDirective *, ASTUnit *TU);
+
+/// \brief Unpack a given inclusion directive cursor to retrieve its
+/// source range.
+InclusionDirective *getCursorInclusionDirective(CXCursor C);
+
 /// \brief Create a label reference at the given location.
 CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, ASTUnit *TU);
 

Modified: cfe/trunk/tools/libclang/libclang.darwin.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.darwin.exports?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.darwin.exports (original)
+++ cfe/trunk/tools/libclang/libclang.darwin.exports Wed Oct 20 17:00:55 2010
@@ -68,6 +68,7 @@
 _clang_getFileName
 _clang_getFileTime
 _clang_getIBOutletCollectionType
+_clang_getIncludedFile
 _clang_getInclusions
 _clang_getInstantiationLocation
 _clang_getLocation

Modified: cfe/trunk/tools/libclang/libclang.exports
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/libclang.exports?rev=116952&r1=116951&r2=116952&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/libclang.exports (original)
+++ cfe/trunk/tools/libclang/libclang.exports Wed Oct 20 17:00:55 2010
@@ -68,6 +68,7 @@
 clang_getFileName
 clang_getFileTime
 clang_getIBOutletCollectionType
+clang_getIncludedFile
 clang_getInclusions
 clang_getInstantiationLocation
 clang_getLocation





More information about the cfe-commits mailing list