]> granicus.if.org Git - clang/blobdiff - include/clang/AST/ExternalASTSource.h
Header guard canonicalization, clang part.
[clang] / include / clang / AST / ExternalASTSource.h
index db8a97034fc4f2b34479b651b69c12917b59b0b4..ff1d180ee8c611a568b5d0de36b86e209f1ab8c3 100644 (file)
@@ -8,34 +8,42 @@
 //===----------------------------------------------------------------------===//
 //
 //  This file defines the ExternalASTSource interface, which enables
-//  construction of AST nodes from some external source.x
+//  construction of AST nodes from some external source.
 //
 //===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
-#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#ifndef LLVM_CLANG_AST_EXTERNALASTSOURCE_H
+#define LLVM_CLANG_AST_EXTERNALASTSOURCE_H
+
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclBase.h"
+#include "llvm/ADT/DenseMap.h"
 
-#include "clang/AST/DeclarationName.h"
-#include "clang/AST/Type.h"
-#include "llvm/ADT/SmallVector.h"
-#include <cassert>
 namespace clang {
 
 class ASTConsumer;
-class Decl;
-class DeclContext;
+class CXXBaseSpecifier;
+class DeclarationName;
 class ExternalSemaSource; // layering violation required for downcasting
+class FieldDecl;
+class Module;
+class NamedDecl;
+class RecordDecl;
+class Selector;
 class Stmt;
+class TagDecl;
 
-/// \brief The deserialized representation of a set of declarations
-/// with the same name that are visible in a given context.
-struct VisibleDeclaration {
-  /// \brief The name of the declarations.
-  DeclarationName Name;
-
-  /// \brief The ID numbers of all of the declarations with this name. 
-  ///
-  /// These declarations have not necessarily been de-serialized.
-  llvm::SmallVector<unsigned, 4> Declarations;
+/// \brief Enumeration describing the result of loading information from
+/// an external source.
+enum ExternalLoadResult {
+  /// \brief Loading the external information has succeeded.
+  ELR_Success,
+  
+  /// \brief Loading the external information has failed.
+  ELR_Failure,
+  
+  /// \brief The external information has already been loaded, and therefore
+  /// no additional processing is required.
+  ELR_AlreadyLoaded
 };
 
 /// \brief Abstract interface for external sources of AST nodes.
@@ -45,7 +53,11 @@ struct VisibleDeclaration {
 /// sources can resolve types and declarations from abstract IDs into
 /// actual type and declaration nodes, and read parts of declaration
 /// contexts.
-class ExternalASTSource {
+class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
+  /// Generation number for this external AST source. Must be increased
+  /// whenever we might have added new redeclarations for existing decls.
+  uint32_t CurrentGeneration;
+
   /// \brief Whether this AST source also provides information for
   /// semantic analysis.
   bool SemaSource;
@@ -53,64 +65,240 @@ class ExternalASTSource {
   friend class ExternalSemaSource;
 
 public:
-  ExternalASTSource() : SemaSource(false) { }
+  ExternalASTSource() : CurrentGeneration(0), SemaSource(false) { }
 
   virtual ~ExternalASTSource();
 
-  /// \brief Resolve a type ID into a type, potentially building a new
-  /// type.
-  virtual QualType GetType(unsigned ID) = 0;
+  /// \brief RAII class for safely pairing a StartedDeserializing call
+  /// with FinishedDeserializing.
+  class Deserializing {
+    ExternalASTSource *Source;
+  public:
+    explicit Deserializing(ExternalASTSource *source) : Source(source) {
+      assert(Source);
+      Source->StartedDeserializing();
+    }
+    ~Deserializing() {
+      Source->FinishedDeserializing();
+    }
+  };
+
+  /// \brief Get the current generation of this AST source. This number
+  /// is incremented each time the AST source lazily extends an existing
+  /// entity.
+  uint32_t getGeneration() const { return CurrentGeneration; }
 
   /// \brief Resolve a declaration ID into a declaration, potentially
   /// building a new declaration.
-  virtual Decl *GetDecl(unsigned ID) = 0;
+  ///
+  /// This method only needs to be implemented if the AST source ever
+  /// passes back decl sets as VisibleDeclaration objects.
+  ///
+  /// The default implementation of this method is a no-op.
+  virtual Decl *GetExternalDecl(uint32_t ID);
+
+  /// \brief Resolve a selector ID into a selector.
+  ///
+  /// This operation only needs to be implemented if the AST source
+  /// returns non-zero for GetNumKnownSelectors().
+  ///
+  /// The default implementation of this method is a no-op.
+  virtual Selector GetExternalSelector(uint32_t ID);
 
-  /// \brief Resolve the offset of a statement in the decl stream into a
-  /// statement.
+  /// \brief Returns the number of selectors known to the external AST
+  /// source.
   ///
-  /// This operation will read a new statement from the external
-  /// source each time it is called, and is meant to be used via a
-  /// LazyOffsetPtr.
-  virtual Stmt *GetDeclStmt(uint64_t Offset) = 0;
+  /// The default implementation of this method is a no-op.
+  virtual uint32_t GetNumExternalSelectors();
 
-  /// \brief Read all of the declarations lexically stored in a
-  /// declaration context.
+  /// \brief Resolve the offset of a statement in the decl stream into
+  /// a statement.
   ///
-  /// \param DC The declaration context whose declarations will be
-  /// read.
+  /// This operation is meant to be used via a LazyOffsetPtr.  It only
+  /// needs to be implemented if the AST source uses methods like
+  /// FunctionDecl::setLazyBody when building decls.
   ///
-  /// \param Decls Vector that will contain the declarations loaded
-  /// from the external source. The caller is responsible for merging
-  /// these declarations with any declarations already stored in the
-  /// declaration context.
+  /// The default implementation of this method is a no-op.
+  virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
+
+  /// \brief Resolve the offset of a set of C++ base specifiers in the decl
+  /// stream into an array of specifiers.
   ///
-  /// \returns true if there was an error while reading the
-  /// declarations for this declaration context.
-  virtual bool ReadDeclsLexicallyInContext(DeclContext *DC,
-                                  llvm::SmallVectorImpl<unsigned> &Decls) = 0;
+  /// The default implementation of this method is a no-op.
+  virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
+
+  /// \brief Update an out-of-date identifier.
+  virtual void updateOutOfDateIdentifier(IdentifierInfo &II) { }
+
+  /// \brief Find all declarations with the given name in the given context,
+  /// and add them to the context by calling SetExternalVisibleDeclsForName
+  /// or SetNoExternalVisibleDeclsForName.
+  /// \return \c true if any declarations might have been found, \c false if
+  /// we definitely have no declarations with tbis name.
+  ///
+  /// The default implementation of this method is a no-op returning \c false.
+  virtual bool
+  FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
+
+  /// \brief Ensures that the table of all visible declarations inside this
+  /// context is up to date.
+  ///
+  /// The default implementation of this function is a no-op.
+  virtual void completeVisibleDeclsMap(const DeclContext *DC);
+
+  /// \brief Retrieve the module that corresponds to the given module ID.
+  virtual Module *getModule(unsigned ID) { return nullptr; }
+
+  /// \brief Finds all declarations lexically contained within the given
+  /// DeclContext, after applying an optional filter predicate.
+  ///
+  /// \param isKindWeWant a predicate function that returns true if the passed
+  /// declaration kind is one we are looking for. If NULL, all declarations
+  /// are returned.
+  ///
+  /// \return an indication of whether the load succeeded or failed.
+  ///
+  /// The default implementation of this method is a no-op.
+  virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
+                                        bool (*isKindWeWant)(Decl::Kind),
+                                        SmallVectorImpl<Decl*> &Result);
+
+  /// \brief Finds all declarations lexically contained within the given
+  /// DeclContext.
+  ///
+  /// \return true if an error occurred
+  ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
+                                SmallVectorImpl<Decl*> &Result) {
+    return FindExternalLexicalDecls(DC, nullptr, Result);
+  }
+
+  template <typename DeclTy>
+  ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC,
+                                  SmallVectorImpl<Decl*> &Result) {
+    return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result);
+  }
+
+  /// \brief Get the decls that are contained in a file in the Offset/Length
+  /// range. \p Length can be 0 to indicate a point at \p Offset instead of
+  /// a range.
+  virtual void FindFileRegionDecls(FileID File, unsigned Offset,
+                                   unsigned Length,
+                                   SmallVectorImpl<Decl *> &Decls);
 
-  /// \brief Read all of the declarations visible from a declaration
-  /// context.
+  /// \brief Gives the external AST source an opportunity to complete
+  /// the redeclaration chain for a declaration. Called each time we
+  /// need the most recent declaration of a declaration after the
+  /// generation count is incremented.
+  virtual void CompleteRedeclChain(const Decl *D);
+
+  /// \brief Gives the external AST source an opportunity to complete
+  /// an incomplete type.
+  virtual void CompleteType(TagDecl *Tag);
+
+  /// \brief Gives the external AST source an opportunity to complete an
+  /// incomplete Objective-C class.
   ///
-  /// \param DC The declaration context whose visible declarations
-  /// will be read.
+  /// This routine will only be invoked if the "externally completed" bit is
+  /// set on the ObjCInterfaceDecl via the function
+  /// \c ObjCInterfaceDecl::setExternallyCompleted().
+  virtual void CompleteType(ObjCInterfaceDecl *Class);
+
+  /// \brief Loads comment ranges.
+  virtual void ReadComments();
+
+  /// \brief Notify ExternalASTSource that we started deserialization of
+  /// a decl or type so until FinishedDeserializing is called there may be
+  /// decls that are initializing. Must be paired with FinishedDeserializing.
   ///
-  /// \param Decls A vector of visible declaration structures,
-  /// providing the mapping from each name visible in the declaration
-  /// context to the declaration IDs of declarations with that name.
+  /// The default implementation of this method is a no-op.
+  virtual void StartedDeserializing();
+
+  /// \brief Notify ExternalASTSource that we finished the deserialization of
+  /// a decl or type. Must be paired with StartedDeserializing.
   ///
-  /// \returns true if there was an error while reading the
-  /// declarations for this declaration context.
-  virtual bool ReadDeclsVisibleInContext(DeclContext *DC,
-                       llvm::SmallVectorImpl<VisibleDeclaration> & Decls) = 0;
+  /// The default implementation of this method is a no-op.
+  virtual void FinishedDeserializing();
 
   /// \brief Function that will be invoked when we begin parsing a new
   /// translation unit involving this external AST source.
-  virtual void StartTranslationUnit(ASTConsumer *Consumer) { }
+  ///
+  /// The default implementation of this method is a no-op.
+  virtual void StartTranslationUnit(ASTConsumer *Consumer);
 
   /// \brief Print any statistics that have been gathered regarding
   /// the external AST source.
+  ///
+  /// The default implementation of this method is a no-op.
   virtual void PrintStats();
+  
+  
+  /// \brief Perform layout on the given record.
+  ///
+  /// This routine allows the external AST source to provide an specific 
+  /// layout for a record, overriding the layout that would normally be
+  /// constructed. It is intended for clients who receive specific layout
+  /// details rather than source code (such as LLDB). The client is expected
+  /// to fill in the field offsets, base offsets, virtual base offsets, and
+  /// complete object size.
+  ///
+  /// \param Record The record whose layout is being requested.
+  ///
+  /// \param Size The final size of the record, in bits.
+  ///
+  /// \param Alignment The final alignment of the record, in bits.
+  ///
+  /// \param FieldOffsets The offset of each of the fields within the record,
+  /// expressed in bits. All of the fields must be provided with offsets.
+  ///
+  /// \param BaseOffsets The offset of each of the direct, non-virtual base
+  /// classes. If any bases are not given offsets, the bases will be laid 
+  /// out according to the ABI.
+  ///
+  /// \param VirtualBaseOffsets The offset of each of the virtual base classes
+  /// (either direct or not). If any bases are not given offsets, the bases will be laid 
+  /// out according to the ABI.
+  /// 
+  /// \returns true if the record layout was provided, false otherwise.
+  virtual bool layoutRecordType(
+      const RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+      llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
+      llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
+      llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets);
+
+  //===--------------------------------------------------------------------===//
+  // Queries for performance analysis.
+  //===--------------------------------------------------------------------===//
+  
+  struct MemoryBufferSizes {
+    size_t malloc_bytes;
+    size_t mmap_bytes;
+    
+    MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
+    : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
+  };
+  
+  /// Return the amount of memory used by memory buffers, breaking down
+  /// by heap-backed versus mmap'ed memory.
+  MemoryBufferSizes getMemoryBufferSizes() const {
+    MemoryBufferSizes sizes(0, 0);
+    getMemoryBufferSizes(sizes);
+    return sizes;
+  }
+
+  virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
+
+protected:
+  static DeclContextLookupResult
+  SetExternalVisibleDeclsForName(const DeclContext *DC,
+                                 DeclarationName Name,
+                                 ArrayRef<NamedDecl*> Decls);
+
+  static DeclContextLookupResult
+  SetNoExternalVisibleDeclsForName(const DeclContext *DC,
+                                   DeclarationName Name);
+
+  /// \brief Increment the current generation.
+  uint32_t incrementGeneration(ASTContext &C);
 };
 
 /// \brief A lazy pointer to an AST node (of base type T) that resides
