[cfe-commits] r99002 - in /cfe/trunk: include/clang/Frontend/PCHBitCodes.h include/clang/Frontend/PCHReader.h include/clang/Frontend/PCHWriter.h include/clang/Lex/PreprocessingRecord.h lib/Frontend/PCHReader.cpp lib/Frontend/PCHWriter.cpp lib/Lex/PreprocessingRecord.cpp test/Index/c-index-getCursor-test.m tools/CIndex/CIndex.cpp

Douglas Gregor dgregor at apple.com
Fri Mar 19 14:51:55 PDT 2010


Author: dgregor
Date: Fri Mar 19 16:51:54 2010
New Revision: 99002

URL: http://llvm.org/viewvc/llvm-project?rev=99002&view=rev
Log:
Implement serialization and lazy deserialization of the preprocessing
record (which includes all macro instantiations and definitions). As
with all lay deserialization, this introduces a new external source
(here, an external preprocessing record source) that loads all of the
preprocessed entities prior to iterating over the entities.

The preprocessing record is an optional part of the precompiled header
that is disabled by default (enabled with
-detailed-preprocessing-record). When the preprocessor given to the
PCH writer has a preprocessing record, that record is written into the
PCH file. When the PCH reader is given a PCH file that contains a
preprocessing record, it will be lazily loaded (which, effectively,
implicitly adds -detailed-preprocessing-record). This is the first
case where we have sections of the precompiled header that are
added/removed based on a compilation flag, which is
unfortunate. However, this data consumes ~550k in the PCH file for
Cocoa.h (out of ~9.9MB), and there is a non-trivial cost to gathering
this detailed preprocessing information, so it's too expensive to turn
on by default. In the future, we should investigate a better encoding
of this information.


Modified:
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/include/clang/Frontend/PCHWriter.h
    cfe/trunk/include/clang/Lex/PreprocessingRecord.h
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/lib/Lex/PreprocessingRecord.cpp
    cfe/trunk/test/Index/c-index-getCursor-test.m
    cfe/trunk/tools/CIndex/CIndex.cpp

Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Fri Mar 19 16:51:54 2010
@@ -224,8 +224,11 @@
       VERSION_CONTROL_BRANCH_REVISION = 21,
       
       /// \brief Record code for the array of unused static functions.
-      UNUSED_STATIC_FUNCS = 22
+      UNUSED_STATIC_FUNCS = 22,
       
+      /// \brief Record code for the table of offsets to macro definition
+      /// entries in the preprocessing record.
+      MACRO_DEFINITION_OFFSETS = 23
     };
 
     /// \brief Record types used within a source manager block.
@@ -264,7 +267,14 @@
 
       /// \brief Describes one token.
       /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags]
-      PP_TOKEN = 3
+      PP_TOKEN = 3,
+
+      /// \brief Describes a macro instantiation within the preprocessing 
+      /// record.
+      PP_MACRO_INSTANTIATION = 4,
+      
+      /// \brief Describes a macro definition within the preprocessing record.
+      PP_MACRO_DEFINITION = 5
     };
 
     /// \defgroup PCHAST Precompiled header AST constants

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Fri Mar 19 16:51:54 2010
@@ -21,6 +21,7 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/Lex/ExternalPreprocessorSource.h"
+#include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceManager.h"
@@ -53,6 +54,7 @@
 class DeclContext;
 class GotoStmt;
 class LabelStmt;
+class MacroDefinition;
 class NamedDecl;
 class Preprocessor;
 class Sema;
@@ -151,6 +153,7 @@
 /// actually required will be de-serialized.
 class PCHReader
   : public ExternalPreprocessorSource,
+    public ExternalPreprocessingRecordSource,
     public ExternalSemaSource,
     public IdentifierInfoLookup,
     public ExternalIdentifierLookup,
@@ -296,6 +299,17 @@
   /// been loaded.
   llvm::SmallVector<Selector, 16> SelectorsLoaded;
 
