class DeclContext;
class Diagnostic;
class Expr;
+ class FileManager;
class IdentifierInfo;
class NestedNameSpecifier;
class Stmt;
/// \brief The contexts we're importing to and from.
ASTContext &ToContext, &FromContext;
+ /// \brief The file managers we're importing to and from.
+ FileManager &ToFileManager, &FromFileManager;
+
/// \brief The diagnostics object that we should use to emit diagnostics
/// within the context we're importing to and from.
Diagnostic &ToDiags, &FromDiags;
/// context to the corresponding declarations in the "to" context.
llvm::DenseMap<Decl *, Decl *> ImportedDecls;
+ /// \brief Mapping from the already-imported FileIDs in the "from" source
+ /// manager to the corresponding FileIDs in the "to" source manager.
+ llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
+
public:
- ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
- ASTContext &FromContext, Diagnostic &FromDiags);
+ ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+ Diagnostic &ToDiags,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ Diagnostic &FromDiags);
virtual ~ASTImporter();
/// \returns the equivalent nested-name-specifier in the "to"
/// context, or NULL if an error occurred.
NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS);
-
+
/// \brief Import the given source location from the "from" context into
/// the "to" context.
///
/// \returns the equivalent identifier in the "to" context.
IdentifierInfo *Import(IdentifierInfo *FromId);
+ /// \brief Import the given file ID from the "from" context into the
+ /// "to" context.
+ ///
+ /// \returns the equivalent file ID in the source manager of the "to"
+ /// context.
+ FileID Import(FileID);
+
/// \brief Cope with a name conflict when importing a declaration into the
/// given context.
///
/// \brief Retrieve the context that AST nodes are being imported from.
ASTContext &getFromContext() const { return FromContext; }
+ /// \brief Retrieve the file manager that AST nodes are being imported into.
+ FileManager &getToFileManager() const { return ToFileManager; }
+
+ /// \brief Retrieve the file manager that AST nodes are being imported from.
+ FileManager &getFromFileManager() const { return FromFileManager; }
+
/// \brief Retrieve the diagnostics object to use to report errors within
/// the context we're importing into.
Diagnostic &getToDiags() const { return ToDiags; }
#include "clang/AST/ASTImporter.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeVisitor.h"
-#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
// Import Declarations
//----------------------------------------------------------------------------
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
- Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
+ Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
return 0;
}
return ToVar;
}
-ASTImporter::ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
- ASTContext &FromContext, Diagnostic &FromDiags)
+ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+ Diagnostic &ToDiags,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ Diagnostic &FromDiags)
: ToContext(ToContext), FromContext(FromContext),
+ ToFileManager(ToFileManager), FromFileManager(FromFileManager),
ToDiags(ToDiags), FromDiags(FromDiags) {
ImportedDecls[FromContext.getTranslationUnitDecl()]
= ToContext.getTranslationUnitDecl();
if (FromLoc.isInvalid())
return SourceLocation();
- // FIXME: Implement!
- return SourceLocation();
+ SourceManager &FromSM = FromContext.getSourceManager();
+
+ // For now, map everything down to its spelling location, so that we
+ // don't have to import macro instantiations.
+ // FIXME: Import macro instantiations!
+ FromLoc = FromSM.getSpellingLoc(FromLoc);
+ std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc);
+ SourceManager &ToSM = ToContext.getSourceManager();
+ return ToSM.getLocForStartOfFile(Import(Decomposed.first))
+ .getFileLocWithOffset(Decomposed.second);
}
SourceRange ASTImporter::Import(SourceRange FromRange) {
return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd()));
}
+FileID ASTImporter::Import(FileID FromID) {
+ llvm::DenseMap<unsigned, FileID>::iterator Pos
+ = ImportedFileIDs.find(FromID.getHashValue());
+ if (Pos != ImportedFileIDs.end())
+ return Pos->second;
+
+ SourceManager &FromSM = FromContext.getSourceManager();
+ SourceManager &ToSM = ToContext.getSourceManager();
+ const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID);
+ assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet");
+
+ // Include location of this file.
+ SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc());
+
+ // Map the FileID for to the "to" source manager.
+ FileID ToID;
+ const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache();
+ if (Cache->Entry) {
+ // FIXME: We probably want to use getVirtualFile(), so we don't hit the
+ // disk again
+ // FIXME: We definitely want to re-use the existing MemoryBuffer, rather
+ // than mmap the files several times.
+ const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName());
+ ToID = ToSM.createFileID(Entry, ToIncludeLoc,
+ FromSLoc.getFile().getFileCharacteristic());
+ } else {
+ // FIXME: We want to re-use the existing MemoryBuffer!
+ const llvm::MemoryBuffer *FromBuf = Cache->getBuffer();
+ llvm::MemoryBuffer *ToBuf
+ = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(),
+ FromBuf->getBufferEnd(),
+ FromBuf->getBufferIdentifier());
+ ToID = ToSM.createFileIDForMemBuffer(ToBuf);
+ }
+
+
+ ImportedFileIDs[FromID.getHashValue()] = ToID;
+ return ToID;
+}
+
DeclarationName ASTImporter::Import(DeclarationName FromName) {
if (!FromName)
return DeclarationName();