@@ -119,7 +307,7 @@ public:
 /// The AST node is identified within the external AST source by a
 /// 63-bit offset, and can be retrieved via an operation on the
 /// external AST source itself.
-template<typename T, T* (ExternalASTSource::*Get)(uint64_t Offset)>
+template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)>
 struct LazyOffsetPtr {
   /// \brief Either a pointer to an AST node or the offset within the
   /// external AST source where the AST node can be found.
@@ -142,7 +330,7 @@ public:
     this->Ptr = reinterpret_cast<uint64_t>(Ptr);
     return *this;
   }
-  
+
   LazyOffsetPtr &operator=(uint64_t Offset) {
     assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits");
     if (Offset == 0)
@@ -156,7 +344,12 @@ public:
   /// \brief Whether this pointer is non-NULL.
   ///
   /// This operation does not require the AST node to be deserialized.
-  operator bool() const { return Ptr != 0; }
+  LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
+
+  /// \brief Whether this pointer is non-NULL.
+  ///
+  /// This operation does not require the AST node to be deserialized.
+  bool isValid() const { return Ptr != 0; }
 
   /// \brief Whether this pointer is currently stored as an offset.
   bool isOffset() const { return Ptr & 0x01; }
@@ -168,7 +361,7 @@ public:
   /// \returns a pointer to the AST node.
   T* get(ExternalASTSource *Source) const {
     if (isOffset()) {
-      assert(Source && 
+      assert(Source &&
              "Cannot deserialize a lazy pointer without an AST source");
       Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
     }
@@ -176,9 +369,285 @@ public:
   }
 };
 
+/// \brief A lazy value (of type T) that is within an AST node of type Owner,
+/// where the value might change in later generations of the external AST
+/// source.
+template<typename Owner, typename T, void (ExternalASTSource::*Update)(Owner)>
+struct LazyGenerationalUpdatePtr {
+  /// A cache of the value of this pointer, in the most recent generation in
+  /// which we queried it.
+  struct LazyData {
+    LazyData(ExternalASTSource *Source, T Value)
+        : ExternalSource(Source), LastGeneration(0), LastValue(Value) {}
+    ExternalASTSource *ExternalSource;
+    uint32_t LastGeneration;
+    T LastValue;
+  };
+
+  // Our value is represented as simply T if there is no external AST source.
+  typedef llvm::PointerUnion<T, LazyData*> ValueType;
+  ValueType Value;
+
+  LazyGenerationalUpdatePtr(ValueType V) : Value(V) {}
+
+  // Defined in ASTContext.h
+  static ValueType makeValue(const ASTContext &Ctx, T Value);
+
+public:
+  explicit LazyGenerationalUpdatePtr(const ASTContext &Ctx, T Value = T())
+      : Value(makeValue(Ctx, Value)) {}
+
+  /// Create a pointer that is not potentially updated by later generations of
+  /// the external AST source.
+  enum NotUpdatedTag { NotUpdated };
+  LazyGenerationalUpdatePtr(NotUpdatedTag, T Value = T())
+      : Value(Value) {}
+
+  /// Forcibly set this pointer (which must be lazy) as needing updates.
+  void markIncomplete() {
+    Value.template get<LazyData *>()->LastGeneration = 0;
+  }
+
+  /// Set the value of this pointer, in the current generation.
+  void set(T NewValue) {
+    if (LazyData *LazyVal = Value.template dyn_cast<LazyData*>()) {
+      LazyVal->LastValue = NewValue;
+      return;
+    }
+    Value = NewValue;
+  }
+
+  /// Set the value of this pointer, for this and all future generations.
+  void setNotUpdated(T NewValue) { Value = NewValue; }
+
+  /// Get the value of this pointer, updating its owner if necessary.
+  T get(Owner O) {
+    if (LazyData *LazyVal = Value.template dyn_cast<LazyData*>()) {
+      if (LazyVal->LastGeneration != LazyVal->ExternalSource->getGeneration()) {
+        LazyVal->LastGeneration = LazyVal->ExternalSource->getGeneration();
+        (LazyVal->ExternalSource->*Update)(O);
+      }
+      return LazyVal->LastValue;
+    }
+    return Value.template get<T>();
+  }
+
+  /// Get the most recently computed value of this pointer without updating it.
+  T getNotUpdated() const {
+    if (LazyData *LazyVal = Value.template dyn_cast<LazyData*>())
+      return LazyVal->LastValue;
+    return Value.template get<T>();
+  }
+
+  void *getOpaqueValue() { return Value.getOpaqueValue(); }
+  static LazyGenerationalUpdatePtr getFromOpaqueValue(void *Ptr) {
+    return LazyGenerationalUpdatePtr(ValueType::getFromOpaqueValue(Ptr));
+  }
+};
+} // end namespace clang
+
+/// Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be
+/// placed into a PointerUnion.
+namespace llvm {
+template<typename Owner, typename T,
+         void (clang::ExternalASTSource::*Update)(Owner)>
+struct PointerLikeTypeTraits<
+    clang::LazyGenerationalUpdatePtr<Owner, T, Update>> {
+  typedef clang::LazyGenerationalUpdatePtr<Owner, T, Update> Ptr;
+  static void *getAsVoidPointer(Ptr P) { return P.getOpaqueValue(); }
+  static Ptr getFromVoidPointer(void *P) { return Ptr::getFromOpaqueValue(P); }
+  enum {
+    NumLowBitsAvailable = PointerLikeTypeTraits<T>::NumLowBitsAvailable - 1
+  };
+};
+}
+
+namespace clang {
+/// \brief Represents a lazily-loaded vector of data.
+///
+/// The lazily-loaded vector of data contains data that is partially loaded
+/// from an external source and partially added by local translation. The 
+/// items loaded from the external source are loaded lazily, when needed for
+/// iteration over the complete vector.
+template<typename T, typename Source, 
+         void (Source::*Loader)(SmallVectorImpl<T>&),
+         unsigned LoadedStorage = 2, unsigned LocalStorage = 4>
+class LazyVector {
+  SmallVector<T, LoadedStorage> Loaded;
+  SmallVector<T, LocalStorage> Local;
+
+public:
+  // Iteration over the elements in the vector.
+  class iterator {
+    LazyVector *Self;
+    
+    /// \brief Position within the vector..
+    ///
+    /// In a complete iteration, the Position field walks the range [-M, N),
+    /// where negative values are used to indicate elements
+    /// loaded from the external source while non-negative values are used to
+    /// indicate elements added via \c push_back().
+    /// However, to provide iteration in source order (for, e.g., chained
+    /// precompiled headers), dereferencing the iterator flips the negative
+    /// values (corresponding to loaded entities), so that position -M 
+    /// corresponds to element 0 in the loaded entities vector, position -M+1
+    /// corresponds to element 1 in the loaded entities vector, etc. This
+    /// gives us a reasonably efficient, source-order walk.
+    int Position;
+    
+    friend class LazyVector;
+    
+  public:
+    typedef T                   value_type;
+    typedef value_type&         reference;
+    typedef value_type*         pointer;
+    typedef std::random_access_iterator_tag iterator_category;
+    typedef int                 difference_type;
+    
+    iterator() : Self(0), Position(0) { }
+    
+    iterator(LazyVector *Self, int Position) 
+      : Self(Self), Position(Position) { }
+    
+    reference operator*() const {
+      if (Position < 0)
+        return Self->Loaded.end()[Position];
+      return Self->Local[Position];
+    }
+    
+    pointer operator->() const {
+      if (Position < 0)
+        return &Self->Loaded.end()[Position];
+      
+      return &Self->Local[Position];        
+    }
+    
+    reference operator[](difference_type D) {
+      return *(*this + D);
+    }
+    
+    iterator &operator++() {
+      ++Position;
+      return *this;
+    }
+    
+    iterator operator++(int) {
+      iterator Prev(*this);
+      ++Position;
+      return Prev;
+    }
+    
+    iterator &operator--() {
+      --Position;
+      return *this;
+    }
+    
+    iterator operator--(int) {
+      iterator Prev(*this);
+      --Position;
+      return Prev;
+    }
+    
+    friend bool operator==(const iterator &X, const iterator &Y) {
+      return X.Position == Y.Position;
+    }
+    
+    friend bool operator!=(const iterator &X, const iterator &Y) {
+      return X.Position != Y.Position;
+    }
+    
+    friend bool operator<(const iterator &X, const iterator &Y) {
+      return X.Position < Y.Position;
+    }
+    
+    friend bool operator>(const iterator &X, const iterator &Y) {
+      return X.Position > Y.Position;
+    }
+    
+    friend bool operator<=(const iterator &X, const iterator &Y) {
+      return X.Position < Y.Position;
+    }
+    
+    friend bool operator>=(const iterator &X, const iterator &Y) {
+      return X.Position > Y.Position;
+    }
+    
+    friend iterator& operator+=(iterator &X, difference_type D) {
+      X.Position += D;
+      return X;
+    }
+    
+    friend iterator& operator-=(iterator &X, difference_type D) {
+      X.Position -= D;
+      return X;
+    }
+    
+    friend iterator operator+(iterator X, difference_type D) {
+      X.Position += D;
+      return X;
+    }
+    
+    friend iterator operator+(difference_type D, iterator X) {
+      X.Position += D;
+      return X;
+    }
+    
+    friend difference_type operator-(const iterator &X, const iterator &Y) {
+      return X.Position - Y.Position;
+    }
+    
+    friend iterator operator-(iterator X, difference_type D) {
+      X.Position -= D;
+      return X;
+    }
+  };
+  friend class iterator;
+  
+  iterator begin(Source *source, bool LocalOnly = false) {
+    if (LocalOnly)
+      return iterator(this, 0);
+    
+    if (source)
+      (source->*Loader)(Loaded);
+    return iterator(this, -(int)Loaded.size());
+  }
+  
+  iterator end() {
+    return iterator(this, Local.size());
+  }
+  
+  void push_back(const T& LocalValue) {
+    Local.push_back(LocalValue);
+  }
+  
+  void erase(iterator From, iterator To) {
+    if (From.Position < 0 && To.Position < 0) {
+      Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position);
+      return;
+    }
+    
+    if (From.Position < 0) {
+      Loaded.erase(Loaded.end() + From.Position, Loaded.end());
+      From = begin(nullptr, true);
+    }
+    
+    Local.erase(Local.begin() + From.Position, Local.begin() + To.Position);
+  }
+};
+
 /// \brief A lazy pointer to a statement.
-typedef LazyOffsetPtr<Stmt, &ExternalASTSource::GetDeclStmt> LazyDeclStmtPtr;
+typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt>
+  LazyDeclStmtPtr;
+
+/// \brief A lazy pointer to a declaration.
+typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>
+  LazyDeclPtr;
+
+/// \brief A lazy pointer to a set of CXXBaseSpecifiers.
+typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, 
+                      &ExternalASTSource::GetExternalCXXBaseSpecifiers>
+  LazyCXXBaseSpecifiersPtr;
 
 } // end namespace clang
 
-#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
+#endif