+  /// \brief Offsets of all of the macro definitions in the preprocessing
+  /// record in the PCH file.
+  const uint32_t *MacroDefinitionOffsets;
+      
+  /// \brief The macro definitions we have already loaded.
+  llvm::SmallVector<MacroDefinition *, 16> MacroDefinitionsLoaded;
+      
+  /// \brief The number of preallocated preprocessing entities in the
+  /// preprocessing record.
+  unsigned NumPreallocatedPreprocessingEntities;
+      
   /// \brief A sorted array of source ranges containing comments.
   SourceRange *Comments;
 
@@ -527,9 +541,7 @@
   }
 
   /// \brief Set the Preprocessor to use.
-  void setPreprocessor(Preprocessor &pp) {
-    PP = &pp;
-  }
+  void setPreprocessor(Preprocessor &pp);
 
   /// \brief Sets and initializes the given Context.
   void InitializeContext(ASTContext &Context);
@@ -550,6 +562,9 @@
   /// which contains a (typically-empty) subset of the predefines
   /// build prior to including the precompiled header.
   const std::string &getSuggestedPredefines() { return SuggestedPredefines; }
+      
+  /// \brief Read preprocessed entities into the 
+  virtual void ReadPreprocessedEntities();
 
   /// \brief Reads the source ranges that correspond to comments from
   /// an external AST source.
@@ -727,6 +742,9 @@
   /// \brief Read the set of macros defined by this external macro source.
   virtual void ReadDefinedMacros();
 
+  /// \brief Retrieve the macro definition with the given ID.
+  MacroDefinition *getMacroDefinition(pch::IdentID ID);
+      
   /// \brief Retrieve the AST context that this PCH reader
   /// supplements.
   ASTContext *getContext() { return Context; }

Modified: cfe/trunk/include/clang/Frontend/PCHWriter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHWriter.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHWriter.h Fri Mar 19 16:51:54 2010
@@ -33,6 +33,7 @@
 
 class ASTContext;
 class LabelStmt;
+class MacroDefinition;
 class MemorizeStatCalls;
 class Preprocessor;
 class Sema;
@@ -160,6 +161,14 @@
   /// defined.
   llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets;
 
+  /// \brief Mapping from macro definitions (as they occur in the preprocessing
+  /// record) to the index into the macro definitions table.
+  llvm::DenseMap<const MacroDefinition *, pch::IdentID> MacroDefinitions;
+  
+  /// \brief Mapping from the macro definition indices in \c MacroDefinitions
+  /// to the corresponding offsets within the preprocessor block.
+  std::vector<uint32_t> MacroDefinitionOffsets;
+  
   /// \brief Declarations encountered that might be external
   /// definitions.
   ///
@@ -272,6 +281,10 @@
     return MacroOffsets[II];
   }
 
+  /// \brief Retrieve the ID number corresponding to the given macro 
+  /// definition.
+  pch::IdentID getMacroDefinitionID(MacroDefinition *MD);
+  
   /// \brief Emit a reference to a type.
   void AddTypeRef(QualType T, RecordData &Record);
 

Modified: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PreprocessingRecord.h?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/PreprocessingRecord.h (original)
+++ cfe/trunk/include/clang/Lex/PreprocessingRecord.h Fri Mar 19 16:51:54 2010
@@ -173,7 +173,18 @@
     }
     static bool classof(const MacroDefinition *) { return true; }
   };
+  
+  /// \brief An abstract class that should be subclassed by any external source
+  /// of preprocessing record entries.
+  class ExternalPreprocessingRecordSource {
+  public:
+    virtual ~ExternalPreprocessingRecordSource();
     
+    /// \brief Read any preallocated preprocessed entities from the external
+    /// source.
+    virtual void ReadPreprocessedEntities() = 0;
+  };
+  
   /// \brief A record of the steps taken while preprocessing a source file,
   /// including the various preprocessing directives processed, macros 
   /// instantiated, etc.
@@ -188,7 +199,21 @@
     /// \brief Mapping from MacroInfo structures to their definitions.
     llvm::DenseMap<const MacroInfo *, MacroDefinition *> MacroDefinitions;
 
+    /// \brief External source of preprocessed entities.
+    ExternalPreprocessingRecordSource *ExternalSource;
+    
+    /// \brief The number of preallocated entities (that are known to the
+    /// external source).
+    unsigned NumPreallocatedEntities;
+    
+    /// \brief Whether we have already loaded all of the preallocated entities.
+    mutable bool LoadedPreallocatedEntities;
+    
+    void MaybeLoadPreallocatedEntities() const ;
+    
   public:
+    PreprocessingRecord();
+    
     /// \brief Allocate memory in the preprocessing record.
     void *Allocate(unsigned Size, unsigned Align = 8) {
       return BumpAlloc.Allocate(Size, Align);
@@ -200,14 +225,32 @@
     // Iteration over the preprocessed entities.
     typedef std::vector<PreprocessedEntity *>::iterator iterator;
     typedef std::vector<PreprocessedEntity *>::const_iterator const_iterator;
-    iterator begin() { return PreprocessedEntities.begin(); }
-    iterator end() { return PreprocessedEntities.end(); }
-    const_iterator begin() const { return PreprocessedEntities.begin(); }
-    const_iterator end() const { return PreprocessedEntities.end(); }
+    iterator begin(bool OnlyLocalEntities = false);
+    iterator end(bool OnlyLocalEntities = false);
+    const_iterator begin(bool OnlyLocalEntities = false) const;
+    const_iterator end(bool OnlyLocalEntities = false) const;
     
     /// \brief Add a new preprocessed entity to this record.
     void addPreprocessedEntity(PreprocessedEntity *Entity);
     
+    /// \brief Set the external source for preprocessed entities.
+    void SetExternalSource(ExternalPreprocessingRecordSource &Source,
+                           unsigned NumPreallocatedEntities);
+    
+    /// \brief Set the preallocated entry at the given index to the given
+    /// preprocessed entity.
+    void SetPreallocatedEntity(unsigned Index, PreprocessedEntity *Entity);
+
+    /// \brief Register a new macro definition.
+    void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinition *MD);
+                           
+    /// \brief Retrieve the preprocessed entity at the given index.
+    PreprocessedEntity *getPreprocessedEntity(unsigned Index) {
+      assert(Index < PreprocessedEntities.size() &&
+             "Out-of-bounds preprocessed entity");
+      return PreprocessedEntities[Index];
+    }
+    
     /// \brief Retrieve the macro definition that corresponds to the given
     /// \c MacroInfo.
     MacroDefinition *findMacroDefinition(MacroInfo *MI);

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Fri Mar 19 16:51:54 2010
@@ -21,6 +21,7 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLocVisitor.h"
 #include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Basic/OnDiskHashTable.h"
@@ -326,8 +327,9 @@
     IdentifierOffsets(0),
     MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
     TotalSelectorsInMethodPool(0), SelectorOffsets(0),
-    TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
-    NumStatHits(0), NumStatMisses(0),
+    TotalNumSelectors(0), MacroDefinitionOffsets(0), 
+    NumPreallocatedPreprocessingEntities(0), Comments(0), NumComments(0), 
+    isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
     NumSLocEntriesRead(0), NumStatementsRead(0),
     NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
     NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
@@ -343,8 +345,9 @@
     IdentifierOffsets(0),
     MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
     TotalSelectorsInMethodPool(0), SelectorOffsets(0),
-    TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot),
-    NumStatHits(0), NumStatMisses(0),
+    TotalNumSelectors(0), MacroDefinitionOffsets(0), 
+    NumPreallocatedPreprocessingEntities(0), Comments(0), NumComments(0), 
+    isysroot(isysroot), NumStatHits(0), NumStatMisses(0),
     NumSLocEntriesRead(0), NumStatementsRead(0),
     NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
     NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0),
@@ -1047,12 +1050,14 @@
       MacroInfo *MI = PP->AllocateMacroInfo(Loc);
       MI->setIsUsed(isUsed);
 
+      unsigned NextIndex = 3;
       if (RecType == pch::PP_MACRO_FUNCTION_LIKE) {
         // Decode function-like macro info.
         bool isC99VarArgs = Record[3];
         bool isGNUVarArgs = Record[4];
         MacroArgs.clear();
         unsigned NumArgs = Record[5];
+        NextIndex = 6 + NumArgs;
         for (unsigned i = 0; i != NumArgs; ++i)
           MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i]));
 
@@ -1070,6 +1075,13 @@
       // Remember that we saw this macro last so that we add the tokens that
       // form its body to it.
       Macro = MI;
+      
+      if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) {
+        // We have a macro definition. Load it now.
+        PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro,
+                                        getMacroDefinition(Record[NextIndex]));
+      }
+      
       ++NumMacrosRead;
       break;
     }
@@ -1090,6 +1102,64 @@
       Macro->AddTokenToBody(Tok);
       break;
     }
+        
+    case pch::PP_MACRO_INSTANTIATION: {
+      // 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 PCH file");
+        return;
+      }
+        
+      PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+      if (PPRec.getPreprocessedEntity(Record[0]))
+        return;
+
+      MacroInstantiation *MI
+        = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]),
+                               SourceRange(
+                                 SourceLocation::getFromRawEncoding(Record[1]),
+                                 SourceLocation::getFromRawEncoding(Record[2])),
+                                         getMacroDefinition(Record[4]));
+      PPRec.SetPreallocatedEntity(Record[0], MI);
+      return;
+    }
+
+    case pch::PP_MACRO_DEFINITION: {
+      // 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 PCH file");
+        return;
+      }
+      
+      PreprocessingRecord &PPRec = *PP->getPreprocessingRecord();
+      if (PPRec.getPreprocessedEntity(Record[0]))
+        return;
+        
+      if (Record[1] >= MacroDefinitionsLoaded.size()) {
+        Error("out-of-bounds macro definition record");
+        return;
+      }
+
+      MacroDefinition *MD
+        = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]),
+                                SourceLocation::getFromRawEncoding(Record[5]),
+                              SourceRange(
+                                SourceLocation::getFromRawEncoding(Record[2]),
+                                SourceLocation::getFromRawEncoding(Record[3])));
+      PPRec.SetPreallocatedEntity(Record[0], MD);
+      MacroDefinitionsLoaded[Record[1]] = MD;
+      return;
+    }
   }
   }
 }
@@ -1139,16 +1209,32 @@
 
     case pch::PP_MACRO_OBJECT_LIKE:
     case pch::PP_MACRO_FUNCTION_LIKE:
-        DecodeIdentifierInfo(Record[0]);
+      DecodeIdentifierInfo(Record[0]);
       break;
 
     case pch::PP_TOKEN:
       // Ignore tokens.
       break;
+        
+    case pch::PP_MACRO_INSTANTIATION:
+    case pch::PP_MACRO_DEFINITION:
+      // Read the macro record.
+      ReadMacroRecord(Cursor.GetCurrentBitNo());
+      break;
     }
   }
 }
 
+MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) {
+  if (ID == 0 || ID >= MacroDefinitionsLoaded.size())
+    return 0;
+  
+  if (!MacroDefinitionsLoaded[ID])
+    ReadMacroRecord(MacroDefinitionOffsets[ID]);
+    
+  return MacroDefinitionsLoaded[ID];
+}
+
 /// \brief If we are loading a relocatable PCH file, and the filename is
 /// not an absolute path, add the system root to the beginning of the file
 /// name.
@@ -1431,6 +1517,19 @@
       }
       break;
     }
+        
+    case pch::MACRO_DEFINITION_OFFSETS:
+      MacroDefinitionOffsets = (const uint32_t *)BlobStart;
+      if (PP) {
+        if (!PP->getPreprocessingRecord())
+          PP->createPreprocessingRecord();
+        PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]);
+      } else {
+        NumPreallocatedPreprocessingEntities = Record[0];
+      }
+       
+      MacroDefinitionsLoaded.resize(Record[1]);
+      break;
     }
   }
   Error("premature end of bitstream in PCH file");
@@ -1562,6 +1661,18 @@
   return Success;
 }
 
+void PCHReader::setPreprocessor(Preprocessor &pp) {
+  PP = &pp;
+  
+  if (NumPreallocatedPreprocessingEntities) {
+    if (!PP->getPreprocessingRecord())
+      PP->createPreprocessingRecord();
+    PP->getPreprocessingRecord()->SetExternalSource(*this, 
+                                          NumPreallocatedPreprocessingEntities);
+    NumPreallocatedPreprocessingEntities = 0;
+  }
+}
+
 void PCHReader::InitializeContext(ASTContext &Ctx) {
   Context = &Ctx;
   assert(Context && "Passed null context!");
@@ -1823,6 +1934,10 @@
   return false;
 }
 
+void PCHReader::ReadPreprocessedEntities() {
+  ReadDefinedMacros();
+}
+
 void PCHReader::ReadComments(std::vector<SourceRange> &Comments) {
   Comments.resize(NumComments);
   std::copy(this->Comments, this->Comments + NumComments,

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Fri Mar 19 16:51:54 2010
@@ -21,6 +21,7 @@
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLocVisitor.h"
 #include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Basic/FileManager.h"
@@ -565,7 +566,9 @@
   RECORD(EXT_VECTOR_DECLS);
   RECORD(COMMENT_RANGES);
   RECORD(VERSION_CONTROL_BRANCH_REVISION);
-
+  RECORD(UNUSED_STATIC_FUNCS);
+  RECORD(MACRO_DEFINITION_OFFSETS);
+  
   // SourceManager Block.
   BLOCK(SOURCE_MANAGER_BLOCK);
   RECORD(SM_SLOC_FILE_ENTRY);
@@ -579,7 +582,9 @@
   RECORD(PP_MACRO_OBJECT_LIKE);
   RECORD(PP_MACRO_FUNCTION_LIKE);
   RECORD(PP_TOKEN);
-
+  RECORD(PP_MACRO_INSTANTIATION);
+  RECORD(PP_MACRO_DEFINITION);
+  
   // Decls and Types block.
   BLOCK(DECLTYPES_BLOCK);
   RECORD(TYPE_EXT_QUAL);
@@ -1174,6 +1179,7 @@
 
   // 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();
   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
@@ -1203,6 +1209,12 @@
            I != E; ++I)
         AddIdentifierRef(*I, Record);
     }
+    
+    // If we have a detailed preprocessing record, record the macro definition
+    // ID that corresponds to this macro.
+    if (PPRec)
+      Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI)));
+    
     Stream.EmitRecord(Code, Record);
     Record.clear();
 
@@ -1230,7 +1242,68 @@
     }
     ++NumMacros;
   }
+  
+  // If the preprocessor has a preprocessing record, emit it.
+  unsigned NumPreprocessingRecords = 0;
+  if (PPRec) {
+    for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end();
+         E != EEnd; ++E) {
+      Record.clear();
+      
+      if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
+        Record.push_back(NumPreprocessingRecords++);
+        AddSourceLocation(MI->getSourceRange().getBegin(), Record);
+        AddSourceLocation(MI->getSourceRange().getEnd(), Record);
+        AddIdentifierRef(MI->getName(), Record);
+        Record.push_back(getMacroDefinitionID(MI->getDefinition()));
+        Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record);
+        continue;
+      }
+      
+      if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) {
+        // Record this macro definition's location.
+        pch::IdentID ID = getMacroDefinitionID(MD);
+        if (ID != MacroDefinitionOffsets.size()) {
+          if (ID > MacroDefinitionOffsets.size())
+            MacroDefinitionOffsets.resize(ID + 1);
+          
+          MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo();            
+        } else
+          MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo());
+        
+        Record.push_back(NumPreprocessingRecords++);
+        Record.push_back(ID);
+        AddSourceLocation(MD->getSourceRange().getBegin(), Record);
+        AddSourceLocation(MD->getSourceRange().getEnd(), Record);
+        AddIdentifierRef(MD->getName(), Record);
+        AddSourceLocation(MD->getLocation(), Record);
+        Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record);
+        continue;
+      }
+    }
+  }
+  
   Stream.ExitBlock();
+  
+  // Write the offsets table for the preprocessing record.
+  if (NumPreprocessingRecords > 0) {
+    // Write the offsets table for identifier IDs.
+    using namespace llvm;
+    BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+    Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS));
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs
+    Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+    unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+    
+    Record.clear();
+    Record.push_back(pch::MACRO_DEFINITION_OFFSETS);
+    Record.push_back(NumPreprocessingRecords);
+    Record.push_back(MacroDefinitionOffsets.size());
+    Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record,
+                              (const char *)&MacroDefinitionOffsets.front(),
+                              MacroDefinitionOffsets.size() * sizeof(uint32_t));
+  }
 }
 
 void PCHWriter::WriteComments(ASTContext &Context) {
@@ -2009,7 +2082,7 @@
 
   // Write the remaining PCH contents.
   RecordData Record;
-  Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
+  Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
   WriteMetadata(Context, isysroot);
   WriteLanguageOptions(Context.getLangOptions());
   if (StatCalls && !isysroot)
@@ -2149,6 +2222,16 @@
   return ID;
 }
 
+pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) {
+  if (MD == 0)
+    return 0;
+  
+  pch::IdentID &ID = MacroDefinitions[MD];
+  if (ID == 0)
+    ID = MacroDefinitions.size();
+  return ID;
+}
+
 void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
   if (SelRef.getAsOpaquePtr() == 0) {
     Record.push_back(0);

Modified: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PreprocessingRecord.cpp?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PreprocessingRecord.cpp (original)
+++ cfe/trunk/lib/Lex/PreprocessingRecord.cpp Fri Mar 19 16:51:54 2010
@@ -17,10 +17,81 @@
 
 using namespace clang;
 
+ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
+
+void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
+  if (!ExternalSource || LoadedPreallocatedEntities)
+    return;
+  
+  LoadedPreallocatedEntities = true;
+  ExternalSource->ReadPreprocessedEntities();
+}
+
+PreprocessingRecord::PreprocessingRecord()
+  : ExternalSource(0), NumPreallocatedEntities(0), 
+    LoadedPreallocatedEntities(false)
+{
+}
+
+PreprocessingRecord::iterator 
+PreprocessingRecord::begin(bool OnlyLocalEntities) {
+  if (OnlyLocalEntities)
+    return PreprocessedEntities.begin() + NumPreallocatedEntities;
+  
+  MaybeLoadPreallocatedEntities();
+  return PreprocessedEntities.begin();
+}
+
+PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) {
+  if (!OnlyLocalEntities)
+    MaybeLoadPreallocatedEntities();
+  
+  return PreprocessedEntities.end();
+}
+
+PreprocessingRecord::const_iterator 
+PreprocessingRecord::begin(bool OnlyLocalEntities) const {
+  if (OnlyLocalEntities)
+    return PreprocessedEntities.begin() + NumPreallocatedEntities;
+  
+  MaybeLoadPreallocatedEntities();
+  return PreprocessedEntities.begin();
+}
+
+PreprocessingRecord::const_iterator 
+PreprocessingRecord::end(bool OnlyLocalEntities) const {
+  if (!OnlyLocalEntities)
+    MaybeLoadPreallocatedEntities();
+  
+  return PreprocessedEntities.end();
+}
+
 void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
   PreprocessedEntities.push_back(Entity);
 }
 
+void PreprocessingRecord::SetExternalSource(
+                                    ExternalPreprocessingRecordSource &Source,
+                                            unsigned NumPreallocatedEntities) {
+  assert(!ExternalSource &&
+         "Preprocessing record already has an external source");
+  ExternalSource = &Source;
+  this->NumPreallocatedEntities = NumPreallocatedEntities;
+  PreprocessedEntities.insert(PreprocessedEntities.begin(), 
+                              NumPreallocatedEntities, 0);
+}
+
+void PreprocessingRecord::SetPreallocatedEntity(unsigned Index, 
+                                                PreprocessedEntity *Entity) {
+  assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity");
+  PreprocessedEntities[Index] = Entity;
+}
+
+void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, 
+                                                  MacroDefinition *MD) {
+  MacroDefinitions[Macro] = MD;
+}
+
 MacroDefinition *PreprocessingRecord::findMacroDefinition(MacroInfo *MI) {
   llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
     = MacroDefinitions.find(MI);
@@ -45,3 +116,4 @@
   MacroDefinitions[MI] = Def;
   PreprocessedEntities.push_back(Def);
 }
+

Modified: cfe/trunk/test/Index/c-index-getCursor-test.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/c-index-getCursor-test.m?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/test/Index/c-index-getCursor-test.m (original)
+++ cfe/trunk/test/Index/c-index-getCursor-test.m Fri Mar 19 16:51:54 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -o %t.ast
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -emit-pch -x objective-c %s -detailed-preprocessing-record -o %t.ast
 // RUN: c-index-test -test-file-scan %t.ast %s | FileCheck %s
 @interface Foo 
 {
@@ -161,3 +161,7 @@
 // CHECK: [52:33 - 52:36] DeclRefExpr=bee:45:8
 // CHECK: [52:36 - 52:37] CallExpr=main:44:5
 // CHECK: [52:37 - 53:2] UnexposedStmt=
+// CHECK: [55:9 - 55:26] macro definition=CONCAT
+// CHECK: [57:6 - 57:10] FunctionDecl=f:57:6 (Definition)
+// CHECK: [58:4 - 58:8] VarDecl=my_var:58:8 (Definition)
+// CHECK: [58:8 - 58:14] macro instantiation=CONCAT:55:9

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=99002&r1=99001&r2=99002&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Fri Mar 19 16:51:54 2010
@@ -158,31 +158,12 @@
 CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
                                           const LangOptions &LangOpts,
                                           SourceRange R) {
-  // FIXME: This is largely copy-paste from
-  // TextDiagnosticPrinter::HighlightRange.  When it is clear that this is what
-  // we want the two routines should be refactored.
-
   // We want the last character in this location, so we will adjust the
-  // instantiation location accordingly.
-
-  // If the location is from a macro instantiation, get the end of the
-  // instantiation range.
+  // location accordingly.
+  // FIXME: How do do this with a macro instantiation location?
   SourceLocation EndLoc = R.getEnd();
-  SourceLocation InstLoc = SM.getInstantiationLoc(EndLoc);
-  if (EndLoc.isMacroID())
-    InstLoc = SM.getInstantiationRange(EndLoc).second;
-
-  // Measure the length token we're pointing at, so we can adjust the physical
-  // location in the file to point at the last character.
-  //
-  // FIXME: This won't cope with trigraphs or escaped newlines well. For that,
-  // we actually need a preprocessor, which isn't currently available
-  // here. Eventually, we'll switch the pointer data of
-  // CXSourceLocation/CXSourceRange to a translation unit (CXXUnit), so that the
-  // preprocessor will be available here. At that point, we can use
-  // Preprocessor::getLocForEndOfToken().
-  if (InstLoc.isValid()) {
-    unsigned Length = Lexer::MeasureTokenLength(InstLoc, SM, LangOpts);
+  if (!EndLoc.isInvalid() && EndLoc.isFileID()) {
+    unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
     EndLoc = EndLoc.getFileLocWithOffset(Length);
   }
 
@@ -434,7 +415,11 @@
                        = CXXUnit->getPreprocessor().getPreprocessingRecord()) {
       // FIXME: Once we have the ability to deserialize a preprocessing record,
       // do so.
-      for (PreprocessingRecord::iterator E = PPRec->begin(),EEnd = PPRec->end();
+      bool OnlyLocalDecls
+        = !CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls();
+      for (PreprocessingRecord::iterator 
+             E = PPRec->begin(OnlyLocalDecls), 
+             EEnd = PPRec->end(OnlyLocalDecls);
            E != EEnd; ++E) {
         if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
           if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit)))





More information about the cfe-commits mailing list